Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

aead: remove stateful AEAD traits (AeadMut*) #1740

Merged
merged 1 commit into from
Jan 30, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
187 changes: 10 additions & 177 deletions aead/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,6 @@ pub trait AeadCore {
}

/// Authenticated Encryption with Associated Data (AEAD) algorithm.
///
/// This trait is intended for use with stateless AEAD algorithms. The
/// [`AeadMut`] trait provides a stateful interface.
#[cfg(feature = "alloc")]
pub trait Aead: AeadCore {
/// Encrypt the given plaintext payload, and return the resulting
Expand Down Expand Up @@ -207,53 +204,6 @@ pub trait Aead: AeadCore {
) -> Result<Vec<u8>>;
}

/// Stateful Authenticated Encryption with Associated Data algorithm.
#[cfg(feature = "alloc")]
pub trait AeadMut: AeadCore {
/// Encrypt the given plaintext slice, and return the resulting ciphertext
/// as a vector of bytes.
///
/// See notes on [`Aead::encrypt()`] about allowable message payloads and
/// Associated Additional Data (AAD).
fn encrypt<'msg, 'aad>(
&mut self,
nonce: &Nonce<Self>,
plaintext: impl Into<Payload<'msg, 'aad>>,
) -> Result<Vec<u8>>;

/// Decrypt the given ciphertext slice, and return the resulting plaintext
/// as a vector of bytes.
///
/// See notes on [`Aead::encrypt()`] and [`Aead::decrypt()`] about allowable
/// message payloads and Associated Additional Data (AAD).
fn decrypt<'msg, 'aad>(
&mut self,
nonce: &Nonce<Self>,
ciphertext: impl Into<Payload<'msg, 'aad>>,
) -> Result<Vec<u8>>;
}

/// Implement the `decrypt_in_place` method on [`AeadInPlace`] and
/// [`AeadMutInPlace]`, using a macro to gloss over the `&self` vs `&mut self`.
///
/// Assumes a postfix authentication tag. AEAD ciphers which do not use a
/// postfix authentication tag will need to define their own implementation.
macro_rules! impl_decrypt_in_place {
($aead:expr, $nonce:expr, $aad:expr, $buffer:expr) => {{
let tag_pos = $buffer
.len()
.checked_sub(Self::TagSize::to_usize())
.ok_or(Error)?;

let (msg, tag) = $buffer.as_mut().split_at_mut(tag_pos);
let tag = Tag::<Self>::try_from(&*tag).expect("tag length mismatch");

$aead.decrypt_in_place_detached($nonce, $aad, msg, &tag)?;
$buffer.truncate(tag_pos);
Ok(())
}};
}

/// In-place stateless AEAD trait.
///
/// This trait is both object safe and has no dependencies on `alloc` or `std`.
Expand Down Expand Up @@ -297,72 +247,24 @@ pub trait AeadInPlace: AeadCore {
associated_data: &[u8],
buffer: &mut dyn Buffer,
) -> Result<()> {
impl_decrypt_in_place!(self, nonce, associated_data, buffer)
}
let tag_pos = buffer
.len()
.checked_sub(Self::TagSize::to_usize())
.ok_or(Error)?;

/// Decrypt the message in-place, returning an error in the event the provided
/// authentication tag does not match the given ciphertext (i.e. ciphertext
/// is modified/unauthentic)
fn decrypt_in_place_detached(
&self,
nonce: &Nonce<Self>,
associated_data: &[u8],
buffer: &mut [u8],
tag: &Tag<Self>,
) -> Result<()>;
}
let (msg, tag) = buffer.as_mut().split_at_mut(tag_pos);
let tag = Tag::<Self>::try_from(&*tag).expect("tag length mismatch");

