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