core_crypto/mls_provider/
crypto_provider.rs

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