use aead::{Aead, AeadInPlace, KeyInit, Payload};
use aes_gcm::Aes256Gcm;
use chacha20poly1305::XChaCha20Poly1305;
use deoxys::DeoxysII256;
use crate::primitives::Algorithm;
use crate::protected::Protected;
pub enum Ciphers {
Aes256Gcm(Box<Aes256Gcm>),
XChaCha(Box<XChaCha20Poly1305>),
DeoxysII(Box<DeoxysII256>),
}
impl Ciphers {
pub fn initialize(key: Protected<[u8; 32]>, algorithm: &Algorithm) -> anyhow::Result<Self> {
let cipher = match algorithm {
Algorithm::Aes256Gcm => {
let cipher = Aes256Gcm::new_from_slice(key.expose())
.map_err(|_| anyhow::anyhow!("Unable to create cipher with hashed key."))?;
Ciphers::Aes256Gcm(Box::new(cipher))
}
Algorithm::XChaCha20Poly1305 => {
let cipher = XChaCha20Poly1305::new_from_slice(key.expose())
.map_err(|_| anyhow::anyhow!("Unable to create cipher with hashed key."))?;
Ciphers::XChaCha(Box::new(cipher))
}
Algorithm::DeoxysII256 => {
let cipher = DeoxysII256::new_from_slice(key.expose())
.map_err(|_| anyhow::anyhow!("Unable to create cipher with hashed key."))?;
Ciphers::DeoxysII(Box::new(cipher))
}
};
drop(key);
Ok(cipher)
}
pub fn encrypt<'msg, 'aad>(
&self,
nonce: &[u8],
plaintext: impl Into<Payload<'msg, 'aad>>,
) -> aead::Result<Vec<u8>> {
match self {
Ciphers::Aes256Gcm(c) => c.encrypt(nonce.as_ref().into(), plaintext),
Ciphers::XChaCha(c) => c.encrypt(nonce.as_ref().into(), plaintext),
Ciphers::DeoxysII(c) => c.encrypt(nonce.as_ref().into(), plaintext),
}
}
pub fn encrypt_in_place(
&self,
nonce: &[u8],
aad: &[u8],
buffer: &mut dyn aead::Buffer,
) -> Result<(), aead::Error> {
match self {
Ciphers::Aes256Gcm(c) => c.encrypt_in_place(nonce.as_ref().into(), aad, buffer),
Ciphers::XChaCha(c) => c.encrypt_in_place(nonce.as_ref().into(), aad, buffer),
Ciphers::DeoxysII(c) => c.encrypt_in_place(nonce.as_ref().into(), aad, buffer),
}
}
pub fn decrypt<'msg, 'aad>(
&self,
nonce: &[u8],
ciphertext: impl Into<Payload<'msg, 'aad>>,
) -> aead::Result<Vec<u8>> {
match self {
Ciphers::Aes256Gcm(c) => c.decrypt(nonce.as_ref().into(), ciphertext),
Ciphers::XChaCha(c) => c.decrypt(nonce.as_ref().into(), ciphertext),
Ciphers::DeoxysII(c) => c.decrypt(nonce.as_ref().into(), ciphertext),
}
}
}