use crate::cipher::Cipher;
pub trait Aead {
fn update(&mut self, ad: &[u8]);
fn encrypt(&mut self, dst: &mut [u8], src: &[u8]);
fn decrypt(&mut self, dst: &mut [u8], src: &[u8]);
fn digest(&mut self, digest: &mut [u8]);
fn digest_size(&self) -> usize;
}
pub trait AeadInternal {
fn update_internal(&mut self, ad: &[u8]);
fn encrypt_internal(&mut self, dst: &mut [u8], src: &[u8]);
fn decrypt_internal(&mut self, dst: &mut [u8], src: &[u8]);
fn digest_internal(&mut self, digest: &mut [u8]);
fn digest_size_internal(&self) -> usize;
}
pub struct AdStream<C: Cipher> {
buffer: Vec<u8>,
finalized: bool,
cipher: std::marker::PhantomData<*const C>,
}
impl<C: Cipher> Default for AdStream<C> {
fn default() -> Self {
AdStream {
buffer: Vec::with_capacity(C::BLOCK_SIZE),
finalized: false,
cipher: std::marker::PhantomData,
}
}
}
impl<C: Cipher> AdStream<C> {
pub fn update(&mut self, aad: &[u8], context: &mut dyn AeadInternal) {
self.stream(aad, false, context);
}
pub fn finalize(&mut self, context: &mut dyn AeadInternal) {
if ! self.finalized {
self.stream(&[], true, context);
}
}
fn stream(&mut self, mut data: &[u8], last: bool,
context: &mut dyn AeadInternal)
{
debug_assert!(self.buffer.len() < C::BLOCK_SIZE);
if self.finalized {
eprintln!("nettle::aead: AAD supplied after cipher use");
return;
}
if self.buffer.len() + data.len() < C::BLOCK_SIZE {
self.buffer.extend_from_slice(data);
} else if self.buffer.is_empty() {
let n_chunks = data.len() / C::BLOCK_SIZE;
let n_chunks_len = n_chunks * C::BLOCK_SIZE;
context.update_internal(&data[..n_chunks_len]);
self.buffer.extend_from_slice(&data[n_chunks_len..]);
} else {
let missing = (C::BLOCK_SIZE - self.buffer.len()).min(data.len());
self.buffer.extend_from_slice(&data[..missing]);
debug_assert_eq!(self.buffer.len(), C::BLOCK_SIZE);
context.update_internal(&self.buffer[..]);
self.buffer.clear();
data = &data[missing..];
let n_chunks = data.len() / C::BLOCK_SIZE;
let n_chunks_len = n_chunks * C::BLOCK_SIZE;
context.update_internal(&data[..n_chunks_len]);
self.buffer.extend_from_slice(&data[n_chunks_len..]);
}
if last {
if ! self.buffer.is_empty() {
context.update_internal(&self.buffer[..]);
self.buffer.clear();
}
self.finalized = true;
}
debug_assert!(self.buffer.len() < C::BLOCK_SIZE);
}
}