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