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