use super::{
EncryptedInfo, credentials::Credentials, encrypt::*, error::Error,
extract_encrypted_info_and_data,
};
use chacha20poly1305::aead::{Aead, Payload, generic_array::GenericArray};
use secure_types::SecureBytes;
use zeroize::Zeroize;
pub fn decrypt_data(data: Vec<u8>, credentials: Credentials) -> Result<SecureBytes, Error> {
let (_, encrypted_data) = extract_encrypted_info_and_data(&data)?;
let info = EncryptedInfo::from_encrypted_data(&data)?;
let decrypted_data = decrypt(credentials, info, encrypted_data)?;
Ok(decrypted_data)
}
fn decrypt(
credentials: Credentials,
info: EncryptedInfo,
data: Vec<u8>,
) -> Result<SecureBytes, Error> {
credentials.is_valid()?;
let argon2 = &info.argon2;
let username = &credentials.username;
let password = &credentials.password;
let mut aad = username
.unlock_str(|username_str| argon2.hash_password(&username_str, info.username_salt.clone()))
.map_err(|e| Error::Custom(e.to_string()))?;
let password_hash = password
.unlock_str(|password_str| argon2.hash_password(&password_str, info.password_salt.clone()))
.map_err(|e| Error::Custom(e.to_string()))?;
let nonce = GenericArray::from_slice(&info.cipher_nonce);
let payload = Payload {
msg: data.as_ref(),
aad: &aad,
};
let cipher = xchacha20_poly_1305(password_hash);
let decrypted_data_res = cipher.decrypt(nonce, payload);
aad.zeroize();
let decrypted_data = match decrypted_data_res {
Ok(data) => data,
Err(e) => {
return Err(Error::DecryptionFailed(e.to_string()));
}
};
let secure_data =
SecureBytes::from_vec(decrypted_data).map_err(|e| Error::Custom(e.to_string()))?;
Ok(secure_data)
}