use crate::types::{AeadAlg, EncFileError};
use aead::{Aead, KeyInit};
use aes_gcm_siv::Aes256GcmSiv;
use chacha20poly1305::{XChaCha20Poly1305, XNonce};
use getrandom::fill as getrandom;
use zeroize::Zeroize;
pub const AEAD_TAG_LEN: usize = 16;
pub const MAX_FILE_SIZE: u64 = 1024 * 1024 * 1024 * 1024;
pub const MAX_CIPHERTEXT_LEN: u64 = MAX_FILE_SIZE + 1024 * 1024;
pub fn nonce_len_for(alg: AeadAlg) -> usize {
match alg {
AeadAlg::XChaCha20Poly1305 => 24,
AeadAlg::Aes256GcmSiv => 12,
}
}
pub fn generate_nonce(alg: AeadAlg) -> Result<Vec<u8>, EncFileError> {
let mut nonce = vec![0u8; nonce_len_for(alg)];
getrandom(&mut nonce).map_err(|_| EncFileError::Crypto)?;
Ok(nonce)
}
pub fn generate_salt() -> Result<Vec<u8>, EncFileError> {
let mut salt = vec![0u8; 16];
getrandom(&mut salt).map_err(|_| EncFileError::Crypto)?;
Ok(salt)
}
pub fn aead_encrypt(
alg: AeadAlg,
key: &[u8; 32],
nonce_bytes: &[u8],
plaintext: &[u8],
) -> Result<Vec<u8>, EncFileError> {
match alg {
AeadAlg::XChaCha20Poly1305 => {
let cipher =
XChaCha20Poly1305::new_from_slice(key).map_err(|_| EncFileError::Crypto)?;
let nonce = XNonce::from_slice(nonce_bytes);
cipher
.encrypt(nonce, plaintext)
.map_err(|_| EncFileError::Crypto)
}
AeadAlg::Aes256GcmSiv => {
use aes_gcm_siv::aead::generic_array::GenericArray;
let cipher = Aes256GcmSiv::new_from_slice(key).map_err(|_| EncFileError::Crypto)?;
let nonce = GenericArray::from_slice(nonce_bytes);
cipher
.encrypt(nonce, plaintext)
.map_err(|_| EncFileError::Crypto)
}
}
}
pub fn aead_decrypt(
alg: AeadAlg,
key: &[u8; 32],
nonce_bytes: &[u8],
ciphertext: &[u8],
) -> Result<Vec<u8>, EncFileError> {
match alg {
AeadAlg::XChaCha20Poly1305 => {
let cipher =
XChaCha20Poly1305::new_from_slice(key).map_err(|_| EncFileError::Crypto)?;
let nonce = XNonce::from_slice(nonce_bytes);
cipher
.decrypt(nonce, ciphertext)
.map_err(|_| EncFileError::Crypto)
}
AeadAlg::Aes256GcmSiv => {
use aes_gcm_siv::aead::generic_array::GenericArray;
let cipher = Aes256GcmSiv::new_from_slice(key).map_err(|_| EncFileError::Crypto)?;
let nonce = GenericArray::from_slice(nonce_bytes);
cipher
.decrypt(nonce, ciphertext)
.map_err(|_| EncFileError::Crypto)
}
}
}
pub fn validate_file_size(size: u64) -> Result<(), EncFileError> {
if size > MAX_FILE_SIZE {
return Err(EncFileError::Invalid("file size exceeds maximum allowed size"));
}
Ok(())
}
pub fn validate_ciphertext_length(len: u64) -> Result<(), EncFileError> {
if len > MAX_CIPHERTEXT_LEN {
return Err(EncFileError::Invalid("ciphertext size exceeds maximum allowed size"));
}
Ok(())
}
pub fn zeroize_key(key: &mut [u8; 32]) {
key.zeroize();
}
pub fn create_xchacha20poly1305_cipher(key: &[u8; 32]) -> Result<XChaCha20Poly1305, EncFileError> {
XChaCha20Poly1305::new_from_slice(key).map_err(|_| EncFileError::Crypto)
}
pub fn create_aes256gcmsiv_cipher(key: &[u8; 32]) -> Result<Aes256GcmSiv, EncFileError> {
Aes256GcmSiv::new_from_slice(key).map_err(|_| EncFileError::Crypto)
}