use core::fmt::Debug;
use crate::aead::{AeadBufferError, OpenError, SealError};
pub trait Aead: Clone {
const KEY_SIZE: usize;
const NONCE_SIZE: usize;
const TAG_SIZE: usize;
type Key: Clone + Eq;
type Nonce: Copy + Eq + Debug + AsRef<[u8]>;
type Tag: Copy + Eq + Debug + AsRef<[u8]>;
#[must_use]
fn new(key: &Self::Key) -> Self;
fn tag_from_slice(bytes: &[u8]) -> Result<Self::Tag, AeadBufferError>;
fn encrypt_in_place(&self, nonce: &Self::Nonce, aad: &[u8], buffer: &mut [u8]) -> Result<Self::Tag, SealError>;
fn decrypt_in_place(
&self,
nonce: &Self::Nonce,
aad: &[u8],
buffer: &mut [u8],
tag: &Self::Tag,
) -> Result<(), OpenError>;
#[inline]
fn encrypt_in_place_detached(
&self,
nonce: &Self::Nonce,
aad: &[u8],
buffer: &mut [u8],
) -> Result<Self::Tag, SealError> {
self.encrypt_in_place(nonce, aad, buffer)
}
#[inline]
fn decrypt_in_place_detached(
&self,
nonce: &Self::Nonce,
aad: &[u8],
buffer: &mut [u8],
tag: &Self::Tag,
) -> Result<(), OpenError> {
self.decrypt_in_place(nonce, aad, buffer, tag)
}
#[inline]
fn ciphertext_len(plaintext_len: usize) -> Result<usize, AeadBufferError> {
plaintext_len
.checked_add(Self::TAG_SIZE)
.ok_or_else(AeadBufferError::new)
}
#[inline]
fn plaintext_len(ciphertext_and_tag_len: usize) -> Result<usize, AeadBufferError> {
if ciphertext_and_tag_len < Self::TAG_SIZE {
return Err(AeadBufferError::new());
}
Ok(ciphertext_and_tag_len.strict_sub(Self::TAG_SIZE))
}
#[inline]
fn encrypt(&self, nonce: &Self::Nonce, aad: &[u8], plaintext: &[u8], out: &mut [u8]) -> Result<(), SealError> {
let expected = Self::ciphertext_len(plaintext.len()).map_err(SealError::from)?;
if out.len() != expected {
return Err(SealError::buffer());
}
let (ciphertext, tag_out) = out.split_at_mut(plaintext.len());
ciphertext.copy_from_slice(plaintext);
let tag = match self.encrypt_in_place(nonce, aad, ciphertext) {
Ok(tag) => tag,
Err(err) => {
super::ct::zeroize(out);
return Err(err);
}
};
tag_out.copy_from_slice(tag.as_ref());
Ok(())
}
#[inline]
fn decrypt(
&self,
nonce: &Self::Nonce,
aad: &[u8],
ciphertext_and_tag: &[u8],
out: &mut [u8],
) -> Result<(), OpenError> {
let plaintext_len = Self::plaintext_len(ciphertext_and_tag.len())?;
if out.len() != plaintext_len {
return Err(OpenError::buffer());
}
let (ciphertext, tag_bytes) = ciphertext_and_tag.split_at(plaintext_len);
out.copy_from_slice(ciphertext);
let tag = Self::tag_from_slice(tag_bytes)?;
if let Err(e) = self.decrypt_in_place(nonce, aad, out, &tag) {
super::ct::zeroize(out);
return Err(e);
}
Ok(())
}
}