1use std::str::FromStr;
2
3use bitwarden_core::key_management::KeyIds;
4#[allow(deprecated)]
5use bitwarden_crypto::dangerous_derive_kdf_material;
6use bitwarden_crypto::{
7 BitwardenLegacyKeyBytes, CoseKeyBytes, CoseSerializable, CoseSign1Bytes, CryptoError,
8 Decryptable, EncString, Kdf, KeyDecryptable, KeyEncryptable, KeyStore, MasterKey,
9 OctetStreamBytes, Pkcs8PrivateKeyBytes, PrimitiveEncryptable, PrivateKey, PublicKey,
10 PublicKeyEncryptionAlgorithm, SignatureAlgorithm, SignedPublicKey, SigningKey,
11 SpkiPublicKeyBytes, SymmetricCryptoKey, UnsignedSharedKey, VerifyingKey,
12};
13use rand::Rng;
14use rsa::{
15 Oaep, RsaPrivateKey, RsaPublicKey,
16 pkcs8::{DecodePrivateKey, DecodePublicKey},
17};
18use sha1::Sha1;
19use wasm_bindgen::prelude::*;
20
21#[wasm_bindgen]
26pub struct PureCrypto {}
27
28#[wasm_bindgen]
30impl PureCrypto {
31 pub fn symmetric_decrypt(enc_string: String, key: Vec<u8>) -> Result<String, CryptoError> {
34 Self::symmetric_decrypt_string(enc_string, key)
35 }
36
37 pub fn symmetric_decrypt_string(
38 enc_string: String,
39 key: Vec<u8>,
40 ) -> Result<String, CryptoError> {
41 let _span = tracing::info_span!("PureCrypto::symmetric_decrypt_string").entered();
42 let key = &BitwardenLegacyKeyBytes::from(key);
43 EncString::from_str(&enc_string)?.decrypt_with_key(&SymmetricCryptoKey::try_from(key)?)
44 }
45
46 pub fn symmetric_decrypt_bytes(
47 enc_string: String,
48 key: Vec<u8>,
49 ) -> Result<Vec<u8>, CryptoError> {
50 let _span = tracing::info_span!("PureCrypto::symmetric_decrypt_bytes").entered();
51 let key = &BitwardenLegacyKeyBytes::from(key);
52 EncString::from_str(&enc_string)?.decrypt_with_key(&SymmetricCryptoKey::try_from(key)?)
53 }
54
55 pub fn symmetric_decrypt_array_buffer(
58 enc_bytes: Vec<u8>,
59 key: Vec<u8>,
60 ) -> Result<Vec<u8>, CryptoError> {
61 Self::symmetric_decrypt_filedata(enc_bytes, key)
62 }
63
64 pub fn symmetric_decrypt_filedata(
65 enc_bytes: Vec<u8>,
66 key: Vec<u8>,
67 ) -> Result<Vec<u8>, CryptoError> {
68 let _span = tracing::info_span!("PureCrypto::symmetric_decrypt_filedata").entered();
69 let key = &BitwardenLegacyKeyBytes::from(key);
70 EncString::from_buffer(&enc_bytes)?.decrypt_with_key(&SymmetricCryptoKey::try_from(key)?)
71 }
72
73 pub fn symmetric_encrypt_string(plain: String, key: Vec<u8>) -> Result<String, CryptoError> {
74 let _span = tracing::info_span!("PureCrypto::symmetric_encrypt_string").entered();
75 let key = &BitwardenLegacyKeyBytes::from(key);
76 plain
77 .encrypt_with_key(&SymmetricCryptoKey::try_from(key)?)
78 .map(|enc| enc.to_string())
79 }
80
81 pub fn symmetric_encrypt_bytes(plain: Vec<u8>, key: Vec<u8>) -> Result<String, CryptoError> {
83 let _span = tracing::info_span!("PureCrypto::symmetric_encrypt_bytes").entered();
84 let key = &BitwardenLegacyKeyBytes::from(key);
85 OctetStreamBytes::from(plain)
86 .encrypt_with_key(&SymmetricCryptoKey::try_from(key)?)
87 .map(|enc| enc.to_string())
88 }
89
90 pub fn symmetric_encrypt_filedata(
91 plain: Vec<u8>,
92 key: Vec<u8>,
93 ) -> Result<Vec<u8>, CryptoError> {
94 let _span = tracing::info_span!("PureCrypto::symmetric_encrypt_filedata").entered();
95 let key = &BitwardenLegacyKeyBytes::from(key);
96 OctetStreamBytes::from(plain)
97 .encrypt_with_key(&SymmetricCryptoKey::try_from(key)?)?
98 .to_buffer()
99 }
100
101 pub fn decrypt_user_key_with_master_password(
102 encrypted_user_key: String,
103 master_password: String,
104 email: String,
105 kdf: Kdf,
106 ) -> Result<Vec<u8>, CryptoError> {
107 let _span = tracing::info_span!(
108 "PureCrypto::decrypt_user_key_with_master_password",
109 email = %email,
110 kdf = ?kdf
111 )
112 .entered();
113
114 let master_key = MasterKey::derive(master_password.as_str(), email.as_str(), &kdf)?;
115 let encrypted_user_key = EncString::from_str(&encrypted_user_key)?;
116 let result = master_key
117 .decrypt_user_key(encrypted_user_key)
118 .map_err(|_| CryptoError::InvalidKey)?;
119 Ok(result.to_encoded().to_vec())
120 }
121
122 pub fn encrypt_user_key_with_master_password(
123 user_key: Vec<u8>,
124 master_password: String,
125 email: String,
126 kdf: Kdf,
127 ) -> Result<String, CryptoError> {
128 let _span = tracing::info_span!(
129 "PureCrypto::encrypt_user_key_with_master_password",
130 email = %email,
131 kdf = ?kdf
132 )
133 .entered();
134 let master_key = MasterKey::derive(master_password.as_str(), email.as_str(), &kdf)?;
135 let user_key = &BitwardenLegacyKeyBytes::from(user_key);
136 let user_key = SymmetricCryptoKey::try_from(user_key)?;
137 let result = master_key.encrypt_user_key(&user_key)?;
138 Ok(result.to_string())
139 }
140
141 pub fn make_user_key_aes256_cbc_hmac() -> Vec<u8> {
142 SymmetricCryptoKey::make_aes256_cbc_hmac_key()
143 .to_encoded()
144 .to_vec()
145 }
146
147 pub fn make_user_key_xchacha20_poly1305() -> Vec<u8> {
148 SymmetricCryptoKey::make_xchacha20_poly1305_key()
149 .to_encoded()
150 .to_vec()
151 }
152
153 pub fn wrap_symmetric_key(
156 key_to_be_wrapped: Vec<u8>,
157 wrapping_key: Vec<u8>,
158 ) -> Result<String, CryptoError> {
159 let _span = tracing::info_span!("PureCrypto::wrap_symmetric_key").entered();
160 let tmp_store: KeyStore<KeyIds> = KeyStore::default();
161 let mut context = tmp_store.context();
162 let wrapping_key =
163 SymmetricCryptoKey::try_from(&BitwardenLegacyKeyBytes::from(wrapping_key))?;
164 let wrapping_key = context.add_local_symmetric_key(wrapping_key);
165 let key_to_be_wrapped =
166 SymmetricCryptoKey::try_from(&BitwardenLegacyKeyBytes::from(key_to_be_wrapped))?;
167 let key_to_wrap = context.add_local_symmetric_key(key_to_be_wrapped);
168 Ok(context
170 .wrap_symmetric_key(wrapping_key, key_to_wrap)?
171 .to_string())
172 }
173
174 pub fn unwrap_symmetric_key(
177 wrapped_key: String,
178 wrapping_key: Vec<u8>,
179 ) -> Result<Vec<u8>, CryptoError> {
180 let _span = tracing::info_span!("PureCrypto::unwrap_symmetric_key").entered();
181 let tmp_store: KeyStore<KeyIds> = KeyStore::default();
182 let mut context = tmp_store.context();
183 let wrapping_key =
184 SymmetricCryptoKey::try_from(&BitwardenLegacyKeyBytes::from(wrapping_key))?;
185 let wrapping_key = context.add_local_symmetric_key(wrapping_key);
186 let unwrapped = context
188 .unwrap_symmetric_key(wrapping_key, &EncString::from_str(wrapped_key.as_str())?)?;
189 #[allow(deprecated)]
190 let key = context.dangerous_get_symmetric_key(unwrapped)?;
191 Ok(key.to_encoded().to_vec())
192 }
193
194 pub fn wrap_encapsulation_key(
200 encapsulation_key: Vec<u8>,
201 wrapping_key: Vec<u8>,
202 ) -> Result<String, CryptoError> {
203 let _span = tracing::info_span!("PureCrypto::wrap_encapsulation_key").entered();
204 let tmp_store: KeyStore<KeyIds> = KeyStore::default();
205 let mut context = tmp_store.context();
206 let wrapping_key = context.add_local_symmetric_key(SymmetricCryptoKey::try_from(
207 &BitwardenLegacyKeyBytes::from(wrapping_key),
208 )?);
209 Ok(SpkiPublicKeyBytes::from(encapsulation_key)
210 .encrypt(&mut context, wrapping_key)?
211 .to_string())
212 }
213
214 pub fn unwrap_encapsulation_key(
217 wrapped_key: String,
218 wrapping_key: Vec<u8>,
219 ) -> Result<Vec<u8>, CryptoError> {
220 let _span = tracing::info_span!("PureCrypto::unwrap_encapsulation_key").entered();
221 let tmp_store: KeyStore<KeyIds> = KeyStore::default();
222 let mut context = tmp_store.context();
223 let wrapping_key = context.add_local_symmetric_key(SymmetricCryptoKey::try_from(
224 &BitwardenLegacyKeyBytes::from(wrapping_key),
225 )?);
226 EncString::from_str(wrapped_key.as_str())?.decrypt(&mut context, wrapping_key)
227 }
228
229 pub fn wrap_decapsulation_key(
232 decapsulation_key: Vec<u8>,
233 wrapping_key: Vec<u8>,
234 ) -> Result<String, CryptoError> {
235 let _span = tracing::info_span!("PureCrypto::wrap_decapsulation_key").entered();
236 let tmp_store: KeyStore<KeyIds> = KeyStore::default();
237 let mut context = tmp_store.context();
238 let wrapping_key = context.add_local_symmetric_key(SymmetricCryptoKey::try_from(
239 &BitwardenLegacyKeyBytes::from(wrapping_key),
240 )?);
241 Ok(Pkcs8PrivateKeyBytes::from(decapsulation_key)
242 .encrypt(&mut context, wrapping_key)?
243 .to_string())
244 }
245
246 pub fn unwrap_decapsulation_key(
249 wrapped_key: String,
250 wrapping_key: Vec<u8>,
251 ) -> Result<Vec<u8>, CryptoError> {
252 let _span = tracing::info_span!("PureCrypto::unwrap_decapsulation_key").entered();
253 let tmp_store: KeyStore<KeyIds> = KeyStore::default();
254 let mut context = tmp_store.context();
255 let wrapping_key = context.add_local_symmetric_key(SymmetricCryptoKey::try_from(
256 &BitwardenLegacyKeyBytes::from(wrapping_key),
257 )?);
258 EncString::from_str(wrapped_key.as_str())?.decrypt(&mut context, wrapping_key)
259 }
260
261 pub fn encapsulate_key_unsigned(
265 shared_key: Vec<u8>,
266 encapsulation_key: Vec<u8>,
267 ) -> Result<String, CryptoError> {
268 let _span = tracing::info_span!("PureCrypto::encapsulate_key_unsigned").entered();
269 let encapsulation_key = PublicKey::from_der(&SpkiPublicKeyBytes::from(encapsulation_key))?;
270 #[expect(deprecated)]
271 Ok(UnsignedSharedKey::encapsulate_key_unsigned(
272 &SymmetricCryptoKey::try_from(&BitwardenLegacyKeyBytes::from(shared_key))?,
273 &encapsulation_key,
274 )?
275 .to_string())
276 }
277
278 pub fn decapsulate_key_unsigned(
282 encapsulated_key: String,
283 decapsulation_key: Vec<u8>,
284 ) -> Result<Vec<u8>, CryptoError> {
285 let _span = tracing::info_span!("PureCrypto::decapsulate_key_unsigned").entered();
286 #[expect(deprecated)]
287 Ok(UnsignedSharedKey::from_str(encapsulated_key.as_str())?
288 .decapsulate_key_unsigned(&PrivateKey::from_der(&Pkcs8PrivateKeyBytes::from(
289 decapsulation_key,
290 ))?)?
291 .to_encoded()
292 .to_vec())
293 }
294
295 pub fn verifying_key_for_signing_key(
298 signing_key: String,
299 wrapping_key: Vec<u8>,
300 ) -> Result<Vec<u8>, CryptoError> {
301 let _span = tracing::info_span!("PureCrypto::verifying_key_for_signing_key").entered();
302 let bytes = Self::symmetric_decrypt_bytes(signing_key, wrapping_key)?;
303 let signing_key = SigningKey::from_cose(&CoseKeyBytes::from(bytes))?;
304 let verifying_key = signing_key.to_verifying_key();
305 Ok(verifying_key.to_cose().to_vec())
306 }
307
308 pub fn key_algorithm_for_verifying_key(
310 verifying_key: Vec<u8>,
311 ) -> Result<SignatureAlgorithm, CryptoError> {
312 let _span = tracing::info_span!("PureCrypto::key_algorithm_for_verifying_key").entered();
313 let verifying_key = VerifyingKey::from_cose(&CoseKeyBytes::from(verifying_key))?;
314 let algorithm = verifying_key.algorithm();
315 Ok(algorithm)
316 }
317
318 pub fn verify_and_unwrap_signed_public_key(
323 signed_public_key: Vec<u8>,
324 verifying_key: Vec<u8>,
325 ) -> Result<Vec<u8>, CryptoError> {
326 let _span =
327 tracing::info_span!("PureCrypto::verify_and_unwrap_signed_public_key").entered();
328 let signed_public_key = SignedPublicKey::try_from(CoseSign1Bytes::from(signed_public_key))?;
329 let verifying_key = VerifyingKey::from_cose(&CoseKeyBytes::from(verifying_key))?;
330 signed_public_key
331 .verify_and_unwrap(&verifying_key)
332 .map(|public_key| public_key.to_der())?
333 .map(|pk| pk.to_vec())
334 }
335
336 pub fn derive_kdf_material(
338 password: &[u8],
339 salt: &[u8],
340 kdf: Kdf,
341 ) -> Result<Vec<u8>, CryptoError> {
342 let _span = tracing::info_span!("PureCrypto::derive_kdf_material", kdf = ?kdf).entered();
343 #[allow(deprecated)]
344 dangerous_derive_kdf_material(password, salt, &kdf)
345 }
346
347 pub fn decrypt_user_key_with_master_key(
348 encrypted_user_key: String,
349 master_key: Vec<u8>,
350 ) -> Result<Vec<u8>, CryptoError> {
351 let _span = tracing::info_span!("PureCrypto::decrypt_user_key_with_master_key").entered();
352 let master_key = &BitwardenLegacyKeyBytes::from(master_key);
353 let master_key = &SymmetricCryptoKey::try_from(master_key)?;
354 let master_key = MasterKey::try_from(master_key)?;
355 let encrypted_user_key = EncString::from_str(&encrypted_user_key)?;
356 let result = master_key
357 .decrypt_user_key(encrypted_user_key)
358 .map_err(|_| CryptoError::InvalidKey)?;
359 Ok(result.to_encoded().to_vec())
360 }
361
362 pub fn rsa_extract_public_key(private_key: Vec<u8>) -> Result<Vec<u8>, RsaError> {
366 let _span = tracing::info_span!("PureCrypto::rsa_extract_public_key").entered();
367 let private_key = PrivateKey::from_der(&Pkcs8PrivateKeyBytes::from(private_key))
368 .map_err(|_| RsaError::KeyParse)?;
369 let public_key = private_key.to_public_key();
370 Ok(public_key
371 .to_der()
372 .map_err(|_| RsaError::KeySerialize)?
373 .to_vec())
374 }
375
376 pub fn rsa_generate_keypair() -> Result<Vec<u8>, RsaError> {
379 let _span = tracing::info_span!("PureCrypto::rsa_generate_keypair").entered();
380 let private_key = PrivateKey::make(PublicKeyEncryptionAlgorithm::RsaOaepSha1);
381 Ok(private_key
382 .to_der()
383 .map_err(|_| RsaError::KeySerialize)?
384 .to_vec())
385 }
386
387 pub fn rsa_decrypt_data(
390 encrypted_data: Vec<u8>,
391 private_key: Vec<u8>,
392 ) -> Result<Vec<u8>, RsaError> {
393 let _span = tracing::info_span!("PureCrypto::rsa_decrypt_data").entered();
394 let private_key = RsaPrivateKey::from_pkcs8_der(private_key.as_slice())
395 .map_err(|_| RsaError::KeyParse)?;
396 let padding = Oaep::new::<Sha1>();
397 private_key
398 .decrypt(padding, &encrypted_data)
399 .map_err(|_| RsaError::Decryption)
400 }
401
402 pub fn rsa_encrypt_data(plain_data: Vec<u8>, public_key: Vec<u8>) -> Result<Vec<u8>, RsaError> {
405 let _span = tracing::info_span!("PureCrypto::rsa_encrypt_data").entered();
406 let public_key = RsaPublicKey::from_public_key_der(public_key.as_slice())
407 .map_err(|_| RsaError::KeyParse)?;
408 let padding = Oaep::new::<Sha1>();
409 let mut rng = rand::thread_rng();
410 public_key
411 .encrypt(&mut rng, padding, &plain_data)
412 .map_err(|_| RsaError::Encryption)
413 }
414
415 pub fn random_number(min: u32, max: u32) -> u32 {
418 let _span = tracing::info_span!("PureCrypto::random_number").entered();
419 let mut rng = rand::thread_rng();
420 rng.gen_range(min..=max)
421 }
422}
423
424#[wasm_bindgen]
425#[derive(Debug)]
426pub enum RsaError {
427 Decryption,
428 Encryption,
429 KeyParse,
430 KeySerialize,
431}
432
433#[cfg(test)]
434mod tests {
435 use std::{num::NonZero, str::FromStr};
436
437 use bitwarden_crypto::EncString;
438
439 use super::*;
440
441 const KEY: &[u8] = &[
442 81, 142, 1, 228, 222, 3, 3, 133, 34, 176, 35, 66, 150, 6, 109, 70, 190, 149, 47, 47, 89,
443 23, 144, 87, 92, 46, 220, 13, 148, 106, 162, 234, 202, 139, 136, 33, 16, 200, 8, 73, 176,
444 172, 185, 187, 224, 10, 65, 223, 228, 54, 92, 181, 8, 213, 162, 221, 117, 254, 245, 111,
445 55, 211, 77, 29,
446 ];
447
448 const ENCRYPTED: &str = "2.Dh7AFLXR+LXcxUaO5cRjpg==|uXyhubjAoNH8lTdy/zgJDQ==|cHEMboj0MYsU5yDRQ1rLCgxcjNbKRc1PWKuv8bpU5pM=";
449 const DECRYPTED: &str = "test";
450 const DECRYPTED_BYTES: &[u8] = b"test";
451 const ENCRYPTED_BYTES: &[u8] = &[
452 2, 209, 195, 115, 49, 205, 253, 128, 162, 169, 246, 175, 217, 144, 73, 108, 191, 27, 113,
453 69, 55, 94, 142, 62, 129, 204, 173, 130, 37, 42, 97, 209, 25, 192, 64, 126, 112, 139, 248,
454 2, 89, 112, 178, 83, 25, 77, 130, 187, 127, 85, 179, 211, 159, 186, 111, 44, 109, 211, 18,
455 120, 104, 144, 4, 76, 3,
456 ];
457
458 const PEM_KEY: &str = "-----BEGIN PRIVATE KEY-----
459MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDiTQVuzhdygFz5
460qv14i+XFDGTnDravzUQT1hPKPGUZOUSZ1gwdNgkWqOIaOnR65BHEnL0sp4bnuiYc
461afeK2JAW5Sc8Z7IxBNSuAwhQmuKx3RochMIiuCkI2/p+JvUQoJu6FBNm8OoJ4Cwm
462qqHGZESMfnpQDCuDrB3JdJEdXhtmnl0C48sGjOk3WaBMcgGqn8LbJDUlyu1zdqyv
463b0waJf0iV4PJm2fkUl7+57D/2TkpbCqURVnZK1FFIEg8mr6FzSN1F2pOfktkNYZw
464P7MSNR7o81CkRSCMr7EkIVa+MZYMBx106BMK7FXgWB7nbSpsWKxBk7ZDHkID2fam
465rEcVtrzDAgMBAAECggEBAKwq9OssGGKgjhvUnyrLJHAZ0dqIMyzk+dotkLjX4gKi
466szJmyqiep6N5sStLNbsZMPtoU/RZMCW0VbJgXFhiEp2YkZU/Py5UAoqw++53J+kx
4670d/IkPphKbb3xUec0+1mg5O6GljDCQuiZXS1dIa/WfeZcezclW6Dz9WovY6ePjJ+
4688vEBR1icbNKzyeINd6MtPtpcgQPHtDwHvhPyUDbKDYGbLvjh9nui8h4+ZUlXKuVR
469jB0ChxiKV1xJRjkrEVoulOOicd5r597WfB2ghax3pvRZ4MdXemCXm3gQYqPVKach
470vGU+1cPQR/MBJZpxT+EZA97xwtFS3gqwbxJaNFcoE8ECgYEA9OaeYZhQPDo485tI
4711u/Z7L/3PNape9hBQIXoW7+MgcQ5NiWqYh8Jnj43EIYa0wM/ECQINr1Za8Q5e6KR
472J30FcU+kfyjuQ0jeXdNELGU/fx5XXNg/vV8GevHwxRlwzqZTCg6UExUZzbYEQqd7
473l+wPyETGeua5xCEywA1nX/D101kCgYEA7I6aMFjhEjO71RmzNhqjKJt6DOghoOfQ
474TjhaaanNEhLYSbenFz1mlb21mW67ulmz162saKdIYLxQNJIP8ZPmxh4ummOJI8w9
475ClHfo8WuCI2hCjJ19xbQJocSbTA5aJg6lA1IDVZMDbQwsnAByPRGpaLHBT/Q9Bye
476KvCMB+9amXsCgYEAx65yXSkP4sumPBrVHUub6MntERIGRxBgw/drKcPZEMWp0FiN
477wEuGUBxyUWrG3F69QK/gcqGZE6F/LSu0JvptQaKqgXQiMYJsrRvhbkFvsHpQyUcZ
478UZL1ebFjm5HOxPAgrQaN/bEqxOwwNRjSUWEMzUImg3c06JIZCzbinvudtKECgYEA
479kY3JF/iIPI/yglP27lKDlCfeeHSYxI3+oTKRhzSAxx8rUGidenJAXeDGDauR/T7W
480pt3pGNfddBBK9Z3uC4Iq3DqUCFE4f/taj7ADAJ1Q0Vh7/28/IJM77ojr8J1cpZwN
481Zy2o6PPxhfkagaDjqEeN9Lrs5LD4nEvDkr5CG1vOjmMCgYEAvIBFKRm31NyF8jLi
482CVuPwC5PzrW5iThDmsWTaXFpB3esUsbICO2pEz872oeQS+Em4GO5vXUlpbbFPzup
483PFhA8iMJ8TAvemhvc7oM0OZqpU6p3K4seHf6BkwLxumoA3vDJfovu9RuXVcJVOnf
484DnqOsltgPomWZ7xVfMkm9niL2OA=
485-----END PRIVATE KEY-----";
486
487 const SIGNING_KEY_WRAPPING_KEY: &[u8] = &[
488 40, 215, 110, 199, 183, 4, 182, 78, 213, 123, 251, 113, 72, 223, 57, 2, 3, 81, 136, 19, 88,
489 78, 206, 176, 158, 251, 211, 84, 1, 199, 203, 142, 176, 227, 187, 136, 209, 79, 23, 13, 44,
490 224, 90, 10, 191, 72, 22, 227, 171, 105, 107, 139, 24, 49, 9, 150, 103, 139, 151, 204, 165,
491 121, 165, 71,
492 ];
493 const SIGNING_KEY: &[u8] = &[
494 166, 1, 1, 2, 80, 123, 226, 102, 228, 194, 232, 71, 30, 183, 42, 219, 193, 50, 30, 21, 43,
495 3, 39, 4, 130, 1, 2, 35, 88, 32, 148, 2, 66, 69, 169, 57, 129, 240, 37, 18, 225, 211, 207,
496 133, 66, 143, 204, 238, 113, 152, 43, 112, 133, 173, 179, 17, 202, 135, 175, 237, 1, 59,
497 32, 6,
498 ];
499 const VERIFYING_KEY: &[u8] = &[
500 166, 1, 1, 2, 80, 123, 226, 102, 228, 194, 232, 71, 30, 183, 42, 219, 193, 50, 30, 21, 43,
501 3, 39, 4, 129, 2, 32, 6, 33, 88, 32, 63, 70, 49, 37, 246, 232, 146, 144, 83, 224, 0, 17,
502 111, 248, 16, 242, 69, 195, 84, 46, 39, 218, 55, 63, 90, 112, 148, 91, 224, 186, 122, 4,
503 ];
504 const PUBLIC_KEY: &[u8] = &[
505 48, 130, 1, 34, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3, 130, 1, 15, 0,
506 48, 130, 1, 10, 2, 130, 1, 1, 0, 173, 4, 54, 63, 125, 12, 254, 38, 115, 34, 95, 164, 148,
507 115, 86, 140, 129, 74, 19, 70, 212, 212, 130, 163, 105, 249, 101, 120, 154, 46, 194, 250,
508 229, 242, 156, 67, 109, 179, 187, 134, 59, 235, 60, 107, 144, 163, 35, 22, 109, 230, 134,
509 243, 44, 243, 79, 84, 76, 11, 64, 56, 236, 167, 98, 26, 30, 213, 143, 105, 52, 92, 129, 92,
510 88, 22, 115, 135, 63, 215, 79, 8, 11, 183, 124, 10, 73, 231, 170, 110, 210, 178, 22, 100,
511 76, 75, 118, 202, 252, 204, 67, 204, 152, 6, 244, 208, 161, 146, 103, 225, 233, 239, 88,
512 195, 88, 150, 230, 111, 62, 142, 12, 157, 184, 155, 34, 84, 237, 111, 11, 97, 56, 152, 130,
513 14, 72, 123, 140, 47, 137, 5, 97, 166, 4, 147, 111, 23, 65, 78, 63, 208, 198, 50, 161, 39,
514 80, 143, 100, 194, 37, 252, 194, 53, 207, 166, 168, 250, 165, 121, 9, 207, 90, 36, 213,
515 211, 84, 255, 14, 205, 114, 135, 217, 137, 105, 232, 58, 169, 222, 10, 13, 138, 203, 16,
516 12, 122, 72, 227, 95, 160, 111, 54, 200, 198, 143, 156, 15, 143, 196, 50, 150, 204, 144,
517 255, 162, 248, 50, 28, 47, 66, 9, 83, 158, 67, 9, 50, 147, 174, 147, 200, 199, 238, 190,
518 248, 60, 114, 218, 32, 209, 120, 218, 17, 234, 14, 128, 192, 166, 33, 60, 73, 227, 108,
519 201, 41, 160, 81, 133, 171, 205, 221, 2, 3, 1, 0, 1,
520 ];
521
522 const SIGNED_PUBLIC_KEY: &[u8] = &[
523 132, 88, 30, 164, 1, 39, 3, 24, 60, 4, 80, 123, 226, 102, 228, 194, 232, 71, 30, 183, 42,
524 219, 193, 50, 30, 21, 43, 58, 0, 1, 56, 127, 1, 160, 89, 1, 78, 163, 105, 97, 108, 103,
525 111, 114, 105, 116, 104, 109, 0, 109, 99, 111, 110, 116, 101, 110, 116, 70, 111, 114, 109,
526 97, 116, 0, 105, 112, 117, 98, 108, 105, 99, 75, 101, 121, 89, 1, 38, 48, 130, 1, 34, 48,
527 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3, 130, 1, 15, 0, 48, 130, 1, 10, 2,
528 130, 1, 1, 0, 173, 4, 54, 63, 125, 12, 254, 38, 115, 34, 95, 164, 148, 115, 86, 140, 129,
529 74, 19, 70, 212, 212, 130, 163, 105, 249, 101, 120, 154, 46, 194, 250, 229, 242, 156, 67,
530 109, 179, 187, 134, 59, 235, 60, 107, 144, 163, 35, 22, 109, 230, 134, 243, 44, 243, 79,
531 84, 76, 11, 64, 56, 236, 167, 98, 26, 30, 213, 143, 105, 52, 92, 129, 92, 88, 22, 115, 135,
532 63, 215, 79, 8, 11, 183, 124, 10, 73, 231, 170, 110, 210, 178, 22, 100, 76, 75, 118, 202,
533 252, 204, 67, 204, 152, 6, 244, 208, 161, 146, 103, 225, 233, 239, 88, 195, 88, 150, 230,
534 111, 62, 142, 12, 157, 184, 155, 34, 84, 237, 111, 11, 97, 56, 152, 130, 14, 72, 123, 140,
535 47, 137, 5, 97, 166, 4, 147, 111, 23, 65, 78, 63, 208, 198, 50, 161, 39, 80, 143, 100, 194,
536 37, 252, 194, 53, 207, 166, 168, 250, 165, 121, 9, 207, 90, 36, 213, 211, 84, 255, 14, 205,
537 114, 135, 217, 137, 105, 232, 58, 169, 222, 10, 13, 138, 203, 16, 12, 122, 72, 227, 95,
538 160, 111, 54, 200, 198, 143, 156, 15, 143, 196, 50, 150, 204, 144, 255, 162, 248, 50, 28,
539 47, 66, 9, 83, 158, 67, 9, 50, 147, 174, 147, 200, 199, 238, 190, 248, 60, 114, 218, 32,
540 209, 120, 218, 17, 234, 14, 128, 192, 166, 33, 60, 73, 227, 108, 201, 41, 160, 81, 133,
541 171, 205, 221, 2, 3, 1, 0, 1, 88, 64, 207, 18, 4, 242, 149, 31, 37, 255, 243, 62, 78, 46,
542 12, 150, 134, 159, 69, 89, 62, 222, 132, 12, 177, 74, 155, 80, 154, 37, 77, 176, 19, 142,
543 73, 4, 134, 242, 24, 56, 54, 38, 178, 59, 11, 118, 230, 159, 87, 91, 20, 237, 188, 186,
544 216, 86, 189, 50, 46, 173, 117, 36, 54, 105, 216, 9,
545 ];
546
547 const DERIVED_KDF_MATERIAL_PBKDF2: &[u8] = &[
548 129, 57, 137, 140, 156, 220, 110, 212, 201, 255, 52, 182, 22, 206, 221, 66, 136, 199, 181,
549 89, 252, 175, 82, 168, 79, 204, 88, 174, 166, 60, 52, 79,
550 ];
551 const DERIVED_KDF_MATERIAL_ARGON2ID: &[u8] = &[
552 221, 57, 158, 206, 27, 154, 188, 170, 33, 198, 250, 144, 191, 231, 29, 74, 201, 102, 253,
553 77, 8, 128, 173, 111, 217, 41, 125, 9, 156, 52, 112, 140,
554 ];
555
556 #[test]
557 fn test_symmetric_decrypt() {
558 let enc_string = EncString::from_str(ENCRYPTED).unwrap();
559
560 let result = PureCrypto::symmetric_decrypt_string(enc_string.to_string(), KEY.to_vec());
561 assert!(result.is_ok());
562 assert_eq!(result.unwrap(), DECRYPTED);
563 }
564
565 #[test]
566 fn test_symmetric_encrypt() {
567 let result = PureCrypto::symmetric_encrypt_string(DECRYPTED.to_string(), KEY.to_vec());
568 assert!(result.is_ok());
569 }
571
572 #[test]
573 fn test_symmetric_string_round_trip() {
574 let encrypted =
575 PureCrypto::symmetric_encrypt_string(DECRYPTED.to_string(), KEY.to_vec()).unwrap();
576 let decrypted =
577 PureCrypto::symmetric_decrypt_string(encrypted.clone(), KEY.to_vec()).unwrap();
578 assert_eq!(decrypted, DECRYPTED);
579 }
580
581 #[test]
582 fn test_symmetric_bytes_round_trip() {
583 let encrypted =
584 PureCrypto::symmetric_encrypt_bytes(DECRYPTED.as_bytes().to_vec(), KEY.to_vec())
585 .unwrap();
586 let decrypted =
587 PureCrypto::symmetric_decrypt_bytes(encrypted.clone(), KEY.to_vec()).unwrap();
588 assert_eq!(decrypted, DECRYPTED.as_bytes().to_vec());
589 }
590
591 #[test]
592 fn test_symmetric_decrypt_array_buffer() {
593 let result = PureCrypto::symmetric_decrypt_filedata(ENCRYPTED_BYTES.to_vec(), KEY.to_vec());
594 assert!(result.is_ok());
595 assert_eq!(result.unwrap(), DECRYPTED_BYTES);
596 }
597
598 #[test]
599 fn test_symmetric_encrypt_to_array_buffer() {
600 let result = PureCrypto::symmetric_encrypt_filedata(DECRYPTED_BYTES.to_vec(), KEY.to_vec());
601 assert!(result.is_ok());
602 }
604
605 #[test]
606 fn test_symmetric_filedata_round_trip() {
607 let encrypted =
608 PureCrypto::symmetric_encrypt_filedata(DECRYPTED_BYTES.to_vec(), KEY.to_vec()).unwrap();
609 let decrypted =
610 PureCrypto::symmetric_decrypt_filedata(encrypted.clone(), KEY.to_vec()).unwrap();
611 assert_eq!(decrypted, DECRYPTED_BYTES);
612 }
613
614 #[test]
615 fn test_make_aes256_cbc_hmac_key() {
616 let key = PureCrypto::make_user_key_aes256_cbc_hmac();
617 assert_eq!(key.len(), 64);
618 }
619
620 #[test]
621 fn test_make_xchacha20_poly1305_key() {
622 let key = PureCrypto::make_user_key_xchacha20_poly1305();
623 assert!(key.len() > 64);
624 }
625
626 #[test]
627 fn roundtrip_encrypt_user_key_with_master_password() {
628 let master_password = "test";
629 let email = "[email protected]";
630 let kdf = Kdf::PBKDF2 {
631 iterations: NonZero::try_from(600000).unwrap(),
632 };
633 let user_key = PureCrypto::make_user_key_aes256_cbc_hmac();
634 let encrypted_user_key = PureCrypto::encrypt_user_key_with_master_password(
635 user_key.clone(),
636 master_password.to_string(),
637 email.to_string(),
638 kdf.clone(),
639 )
640 .unwrap();
641 let decrypted_user_key = PureCrypto::decrypt_user_key_with_master_password(
642 encrypted_user_key,
643 master_password.to_string(),
644 email.to_string(),
645 kdf,
646 )
647 .unwrap();
648 assert_eq!(user_key, decrypted_user_key);
649 }
650
651 #[test]
652 fn test_wrap_unwrap_symmetric_key() {
653 let key_to_be_wrapped = PureCrypto::make_user_key_aes256_cbc_hmac();
654 let wrapping_key = PureCrypto::make_user_key_aes256_cbc_hmac();
655 let wrapped_key =
656 PureCrypto::wrap_symmetric_key(key_to_be_wrapped.clone(), wrapping_key.clone())
657 .unwrap();
658 let unwrapped_key = PureCrypto::unwrap_symmetric_key(wrapped_key, wrapping_key).unwrap();
659 assert_eq!(key_to_be_wrapped, unwrapped_key);
660 }
661
662 #[test]
663 fn test_wrap_encapsulation_key() {
664 let decapsulation_key = PrivateKey::from_pem(PEM_KEY).unwrap();
665 let encapsulation_key = decapsulation_key
666 .to_public_key()
667 .to_der()
668 .unwrap()
669 .as_ref()
670 .to_vec();
671 let wrapping_key = PureCrypto::make_user_key_aes256_cbc_hmac();
672 let wrapped_key =
673 PureCrypto::wrap_encapsulation_key(encapsulation_key.clone(), wrapping_key.clone())
674 .unwrap();
675 let unwrapped_key =
676 PureCrypto::unwrap_encapsulation_key(wrapped_key, wrapping_key).unwrap();
677 assert_eq!(encapsulation_key, unwrapped_key);
678 }
679
680 #[test]
681 fn test_wrap_decapsulation_key() {
682 let decapsulation_key = PrivateKey::from_pem(PEM_KEY).unwrap();
683 let wrapping_key = PureCrypto::make_user_key_aes256_cbc_hmac();
684 let wrapped_key = PureCrypto::wrap_decapsulation_key(
685 decapsulation_key.to_der().unwrap().to_vec(),
686 wrapping_key.clone(),
687 )
688 .unwrap();
689 let unwrapped_key =
690 PureCrypto::unwrap_decapsulation_key(wrapped_key, wrapping_key).unwrap();
691 assert_eq!(decapsulation_key.to_der().unwrap().to_vec(), unwrapped_key);
692 }
693
694 #[test]
695 fn test_encapsulate_key_unsigned() {
696 let shared_key = PureCrypto::make_user_key_aes256_cbc_hmac();
697 let decapsulation_key = PrivateKey::from_pem(PEM_KEY).unwrap();
698 let encapsulation_key = decapsulation_key.to_public_key().to_der().unwrap();
699 let encapsulated_key = PureCrypto::encapsulate_key_unsigned(
700 shared_key.clone(),
701 encapsulation_key.clone().to_vec(),
702 )
703 .unwrap();
704 let unwrapped_key = PureCrypto::decapsulate_key_unsigned(
705 encapsulated_key,
706 decapsulation_key.to_der().unwrap().to_vec(),
707 )
708 .unwrap();
709 assert_eq!(shared_key, unwrapped_key);
710 }
711
712 #[test]
713 fn test_key_algorithm_for_verifying_key() {
714 let verifying_key =
715 VerifyingKey::from_cose(&CoseKeyBytes::from(VERIFYING_KEY.to_vec())).unwrap();
716 let algorithm =
717 PureCrypto::key_algorithm_for_verifying_key(verifying_key.to_cose().to_vec()).unwrap();
718 assert_eq!(algorithm, SignatureAlgorithm::Ed25519);
719 }
720
721 #[test]
722 fn test_verifying_key_for_signing_key() {
723 let wrapped_signing_key = PureCrypto::symmetric_encrypt_bytes(
724 SIGNING_KEY.to_vec(),
725 SIGNING_KEY_WRAPPING_KEY.to_vec(),
726 )
727 .unwrap();
728 let verifying_key =
729 VerifyingKey::from_cose(&CoseKeyBytes::from(VERIFYING_KEY.to_vec())).unwrap();
730 let verifying_key_derived = PureCrypto::verifying_key_for_signing_key(
731 wrapped_signing_key.to_string(),
732 SIGNING_KEY_WRAPPING_KEY.to_vec(),
733 )
734 .unwrap();
735 let verifying_key_derived =
736 VerifyingKey::from_cose(&CoseKeyBytes::from(verifying_key_derived)).unwrap();
737 assert_eq!(verifying_key.to_cose(), verifying_key_derived.to_cose());
738 }
739
740 #[test]
741 fn test_verify_and_unwrap_signed_public_key() {
742 let public_key = PureCrypto::verify_and_unwrap_signed_public_key(
743 SIGNED_PUBLIC_KEY.to_vec(),
744 VERIFYING_KEY.to_vec(),
745 )
746 .unwrap();
747 assert_eq!(public_key, PUBLIC_KEY);
748 }
749
750 #[test]
751 fn test_derive_pbkdf2_output() {
752 let password = "test_password".as_bytes();
753 let email = "[email protected]".as_bytes();
754 let kdf = Kdf::PBKDF2 {
755 iterations: NonZero::try_from(600000).unwrap(),
756 };
757 let derived_key = PureCrypto::derive_kdf_material(password, email, kdf).unwrap();
758 assert_eq!(derived_key, DERIVED_KDF_MATERIAL_PBKDF2);
759 }
760
761 #[test]
762 fn test_derived_argon2_output() {
763 let password = "test_password".as_bytes();
764 let email = "[email protected]".as_bytes();
765 let kdf = Kdf::Argon2id {
766 iterations: NonZero::try_from(3).unwrap(),
767 memory: NonZero::try_from(64).unwrap(),
768 parallelism: NonZero::try_from(4).unwrap(),
769 };
770 let derived_key = PureCrypto::derive_kdf_material(password, email, kdf).unwrap();
771 assert_eq!(derived_key, DERIVED_KDF_MATERIAL_ARGON2ID);
772 }
773
774 #[test]
775 fn test_decrypt_user_key_with_master_key() {
776 let password = "test_password";
777 let email = "[email protected]";
778 let kdf = &Kdf::Argon2id {
779 iterations: NonZero::try_from(3).unwrap(),
780 memory: NonZero::try_from(64).unwrap(),
781 parallelism: NonZero::try_from(4).unwrap(),
782 };
783 let master_key = MasterKey::derive(password, email, kdf).unwrap();
784 let (user_key, encrypted_user_key) = master_key.make_user_key().unwrap();
785 let master_key_bytes = master_key.to_base64().into_bytes();
786
787 let decrypted_user_key = PureCrypto::decrypt_user_key_with_master_key(
788 encrypted_user_key.to_string(),
789 master_key_bytes,
790 )
791 .unwrap();
792 assert_eq!(user_key.0.to_encoded().to_vec(), decrypted_user_key);
793 }
794
795 #[test]
796 fn test_rsa_round_trip() {
797 let private_key = PureCrypto::rsa_generate_keypair().unwrap();
798 let public_key = PureCrypto::rsa_extract_public_key(private_key.clone()).unwrap();
799 let plain_data = b"Test RSA encryption data".to_vec();
800 let encrypted_data = PureCrypto::rsa_encrypt_data(plain_data.clone(), public_key).unwrap();
801 let decrypted_data = PureCrypto::rsa_decrypt_data(encrypted_data, private_key).unwrap();
802 assert_eq!(plain_data, decrypted_data);
803 }
804}