use std::error::Error;
use aes_gcm::{
aead::{generic_array::GenericArray, Aead, KeyInit},
aes::cipher::ArrayLength,
Aes256Gcm, Nonce,
};
use chacha20::ChaCha8;
use chacha20::{
cipher::{KeyIvInit, StreamCipher, StreamCipherSeek},
ChaCha20,
};
use chacha20poly1305::ChaCha20Poly1305;
use rand::Rng;
use secrecy::{ExposeSecret, SecretVec};
pub struct Encryption {
aes_cipher: Aes256Gcm,
chacha_cipher: ChaCha20Poly1305,
}
pub struct EncryptionPayload {
pub data: Vec<u8>,
pub nonce: [u8; 12],
}
impl Encryption {
pub fn new(master_key: &SecretVec<u8>) -> Encryption {
Encryption {
aes_cipher: Aes256Gcm::new(GenericArray::from_slice(master_key.expose_secret())),
chacha_cipher: ChaCha20Poly1305::new(GenericArray::from_slice(
master_key.expose_secret(),
)),
}
}
pub fn encrypt(
&mut self,
plaintext: Vec<u8>,
algorithm: u8,
) -> Result<EncryptionPayload, Box<dyn Error>> {
let mut nonce: [u8; 12] = [0; 12];
let mut rng = rand::thread_rng();
rng.fill(&mut nonce);
match algorithm {
1 => {
let encryption_result = self
.aes_cipher
.encrypt(GenericArray::from_slice(&nonce), plaintext.as_ref());
match encryption_result {
Ok(ciphertext) => Ok(EncryptionPayload {
data: ciphertext,
nonce,
}),
Err(e) => Err(e.to_string().into()),
}
}
2 => {
let encryption_result = self
.chacha_cipher
.encrypt(GenericArray::from_slice(&nonce), plaintext.as_ref());
match encryption_result {
Ok(ciphertext) => Ok(EncryptionPayload {
data: ciphertext,
nonce,
}),
Err(e) => Err(e.to_string().into()),
}
}
_ => Err("Unknown algorithm".to_string().into()),
}
}
pub fn decrypt(
&mut self,
nonce: [u8; 12],
ciphertext: Vec<u8>,
algorithm: u8,
) -> Result<EncryptionPayload, Box<dyn Error>> {
match algorithm {
1 => {
let decryption_result = self.aes_cipher.decrypt(
GenericArray::from_slice(nonce.as_ref()),
ciphertext.as_ref(),
);
match decryption_result {
Ok(plaintext) => Ok(EncryptionPayload {
data: plaintext,
nonce,
}),
Err(e) => Err(e.to_string().into()),
}
}
2 => {
let decryption_result = self.chacha_cipher.decrypt(
GenericArray::from_slice(nonce.as_ref()),
ciphertext.as_ref(),
);
match decryption_result {
Ok(plaintext) => Ok(EncryptionPayload {
data: plaintext,
nonce,
}),
Err(e) => Err(e.to_string().into()),
}
}
_ => Err("Unknown algorithm".to_string().into()),
}
}
}
pub struct StreamEncryption {}
impl StreamEncryption {
pub fn encrypt(child_key: &SecretVec<u8>, plaintext: &[u8]) -> Vec<u8> {
let mut nonce: [u8; 12] = [0; 12];
let mut rng = rand::thread_rng();
rng.fill(&mut nonce);
let key = GenericArray::from_slice(child_key.expose_secret());
let mut cipher = ChaCha8::new(key, &nonce.into());
let mut buffer = plaintext.to_owned();
cipher.apply_keystream(&mut buffer);
let mut ciphertext: Vec<u8> = nonce.to_vec();
ciphertext.extend(buffer);
ciphertext
}
pub fn decrypt(child_key: &SecretVec<u8>, ciphertext: &[u8]) -> Vec<u8> {
let key = GenericArray::from_slice(child_key.expose_secret());
let mut cipher = ChaCha8::new(key, ciphertext[..12].try_into().unwrap());
let mut buffer = ciphertext[12..].to_vec();
cipher.apply_keystream(&mut buffer);
buffer
}
}