1use super::{
2 EncryptedInfo, credentials::Credentials, encrypt::*, error::Error,
3 extract_encrypted_info_and_data,
4};
5use bincode::{config::standard, decode_from_slice};
6use chacha20poly1305::aead::{Aead, Payload, generic_array::GenericArray};
7use secure_types::SecureBytes;
8use zeroize::Zeroize;
9
10pub fn decrypt_data(data: Vec<u8>, credentials: Credentials) -> Result<SecureBytes, Error> {
17 if &data[0..8] != HEADER {
19 return Err(Error::InvalidFileFormat);
20 }
21
22 let (encrypted_info, encrypted_data) = extract_encrypted_info_and_data(&data)?;
23
24 let info: (EncryptedInfo, usize) = decode_from_slice(&encrypted_info, standard())
25 .map_err(|e| Error::DecodingFailed(e.to_string()))?;
26
27 let decrypted_data = decrypt(credentials, info.0, encrypted_data)?;
28 Ok(decrypted_data)
29}
30
31fn decrypt(
32 credentials: Credentials,
33 info: EncryptedInfo,
34 data: Vec<u8>,
35) -> Result<SecureBytes, Error> {
36 credentials.is_valid()?;
37
38 let password_hash = info
39 .argon2
40 .hash_password(&credentials.password, info.password_salt.clone())?;
41
42 let username_hash = info
43 .argon2
44 .hash_password(&credentials.username, info.username_salt.clone())?;
45
46 let nonce = GenericArray::from_slice(&info.cipher_nonce);
47 let mut aad = username_hash.slice_scope(|bytes| bytes.to_vec());
48
49 let payload = Payload {
50 msg: data.as_ref(),
51 aad: &aad,
52 };
53
54 let cipher = xchacha20_poly_1305(password_hash);
55 let decrypted_data_res = cipher.decrypt(nonce, payload);
56 aad.zeroize();
57
58 let decrypted_data = match decrypted_data_res {
59 Ok(data) => data,
60 Err(e) => {
61 return Err(Error::DecryptionFailed(e.to_string()));
62 }
63 };
64
65 let secure_data =
66 SecureBytes::from_vec(decrypted_data).map_err(|e| Error::Custom(e.to_string()))?;
67
68 Ok(secure_data)
69}