1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
//! Authenticated encryption interface definitions.
use crate::cipher::Cipher;
/// A AEAD mode of operation.
pub trait Aead {
/// Adds associated data `ad`.
///
/// Can be invoked multiple times *prior to invoking*
/// [`Aead::encrypt`] or [`Aead::decrypt`] to provide the
/// additional authenticated data in a streaming fashion.
fn update(&mut self, ad: &[u8]);
/// Encrypts one block `src` to `dst`.
fn encrypt(&mut self, dst: &mut [u8], src: &[u8]);
/// Decrypts one block `src` to `dst`.
fn decrypt(&mut self, dst: &mut [u8], src: &[u8]);
/// Produce the digest.
fn digest(&mut self, digest: &mut [u8]);
/// Length of the digest in bytes.
fn digest_size(&self) -> usize;
}
/// Internal interface to Nettle's AEAD modes.
///
/// Some of Nettle's AEAD modes require additional authenticated data
/// to be updated in multiples of the ciphers block size (except for
/// the last chunk), and will either silently mis-compute the digest
/// (EAX, OCB), or abort(2) (GCM).
///
/// For these modes, we use [`AdStream`] to stream the AAD, and trait
/// [`AeadInternal`] as raw interface.
pub trait AeadInternal {
/// Adds associated data `ad`.
///
/// Note: can be invoked multiple times to stream the additional
/// authenticated data, but the length of all but the last chunk
/// **MUST BE** of a multiple of the cipher's block size. Failure
/// to adhere to that may lead to Nettle aborting or silently
/// mis-computing the digest.
///
/// Note: **MUST NOT BE** invoked after invoking
/// [`AeadInternal::_encrypt`] or [`AeadInternal::_decrypt`].
/// Failure to adhere to that may lead to Nettle aborting or
/// silently mis-computing.
fn update_internal(&mut self, ad: &[u8]);
/// Encrypts one block `src` to `dst`.
fn encrypt_internal(&mut self, dst: &mut [u8], src: &[u8]);
/// Decrypts one block `src` to `dst`.
fn decrypt_internal(&mut self, dst: &mut [u8], src: &[u8]);
/// Produce the digest.
fn digest_internal(&mut self, digest: &mut [u8]);
/// Length of the digest in bytes.
fn digest_size_internal(&self) -> usize;
}
/// Streaming AAD support for EAX, OCB, and GCM.
///
/// Some of Nettle's AEAD modes require additional authenticated data
/// to be updated in multiples of the ciphers block size (except for
/// the last chunk), and will either silently mis-compute the digest
/// (EAX, OCB), or abort(2) (GCM).
///
/// For these modes, we use [`AdStream`] to stream the AAD, and trait
/// [`AeadInternal`] as raw interface.
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> {
/// Stream the given AAD.
///
/// Note: additional data provided after invoking
/// [`AdStream::finalize`] is **discarded** and an error is
/// emitted to stderr. This will be an error in future versions.
pub fn update(&mut self, aad: &[u8], context: &mut dyn AeadInternal) {
self.stream(aad, false, context);
}
/// Finalize the AAD streaming.
///
/// After calling this function, no further AAD may be streamed.
/// This function is idempotent.
pub fn finalize(&mut self, context: &mut dyn AeadInternal) {
if ! self.finalized {
self.stream(&[], true, context);
}
}
/// Stream the given AAD and finalize streaming.
///
/// After calling this function with `last = true`, no further AAD
/// may be streamed.
///
/// Note: additional data provided after invoking
/// [`AdStream::finalize`] or this function with `last = true` is
/// **discarded** and an error is emitted to stderr. This will be
/// an error in future versions.
fn stream(&mut self, mut data: &[u8], last: bool,
context: &mut dyn AeadInternal)
{
debug_assert!(self.buffer.len() < C::BLOCK_SIZE);
// XXX: This should return an error or be made impossible
// using type states.
if self.finalized {
eprintln!("nettle::aead: AAD supplied after cipher use");
return;
}
if self.buffer.len() + data.len() < C::BLOCK_SIZE {
// No full block. Buffer.
self.buffer.extend_from_slice(data);
} else if self.buffer.is_empty() {
// No data in buffer, update digest with all whole blocks
// from `data`.
let n_chunks = data.len() / C::BLOCK_SIZE;
let n_chunks_len = n_chunks * C::BLOCK_SIZE;
context.update_internal(&data[..n_chunks_len]);
// Finally, buffer the rest, if any.
self.buffer.extend_from_slice(&data[n_chunks_len..]);
} else {
// Some buffered data. Fill up to the BLOCK_SIZE and
// update digest from that.
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..];
// Update digest with all whole blocks from `data`.
let n_chunks = data.len() / C::BLOCK_SIZE;
let n_chunks_len = n_chunks * C::BLOCK_SIZE;
context.update_internal(&data[..n_chunks_len]);
// Finally, buffer the rest, if any.
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);
}
}