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