1#![cfg_attr(not(feature = "std"), no_std)]
6extern crate alloc;
7
8pub mod aead;
9mod ec;
10pub mod ec_signer;
11pub mod ecdh;
12pub mod kdf;
13pub mod mac;
14
15#[cfg(feature = "x509")]
16pub mod x509;
17
18#[cfg(feature = "x509")]
19mod ec_for_x509;
20
21use crate::aead::Aead;
22use ec_signer::{EcSigner, EcSignerError};
23use ecdh::Ecdh;
24use kdf::Kdf;
25use mac::{Hash, HashError};
26use mls_rs_crypto_hpke::{
27 context::{ContextR, ContextS},
28 dhkem::DhKem,
29 hpke::{Hpke, HpkeError},
30};
31use mls_rs_crypto_traits::{AeadType, KdfType, KemId, KemType};
32use rand_core::{OsRng, RngCore};
33
34use mls_rs_core::{
35 crypto::{
36 CipherSuite, CipherSuiteProvider, CryptoProvider, HpkeCiphertext, HpkePublicKey,
37 HpkeSecretKey, SignaturePublicKey, SignatureSecretKey,
38 },
39 error::{AnyError, IntoAnyError},
40};
41use zeroize::Zeroizing;
42
43use alloc::vec;
44use alloc::vec::Vec;
45
46#[cfg(all(test, target_arch = "wasm32"))]
47wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
48
49#[derive(Debug)]
50#[cfg_attr(feature = "std", derive(thiserror::Error))]
51pub enum RustCryptoError {
52 #[cfg_attr(feature = "std", error(transparent))]
53 AeadError(AnyError),
54 #[cfg_attr(feature = "std", error(transparent))]
55 HpkeError(HpkeError),
56 #[cfg_attr(feature = "std", error(transparent))]
57 KdfError(AnyError),
58 #[cfg_attr(feature = "std", error(transparent))]
59 HashError(HashError),
60 #[cfg_attr(feature = "std", error("rand core error: {0:?}"))]
61 RandError(rand_core::Error),
62 #[cfg_attr(feature = "std", error(transparent))]
63 EcSignerError(EcSignerError),
64}
65
66impl From<rand_core::Error> for RustCryptoError {
67 fn from(value: rand_core::Error) -> Self {
68 RustCryptoError::RandError(value)
69 }
70}
71
72impl From<HpkeError> for RustCryptoError {
73 fn from(e: HpkeError) -> Self {
74 RustCryptoError::HpkeError(e)
75 }
76}
77
78impl From<HashError> for RustCryptoError {
79 fn from(e: HashError) -> Self {
80 RustCryptoError::HashError(e)
81 }
82}
83
84impl From<EcSignerError> for RustCryptoError {
85 fn from(e: EcSignerError) -> Self {
86 RustCryptoError::EcSignerError(e)
87 }
88}
89
90impl IntoAnyError for RustCryptoError {
91 #[cfg(feature = "std")]
92 fn into_dyn_error(self) -> Result<Box<dyn std::error::Error + Send + Sync>, Self> {
93 Ok(self.into())
94 }
95}
96
97#[derive(Debug, Clone)]
98#[non_exhaustive]
99pub struct RustCryptoProvider {
100 pub enabled_cipher_suites: Vec<CipherSuite>,
101}
102
103impl RustCryptoProvider {
104 pub fn new() -> Self {
105 Self::default()
106 }
107
108 pub fn with_enabled_cipher_suites(enabled_cipher_suites: Vec<CipherSuite>) -> Self {
109 Self {
110 enabled_cipher_suites,
111 }
112 }
113
114 pub fn all_supported_cipher_suites() -> Vec<CipherSuite> {
115 vec![
116 CipherSuite::P256_AES128,
117 CipherSuite::P384_AES256,
118 CipherSuite::CURVE25519_AES128,
119 CipherSuite::CURVE25519_CHACHA,
120 ]
121 }
122}
123
124impl Default for RustCryptoProvider {
125 fn default() -> Self {
126 Self {
127 enabled_cipher_suites: Self::all_supported_cipher_suites(),
128 }
129 }
130}
131
132impl CryptoProvider for RustCryptoProvider {
133 type CipherSuiteProvider = RustCryptoCipherSuite<DhKem<Ecdh, Kdf>, Kdf, Aead>;
134
135 fn supported_cipher_suites(&self) -> Vec<CipherSuite> {
136 self.enabled_cipher_suites.clone()
137 }
138
139 fn cipher_suite_provider(
140 &self,
141 cipher_suite: CipherSuite,
142 ) -> Option<Self::CipherSuiteProvider> {
143 if !self.enabled_cipher_suites.contains(&cipher_suite) {
144 return None;
145 }
146
147 let kdf = Kdf::new(cipher_suite)?;
148 let ecdh = Ecdh::new(cipher_suite)?;
149 let kem_id = KemId::new(cipher_suite)?;
150 let kem = DhKem::new(ecdh, kdf, kem_id as u16, kem_id.n_secret());
151 let aead = Aead::new(cipher_suite)?;
152
153 RustCryptoCipherSuite::new(cipher_suite, kem, kdf, aead)
154 }
155}
156
157#[derive(Clone)]
158pub struct RustCryptoCipherSuite<KEM, KDF, AEAD>
159where
160 KEM: KemType + Clone,
161 KDF: KdfType + Clone,
162 AEAD: AeadType + Clone,
163{
164 cipher_suite: CipherSuite,
165 aead: AEAD,
166 kdf: KDF,
167 hash: Hash,
168 hpke: Hpke<KEM, KDF, AEAD>,
169 ec_signer: EcSigner,
170}
171
172impl<KEM, KDF, AEAD> RustCryptoCipherSuite<KEM, KDF, AEAD>
173where
174 KEM: KemType + Clone,
175 KDF: KdfType + Clone,
176 AEAD: AeadType + Clone,
177{
178 pub fn new(cipher_suite: CipherSuite, kem: KEM, kdf: KDF, aead: AEAD) -> Option<Self> {
179 let hpke = Hpke::new(kem, kdf.clone(), Some(aead.clone()));
180
181 Some(Self {
182 cipher_suite,
183 kdf,
184 aead,
185 hash: Hash::new(cipher_suite).ok()?,
186 hpke,
187 ec_signer: EcSigner::new(cipher_suite)?,
188 })
189 }
190
191 pub fn random_bytes(&self, out: &mut [u8]) -> Result<(), RustCryptoError> {
192 OsRng.try_fill_bytes(out).map_err(Into::into)
193 }
194}
195
196#[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)]
197#[cfg_attr(all(target_arch = "wasm32", mls_build_async), maybe_async::must_be_async(?Send))]
198#[cfg_attr(
199 all(not(target_arch = "wasm32"), mls_build_async),
200 maybe_async::must_be_async
201)]
202impl<KEM, KDF, AEAD> CipherSuiteProvider for RustCryptoCipherSuite<KEM, KDF, AEAD>
203where
204 KEM: KemType + Clone + Send + Sync,
205 KDF: KdfType + Clone + Send + Sync,
206 AEAD: AeadType + Clone + Send + Sync,
207{
208 type Error = RustCryptoError;
209 type HpkeContextR = ContextR<KDF, AEAD>;
211 type HpkeContextS = ContextS<KDF, AEAD>;
212
213 async fn hash(&self, data: &[u8]) -> Result<Vec<u8>, Self::Error> {
214 Ok(self.hash.hash(data))
215 }
216
217 async fn mac(&self, key: &[u8], data: &[u8]) -> Result<Vec<u8>, Self::Error> {
218 Ok(self.hash.mac(key, data)?)
219 }
220
221 async fn aead_seal(
222 &self,
223 key: &[u8],
224 data: &[u8],
225 aad: Option<&[u8]>,
226 nonce: &[u8],
227 ) -> Result<Vec<u8>, Self::Error> {
228 self.aead
229 .seal(key, data, aad, nonce)
230 .await
231 .map_err(|e| RustCryptoError::AeadError(e.into_any_error()))
232 }
233
234 async fn aead_open(
235 &self,
236 key: &[u8],
237 cipher_text: &[u8],
238 aad: Option<&[u8]>,
239 nonce: &[u8],
240 ) -> Result<Zeroizing<Vec<u8>>, Self::Error> {
241 self.aead
242 .open(key, cipher_text, aad, nonce)
243 .await
244 .map_err(|e| RustCryptoError::AeadError(e.into_any_error()))
245 .map(Zeroizing::new)
246 }
247
248 fn aead_key_size(&self) -> usize {
249 self.aead.key_size()
250 }
251
252 fn aead_nonce_size(&self) -> usize {
253 self.aead.nonce_size()
254 }
255
256 async fn kdf_expand(
257 &self,
258 prk: &[u8],
259 info: &[u8],
260 len: usize,
261 ) -> Result<Zeroizing<Vec<u8>>, Self::Error> {
262 self.kdf
263 .expand(prk, info, len)
264 .await
265 .map_err(|e| RustCryptoError::KdfError(e.into_any_error()))
266 .map(Zeroizing::new)
267 }
268
269 async fn kdf_extract(
270 &self,
271 salt: &[u8],
272 ikm: &[u8],
273 ) -> Result<Zeroizing<Vec<u8>>, Self::Error> {
274 self.kdf
275 .extract(salt, ikm)
276 .await
277 .map_err(|e| RustCryptoError::KdfError(e.into_any_error()))
278 .map(Zeroizing::new)
279 }
280
281 fn kdf_extract_size(&self) -> usize {
282 self.kdf.extract_size()
283 }
284
285 async fn hpke_seal(
286 &self,
287 remote_key: &HpkePublicKey,
288 info: &[u8],
289 aad: Option<&[u8]>,
290 pt: &[u8],
291 ) -> Result<HpkeCiphertext, Self::Error> {
292 Ok(self.hpke.seal(remote_key, info, None, aad, pt).await?)
293 }
294
295 async fn hpke_open(
296 &self,
297 ciphertext: &HpkeCiphertext,
298 local_secret: &HpkeSecretKey,
299 local_public: &HpkePublicKey,
300 info: &[u8],
301 aad: Option<&[u8]>,
302 ) -> Result<Vec<u8>, Self::Error> {
303 Ok(self
304 .hpke
305 .open(ciphertext, local_secret, local_public, info, None, aad)
306 .await?)
307 }
308
309 async fn hpke_setup_r(
310 &self,
311 enc: &[u8],
312 local_secret: &HpkeSecretKey,
313 local_public: &HpkePublicKey,
314 info: &[u8],
315 ) -> Result<Self::HpkeContextR, Self::Error> {
316 Ok(self
317 .hpke
318 .setup_receiver(enc, local_secret, local_public, info, None)
319 .await?)
320 }
321
322 async fn hpke_setup_s(
323 &self,
324 remote_key: &HpkePublicKey,
325 info: &[u8],
326 ) -> Result<(Vec<u8>, Self::HpkeContextS), Self::Error> {
327 Ok(self.hpke.setup_sender(remote_key, info, None).await?)
328 }
329
330 async fn kem_derive(&self, ikm: &[u8]) -> Result<(HpkeSecretKey, HpkePublicKey), Self::Error> {
331 Ok(self.hpke.derive(ikm).await?)
332 }
333
334 async fn kem_generate(&self) -> Result<(HpkeSecretKey, HpkePublicKey), Self::Error> {
335 Ok(self.hpke.generate().await?)
336 }
337
338 fn kem_public_key_validate(&self, key: &HpkePublicKey) -> Result<(), Self::Error> {
339 Ok(self.hpke.public_key_validate(key)?)
340 }
341
342 fn random_bytes(&self, out: &mut [u8]) -> Result<(), Self::Error> {
343 self.random_bytes(out)
344 }
345
346 fn cipher_suite(&self) -> CipherSuite {
347 self.cipher_suite
348 }
349
350 async fn sign(
351 &self,
352 secret_key: &SignatureSecretKey,
353 data: &[u8],
354 ) -> Result<Vec<u8>, Self::Error> {
355 Ok(self.ec_signer.sign(secret_key, data)?)
356 }
357
358 async fn verify(
359 &self,
360 public_key: &SignaturePublicKey,
361 signature: &[u8],
362 data: &[u8],
363 ) -> Result<(), Self::Error> {
364 Ok(self.ec_signer.verify(public_key, signature, data)?)
365 }
366
367 async fn signature_key_generate(
368 &self,
369 ) -> Result<(SignatureSecretKey, SignaturePublicKey), Self::Error> {
370 Ok(self.ec_signer.signature_key_generate()?)
371 }
372
373 async fn signature_key_derive_public(
374 &self,
375 secret_key: &SignatureSecretKey,
376 ) -> Result<SignaturePublicKey, Self::Error> {
377 Ok(self.ec_signer.signature_key_derive_public(secret_key)?)
378 }
379}
380
381#[cfg(not(mls_build_async))]
382#[test]
383fn mls_core_tests() {
384 let provider = RustCryptoProvider::new();
385 mls_rs_core::crypto::test_suite::verify_tests(&provider, true);
386
387 for cs in RustCryptoProvider::all_supported_cipher_suites() {
388 let mut hpke = provider.cipher_suite_provider(cs).unwrap().hpke;
389
390 mls_rs_core::crypto::test_suite::verify_hpke_context_tests(&hpke, cs);
391 mls_rs_core::crypto::test_suite::verify_hpke_encap_tests(&mut hpke, cs);
392 }
393}
394
395#[cfg(all(test, target_arch = "wasm32"))]
396#[wasm_bindgen_test::wasm_bindgen_test]
397async fn mls_rs_core_test() {
398 let provider = RustCryptoProvider::new();
399 mls_rs_core::crypto::test_suite::verify_tests(&provider, true).await;
400}