Skip to main content

ncrypt_me/
decrypt.rs

1use super::{
2   EncryptedInfo, credentials::Credentials, encrypt::*, error::Error,
3   extract_encrypted_info_and_data,
4};
5use chacha20poly1305::aead::{Aead, Payload, generic_array::GenericArray};
6use secure_types::{SecureBytes, Zeroize};
7
8/// Decrypts the data using the provided credentials
9///
10/// ### Arguments
11///
12/// - `data` - The data to decrypt
13/// - `credentials` - The credentials to use for decryption
14pub fn decrypt_data(data: Vec<u8>, credentials: Credentials) -> Result<SecureBytes, Error> {
15   let (_, encrypted_data) = extract_encrypted_info_and_data(&data)?;
16
17   let info = EncryptedInfo::from_encrypted_data(&data)?;
18
19   let decrypted_data = decrypt(credentials, info, encrypted_data)?;
20   let secure_data =
21      SecureBytes::from_vec(decrypted_data).map_err(|e| Error::Custom(e.to_string()))?;
22
23   Ok(secure_data)
24}
25
26/// Decrypts the data using the provided credentials
27///
28/// This is the same as `decrypt_data` but returns an unsecure [Vec<u8>]
29///
30/// Use this if the data you want to decrypt is too large to fit in a [SecureBytes]
31///
32/// ### Arguments
33///
34/// - `data` - The data to decrypt
35/// - `credentials` - The credentials to use for decryption
36pub fn decrypt_data_unsecured(data: Vec<u8>, credentials: Credentials) -> Result<Vec<u8>, Error> {
37   let (_, encrypted_data) = extract_encrypted_info_and_data(&data)?;
38
39   let info = EncryptedInfo::from_encrypted_data(&data)?;
40
41   let decrypted_data = decrypt(credentials, info, encrypted_data)?;
42   Ok(decrypted_data)
43}
44
45fn decrypt(credentials: Credentials, info: EncryptedInfo, data: Vec<u8>) -> Result<Vec<u8>, Error> {
46   credentials.is_valid()?;
47
48   let argon2 = &info.argon2;
49   let username = &credentials.username;
50   let password = &credentials.password;
51
52   let mut aad = username
53      .unlock_str(|username_str| argon2.hash_password(&username_str, info.username_salt.clone()))
54      .map_err(|e| Error::Custom(e.to_string()))?;
55
56   let password_hash = password
57      .unlock_str(|password_str| argon2.hash_password(&password_str, info.password_salt.clone()))
58      .map_err(|e| Error::Custom(e.to_string()))?;
59
60   let nonce = GenericArray::from_slice(&info.cipher_nonce);
61
62   let payload = Payload {
63      msg: data.as_ref(),
64      aad: &aad,
65   };
66
67   let cipher = xchacha20_poly_1305(password_hash);
68   let decrypted_data_res = cipher.decrypt(nonce, payload);
69   aad.zeroize();
70
71   let decrypted_data = match decrypted_data_res {
72      Ok(data) => data,
73      Err(e) => {
74         return Err(Error::DecryptionFailed(e.to_string()));
75      }
76   };
77
78   Ok(decrypted_data)
79}