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
27pub(crate) static CRYPTO: LazyLock<Arc<RustCrypto>> = LazyLock::new(|| Arc::new(RustCrypto::default()));
30
31#[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 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 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 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 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 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}