Skip to main content

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