mls_crypto_provider/
crypto_provider.rs

1use std::sync::{Arc, RwLock, RwLockWriteGuard};
2
3use aes_gcm::{
4    Aes128Gcm, Aes256Gcm, KeyInit,
5    aead::{Aead, Payload},
6};
7use chacha20poly1305::ChaCha20Poly1305;
8use hkdf::Hkdf;
9use openmls_traits::{
10    crypto::OpenMlsCrypto,
11    random::OpenMlsRand,
12    types::{
13        self, AeadType, Ciphersuite, CryptoError, ExporterSecret, HashType, HpkeAeadType, HpkeConfig, HpkeKdfType,
14        HpkeKemType, SignatureScheme,
15    },
16};
17use rand_core::{RngCore, SeedableRng};
18use sha2::{Digest, Sha256, Sha384, Sha512};
19use signature::digest::typenum::Unsigned;
20use tls_codec::SecretVLBytes;
21
22use crate::{EntropySeed, MlsProviderError};
23
24#[derive(Debug, Clone)]
25pub struct RustCrypto {
26    pub(crate) rng: Arc<RwLock<rand_chacha::ChaCha20Rng>>,
27}
28
29impl Default for RustCrypto {
30    fn default() -> Self {
31        Self {
32            rng: Arc::new(rand_chacha::ChaCha20Rng::from_entropy().into()),
33        }
34    }
35}
36
37#[inline]
38fn normalize_p521_secret_key(sk: &[u8]) -> zeroize::Zeroizing<[u8; 66]> {
39    let mut sk_buf = zeroize::Zeroizing::new([0u8; 66]);
40    sk_buf[66 - sk.len()..].copy_from_slice(sk);
41    sk_buf
42}
43
44impl RustCrypto {
45    pub fn new_with_seed(seed: EntropySeed) -> Self {
46        Self {
47            rng: Arc::new(rand_chacha::ChaCha20Rng::from_seed(seed.0).into()),
48        }
49    }
50
51    pub fn reseed(&self, seed: Option<EntropySeed>) -> Result<(), MlsProviderError> {
52        let mut val = self.rng.write().map_err(|_| MlsProviderError::RngLockPoison)?;
53        *val = rand_chacha::ChaCha20Rng::from_seed(seed.unwrap_or_default().0);
54        Ok(())
55    }
56
57    pub fn normalize_p521_secret_key(sk: &[u8]) -> zeroize::Zeroizing<[u8; 66]> {
58        normalize_p521_secret_key(sk)
59    }
60
61    pub fn normalize_ed25519_key(key: &[u8]) -> Result<ed25519_dalek::SigningKey, CryptoError> {
62        let k = match key.len() {
63            // Compat layer for legacy keypairs [seed, pk]
64            ed25519_dalek::KEYPAIR_LENGTH => {
65                let mut sk = zeroize::Zeroizing::new([0u8; ed25519_dalek::KEYPAIR_LENGTH]);
66                sk.copy_from_slice(key);
67                ed25519_dalek::SigningKey::from_keypair_bytes(&sk).map_err(|_| CryptoError::CryptoLibraryError)?
68            }
69            ed25519_dalek::SECRET_KEY_LENGTH => {
70                let mut sk = zeroize::Zeroizing::new([0u8; ed25519_dalek::SECRET_KEY_LENGTH]);
71                sk.copy_from_slice(key);
72                ed25519_dalek::SigningKey::from_bytes(&sk)
73            }
74            _ => return Err(CryptoError::CryptoLibraryError),
75        };
76        Ok(k)
77    }
78}
79
80impl OpenMlsCrypto for RustCrypto {
81    fn signature_public_key_len(&self, signature_scheme: SignatureScheme) -> usize {
82        match signature_scheme {
83            SignatureScheme::ECDSA_SECP256R1_SHA256 => {
84                <p256::NistP256 as p256::elliptic_curve::Curve>::FieldBytesSize::to_usize()
85            }
86            SignatureScheme::ECDSA_SECP384R1_SHA384 => {
87                <p384::NistP384 as p384::elliptic_curve::Curve>::FieldBytesSize::to_usize()
88            }
89            SignatureScheme::ECDSA_SECP521R1_SHA512 => {
90                <p521::NistP521 as p521::elliptic_curve::Curve>::FieldBytesSize::to_usize()
91            }
92            SignatureScheme::ED25519 => ed25519_dalek::PUBLIC_KEY_LENGTH,
93            SignatureScheme::ED448 => 57,
94        }
95    }
96
97    fn supports(&self, ciphersuite: Ciphersuite) -> Result<(), CryptoError> {
98        match ciphersuite {
99            Ciphersuite::MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519
100            | Ciphersuite::MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519
101            | Ciphersuite::MLS_128_DHKEMP256_AES128GCM_SHA256_P256
102            | Ciphersuite::MLS_256_DHKEMP384_AES256GCM_SHA384_P384
103            | Ciphersuite::MLS_256_DHKEMP521_AES256GCM_SHA512_P521 => Ok(()),
104            _ => Err(CryptoError::UnsupportedCiphersuite),
105        }
106    }
107
108    fn supported_ciphersuites(&self) -> Vec<Ciphersuite> {
109        vec![
110            Ciphersuite::MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519,
111            Ciphersuite::MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519,
112            Ciphersuite::MLS_128_DHKEMP256_AES128GCM_SHA256_P256,
113            Ciphersuite::MLS_256_DHKEMP384_AES256GCM_SHA384_P384,
114            Ciphersuite::MLS_256_DHKEMP521_AES256GCM_SHA512_P521,
115        ]
116    }
117
118    fn hkdf_extract(&self, hash_type: HashType, salt: &[u8], ikm: &[u8]) -> Result<SecretVLBytes, CryptoError> {
119        match hash_type {
120            HashType::Sha2_256 => Ok(Hkdf::<Sha256>::extract(Some(salt), ikm).0.as_slice().into()),
121            HashType::Sha2_384 => Ok(Hkdf::<Sha384>::extract(Some(salt), ikm).0.as_slice().into()),
122            HashType::Sha2_512 => Ok(Hkdf::<Sha512>::extract(Some(salt), ikm).0.as_slice().into()),
123        }
124    }
125
126    fn hkdf_expand(
127        &self,
128        hash_type: HashType,
129        prk: &[u8],
130        info: &[u8],
131        okm_len: usize,
132    ) -> Result<SecretVLBytes, CryptoError> {
133        match hash_type {
134            HashType::Sha2_256 => {
135                let hkdf = Hkdf::<Sha256>::from_prk(prk).map_err(|_| CryptoError::HkdfOutputLengthInvalid)?;
136
137                let mut okm = vec![0u8; okm_len];
138                hkdf.expand(info, &mut okm)
139                    .map_err(|_| CryptoError::HkdfOutputLengthInvalid)?;
140
141                Ok(okm.into())
142            }
143            HashType::Sha2_384 => {
144                let hkdf = Hkdf::<Sha384>::from_prk(prk).map_err(|_| CryptoError::HkdfOutputLengthInvalid)?;
145
146                let mut okm = vec![0u8; okm_len];
147                hkdf.expand(info, &mut okm)
148                    .map_err(|_| CryptoError::HkdfOutputLengthInvalid)?;
149
150                Ok(okm.into())
151            }
152            HashType::Sha2_512 => {
153                let hkdf = Hkdf::<Sha512>::from_prk(prk).map_err(|_| CryptoError::HkdfOutputLengthInvalid)?;
154
155                let mut okm = vec![0u8; okm_len];
156                hkdf.expand(info, &mut okm)
157                    .map_err(|_| CryptoError::HkdfOutputLengthInvalid)?;
158
159                Ok(okm.into())
160            }
161        }
162    }
163
164    fn hash(&self, hash_type: HashType, data: &[u8]) -> Result<Vec<u8>, CryptoError> {
165        match hash_type {
166            HashType::Sha2_256 => Ok(Sha256::digest(data).as_slice().into()),
167            HashType::Sha2_384 => Ok(Sha384::digest(data).as_slice().into()),
168            HashType::Sha2_512 => Ok(Sha512::digest(data).as_slice().into()),
169        }
170    }
171
172    fn aead_encrypt(
173        &self,
174        alg: AeadType,
175        key: &[u8],
176        data: &[u8],
177        nonce: &[u8],
178        aad: &[u8],
179    ) -> Result<Vec<u8>, CryptoError> {
180        match alg {
181            AeadType::Aes128Gcm => {
182                let aes = Aes128Gcm::new_from_slice(key).map_err(|_| CryptoError::CryptoLibraryError)?;
183
184                aes.encrypt(nonce.into(), Payload { msg: data, aad })
185                    .map(|r| r.as_slice().into())
186                    .map_err(|_| CryptoError::CryptoLibraryError)
187            }
188            AeadType::Aes256Gcm => {
189                let aes = Aes256Gcm::new_from_slice(key).map_err(|_| CryptoError::CryptoLibraryError)?;
190
191                aes.encrypt(nonce.into(), Payload { msg: data, aad })
192                    .map(|r| r.as_slice().into())
193                    .map_err(|_| CryptoError::CryptoLibraryError)
194            }
195            AeadType::ChaCha20Poly1305 => {
196                let chacha_poly = ChaCha20Poly1305::new_from_slice(key).map_err(|_| CryptoError::CryptoLibraryError)?;
197
198                chacha_poly
199                    .encrypt(nonce.into(), Payload { msg: data, aad })
200                    .map(|r| r.as_slice().into())
201                    .map_err(|_| CryptoError::CryptoLibraryError)
202            }
203        }
204    }
205
206    fn aead_decrypt(
207        &self,
208        alg: AeadType,
209        key: &[u8],
210        ct_tag: &[u8],
211        nonce: &[u8],
212        aad: &[u8],
213    ) -> Result<Vec<u8>, CryptoError> {
214        match alg {
215            AeadType::Aes128Gcm => {
216                let aes = Aes128Gcm::new_from_slice(key).map_err(|_| CryptoError::CryptoLibraryError)?;
217                aes.decrypt(nonce.into(), Payload { msg: ct_tag, aad })
218                    .map(|r| r.as_slice().into())
219                    .map_err(|_| CryptoError::AeadDecryptionError)
220            }
221            AeadType::Aes256Gcm => {
222                let aes = Aes256Gcm::new_from_slice(key).map_err(|_| CryptoError::CryptoLibraryError)?;
223                aes.decrypt(nonce.into(), Payload { msg: ct_tag, aad })
224                    .map(|r| r.as_slice().into())
225                    .map_err(|_| CryptoError::AeadDecryptionError)
226            }
227            AeadType::ChaCha20Poly1305 => {
228                let chacha_poly = ChaCha20Poly1305::new_from_slice(key).map_err(|_| CryptoError::CryptoLibraryError)?;
229                chacha_poly
230                    .decrypt(nonce.into(), Payload { msg: ct_tag, aad })
231                    .map(|r| r.as_slice().into())
232                    .map_err(|_| CryptoError::AeadDecryptionError)
233            }
234        }
235    }
236
237    /// Generate a `(secret key, public key)` pair from a signature scheme.
238    fn signature_key_gen(&self, alg: SignatureScheme) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {
239        let mut rng = self.rng.write().map_err(|_| CryptoError::InsufficientRandomness)?;
240
241        match alg {
242            SignatureScheme::ECDSA_SECP256R1_SHA256 => {
243                let sk = p256::ecdsa::SigningKey::random(&mut *rng);
244                let pk = sk.verifying_key().to_sec1_bytes().to_vec();
245                Ok((sk.to_bytes().to_vec(), pk))
246            }
247            SignatureScheme::ECDSA_SECP384R1_SHA384 => {
248                let sk = p384::ecdsa::SigningKey::random(&mut *rng);
249                let pk = sk.verifying_key().to_sec1_bytes().to_vec();
250                Ok((sk.to_bytes().to_vec(), pk))
251            }
252            SignatureScheme::ECDSA_SECP521R1_SHA512 => {
253                let sk = p521::ecdsa::SigningKey::random(&mut *rng);
254                let pk = p521::ecdsa::VerifyingKey::from(&sk)
255                    .to_encoded_point(false)
256                    .to_bytes()
257                    .into();
258                Ok((sk.to_bytes().to_vec(), pk))
259            }
260            SignatureScheme::ED25519 => {
261                let k = ed25519_dalek::SigningKey::generate(&mut *rng);
262                let pk = k.verifying_key();
263                Ok((k.to_bytes().into(), pk.to_bytes().into()))
264            }
265            _ => Err(CryptoError::UnsupportedSignatureScheme),
266        }
267    }
268
269    fn validate_signature_key(&self, alg: SignatureScheme, key: &[u8]) -> Result<(), CryptoError> {
270        match alg {
271            SignatureScheme::ED25519 => {
272                ed25519_dalek::VerifyingKey::try_from(key).map_err(|_| CryptoError::InvalidKey)?;
273            }
274            SignatureScheme::ECDSA_SECP256R1_SHA256 => {
275                p256::ecdsa::VerifyingKey::try_from(key).map_err(|_| CryptoError::InvalidKey)?;
276            }
277            SignatureScheme::ECDSA_SECP384R1_SHA384 => {
278                p384::ecdsa::VerifyingKey::try_from(key).map_err(|_| CryptoError::InvalidKey)?;
279            }
280            SignatureScheme::ECDSA_SECP521R1_SHA512 => {
281                p521::ecdsa::VerifyingKey::from_sec1_bytes(key).map_err(|_| CryptoError::InvalidKey)?;
282            }
283            SignatureScheme::ED448 => {
284                return Err(CryptoError::UnsupportedSignatureScheme);
285            }
286        }
287        Ok(())
288    }
289
290    fn verify_signature(
291        &self,
292        alg: SignatureScheme,
293        data: &[u8],
294        pk: &[u8],
295        signature: &[u8],
296    ) -> Result<(), CryptoError> {
297        use signature::Verifier as _;
298        match alg {
299            SignatureScheme::ECDSA_SECP256R1_SHA256 => {
300                let k = p256::ecdsa::VerifyingKey::from_sec1_bytes(pk).map_err(|_| CryptoError::CryptoLibraryError)?;
301
302                let signature =
303                    p256::ecdsa::DerSignature::from_bytes(signature).map_err(|_| CryptoError::InvalidSignature)?;
304
305                k.verify(data, &signature).map_err(|_| CryptoError::InvalidSignature)
306            }
307            SignatureScheme::ECDSA_SECP384R1_SHA384 => {
308                let k = p384::ecdsa::VerifyingKey::from_sec1_bytes(pk).map_err(|_| CryptoError::CryptoLibraryError)?;
309
310                let signature =
311                    p384::ecdsa::DerSignature::from_bytes(signature).map_err(|_| CryptoError::InvalidSignature)?;
312
313                k.verify(data, &signature).map_err(|_| CryptoError::InvalidSignature)
314            }
315            SignatureScheme::ECDSA_SECP521R1_SHA512 => {
316                let k = p521::ecdsa::VerifyingKey::from_sec1_bytes(pk).map_err(|_| CryptoError::CryptoLibraryError)?;
317
318                let signature =
319                    p521::ecdsa::Signature::from_der(signature).map_err(|_| CryptoError::InvalidSignature)?;
320
321                k.verify(data, &signature).map_err(|_| CryptoError::InvalidSignature)
322            }
323            SignatureScheme::ED25519 => {
324                let k = ed25519_dalek::VerifyingKey::try_from(pk).map_err(|_| CryptoError::CryptoLibraryError)?;
325
326                let sig = ed25519_dalek::Signature::from_slice(signature).map_err(|_| CryptoError::InvalidSignature)?;
327
328                k.verify_strict(data, &sig).map_err(|_| CryptoError::InvalidSignature)
329            }
330            _ => Err(CryptoError::UnsupportedSignatureScheme),
331        }
332    }
333
334    fn sign(&self, alg: SignatureScheme, data: &[u8], key: &[u8]) -> Result<Vec<u8>, CryptoError> {
335        use signature::Signer as _;
336
337        match alg {
338            SignatureScheme::ECDSA_SECP256R1_SHA256 => {
339                let k = p256::ecdsa::SigningKey::from_slice(key).map_err(|_| CryptoError::CryptoLibraryError)?;
340                let signature: p256::ecdsa::DerSignature =
341                    k.try_sign(data).map_err(|_| CryptoError::CryptoLibraryError)?;
342                Ok(signature.to_bytes().into())
343            }
344            SignatureScheme::ECDSA_SECP384R1_SHA384 => {
345                let k = p384::ecdsa::SigningKey::from_slice(key).map_err(|_| CryptoError::CryptoLibraryError)?;
346                let signature: p384::ecdsa::DerSignature =
347                    k.try_sign(data).map_err(|_| CryptoError::CryptoLibraryError)?;
348                Ok(signature.to_bytes().into())
349            }
350            SignatureScheme::ECDSA_SECP521R1_SHA512 => {
351                let k = p521::ecdsa::SigningKey::from_slice(&*normalize_p521_secret_key(key))
352                    .map_err(|_| CryptoError::CryptoLibraryError)?;
353                let signature: p521::ecdsa::DerSignature =
354                    k.try_sign(data).map_err(|_| CryptoError::CryptoLibraryError)?.to_der();
355                Ok(signature.to_bytes().into())
356            }
357            SignatureScheme::ED25519 => {
358                let k = Self::normalize_ed25519_key(key)?;
359                let signature = k.try_sign(data).map_err(|_| CryptoError::CryptoLibraryError)?;
360                Ok(signature.to_bytes().into())
361            }
362            _ => Err(CryptoError::UnsupportedSignatureScheme),
363        }
364    }
365
366    fn hpke_seal(
367        &self,
368        config: HpkeConfig,
369        pk_r: &[u8],
370        info: &[u8],
371        aad: &[u8],
372        ptxt: &[u8],
373    ) -> Result<types::HpkeCiphertext, CryptoError> {
374        let mut rng = self.rng.write().map_err(|_| CryptoError::InsufficientRandomness)?;
375
376        match config {
377            HpkeConfig(HpkeKemType::DhKem25519, HpkeKdfType::HkdfSha256, HpkeAeadType::AesGcm128) => {
378                hpke_core::hpke_seal::<hpke::aead::AesGcm128, hpke::kdf::HkdfSha256, hpke::kem::X25519HkdfSha256>(
379                    pk_r, info, aad, ptxt, &mut *rng,
380                )
381            }
382            HpkeConfig(HpkeKemType::DhKem25519, HpkeKdfType::HkdfSha256, HpkeAeadType::ChaCha20Poly1305) => {
383                hpke_core::hpke_seal::<hpke::aead::ChaCha20Poly1305, hpke::kdf::HkdfSha256, hpke::kem::X25519HkdfSha256>(
384                    pk_r, info, aad, ptxt, &mut *rng,
385                )
386            }
387            HpkeConfig(HpkeKemType::DhKemP256, HpkeKdfType::HkdfSha256, HpkeAeadType::AesGcm128) => {
388                hpke_core::hpke_seal::<hpke::aead::AesGcm128, hpke::kdf::HkdfSha256, hpke::kem::DhP256HkdfSha256>(
389                    pk_r, info, aad, ptxt, &mut *rng,
390                )
391            }
392            HpkeConfig(HpkeKemType::DhKemP384, HpkeKdfType::HkdfSha384, HpkeAeadType::AesGcm256) => {
393                hpke_core::hpke_seal::<hpke::aead::AesGcm256, hpke::kdf::HkdfSha384, hpke::kem::DhP384HkdfSha384>(
394                    pk_r, info, aad, ptxt, &mut *rng,
395                )
396            }
397            HpkeConfig(HpkeKemType::DhKemP521, HpkeKdfType::HkdfSha512, HpkeAeadType::AesGcm256) => {
398                hpke_core::hpke_seal::<hpke::aead::AesGcm256, hpke::kdf::HkdfSha512, hpke::kem::DhP521HkdfSha512>(
399                    pk_r, info, aad, ptxt, &mut *rng,
400                )
401            }
402            _ => Err(CryptoError::UnsupportedKem),
403        }
404    }
405
406    fn hpke_open(
407        &self,
408        config: HpkeConfig,
409        input: &types::HpkeCiphertext,
410        sk_r: &[u8],
411        info: &[u8],
412        aad: &[u8],
413    ) -> Result<Vec<u8>, CryptoError> {
414        let plaintext = match config {
415            HpkeConfig(HpkeKemType::DhKem25519, HpkeKdfType::HkdfSha256, HpkeAeadType::AesGcm128) => {
416                hpke_core::hpke_open::<hpke::aead::AesGcm128, hpke::kdf::HkdfSha256, hpke::kem::X25519HkdfSha256>(
417                    sk_r,
418                    input.kem_output.as_slice(),
419                    info,
420                    aad,
421                    input.ciphertext.as_slice(),
422                )?
423            }
424            HpkeConfig(HpkeKemType::DhKem25519, HpkeKdfType::HkdfSha256, HpkeAeadType::ChaCha20Poly1305) => {
425                hpke_core::hpke_open::<hpke::aead::ChaCha20Poly1305, hpke::kdf::HkdfSha256, hpke::kem::X25519HkdfSha256>(
426                    sk_r,
427                    input.kem_output.as_slice(),
428                    info,
429                    aad,
430                    input.ciphertext.as_slice(),
431                )?
432            }
433            HpkeConfig(HpkeKemType::DhKemP256, HpkeKdfType::HkdfSha256, HpkeAeadType::AesGcm128) => {
434                hpke_core::hpke_open::<hpke::aead::AesGcm128, hpke::kdf::HkdfSha256, hpke::kem::DhP256HkdfSha256>(
435                    sk_r,
436                    input.kem_output.as_slice(),
437                    info,
438                    aad,
439                    input.ciphertext.as_slice(),
440                )?
441            }
442            HpkeConfig(HpkeKemType::DhKemP384, HpkeKdfType::HkdfSha384, HpkeAeadType::AesGcm256) => {
443                hpke_core::hpke_open::<hpke::aead::AesGcm256, hpke::kdf::HkdfSha384, hpke::kem::DhP384HkdfSha384>(
444                    sk_r,
445                    input.kem_output.as_slice(),
446                    info,
447                    aad,
448                    input.ciphertext.as_slice(),
449                )?
450            }
451            HpkeConfig(HpkeKemType::DhKemP521, HpkeKdfType::HkdfSha512, HpkeAeadType::AesGcm256) => {
452                hpke_core::hpke_open::<hpke::aead::AesGcm256, hpke::kdf::HkdfSha512, hpke::kem::DhP521HkdfSha512>(
453                    sk_r,
454                    input.kem_output.as_slice(),
455                    info,
456                    aad,
457                    input.ciphertext.as_slice(),
458                )?
459            }
460            _ => return Err(CryptoError::UnsupportedKem),
461        };
462
463        Ok(plaintext)
464    }
465
466    fn hpke_setup_sender_and_export(
467        &self,
468        config: HpkeConfig,
469        pk_r: &[u8],
470        info: &[u8],
471        exporter_context: &[u8],
472        exporter_length: usize,
473    ) -> Result<(Vec<u8>, ExporterSecret), CryptoError> {
474        let mut rng = self.rng.write().map_err(|_| CryptoError::InsufficientRandomness)?;
475
476        let (kem_output, export) =
477            match config {
478                HpkeConfig(HpkeKemType::DhKem25519, HpkeKdfType::HkdfSha256, HpkeAeadType::AesGcm128) => {
479                    hpke_core::hpke_export_tx::<
480                        hpke::aead::AesGcm128,
481                        hpke::kdf::HkdfSha256,
482                        hpke::kem::X25519HkdfSha256,
483                    >(pk_r, info, exporter_context, exporter_length, &mut *rng)?
484                }
485                HpkeConfig(HpkeKemType::DhKem25519, HpkeKdfType::HkdfSha256, HpkeAeadType::ChaCha20Poly1305) => {
486                    hpke_core::hpke_export_tx::<
487                        hpke::aead::ChaCha20Poly1305,
488                        hpke::kdf::HkdfSha256,
489                        hpke::kem::X25519HkdfSha256,
490                    >(pk_r, info, exporter_context, exporter_length, &mut *rng)?
491                }
492                HpkeConfig(HpkeKemType::DhKemP256, HpkeKdfType::HkdfSha256, HpkeAeadType::AesGcm128) => {
493                    hpke_core::hpke_export_tx::<
494                        hpke::aead::AesGcm128,
495                        hpke::kdf::HkdfSha256,
496                        hpke::kem::DhP256HkdfSha256,
497                    >(pk_r, info, exporter_context, exporter_length, &mut *rng)?
498                }
499                HpkeConfig(HpkeKemType::DhKemP384, HpkeKdfType::HkdfSha384, HpkeAeadType::AesGcm256) => {
500                    hpke_core::hpke_export_tx::<
501                        hpke::aead::AesGcm256,
502                        hpke::kdf::HkdfSha384,
503                        hpke::kem::DhP384HkdfSha384,
504                    >(pk_r, info, exporter_context, exporter_length, &mut *rng)?
505                }
506                HpkeConfig(HpkeKemType::DhKemP521, HpkeKdfType::HkdfSha512, HpkeAeadType::AesGcm256) => {
507                    hpke_core::hpke_export_tx::<
508                        hpke::aead::AesGcm256,
509                        hpke::kdf::HkdfSha512,
510                        hpke::kem::DhP521HkdfSha512,
511                    >(pk_r, info, exporter_context, exporter_length, &mut *rng)?
512                }
513                _ => return Err(CryptoError::UnsupportedKem),
514            };
515
516        debug_assert_eq!(export.len(), exporter_length);
517
518        Ok((kem_output, export.into()))
519    }
520
521    fn hpke_setup_receiver_and_export(
522        &self,
523        config: HpkeConfig,
524        enc: &[u8],
525        sk_r: &[u8],
526        info: &[u8],
527        exporter_context: &[u8],
528        exporter_length: usize,
529    ) -> Result<ExporterSecret, CryptoError> {
530        let export =
531            match config {
532                HpkeConfig(HpkeKemType::DhKem25519, HpkeKdfType::HkdfSha256, HpkeAeadType::AesGcm128) => {
533                    hpke_core::hpke_export_rx::<
534                        hpke::aead::AesGcm128,
535                        hpke::kdf::HkdfSha256,
536                        hpke::kem::X25519HkdfSha256,
537                    >(enc, sk_r, info, exporter_context, exporter_length)?
538                }
539                HpkeConfig(HpkeKemType::DhKem25519, HpkeKdfType::HkdfSha256, HpkeAeadType::ChaCha20Poly1305) => {
540                    hpke_core::hpke_export_rx::<
541                        hpke::aead::ChaCha20Poly1305,
542                        hpke::kdf::HkdfSha256,
543                        hpke::kem::X25519HkdfSha256,
544                    >(enc, sk_r, info, exporter_context, exporter_length)?
545                }
546                HpkeConfig(HpkeKemType::DhKemP256, HpkeKdfType::HkdfSha256, HpkeAeadType::AesGcm128) => {
547                    hpke_core::hpke_export_rx::<
548                        hpke::aead::AesGcm128,
549                        hpke::kdf::HkdfSha256,
550                        hpke::kem::DhP256HkdfSha256,
551                    >(enc, sk_r, info, exporter_context, exporter_length)?
552                }
553                HpkeConfig(HpkeKemType::DhKemP384, HpkeKdfType::HkdfSha384, HpkeAeadType::AesGcm256) => {
554                    hpke_core::hpke_export_rx::<
555                        hpke::aead::AesGcm256,
556                        hpke::kdf::HkdfSha384,
557                        hpke::kem::DhP384HkdfSha384,
558                    >(enc, sk_r, info, exporter_context, exporter_length)?
559                }
560                HpkeConfig(HpkeKemType::DhKemP521, HpkeKdfType::HkdfSha512, HpkeAeadType::AesGcm256) => {
561                    hpke_core::hpke_export_rx::<
562                        hpke::aead::AesGcm256,
563                        hpke::kdf::HkdfSha512,
564                        hpke::kem::DhP521HkdfSha512,
565                    >(enc, sk_r, info, exporter_context, exporter_length)?
566                }
567                _ => return Err(CryptoError::UnsupportedKem),
568            };
569
570        debug_assert_eq!(export.len(), exporter_length);
571
572        Ok(export.into())
573    }
574
575    fn derive_hpke_keypair(&self, config: HpkeConfig, ikm: &[u8]) -> Result<types::HpkeKeyPair, CryptoError> {
576        match config.0 {
577            HpkeKemType::DhKemP256 => hpke_core::hpke_derive_keypair::<hpke::kem::DhP256HkdfSha256>(ikm),
578            HpkeKemType::DhKemP384 => hpke_core::hpke_derive_keypair::<hpke::kem::DhP384HkdfSha384>(ikm),
579            HpkeKemType::DhKemP521 => hpke_core::hpke_derive_keypair::<hpke::kem::DhP521HkdfSha512>(ikm),
580            HpkeKemType::DhKem25519 => hpke_core::hpke_derive_keypair::<hpke::kem::X25519HkdfSha256>(ikm),
581            _ => Err(CryptoError::UnsupportedKem),
582        }
583    }
584}
585
586mod hpke_core {
587    use openmls_traits::types::{CryptoError, HpkeCiphertext, HpkeKeyPair};
588
589    pub(crate) fn hpke_open<Aead: hpke::aead::Aead, Kdf: hpke::kdf::Kdf, Kem: hpke::Kem>(
590        private_key: &[u8],
591        kem_output: &[u8],
592        info: &[u8],
593        aad: &[u8],
594        ciphertext: &[u8],
595    ) -> Result<Vec<u8>, CryptoError> {
596        use hpke::{Deserializable as _, Serializable as _};
597        let encapped_key = Kem::EncappedKey::from_bytes(kem_output).map_err(|_| CryptoError::HpkeDecryptionError)?;
598        // Systematically normalize private keys
599        let sk_len = Kem::PrivateKey::size();
600        let mut sk_buf = zeroize::Zeroizing::new(Vec::with_capacity(sk_len));
601        if private_key.len() < sk_len {
602            for _ in 0..(sk_len - private_key.len()) {
603                sk_buf.push(0x00);
604            }
605        }
606        sk_buf.extend_from_slice(private_key);
607        let key = Kem::PrivateKey::from_bytes(&sk_buf).map_err(|_| CryptoError::HpkeDecryptionError)?;
608        let plaintext =
609            hpke::single_shot_open::<Aead, Kdf, Kem>(&hpke::OpModeR::Base, &key, &encapped_key, info, ciphertext, aad)
610                .map_err(|_| CryptoError::HpkeDecryptionError)?;
611
612        Ok(plaintext)
613    }
614
615    pub(crate) fn hpke_seal<Aead: hpke::aead::Aead, Kdf: hpke::kdf::Kdf, Kem: hpke::Kem>(
616        public_key: &[u8],
617        info: &[u8],
618        aad: &[u8],
619        plaintext: &[u8],
620        csprng: &mut impl rand_core::CryptoRngCore,
621    ) -> Result<HpkeCiphertext, CryptoError> {
622        use hpke::{Deserializable as _, Serializable as _};
623        let key = Kem::PublicKey::from_bytes(public_key).map_err(|_| CryptoError::HpkeEncryptionError)?;
624        let (encapped, ciphertext) =
625            hpke::single_shot_seal::<Aead, Kdf, Kem, _>(&hpke::OpModeS::Base, &key, info, plaintext, aad, csprng)
626                .map_err(|_| CryptoError::HpkeEncryptionError)?;
627
628        Ok(HpkeCiphertext {
629            kem_output: encapped.to_bytes().to_vec().into(),
630            ciphertext: ciphertext.into(),
631        })
632    }
633
634    #[allow(dead_code)]
635    pub(crate) fn hpke_gen_keypair<Kem: hpke::Kem>(
636        csprng: &mut impl rand_core::CryptoRngCore,
637    ) -> Result<HpkeKeyPair, CryptoError> {
638        use hpke::Serializable as _;
639        let (sk, pk) = Kem::gen_keypair(csprng);
640        let (private, public) = (sk.to_bytes().to_vec().into(), pk.to_bytes().to_vec());
641
642        Ok(HpkeKeyPair { private, public })
643    }
644
645    pub(crate) fn hpke_derive_keypair<Kem: hpke::Kem>(ikm: &[u8]) -> Result<HpkeKeyPair, CryptoError> {
646        use hpke::Serializable as _;
647        let (sk, pk) = Kem::derive_keypair(ikm);
648        let (private, public) = (sk.to_bytes().to_vec().into(), pk.to_bytes().to_vec());
649
650        Ok(HpkeKeyPair { private, public })
651    }
652
653    pub(crate) fn hpke_export_rx<Aead: hpke::aead::Aead, Kdf: hpke::kdf::Kdf, Kem: hpke::Kem>(
654        encapped_key: &[u8],
655        rx_private_key: &[u8],
656        info: &[u8],
657        export_info: &[u8],
658        export_len: usize,
659    ) -> Result<Vec<u8>, CryptoError> {
660        use hpke::Deserializable as _;
661        let key = Kem::PrivateKey::from_bytes(rx_private_key).map_err(|_| CryptoError::ReceiverSetupError)?;
662        let encapped_key = Kem::EncappedKey::from_bytes(encapped_key).map_err(|_| CryptoError::ReceiverSetupError)?;
663        let ctx = hpke::setup_receiver::<Aead, Kdf, Kem>(&hpke::OpModeR::Base, &key, &encapped_key, info)
664            .map_err(|_| CryptoError::ReceiverSetupError)?;
665
666        let mut export = vec![0u8; export_len];
667
668        ctx.export(export_info, &mut export)
669            .map_err(|_| CryptoError::ExporterError)?;
670
671        Ok(export)
672    }
673
674    pub(crate) fn hpke_export_tx<Aead: hpke::aead::Aead, Kdf: hpke::kdf::Kdf, Kem: hpke::Kem>(
675        tx_public_key: &[u8],
676        info: &[u8],
677        export_info: &[u8],
678        export_len: usize,
679        csprng: &mut impl rand_core::CryptoRngCore,
680    ) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {
681        use hpke::{Deserializable as _, Serializable as _};
682        let key = Kem::PublicKey::from_bytes(tx_public_key).map_err(|_| CryptoError::SenderSetupError)?;
683        let (kem_output, ctx) = hpke::setup_sender::<Aead, Kdf, Kem, _>(&hpke::OpModeS::Base, &key, info, csprng)
684            .map_err(|_| CryptoError::SenderSetupError)?;
685
686        let mut export = vec![0u8; export_len];
687
688        ctx.export(export_info, &mut export)
689            .map_err(|_| CryptoError::ExporterError)?;
690
691        Ok((kem_output.to_bytes().to_vec(), export))
692    }
693}
694
695impl OpenMlsRand for RustCrypto {
696    type Error = MlsProviderError;
697
698    type RandImpl = rand_chacha::ChaCha20Rng;
699    type BorrowTarget<'a> = RwLockWriteGuard<'a, Self::RandImpl>;
700
701    fn borrow_rand(&self) -> Result<Self::BorrowTarget<'_>, Self::Error> {
702        self.rng.write().map_err(|_| MlsProviderError::RngLockPoison)
703    }
704
705    fn random_array<const N: usize>(&self) -> Result<[u8; N], Self::Error> {
706        let mut rng = self.borrow_rand()?;
707        let mut out = [0u8; N];
708        rng.try_fill_bytes(&mut out)
709            .map_err(|_| MlsProviderError::UnsufficientEntropy)?;
710        Ok(out)
711    }
712
713    fn random_vec(&self, len: usize) -> Result<Vec<u8>, Self::Error> {
714        let mut rng = self.borrow_rand()?;
715        let mut out = vec![0u8; len];
716        rng.try_fill_bytes(&mut out)
717            .map_err(|_| MlsProviderError::UnsufficientEntropy)?;
718        Ok(out)
719    }
720}