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