use std::time::{SystemTime, UNIX_EPOCH};
use crate::dek::DEK;
use crate::error::encryption::EncryptionError;
use crate::held_data::encryption::EncryptionStrategy;
use aes_gcm::aead::generic_array::GenericArray;
use aes_gcm::aead::{Aead, OsRng, Payload};
use aes_gcm::{AeadCore, Aes256Gcm, Key, KeyInit};
use async_trait::async_trait;
pub const AAD_SIZE: usize = 16;
pub const NONCE_SIZE: usize = 12;
pub const KEY_SIZE: usize = 32;
#[derive(Debug, Clone)]
pub struct AesGcm256Strategy;
#[derive(Debug, Clone)]
pub struct AesGcmEncryptionData {
pub aad: [u8; AAD_SIZE],
pub nonce: [u8; NONCE_SIZE],
}
#[async_trait]
impl EncryptionStrategy for AesGcm256Strategy {
type EncryptionData = AesGcmEncryptionData;
async fn encrypt(
&self,
dek: DEK,
plaintext: Vec<u8>,
encryption_data: Self::EncryptionData
) -> Result<Vec<u8>, EncryptionError> {
let cipher = get_cipher(dek)?;
let AesGcmEncryptionData { aad, nonce } = encryption_data;
let nonce = GenericArray::from(nonce);
let payload = Payload {
msg: plaintext.as_slice(),
aad: &aad,
};
let encrypted = cipher
.encrypt(&nonce.clone(), payload)
.map_err(|e| EncryptionError::new(format!("Could not encrypt! Error: {:?}", e)))?;
let ciphertext = merge_aad_and_ciphertext(encrypted, encryption_data);
Ok(ciphertext)
}
async fn decrypt(
&self,
dek: DEK,
ciphertext: Vec<u8>,
encryption_data: Self::EncryptionData
) -> Result<Vec<u8>, EncryptionError> {
let cipher = get_cipher(dek)?;
let AesGcmEncryptionData { aad, nonce } = encryption_data;
let nonce = GenericArray::from(nonce);
let payload = Payload {
msg: ciphertext.as_slice(),
aad: &aad,
};
cipher
.decrypt(&nonce, payload)
.map_err(|e| EncryptionError::new(format!("Error Decrypting, Error: {:?}", e)))
}
}
fn get_cipher(dek: DEK) -> Result<Aes256Gcm, EncryptionError> {
let key: Vec<u8> = dek.into();
if key.len() != KEY_SIZE {
return Err(
EncryptionError::new(
format!(
"DEK must have a length of 32 bits to use AES GCM 256, instead has length of {}",
key.len()
)
)
);
}
let key: &[u8; KEY_SIZE] = key
.as_slice()
.try_into()
.map_err(|_| EncryptionError::new("Could not convert DEK into array".to_string()))?;
let key: &Key<Aes256Gcm> = key.into();
Ok(Aes256Gcm::new(key))
}
pub fn split_encryption_data(
inp: Vec<u8>
) -> Result<(Vec<u8>, AesGcmEncryptionData), EncryptionError> {
if inp.len() < AAD_SIZE + NONCE_SIZE {
return Err(
EncryptionError::new(
format!(
"Size of input needs to be larger than {}, but was {}",
AAD_SIZE + NONCE_SIZE,
inp.len()
)
)
);
}
let aad: &[u8] = &inp[0..AAD_SIZE];
let nonce: &[u8] = &inp[AAD_SIZE..AAD_SIZE + NONCE_SIZE];
let ciphertext: &[u8] = &inp[AAD_SIZE + NONCE_SIZE..];
let result = (
ciphertext.to_vec(),
AesGcmEncryptionData {
aad: aad
.try_into()
.map_err(|_| EncryptionError::new("Could not properly resize aad".to_string()))?,
nonce: nonce
.try_into()
.map_err(|_| EncryptionError::new("Could not properly resize nonce".to_string()))?,
},
);
Ok(result)
}
pub fn merge_aad_and_ciphertext(ciphertext: Vec<u8>, aad: AesGcmEncryptionData) -> Vec<u8> {
let mut new_vec: Vec<u8> = vec![];
new_vec.append(&mut aad.aad.clone().to_vec());
new_vec.append(&mut aad.nonce.clone().to_vec());
new_vec.append(&mut ciphertext.clone());
new_vec
}
pub fn generate_nonce() -> Result<[u8; NONCE_SIZE], EncryptionError> {
let mut nonce_vec = Vec::new();
let mut time_millis = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map_err(|e| EncryptionError::new(format!("System Time Error, Error: {:?}", e)))?
.as_millis()
.to_be_bytes()
.to_vec();
time_millis.resize(4, 0);
let nonce_random_bits_vec = Aes256Gcm::generate_nonce(&mut OsRng)
.as_slice()
.split_at(8)
.0.to_vec();
nonce_vec.append(&mut time_millis.clone());
nonce_vec.append(&mut nonce_random_bits_vec.clone());
nonce_vec.resize(NONCE_SIZE, 0);
nonce_vec
.as_slice()
.try_into()
.map_err(|e| EncryptionError(format!("Could not convert nonce into array, Error: {:?}", e)))
}