use crate::crypto_algorithm::CryptoAlgorithm;
use crate::error::DatError;
use aes_gcm::aead::array::Array;
use aes_gcm::aead::common::Generate;
use aes_gcm::aead::consts::{U12, U16, U32};
use aes_gcm::aes::cipher::InOutBuf;
use aes_gcm::{AeadInOut, Aes128Gcm, AesGcm, Nonce};
use aes_gcm::{Aes256Gcm, Key, KeyInit};
const NONCE_LEN: usize = 12;
pub enum CryptoKey {
AES128GCMN(Array<u8, U16>, AesGcm<aes_gcm::aes::Aes128, U12>),
AES256GCMN(Array<u8, U32>, AesGcm<aes_gcm::aes::Aes256, U12>),
}
impl CryptoKey {
pub fn algorithm(&self) -> CryptoAlgorithm {
match self {
CryptoKey::AES128GCMN(_,_) => CryptoAlgorithm::AES128GCMN,
CryptoKey::AES256GCMN(_,_) => CryptoAlgorithm::AES256GCMN,
}
}
pub fn from_bytes(algorithm: CryptoAlgorithm, data: &[u8]) -> Result<CryptoKey, DatError> {
Ok(match algorithm {
CryptoAlgorithm::AES128GCMN => {
let bytes = Array::<u8, U16>::try_from(data)
.map_err(|_| DatError::ParseCryptoKeyError)?;
CryptoKey::AES128GCMN(bytes, Aes128Gcm::new(&bytes))
},
CryptoAlgorithm::AES256GCMN => {
let bytes = Array::<u8, U32>::try_from(data)
.map_err(|_| DatError::ParseCryptoKeyError)?;
CryptoKey::AES256GCMN(bytes, Aes256Gcm::new(&bytes))
},
})
}
pub fn to_bytes(&self) -> Box<[u8]> {
match self {
CryptoKey::AES128GCMN(c, _) => Box::from(c.as_slice()),
CryptoKey::AES256GCMN(c, _) => Box::from(c.as_slice()),
}
}
pub fn generate(algorithm: CryptoAlgorithm) -> Self {
match algorithm {
CryptoAlgorithm::AES128GCMN => {
let bytes = Key::<Aes128Gcm>::generate();
CryptoKey::AES128GCMN(bytes, Aes128Gcm::new(&bytes))
},
CryptoAlgorithm::AES256GCMN => {
let bytes = Key::<Aes256Gcm>::generate();
CryptoKey::AES256GCMN(bytes, Aes256Gcm::new(&bytes))
},
}
}
pub fn encrypt(&self, body: &[u8]) -> Result<Vec<u8>, DatError> {
if body.is_empty() {
return Ok(vec![]);
}
let nonce: Array<u8, U12> = Nonce::generate();
let mut enc_data = Vec::with_capacity(64 + body.len());
enc_data.extend_from_slice(&nonce);
enc_data.extend_from_slice(body);
let inout = InOutBuf::from(&mut enc_data[NONCE_LEN..]);
match self {
CryptoKey::AES128GCMN(_, c) => {
let tag = c.encrypt_inout_detached(&nonce, &[], inout)
.map_err(|_| DatError::EncryptError)?;
enc_data.extend_from_slice(&tag.as_slice());
},
CryptoKey::AES256GCMN(_, c) => {
let tag = c.encrypt_inout_detached(&nonce, &[], inout)
.map_err(|_| DatError::EncryptError)?;
enc_data.extend_from_slice(&tag.as_slice());
},
};
Ok(enc_data)
}
pub fn decrypt(&self, mut data: Vec<u8>) -> Result<Vec<u8>, DatError> {
if data.is_empty() {
return Ok(Vec::with_capacity(0));
}
if data.len() <= NONCE_LEN {
return Err(DatError::DecryptError);
}
let mut secure = data.split_off(NONCE_LEN);
let nonce = data.try_into().map_err(|_| DatError::DecryptError)?;
match self {
CryptoKey::AES128GCMN(_, c) => {
c.decrypt_in_place(&nonce, &[], &mut secure).map_err(|_| DatError::DecryptError)
},
CryptoKey::AES256GCMN(_, c) => {
c.decrypt_in_place(&nonce, &[], &mut secure).map_err(|_| DatError::DecryptError)
},
}?;
Ok(secure)
}
}
impl Clone for CryptoKey {
fn clone(&self) -> Self {
match self {
CryptoKey::AES128GCMN(b, c) => CryptoKey::AES128GCMN(b.clone(), c.clone()),
CryptoKey::AES256GCMN(b, c) => CryptoKey::AES256GCMN(b.clone(), c.clone()),
}
}
}