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