use super::buffer::TailBuffer;
use super::gcmsiv::derive_key;
use crate::{Error, Key};
use aes_gcm_siv::{
aead::{Aead, AeadInPlace, KeyInit},
Aes256GcmSiv, Nonce,
};
const NONCE_SIZE: usize = 12;
const MIN_PAYLOAD_LEN: usize = 17;
#[inline]
pub fn encrypt(plaintext: &[u8], key: &Key) -> Result<Vec<u8>, Error> {
if plaintext.is_empty() {
return Err(Error::EmptyPlaintext);
}
let key_arr = derive_key(key);
let cipher = Aes256GcmSiv::new((&*key_arr).into());
let nonce = Nonce::from([0u8; NONCE_SIZE]);
cipher
.encrypt(&nonce, plaintext)
.map_err(|_| Error::EncryptionFailed)
}
#[inline]
pub fn encrypt_into(plaintext: &[u8], key: &Key, out: &mut Vec<u8>) -> Result<(), Error> {
if plaintext.is_empty() {
return Err(Error::EmptyPlaintext);
}
let key_arr = derive_key(key);
let cipher = Aes256GcmSiv::new((&*key_arr).into());
let nonce = Nonce::from([0u8; NONCE_SIZE]);
let start = out.len();
out.extend_from_slice(plaintext);
let mut tail = TailBuffer::new(out, start);
if cipher.encrypt_in_place(&nonce, b"", &mut tail).is_err() {
out.truncate(start);
return Err(Error::EncryptionFailed);
}
Ok(())
}
#[inline]
pub fn decrypt(ciphertext: &[u8], key: &Key) -> Result<Vec<u8>, Error> {
if ciphertext.len() < MIN_PAYLOAD_LEN {
return Err(Error::PayloadTooShort);
}
let key_arr = derive_key(key);
let cipher = Aes256GcmSiv::new((&*key_arr).into());
let nonce = Nonce::from([0u8; NONCE_SIZE]);
cipher
.decrypt(&nonce, ciphertext)
.map_err(|_| Error::DecryptionFailed)
}
#[inline]
pub fn decrypt_into(ciphertext: &[u8], key: &Key, out: &mut Vec<u8>) -> Result<(), Error> {
if ciphertext.len() < MIN_PAYLOAD_LEN {
return Err(Error::PayloadTooShort);
}
let key_arr = derive_key(key);
let cipher = Aes256GcmSiv::new((&*key_arr).into());
let nonce = Nonce::from([0u8; NONCE_SIZE]);
let start = out.len();
out.extend_from_slice(ciphertext);
let mut tail = TailBuffer::new(out, start);
if cipher.decrypt_in_place(&nonce, b"", &mut tail).is_err() {
out.truncate(start);
return Err(Error::DecryptionFailed);
}
Ok(())
}