mls_crypto_provider/
crypto_provider.rs

1use crate::EntropySeed;
2use crate::MlsProviderError;
3use rand_core::{RngCore, SeedableRng};
4use signature::digest::typenum::Unsigned;
5use std::sync::{Arc, RwLock, RwLockWriteGuard};
6
7use aes_gcm::{
8    aead::{Aead, Payload},
9    Aes128Gcm, Aes256Gcm, KeyInit,
10};
11use chacha20poly1305::ChaCha20Poly1305;
12use hkdf::Hkdf;
13use openmls_traits::{
14    crypto::OpenMlsCrypto,
15    random::OpenMlsRand,
16    types::{
17        self, AeadType, Ciphersuite, CryptoError, ExporterSecret, HashType, HpkeAeadType, HpkeConfig, HpkeKdfType,
18        HpkeKemType, SignatureScheme,
19    },
20};
21use sha2::{Digest, Sha256, Sha384, Sha512};
22use tls_codec::SecretVLBytes;
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    fn signature_key_gen(&self, alg: SignatureScheme) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {
238        let mut rng = self.rng.write().map_err(|_| CryptoError::InsufficientRandomness)?;
239
240        match alg {
241            SignatureScheme::ECDSA_SECP256R1_SHA256 => {
242                let sk = p256::ecdsa::SigningKey::random(&mut *rng);
243                let pk = sk.verifying_key().to_sec1_bytes().to_vec();
244                Ok((sk.to_bytes().to_vec(), pk))
245            }
246            SignatureScheme::ECDSA_SECP384R1_SHA384 => {
247                let sk = p384::ecdsa::SigningKey::random(&mut *rng);
248                let pk = sk.verifying_key().to_sec1_bytes().to_vec();
249                Ok((sk.to_bytes().to_vec(), pk))
250            }
251            SignatureScheme::ECDSA_SECP521R1_SHA512 => {
252                let sk = p521::ecdsa::SigningKey::random(&mut *rng);
253                let pk = p521::ecdsa::VerifyingKey::from(&sk)
254                    .to_encoded_point(false)
255                    .to_bytes()
256                    .into();
257                Ok((sk.to_bytes().to_vec(), pk))
258            }
259            SignatureScheme::ED25519 => {
260                let k = ed25519_dalek::SigningKey::generate(&mut *rng);
261                let pk = k.verifying_key();
262                Ok((k.to_bytes().into(), pk.to_bytes().into()))
263            }
264            _ => Err(CryptoError::UnsupportedSignatureScheme),
265        }
266    }
267
268    fn validate_signature_key(&self, alg: SignatureScheme, key: &[u8]) -> Result<(), CryptoError> {
269        match alg {
270            SignatureScheme::ED25519 => {
271                ed25519_dalek::VerifyingKey::try_from(key).map_err(|_| CryptoError::InvalidKey)?;
272            }
273            SignatureScheme::ECDSA_SECP256R1_SHA256 => {
274                p256::ecdsa::VerifyingKey::try_from(key).map_err(|_| CryptoError::InvalidKey)?;
275            }
276            SignatureScheme::ECDSA_SECP384R1_SHA384 => {
277                p384::ecdsa::VerifyingKey::try_from(key).map_err(|_| CryptoError::InvalidKey)?;
278            }
279            SignatureScheme::ECDSA_SECP521R1_SHA512 => {
280                p521::ecdsa::VerifyingKey::from_sec1_bytes(key).map_err(|_| CryptoError::InvalidKey)?;
281            }
282            SignatureScheme::ED448 => {
283                return Err(CryptoError::UnsupportedSignatureScheme);
284            }
285        }
286        Ok(())
287    }
288
289    fn verify_signature(
290        &self,
291        alg: SignatureScheme,
292        data: &[u8],
293        pk: &[u8],
294        signature: &[u8],
295    ) -> Result<(), CryptoError> {
296        use signature::Verifier as _;
297        match alg {
298            SignatureScheme::ECDSA_SECP256R1_SHA256 => {
299                let k = p256::ecdsa::VerifyingKey::from_sec1_bytes(pk).map_err(|_| CryptoError::CryptoLibraryError)?;
300
301                let signature =
302                    p256::ecdsa::DerSignature::from_bytes(signature).map_err(|_| CryptoError::InvalidSignature)?;
303
304                k.verify(data, &signature).map_err(|_| CryptoError::InvalidSignature)
305            }
306            SignatureScheme::ECDSA_SECP384R1_SHA384 => {
307                let k = p384::ecdsa::VerifyingKey::from_sec1_bytes(pk).map_err(|_| CryptoError::CryptoLibraryError)?;
308
309                let signature =
310                    p384::ecdsa::DerSignature::from_bytes(signature).map_err(|_| CryptoError::InvalidSignature)?;
311
312                k.verify(data, &signature).map_err(|_| CryptoError::InvalidSignature)
313            }
314            SignatureScheme::ECDSA_SECP521R1_SHA512 => {
315                let k = p521::ecdsa::VerifyingKey::from_sec1_bytes(pk).map_err(|_| CryptoError::CryptoLibraryError)?;
316
317                let signature =
318                    p521::ecdsa::Signature::from_der(signature).map_err(|_| CryptoError::InvalidSignature)?;
319
320                k.verify(data, &signature).map_err(|_| CryptoError::InvalidSignature)
321            }
322            SignatureScheme::ED25519 => {
323                let k = ed25519_dalek::VerifyingKey::try_from(pk).map_err(|_| CryptoError::CryptoLibraryError)?;
324
325                let sig = ed25519_dalek::Signature::from_slice(signature).map_err(|_| CryptoError::InvalidSignature)?;
326
327                k.verify_strict(data, &sig).map_err(|_| CryptoError::InvalidSignature)
328            }
329            _ => Err(CryptoError::UnsupportedSignatureScheme),
330        }
331    }
332
333    fn sign(&self, alg: SignatureScheme, data: &[u8], key: &[u8]) -> Result<Vec<u8>, CryptoError> {
334        use signature::Signer as _;
335
336        match alg {
337            SignatureScheme::ECDSA_SECP256R1_SHA256 => {
338                let k = p256::ecdsa::SigningKey::from_slice(key).map_err(|_| CryptoError::CryptoLibraryError)?;
339                let signature: p256::ecdsa::DerSignature =
340                    k.try_sign(data).map_err(|_| CryptoError::CryptoLibraryError)?;
341                Ok(signature.to_bytes().into())
342            }
343            SignatureScheme::ECDSA_SECP384R1_SHA384 => {
344                let k = p384::ecdsa::SigningKey::from_slice(key).map_err(|_| CryptoError::CryptoLibraryError)?;
345                let signature: p384::ecdsa::DerSignature =
346                    k.try_sign(data).map_err(|_| CryptoError::CryptoLibraryError)?;
347                Ok(signature.to_bytes().into())
348            }
349            SignatureScheme::ECDSA_SECP521R1_SHA512 => {
350                let k = p521::ecdsa::SigningKey::from_slice(&*normalize_p521_secret_key(key))
351                    .map_err(|_| CryptoError::CryptoLibraryError)?;
352                let signature: p521::ecdsa::DerSignature =
353                    k.try_sign(data).map_err(|_| CryptoError::CryptoLibraryError)?.to_der();
354                Ok(signature.to_bytes().into())
355            }
356            SignatureScheme::ED25519 => {
357                let k = Self::normalize_ed25519_key(key)?;
358                let signature = k.try_sign(data).map_err(|_| CryptoError::CryptoLibraryError)?;
359                Ok(signature.to_bytes().into())
360            }
361            _ => Err(CryptoError::UnsupportedSignatureScheme),
362        }
363    }
364
365    fn hpke_seal(
366        &self,
367        config: HpkeConfig,
368        pk_r: &[u8],
369        info: &[u8],
370        aad: &[u8],
371        ptxt: &[u8],
372    ) -> Result<types::HpkeCiphertext, CryptoError> {
373        let mut rng = self.rng.write().map_err(|_| CryptoError::InsufficientRandomness)?;
374
375        match config {
376            HpkeConfig(HpkeKemType::DhKem25519, HpkeKdfType::HkdfSha256, HpkeAeadType::AesGcm128) => {
377                hpke_core::hpke_seal::<hpke::aead::AesGcm128, hpke::kdf::HkdfSha256, hpke::kem::X25519HkdfSha256>(
378                    pk_r, info, aad, ptxt, &mut *rng,
379                )
380            }
381            HpkeConfig(HpkeKemType::DhKem25519, HpkeKdfType::HkdfSha256, HpkeAeadType::ChaCha20Poly1305) => {
382                hpke_core::hpke_seal::<hpke::aead::ChaCha20Poly1305, hpke::kdf::HkdfSha256, hpke::kem::X25519HkdfSha256>(
383                    pk_r, info, aad, ptxt, &mut *rng,
384                )
385            }
386            HpkeConfig(HpkeKemType::DhKemP256, HpkeKdfType::HkdfSha256, HpkeAeadType::AesGcm128) => {
387                hpke_core::hpke_seal::<hpke::aead::AesGcm128, hpke::kdf::HkdfSha256, hpke::kem::DhP256HkdfSha256>(
388                    pk_r, info, aad, ptxt, &mut *rng,
389                )
390            }
391            HpkeConfig(HpkeKemType::DhKemP384, HpkeKdfType::HkdfSha384, HpkeAeadType::AesGcm256) => {
392                hpke_core::hpke_seal::<hpke::aead::AesGcm256, hpke::kdf::HkdfSha384, hpke::kem::DhP384HkdfSha384>(
393                    pk_r, info, aad, ptxt, &mut *rng,
394                )
395            }
396            HpkeConfig(HpkeKemType::DhKemP521, HpkeKdfType::HkdfSha512, HpkeAeadType::AesGcm256) => {
397                hpke_core::hpke_seal::<hpke::aead::AesGcm256, hpke::kdf::HkdfSha512, hpke::kem::DhP521HkdfSha512>(
398                    pk_r, info, aad, ptxt, &mut *rng,
399                )
400            }
401            _ => Err(CryptoError::UnsupportedKem),
402        }
403    }
404
405    fn hpke_open(
406        &self,
407        config: HpkeConfig,
408        input: &types::HpkeCiphertext,
409        sk_r: &[u8],
410        info: &[u8],
411        aad: &[u8],
412    ) -> Result<Vec<u8>, CryptoError> {
413        let plaintext = match config {
414            HpkeConfig(HpkeKemType::DhKem25519, HpkeKdfType::HkdfSha256, HpkeAeadType::AesGcm128) => {
415                hpke_core::hpke_open::<hpke::aead::AesGcm128, hpke::kdf::HkdfSha256, hpke::kem::X25519HkdfSha256>(
416                    sk_r,
417                    input.kem_output.as_slice(),
418                    info,
419                    aad,
420                    input.ciphertext.as_slice(),
421                )?
422            }
423            HpkeConfig(HpkeKemType::DhKem25519, HpkeKdfType::HkdfSha256, HpkeAeadType::ChaCha20Poly1305) => {
424                hpke_core::hpke_open::<hpke::aead::ChaCha20Poly1305, hpke::kdf::HkdfSha256, hpke::kem::X25519HkdfSha256>(
425                    sk_r,
426                    input.kem_output.as_slice(),
427                    info,
428                    aad,
429                    input.ciphertext.as_slice(),
430                )?
431            }
432            HpkeConfig(HpkeKemType::DhKemP256, HpkeKdfType::HkdfSha256, HpkeAeadType::AesGcm128) => {
433                hpke_core::hpke_open::<hpke::aead::AesGcm128, hpke::kdf::HkdfSha256, hpke::kem::DhP256HkdfSha256>(
434                    sk_r,
435                    input.kem_output.as_slice(),
436                    info,
437                    aad,
438                    input.ciphertext.as_slice(),
439                )?
440            }
441            HpkeConfig(HpkeKemType::DhKemP384, HpkeKdfType::HkdfSha384, HpkeAeadType::AesGcm256) => {
442                hpke_core::hpke_open::<hpke::aead::AesGcm256, hpke::kdf::HkdfSha384, hpke::kem::DhP384HkdfSha384>(
443                    sk_r,
444                    input.kem_output.as_slice(),
445                    info,
446                    aad,
447                    input.ciphertext.as_slice(),
448                )?
449            }
450            HpkeConfig(HpkeKemType::DhKemP521, HpkeKdfType::HkdfSha512, HpkeAeadType::AesGcm256) => {
451                hpke_core::hpke_open::<hpke::aead::AesGcm256, hpke::kdf::HkdfSha512, hpke::kem::DhP521HkdfSha512>(
452                    sk_r,
453                    input.kem_output.as_slice(),
454                    info,
455                    aad,
456                    input.ciphertext.as_slice(),
457                )?
458            }
459            _ => return Err(CryptoError::UnsupportedKem),
460        };
461
462        Ok(plaintext)
463    }
464
465    fn hpke_setup_sender_and_export(
466        &self,
467        config: HpkeConfig,
468        pk_r: &[u8],
469        info: &[u8],
470        exporter_context: &[u8],
471        exporter_length: usize,
472    ) -> Result<(Vec<u8>, ExporterSecret), CryptoError> {
473        let mut rng = self.rng.write().map_err(|_| CryptoError::InsufficientRandomness)?;
474
475        let (kem_output, export) =
476            match config {
477                HpkeConfig(HpkeKemType::DhKem25519, HpkeKdfType::HkdfSha256, HpkeAeadType::AesGcm128) => {
478                    hpke_core::hpke_export_tx::<
479                        hpke::aead::AesGcm128,
480                        hpke::kdf::HkdfSha256,
481                        hpke::kem::X25519HkdfSha256,
482                    >(pk_r, info, exporter_context, exporter_length, &mut *rng)?
483                }
484                HpkeConfig(HpkeKemType::DhKem25519, HpkeKdfType::HkdfSha256, HpkeAeadType::ChaCha20Poly1305) => {
485                    hpke_core::hpke_export_tx::<
486                        hpke::aead::ChaCha20Poly1305,
487                        hpke::kdf::HkdfSha256,
488                        hpke::kem::X25519HkdfSha256,
489                    >(pk_r, info, exporter_context, exporter_length, &mut *rng)?
490                }
491                HpkeConfig(HpkeKemType::DhKemP256, HpkeKdfType::HkdfSha256, HpkeAeadType::AesGcm128) => {
492                    hpke_core::hpke_export_tx::<
493                        hpke::aead::AesGcm128,
494                        hpke::kdf::HkdfSha256,
495                        hpke::kem::DhP256HkdfSha256,
496                    >(pk_r, info, exporter_context, exporter_length, &mut *rng)?
497                }
498                HpkeConfig(HpkeKemType::DhKemP384, HpkeKdfType::HkdfSha384, HpkeAeadType::AesGcm256) => {
499                    hpke_core::hpke_export_tx::<
500                        hpke::aead::AesGcm256,
501                        hpke::kdf::HkdfSha384,
502                        hpke::kem::DhP384HkdfSha384,
503                    >(pk_r, info, exporter_context, exporter_length, &mut *rng)?
504                }
505                HpkeConfig(HpkeKemType::DhKemP521, HpkeKdfType::HkdfSha512, HpkeAeadType::AesGcm256) => {
506                    hpke_core::hpke_export_tx::<
507                        hpke::aead::AesGcm256,
508                        hpke::kdf::HkdfSha512,
509                        hpke::kem::DhP521HkdfSha512,
510                    >(pk_r, info, exporter_context, exporter_length, &mut *rng)?
511                }
512                _ => return Err(CryptoError::UnsupportedKem),
513            };
514
515        debug_assert_eq!(export.len(), exporter_length);
516
517        Ok((kem_output, export.into()))
518    }
519
520    fn hpke_setup_receiver_and_export(
521        &self,
522        config: HpkeConfig,
523        enc: &[u8],
524        sk_r: &[u8],
525        info: &[u8],
526        exporter_context: &[u8],
527        exporter_length: usize,
528    ) -> Result<ExporterSecret, CryptoError> {
529        let export =
530            match config {
531                HpkeConfig(HpkeKemType::DhKem25519, HpkeKdfType::HkdfSha256, HpkeAeadType::AesGcm128) => {
532                    hpke_core::hpke_export_rx::<
533                        hpke::aead::AesGcm128,
534                        hpke::kdf::HkdfSha256,
535                        hpke::kem::X25519HkdfSha256,
536                    >(enc, sk_r, info, exporter_context, exporter_length)?
537                }
538                HpkeConfig(HpkeKemType::DhKem25519, HpkeKdfType::HkdfSha256, HpkeAeadType::ChaCha20Poly1305) => {
539                    hpke_core::hpke_export_rx::<
540                        hpke::aead::ChaCha20Poly1305,
541                        hpke::kdf::HkdfSha256,
542                        hpke::kem::X25519HkdfSha256,
543                    >(enc, sk_r, info, exporter_context, exporter_length)?
544                }
545                HpkeConfig(HpkeKemType::DhKemP256, HpkeKdfType::HkdfSha256, HpkeAeadType::AesGcm128) => {
546                    hpke_core::hpke_export_rx::<
547                        hpke::aead::AesGcm128,
548                        hpke::kdf::HkdfSha256,
549                        hpke::kem::DhP256HkdfSha256,
550                    >(enc, sk_r, info, exporter_context, exporter_length)?
551                }
552                HpkeConfig(HpkeKemType::DhKemP384, HpkeKdfType::HkdfSha384, HpkeAeadType::AesGcm256) => {
553                    hpke_core::hpke_export_rx::<
554                        hpke::aead::AesGcm256,
555                        hpke::kdf::HkdfSha384,
556                        hpke::kem::DhP384HkdfSha384,
557                    >(enc, sk_r, info, exporter_context, exporter_length)?
558                }
559                HpkeConfig(HpkeKemType::DhKemP521, HpkeKdfType::HkdfSha512, HpkeAeadType::AesGcm256) => {
560                    hpke_core::hpke_export_rx::<
561                        hpke::aead::AesGcm256,
562                        hpke::kdf::HkdfSha512,
563                        hpke::kem::DhP521HkdfSha512,
564                    >(enc, sk_r, info, exporter_context, exporter_length)?
565                }
566                _ => return Err(CryptoError::UnsupportedKem),
567            };
568
569        debug_assert_eq!(export.len(), exporter_length);
570
571        Ok(export.into())
572    }
573
574    fn derive_hpke_keypair(&self, config: HpkeConfig, ikm: &[u8]) -> Result<types::HpkeKeyPair, CryptoError> {
575        match config.0 {
576            HpkeKemType::DhKemP256 => hpke_core::hpke_derive_keypair::<hpke::kem::DhP256HkdfSha256>(ikm),
577            HpkeKemType::DhKemP384 => hpke_core::hpke_derive_keypair::<hpke::kem::DhP384HkdfSha384>(ikm),
578            HpkeKemType::DhKemP521 => hpke_core::hpke_derive_keypair::<hpke::kem::DhP521HkdfSha512>(ikm),
579            HpkeKemType::DhKem25519 => hpke_core::hpke_derive_keypair::<hpke::kem::X25519HkdfSha256>(ikm),
580            _ => Err(CryptoError::UnsupportedKem),
581        }
582    }
583}
584
585mod hpke_core {
586    use openmls_traits::types::{CryptoError, HpkeCiphertext, HpkeKeyPair};
587
588    pub(crate) fn hpke_open<Aead: hpke::aead::Aead, Kdf: hpke::kdf::Kdf, Kem: hpke::Kem>(
589        private_key: &[u8],
590        kem_output: &[u8],
591        info: &[u8],
592        aad: &[u8],
593        ciphertext: &[u8],
594    ) -> Result<Vec<u8>, CryptoError> {
595        use hpke::{Deserializable as _, Serializable as _};
596        let encapped_key = Kem::EncappedKey::from_bytes(kem_output).map_err(|_| CryptoError::HpkeDecryptionError)?;
597        // Systematically normalize private keys
598        let sk_len = Kem::PrivateKey::size();
599        let mut sk_buf = zeroize::Zeroizing::new(Vec::with_capacity(sk_len));
600        if private_key.len() < sk_len {
601            for _ in 0..(sk_len - private_key.len()) {
602                sk_buf.push(0x00);
603            }
604        }
605        sk_buf.extend_from_slice(private_key);
606        let key = Kem::PrivateKey::from_bytes(&sk_buf).map_err(|_| CryptoError::HpkeDecryptionError)?;
607        let plaintext =
608            hpke::single_shot_open::<Aead, Kdf, Kem>(&hpke::OpModeR::Base, &key, &encapped_key, info, ciphertext, aad)
609                .map_err(|_| CryptoError::HpkeDecryptionError)?;
610
611        Ok(plaintext)
612    }
613
614    pub(crate) fn hpke_seal<Aead: hpke::aead::Aead, Kdf: hpke::kdf::Kdf, Kem: hpke::Kem>(
615        public_key: &[u8],
616        info: &[u8],
617        aad: &[u8],
618        plaintext: &[u8],
619        csprng: &mut impl rand_core::CryptoRngCore,
620    ) -> Result<HpkeCiphertext, CryptoError> {
621        use hpke::{Deserializable as _, Serializable as _};
622        let key = Kem::PublicKey::from_bytes(public_key).map_err(|_| CryptoError::HpkeEncryptionError)?;
623        let (encapped, ciphertext) =
624            hpke::single_shot_seal::<Aead, Kdf, Kem, _>(&hpke::OpModeS::Base, &key, info, plaintext, aad, csprng)
625                .map_err(|_| CryptoError::HpkeEncryptionError)?;
626
627        Ok(HpkeCiphertext {
628            kem_output: encapped.to_bytes().to_vec().into(),
629            ciphertext: ciphertext.into(),
630        })
631    }
632
633    #[allow(dead_code)]
634    pub(crate) fn hpke_gen_keypair<Kem: hpke::Kem>(
635        csprng: &mut impl rand_core::CryptoRngCore,
636    ) -> Result<HpkeKeyPair, CryptoError> {
637        use hpke::Serializable as _;
638        let (sk, pk) = Kem::gen_keypair(csprng);
639        let (private, public) = (sk.to_bytes().to_vec().into(), pk.to_bytes().to_vec());
640
641        Ok(HpkeKeyPair { private, public })
642    }
643
644    pub(crate) fn hpke_derive_keypair<Kem: hpke::Kem>(ikm: &[u8]) -> Result<HpkeKeyPair, CryptoError> {
645        use hpke::Serializable as _;
646        let (sk, pk) = Kem::derive_keypair(ikm);
647        let (private, public) = (sk.to_bytes().to_vec().into(), pk.to_bytes().to_vec());
648
649        Ok(HpkeKeyPair { private, public })
650    }
651
652    pub(crate) fn hpke_export_rx<Aead: hpke::aead::Aead, Kdf: hpke::kdf::Kdf, Kem: hpke::Kem>(
653        encapped_key: &[u8],
654        rx_private_key: &[u8],
655        info: &[u8],
656        export_info: &[u8],
657        export_len: usize,
658    ) -> Result<Vec<u8>, CryptoError> {
659        use hpke::Deserializable as _;
660        let key = Kem::PrivateKey::from_bytes(rx_private_key).map_err(|_| CryptoError::ReceiverSetupError)?;
661        let encapped_key = Kem::EncappedKey::from_bytes(encapped_key).map_err(|_| CryptoError::ReceiverSetupError)?;
662        let ctx = hpke::setup_receiver::<Aead, Kdf, Kem>(&hpke::OpModeR::Base, &key, &encapped_key, info)
663            .map_err(|_| CryptoError::ReceiverSetupError)?;
664
665        let mut export = vec![0u8; export_len];
666
667        ctx.export(export_info, &mut export)
668            .map_err(|_| CryptoError::ExporterError)?;
669
670        Ok(export)
671    }
672
673    pub(crate) fn hpke_export_tx<Aead: hpke::aead::Aead, Kdf: hpke::kdf::Kdf, Kem: hpke::Kem>(
674        tx_public_key: &[u8],
675        info: &[u8],
676        export_info: &[u8],
677        export_len: usize,
678        csprng: &mut impl rand_core::CryptoRngCore,
679    ) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {
680        use hpke::{Deserializable as _, Serializable as _};
681        let key = Kem::PublicKey::from_bytes(tx_public_key).map_err(|_| CryptoError::SenderSetupError)?;
682        let (kem_output, ctx) = hpke::setup_sender::<Aead, Kdf, Kem, _>(&hpke::OpModeS::Base, &key, info, csprng)
683            .map_err(|_| CryptoError::SenderSetupError)?;
684
685        let mut export = vec![0u8; export_len];
686
687        ctx.export(export_info, &mut export)
688            .map_err(|_| CryptoError::ExporterError)?;
689
690        Ok((kem_output.to_bytes().to_vec(), export))
691    }
692}
693
694impl OpenMlsRand for RustCrypto {
695    type Error = MlsProviderError;
696
697    type RandImpl = rand_chacha::ChaCha20Rng;
698    type BorrowTarget<'a> = RwLockWriteGuard<'a, Self::RandImpl>;
699
700    fn borrow_rand(&self) -> Result<Self::BorrowTarget<'_>, Self::Error> {
701        self.rng.write().map_err(|_| MlsProviderError::RngLockPoison)
702    }
703
704    fn random_array<const N: usize>(&self) -> Result<[u8; N], Self::Error> {
705        let mut rng = self.borrow_rand()?;
706        let mut out = [0u8; N];
707        rng.try_fill_bytes(&mut out)
708            .map_err(|_| MlsProviderError::UnsufficientEntropy)?;
709        Ok(out)
710    }
711
712    fn random_vec(&self, len: usize) -> Result<Vec<u8>, Self::Error> {
713        let mut rng = self.borrow_rand()?;
714        let mut out = vec![0u8; len];
715        rng.try_fill_bytes(&mut out)
716            .map_err(|_| MlsProviderError::UnsufficientEntropy)?;
717        Ok(out)
718    }
719}