diff --git a/aead/src/lib.rs b/aead/src/lib.rs index 74ea85353..bd6baed58 100644 --- a/aead/src/lib.rs +++ b/aead/src/lib.rs @@ -263,6 +263,89 @@ macro_rules! impl_decrypt_in_place { }}; } + +/// Caller-provided input and output stateless AEAD trait. +/// +/// This trait is both object safe and has no dependencies on `alloc` or `std`. +pub trait AeadInto: AeadCore { + /// Encrypt the given plaintext, writing the ciphertext and authentication + /// tag into the given buffer. + /// + /// 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. + /// + /// The default implementation assumes a postfix tag (ala AES-GCM, + /// AES-GCM-SIV, ChaCha20Poly1305). [`AeadInto`] implementations which do + /// not use a postfix tag will need to override this to correctly assemble + /// the ciphertext message. + fn encrypt_into( + &self, + nonce: &Nonce, + plaintext: &[u8], + associated_data: &[u8], + ciphertext: &mut [u8], + ) -> Result<()> { + if ciphertext.len() != plaintext.len().checked_add(Self::TagSize::to_usize()).ok_or(Error)? { + return Err(Error); + } + let (ciphertext, t) = ciphertext.split_at_mut(plaintext.len()); + let tag = self.encrypt_into_detached(nonce, plaintext, associated_data, ciphertext)?; + t.copy_from_slice(tag.as_slice()); + Ok(()) + } + + /// Encrypt the data into the given buffer, returning the authentication + /// tag. + fn encrypt_into_detached( + &self, + nonce: &Nonce, + plaintext: &[u8], + associated_data: &[u8], + ciphertext: &mut [u8], + ) -> Result>; + + /// Decrypt the message into the given buffer, returning an error in the + /// event the provided authentication tag does not match the given + /// ciphertext (i.e. ciphertext is modified/unauthentic + /// + /// The default implementation assumes a postfix tag (ala AES-GCM, + /// AES-GCM-SIV, ChaCha20Poly1305). [`AeadInto`] implementations which do + /// not use a postfix tag will need to override this to correctly assemble + /// the ciphertext message. + fn decrypt_into( + &self, + nonce: &Nonce, + ciphertext: &[u8], + associated_data: &[u8], + plaintext: &mut [u8], + ) -> Result<()> { + if ciphertext.len() != plaintext.len().checked_add(Self::TagSize::to_usize()).ok_or(Error)? { + return Err(Error); + } + let (ciphertext, t) = ciphertext.split_at(plaintext.len()); + let tag = t.try_into().map_err(|_| Error)?; + self.decrypt_into_detached(nonce, ciphertext, associated_data, plaintext, tag)?; + Ok(()) + } + + /// Decrypt the message into the given buffer, returning an error in the + /// event the provided authentication tag does not match the given + /// ciphertext (i.e. ciphertext is modified/unauthentic) + fn decrypt_into_detached( + &self, + nonce: &Nonce, + ciphertext: &[u8], + associated_data: &[u8], + plaintext: &mut [u8], + tag: &Tag, + ) -> Result<()>; +} + /// In-place stateless AEAD trait. /// /// This trait is both object safe and has no dependencies on `alloc` or `std`. @@ -379,6 +462,88 @@ pub trait AeadMutInPlace: AeadCore { ) -> Result<()>; } +/// Caller-provided input and output statelful AEAD trait. +/// +/// This trait is both object safe and has no dependencies on `alloc` or `std`. +pub trait AeadMutInto: AeadCore { + /// Encrypt the given plaintext, writing the ciphertext and authentication + /// tag into the given buffer. + /// + /// 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. + /// + /// The default implementation assumes a postfix tag (ala AES-GCM, + /// AES-GCM-SIV, ChaCha20Poly1305). [`AeadMutInto`] implementations which + /// do not use a postfix tag will need to override this to correctly + /// assemble the ciphertext message. + fn encrypt_into( + &mut self, + nonce: &Nonce, + plaintext: &[u8], + associated_data: &[u8], + ciphertext: &mut [u8], + ) -> Result<()> { + if ciphertext.len() != plaintext.len().checked_add(Self::TagSize::to_usize()).ok_or(Error)? { + return Err(Error); + } + let (ciphertext, t) = ciphertext.split_at_mut(plaintext.len()); + let tag = self.encrypt_into_detached(nonce, plaintext, associated_data, ciphertext)?; + t.copy_from_slice(tag.as_slice()); + Ok(()) + } + + /// Encrypt the data into the given buffer, returning the authentication + /// tag + fn encrypt_into_detached( + &mut self, + nonce: &Nonce, + plaintext: &[u8], + associated_data: &[u8], + ciphertext: &mut [u8], + ) -> Result>; + + /// Decrypt the message into the given buffer, returning an error in the + /// event the provided authentication tag does not match the given + /// ciphertext (i.e. ciphertext is modified/unauthentic + /// + /// The default implementation assumes a postfix tag (ala AES-GCM, + /// AES-GCM-SIV, ChaCha20Poly1305). [`AeadMutInto`] implementations which + /// do not use a postfix tag will need to override this to correctly + /// assemble the ciphertext message. + fn decrypt_into( + &mut self, + nonce: &Nonce, + ciphertext: &[u8], + associated_data: &[u8], + plaintext: &mut [u8], + ) -> Result<()> { + if ciphertext.len() != plaintext.len().checked_add(Self::TagSize::to_usize()).ok_or(Error)? { + return Err(Error); + } + let (ciphertext, t) = ciphertext.split_at(plaintext.len()); + let tag = t.try_into().map_err(|_| Error)?; + self.decrypt_into_detached(nonce, ciphertext, associated_data, plaintext, tag)?; + Ok(()) + } + + /// Decrypt the message into the given buffer, returning an error in the + /// event the provided authentication tag does not match the given + /// ciphertext (i.e. ciphertext is modified/unauthentic) + fn decrypt_into_detached( + &mut self, + nonce: &Nonce, + ciphertext: &[u8], + associated_data: &[u8], + plaintext: &mut [u8], + tag: &Tag, + ) -> Result<()>; +} + #[cfg(feature = "alloc")] impl Aead for Alg { fn encrypt<'msg, 'aad>(