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