/// In-place stateful AEAD trait.
///
/// This trait is both object safe and has no dependencies on `alloc` or `std`.
pub trait AeadMutInPlace: AeadCore {
/// Encrypt the given buffer containing a plaintext message in-place.
///
/// The buffer must have sufficient capacity to store the ciphertext
/// message, which will always be larger than the original plaintext.
/// The exact size needed is cipher-dependent, but generally includes
/// the size of an authentication tag.
///
/// Returns an error if the buffer has insufficient capacity to store the
/// resulting ciphertext message.
fn encrypt_in_place(
&mut self,
nonce: &Nonce<Self>,
associated_data: &[u8],
buffer: &mut impl Buffer,
) -> Result<()> {
let tag = self.encrypt_in_place_detached(nonce, associated_data, buffer.as_mut())?;
buffer.extend_from_slice(tag.as_slice())?;
self.decrypt_in_place_detached(nonce, associated_data, msg, &tag)?;
buffer.truncate(tag_pos);
Ok(())
}

/// Encrypt the data in-place, returning the authentication tag
fn encrypt_in_place_detached(
&mut self,
nonce: &Nonce<Self>,
associated_data: &[u8],
buffer: &mut [u8],
) -> Result<Tag<Self>>;

/// Decrypt the message in-place, returning an error in the event the
/// provided authentication tag does not match the given ciphertext.
///
/// The buffer will be truncated to the length of the original plaintext
/// message upon success.
fn decrypt_in_place(
&mut self,
nonce: &Nonce<Self>,
associated_data: &[u8],
buffer: &mut impl Buffer,
) -> Result<()> {
impl_decrypt_in_place!(self, nonce, associated_data, buffer)
}

/// Decrypt the data in-place, returning an error in the event the provided
/// Decrypt the message in-place, returning an error in the event the provided
/// authentication tag does not match the given ciphertext (i.e. ciphertext
/// is modified/unauthentic)
fn decrypt_in_place_detached(
&mut self,
&self,
nonce: &Nonce<Self>,
associated_data: &[u8],
buffer: &mut [u8],
Expand Down Expand Up @@ -396,71 +298,6 @@ impl<Alg: AeadInPlace> Aead for Alg {
}
}

#[cfg(feature = "alloc")]
impl<Alg: AeadMutInPlace> AeadMut for Alg {
fn encrypt<'msg, 'aad>(
&mut self,
nonce: &Nonce<Self>,
plaintext: impl Into<Payload<'msg, 'aad>>,
) -> Result<Vec<u8>> {
let payload = plaintext.into();
let mut buffer = Vec::with_capacity(payload.msg.len() + Self::TagSize::to_usize());
buffer.extend_from_slice(payload.msg);
self.encrypt_in_place(nonce, payload.aad, &mut buffer)?;
Ok(buffer)
}

fn decrypt<'msg, 'aad>(
&mut self,
nonce: &Nonce<Self>,
ciphertext: impl Into<Payload<'msg, 'aad>>,
) -> Result<Vec<u8>> {
let payload = ciphertext.into();
let mut buffer = Vec::from(payload.msg);
self.decrypt_in_place(nonce, payload.aad, &mut buffer)?;
Ok(buffer)
}
}

impl<Alg: AeadInPlace> AeadMutInPlace for Alg {
fn encrypt_in_place(
&mut self,
nonce: &Nonce<Self>,
associated_data: &[u8],
buffer: &mut impl Buffer,
) -> Result<()> {
<Self as AeadInPlace>::encrypt_in_place(self, nonce, associated_data, buffer)
}

fn encrypt_in_place_detached(
&mut self,
nonce: &Nonce<Self>,
associated_data: &[u8],
buffer: &mut [u8],
) -> Result<Tag<Self>> {
<Self as AeadInPlace>::encrypt_in_place_detached(self, nonce, associated_data, buffer)
}

fn decrypt_in_place(
&mut self,
nonce: &Nonce<Self>,
associated_data: &[u8],
buffer: &mut impl Buffer,
) -> Result<()> {
<Self as AeadInPlace>::decrypt_in_place(self, nonce, associated_data, buffer)
}

fn decrypt_in_place_detached(
&mut self,
nonce: &Nonce<Self>,
associated_data: &[u8],
buffer: &mut [u8],
tag: &Tag<Self>,
) -> Result<()> {
<Self as AeadInPlace>::decrypt_in_place_detached(self, nonce, associated_data, buffer, tag)
}
}

/// AEAD payloads (message + AAD).
///
/// Combination of a message (plaintext or ciphertext) and
Expand Down Expand Up @@ -572,8 +409,4 @@ mod tests {
/// Ensure that `AeadInPlace` is object-safe
#[allow(dead_code)]
type DynAeadInPlace<N, T> = dyn AeadInPlace<NonceSize = N, TagSize = T>;

/// Ensure that `AeadMutInPlace` is object-safe
#[allow(dead_code)]
type DynAeadMutInPlace<N, T> = dyn AeadMutInPlace<NonceSize = N, TagSize = T>;
}