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