use crate::{
errors::{FileError, HeaderError},
file::PlaintextFile,
memory::SecureKey,
v2::crypt,
};
use super::header::{AadPurpose, FileHeader, HeaderBinding};
#[derive(Debug)]
pub struct EncryptedFile {
header: FileHeader,
ciphertext: Vec<u8>,
}
impl EncryptedFile {
pub fn new(header: FileHeader, ciphertext: Vec<u8>) -> Self {
Self { header, ciphertext }
}
pub fn seal(
plaintext_file: &PlaintextFile,
key: &SecureKey,
kdf_params: super::key::KeyDerivationParams,
salt: [u8; 16],
content_nonce: [u8; 24],
filename_nonce: [u8; 24],
) -> Result<Self, FileError> {
let binding = HeaderBinding::new(&salt, &kdf_params, &content_nonce, &filename_nonce);
let (filename_ciphertext, _) = crypt::encrypt_bytes(
plaintext_file.filename().as_str().as_bytes(),
key.as_bytes(),
&filename_nonce,
&binding.aad(AadPurpose::Filename),
)?;
let (content_ciphertext, _) = crypt::encrypt_bytes(
plaintext_file.content().as_slice(),
key.as_bytes(),
&content_nonce,
&binding.aad(AadPurpose::Content),
)?;
let header = FileHeader::new(
salt,
kdf_params,
content_nonce,
filename_nonce,
filename_ciphertext,
)?;
Ok(Self::new(header, content_ciphertext))
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, HeaderError> {
let header = FileHeader::try_deserialize(bytes)?;
let ciphertext = bytes[header.header_length()..].to_vec();
Ok(Self::new(header, ciphertext))
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes = self.header.serialize();
bytes.extend_from_slice(&self.ciphertext);
bytes
}
pub fn decrypt(&self, key: &SecureKey) -> Result<PlaintextFile, FileError> {
let filename = self.header.decrypt_filename(key)?;
let content = self.header.decrypt_content(&self.ciphertext, key)?;
Ok(PlaintextFile::new(filename, content))
}
pub fn header(&self) -> &FileHeader {
&self.header
}
pub fn ciphertext(&self) -> &[u8] {
&self.ciphertext
}
}