diff --git a/Cargo.lock b/Cargo.lock index 7e7a691a..43016a75 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,13 +6,14 @@ version = 4 [[package]] name = "aead" version = "0.6.0-rc.0" -source = "git+https://github.com/RustCrypto/traits.git#1548d2a7d7ce71a278a783d19d94b59b0103ab15" +source = "git+https://github.com/baloo/traits.git?branch=baloo%2Faead%2Fmockbuffer-merge#38a7ef2feea0a0bdf8f27d496c945968c272d934" dependencies = [ "arrayvec", "blobby 0.4.0-pre.0", "bytes", "crypto-common", "heapless", + "inout", ] [[package]] @@ -99,6 +100,7 @@ dependencies = [ "aead", "ascon", "hex-literal", + "inout", "subtle", "zeroize", ] @@ -215,7 +217,7 @@ dependencies = [ [[package]] name = "crypto-common" version = "0.2.0-rc.2" -source = "git+https://github.com/RustCrypto/traits.git#1548d2a7d7ce71a278a783d19d94b59b0103ab15" +source = "git+https://github.com/baloo/traits.git?branch=baloo%2Faead%2Fmockbuffer-merge#38a7ef2feea0a0bdf8f27d496c945968c272d934" dependencies = [ "hybrid-array", "rand_core", @@ -245,6 +247,7 @@ dependencies = [ "aead", "aes", "hex-literal", + "inout", "subtle", "zeroize", ] @@ -418,9 +421,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] @@ -448,9 +451,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.99" +version = "2.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index bfec3ed2..5d2e127f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,8 +18,8 @@ resolver = "2" aead-stream = { path = "./aead-stream" } aes-gcm = { path = "./aes-gcm" } -aead = { git = "https://github.com/RustCrypto/traits.git" } -crypto-common = { git = "https://github.com/RustCrypto/traits.git" } +aead = { git = "https://github.com/baloo/traits.git", branch = "baloo/aead/mockbuffer-merge" } +crypto-common = { git = "https://github.com/baloo/traits.git", branch = "baloo/aead/mockbuffer-merge" } chacha20 = { git = "https://github.com/RustCrypto/stream-ciphers.git" } diff --git a/aead-stream/src/lib.rs b/aead-stream/src/lib.rs index b3332681..4d095902 100644 --- a/aead-stream/src/lib.rs +++ b/aead-stream/src/lib.rs @@ -6,7 +6,7 @@ extern crate alloc; use aead::{ - AeadCore, AeadInPlace, Buffer, Error, Result, + AeadCore, AeadInOut, Buffer, Error, Result, array::{ Array, ArraySize, typenum::{U4, U5, Unsigned}, @@ -32,7 +32,7 @@ pub type NonceSize = /// Create a new STREAM from the provided AEAD. pub trait NewStream: StreamPrimitive where - A: AeadInPlace, + A: AeadInOut, A::NonceSize: Sub, NonceSize: ArraySize, { @@ -57,7 +57,7 @@ where /// Deliberately immutable and stateless to permit parallel operation. pub trait StreamPrimitive where - A: AeadInPlace, + A: AeadInOut, A::NonceSize: Sub, NonceSize: ArraySize, { @@ -165,7 +165,7 @@ macro_rules! impl_stream_object { #[derive(Debug)] pub struct $name where - A: AeadInPlace, + A: AeadInOut, S: StreamPrimitive, A::NonceSize: Sub<>::NonceOverhead>, NonceSize: ArraySize, @@ -179,7 +179,7 @@ macro_rules! impl_stream_object { impl $name where - A: AeadInPlace, + A: AeadInOut, S: StreamPrimitive, A::NonceSize: Sub<>::NonceOverhead>, NonceSize: ArraySize, @@ -344,7 +344,7 @@ pub type DecryptorLE31 = Decryptor>; #[derive(Debug)] pub struct StreamBE32 where - A: AeadInPlace, + A: AeadInOut, A::NonceSize: Sub, <::NonceSize as Sub>::Output: ArraySize, { @@ -357,7 +357,7 @@ where impl NewStream for StreamBE32 where - A: AeadInPlace, + A: AeadInOut, A::NonceSize: Sub, <::NonceSize as Sub>::Output: ArraySize, { @@ -371,7 +371,7 @@ where impl StreamPrimitive for StreamBE32 where - A: AeadInPlace, + A: AeadInOut, A::NonceSize: Sub, <::NonceSize as Sub>::Output: ArraySize, { @@ -405,7 +405,7 @@ where impl StreamBE32 where - A: AeadInPlace, + A: AeadInOut, A::NonceSize: Sub, <::NonceSize as Sub>::Output: ArraySize, { @@ -434,7 +434,7 @@ where #[derive(Debug)] pub struct StreamLE31 where - A: AeadInPlace, + A: AeadInOut, A::NonceSize: Sub, <::NonceSize as Sub>::Output: ArraySize, { @@ -447,7 +447,7 @@ where impl NewStream for StreamLE31 where - A: AeadInPlace, + A: AeadInOut, A::NonceSize: Sub, <::NonceSize as Sub>::Output: ArraySize, { @@ -461,7 +461,7 @@ where impl StreamPrimitive for StreamLE31 where - A: AeadInPlace, + A: AeadInOut, A::NonceSize: Sub, <::NonceSize as Sub>::Output: ArraySize, { @@ -495,7 +495,7 @@ where impl StreamLE31 where - A: AeadInPlace, + A: AeadInOut, A::NonceSize: Sub, <::NonceSize as Sub>::Output: ArraySize, { diff --git a/aes-gcm-siv/src/lib.rs b/aes-gcm-siv/src/lib.rs index 7f2ca194..070f8e5d 100644 --- a/aes-gcm-siv/src/lib.rs +++ b/aes-gcm-siv/src/lib.rs @@ -34,7 +34,7 @@ //! This crate has an optional `alloc` feature which can be disabled in e.g. //! microcontroller environments that don't have a heap. //! -//! The [`AeadInPlace::encrypt_in_place`] and [`AeadInPlace::decrypt_in_place`] +//! The [`AeadInOut::encrypt_in_place`] and [`AeadInOut::decrypt_in_place`] //! methods accept any type that impls the [`aead::Buffer`] trait which //! contains the plaintext for encryption or ciphertext for decryption. //! @@ -48,7 +48,7 @@ #![cfg_attr(not(all(feature = "os_rng", feature = "heapless")), doc = "```ignore")] //! # fn main() -> Result<(), Box> { //! use aes_gcm_siv::{ -//! aead::{AeadInPlace, KeyInit, rand_core::OsRng, heapless::Vec}, +//! aead::{AeadInOut, KeyInit, rand_core::OsRng, heapless::Vec}, //! Aes256GcmSiv, Nonce, // Or `Aes128GcmSiv` //! }; //! @@ -78,12 +78,12 @@ //! provide an impl of [`aead::Buffer`] for `bytes::BytesMut` (re-exported from the //! [`aead`] crate as [`aead::bytes::BytesMut`]). -pub use aead::{self, AeadCore, AeadInPlaceDetached, Error, Key, KeyInit, KeySizeUser}; +pub use aead::{self, AeadCore, AeadInOut, Error, Key, KeyInit, KeySizeUser}; #[cfg(feature = "aes")] pub use aes; -use aead::PostfixTagged; +use aead::{TagPosition, inout::InOutBuf}; use cipher::{ BlockCipherEncrypt, BlockSizeUser, InnerIvInit, StreamCipherCore, array::Array, @@ -161,32 +161,31 @@ where { type NonceSize = U12; type TagSize = U16; + const TAG_POSITION: TagPosition = TagPosition::Postfix; } -impl PostfixTagged for AesGcmSiv {} - -impl AeadInPlaceDetached for AesGcmSiv +impl AeadInOut for AesGcmSiv where Aes: BlockSizeUser + BlockCipherEncrypt + KeyInit, { - fn encrypt_in_place_detached( + fn encrypt_inout_detached( &self, nonce: &Nonce, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, ) -> Result { Cipher::::new(&self.key_generating_key, nonce) - .encrypt_in_place_detached(associated_data, buffer) + .encrypt_inout_detached(associated_data, buffer) } - fn decrypt_in_place_detached( + fn decrypt_inout_detached( &self, nonce: &Nonce, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, tag: &Tag, ) -> Result<(), Error> { - Cipher::::new(&self.key_generating_key, nonce).decrypt_in_place_detached( + Cipher::::new(&self.key_generating_key, nonce).decrypt_inout_detached( associated_data, buffer, tag, @@ -268,30 +267,30 @@ where } /// Encrypt the given message in-place, returning the authentication tag. - pub(crate) fn encrypt_in_place_detached( + pub(crate) fn encrypt_inout_detached( mut self, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, ) -> Result { if buffer.len() as u64 > P_MAX || associated_data.len() as u64 > A_MAX { return Err(Error); } self.polyval.update_padded(associated_data); - self.polyval.update_padded(buffer); + self.polyval.update_padded(buffer.get_in()); let tag = self.finish_tag(associated_data.len(), buffer.len()); - init_ctr(&self.enc_cipher, &tag).apply_keystream_partial(buffer.into()); + init_ctr(&self.enc_cipher, &tag).apply_keystream_partial(buffer); Ok(tag) } /// Decrypt the given message, first authenticating ciphertext integrity /// and returning an error if it's been tampered with. - pub(crate) fn decrypt_in_place_detached( + pub(crate) fn decrypt_inout_detached( mut self, associated_data: &[u8], - buffer: &mut [u8], + mut buffer: InOutBuf<'_, '_, u8>, tag: &Tag, ) -> Result<(), Error> { if buffer.len() as u64 > C_MAX || associated_data.len() as u64 > A_MAX { @@ -301,8 +300,8 @@ where self.polyval.update_padded(associated_data); // TODO(tarcieri): interleave decryption and authentication - init_ctr(&self.enc_cipher, tag).apply_keystream_partial(buffer.into()); - self.polyval.update_padded(buffer); + init_ctr(&self.enc_cipher, tag).apply_keystream_partial(buffer.reborrow()); + self.polyval.update_padded(buffer.get_out()); let expected_tag = self.finish_tag(associated_data.len(), buffer.len()); @@ -312,7 +311,7 @@ where } else { // On MAC verify failure, re-encrypt the plaintext buffer to // prevent accidental exposure. - init_ctr(&self.enc_cipher, tag).apply_keystream_partial(buffer.into()); + init_ctr(&self.enc_cipher, tag).apply_keystream_partial(buffer); Err(Error) } } diff --git a/aes-gcm/Cargo.toml b/aes-gcm/Cargo.toml index 0adb5f53..774e9fd5 100644 --- a/aes-gcm/Cargo.toml +++ b/aes-gcm/Cargo.toml @@ -26,7 +26,7 @@ subtle = { version = "2", default-features = false } zeroize = { version = "1", optional = true, default-features = false } [dev-dependencies] -aead = { version = "0.6.0-rc.0", features = ["dev"], default-features = false } +aead = { version = "0.6.0-rc.0", features = ["alloc", "dev"], default-features = false } hex-literal = "0.4" [features] diff --git a/aes-gcm/src/lib.rs b/aes-gcm/src/lib.rs index 6b307d68..90d41b64 100644 --- a/aes-gcm/src/lib.rs +++ b/aes-gcm/src/lib.rs @@ -54,7 +54,7 @@ //! This crate has an optional `alloc` feature which can be disabled in e.g. //! microcontroller environments that don't have a heap. //! -//! The [`AeadInPlace::encrypt_in_place`] and [`AeadInPlace::decrypt_in_place`] +//! The [`AeadInOut::encrypt_in_place`] and [`AeadInOut::decrypt_in_place`] //! methods accept any type that impls the [`aead::Buffer`] trait which //! contains the plaintext for encryption or ciphertext for decryption. //! @@ -68,7 +68,7 @@ #![cfg_attr(not(all(feature = "os_rng", feature = "heapless")), doc = "```ignore")] //! # fn main() -> Result<(), Box> { //! use aes_gcm::{ -//! aead::{AeadCore, AeadInPlace, KeyInit, rand_core::OsRng, heapless::Vec}, +//! aead::{AeadCore, AeadInOut, KeyInit, rand_core::OsRng, heapless::Vec}, //! Aes256Gcm, Nonce, // Or `Aes128Gcm` //! }; //! @@ -98,12 +98,12 @@ //! provide an impl of [`aead::Buffer`] for `bytes::BytesMut` (re-exported from the //! [`aead`] crate as [`aead::bytes::BytesMut`]). -pub use aead::{self, AeadCore, AeadInPlaceDetached, Error, Key, KeyInit, KeySizeUser}; +pub use aead::{self, AeadCore, AeadInOut, Error, Key, KeyInit, KeySizeUser}; #[cfg(feature = "aes")] pub use aes; -use aead::PostfixTagged; +use aead::{TagPosition, inout::InOutBuf}; use cipher::{ BlockCipherEncrypt, BlockSizeUser, InnerIvInit, StreamCipherCore, @@ -253,24 +253,20 @@ where { type NonceSize = NonceSize; type TagSize = TagSize; + const TAG_POSITION: TagPosition = TagPosition::Postfix; } -impl PostfixTagged for AesGcm where - TagSize: self::TagSize -{ -} - -impl AeadInPlaceDetached for AesGcm +impl AeadInOut for AesGcm where Aes: BlockSizeUser + BlockCipherEncrypt, NonceSize: ArraySize, TagSize: self::TagSize, { - fn encrypt_in_place_detached( + fn encrypt_inout_detached( &self, nonce: &Nonce, associated_data: &[u8], - buffer: &mut [u8], + mut buffer: InOutBuf<'_, '_, u8>, ) -> Result, Error> { if buffer.len() as u64 > P_MAX || associated_data.len() as u64 > A_MAX { return Err(Error); @@ -280,17 +276,17 @@ where // TODO(tarcieri): interleave encryption with GHASH // See: - ctr.apply_keystream_partial(buffer.into()); + ctr.apply_keystream_partial(buffer.reborrow()); - let full_tag = self.compute_tag(mask, associated_data, buffer); + let full_tag = self.compute_tag(mask, associated_data, buffer.get_out()); Ok(Tag::try_from(&full_tag[..TagSize::to_usize()]).expect("tag size mismatch")) } - fn decrypt_in_place_detached( + fn decrypt_inout_detached( &self, nonce: &Nonce, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, tag: &Tag, ) -> Result<(), Error> { if buffer.len() as u64 > C_MAX || associated_data.len() as u64 > A_MAX { @@ -301,11 +297,11 @@ where // TODO(tarcieri): interleave encryption with GHASH // See: - let expected_tag = self.compute_tag(mask, associated_data, buffer); + let expected_tag = self.compute_tag(mask, associated_data, buffer.get_in()); use subtle::ConstantTimeEq; if expected_tag[..TagSize::to_usize()].ct_eq(tag).into() { - ctr.apply_keystream_partial(buffer.into()); + ctr.apply_keystream_partial(buffer); Ok(()) } else { Err(Error) diff --git a/aes-gcm/tests/aes128gcm.rs b/aes-gcm/tests/aes128gcm.rs index 1e0f82e0..819a631b 100644 --- a/aes-gcm/tests/aes128gcm.rs +++ b/aes-gcm/tests/aes128gcm.rs @@ -7,7 +7,7 @@ mod common; use self::common::TestVector; use aes_gcm::Aes128Gcm; -use aes_gcm::aead::{Aead, AeadInPlaceDetached, KeyInit, Payload, array::Array}; +use aes_gcm::aead::{Aead, AeadInOut, KeyInit, Payload, array::Array}; use hex_literal::hex; /// NIST CAVS vectors diff --git a/aes-gcm/tests/aes256gcm.rs b/aes-gcm/tests/aes256gcm.rs index e56e5110..7f0ea0b5 100644 --- a/aes-gcm/tests/aes256gcm.rs +++ b/aes-gcm/tests/aes256gcm.rs @@ -7,7 +7,7 @@ mod common; use self::common::TestVector; use aes_gcm::Aes256Gcm; -use aes_gcm::aead::{Aead, AeadInPlaceDetached, KeyInit, Payload, array::Array}; +use aes_gcm::aead::{Aead, AeadInOut, KeyInit, Payload, array::Array}; use hex_literal::hex; /// NIST CAVS vectors diff --git a/aes-gcm/tests/common/mod.rs b/aes-gcm/tests/common/mod.rs index 5833b250..ef1dd674 100644 --- a/aes-gcm/tests/common/mod.rs +++ b/aes-gcm/tests/common/mod.rs @@ -92,7 +92,7 @@ macro_rules! tests { let cipher = <$aead>::new(&key); assert!( cipher - .decrypt_in_place_detached(&nonce, &[], &mut buffer, &tag) + .decrypt_inout_detached(&nonce, &[], buffer.as_mut_slice().into(), &tag) .is_err() ); diff --git a/aes-siv/Cargo.toml b/aes-siv/Cargo.toml index 2f1faac7..d290c7a7 100644 --- a/aes-siv/Cargo.toml +++ b/aes-siv/Cargo.toml @@ -32,6 +32,7 @@ pmac = { version = "0.8.0-pre.2", optional = true } [dev-dependencies] blobby = "0.3" hex-literal = "0.4" +aead = { version = "0.6.0-rc.0", features = ["alloc", "dev"], default-features = false } [features] default = ["alloc", "os_rng"] diff --git a/aes-siv/src/lib.rs b/aes-siv/src/lib.rs index 9fd9e289..c0cad4cc 100644 --- a/aes-siv/src/lib.rs +++ b/aes-siv/src/lib.rs @@ -34,7 +34,7 @@ //! This crate has an optional `alloc` feature which can be disabled in e.g. //! microcontroller environments that don't have a heap. //! -//! The [`AeadInPlace::encrypt_in_place`] and [`AeadInPlace::decrypt_in_place`] +//! The [`AeadInOut::encrypt_in_place`] and [`AeadInOut::decrypt_in_place`] //! methods accept any type that impls the [`aead::Buffer`] trait which //! contains the plaintext for encryption or ciphertext for decryption. //! @@ -48,7 +48,7 @@ #![cfg_attr(not(all(feature = "os_rng", feature = "heapless")), doc = "```ignore")] //! # fn main() -> Result<(), Box> { //! use aes_siv::{ -//! aead::{AeadCore, AeadInPlace, KeyInit, rand_core::OsRng, heapless::Vec}, +//! aead::{AeadCore, AeadInOut, KeyInit, rand_core::OsRng, heapless::Vec}, //! Aes256SivAead, Nonce, // Or `Aes128SivAead` //! }; //! @@ -83,15 +83,14 @@ extern crate alloc; pub mod siv; -pub use aead::{ - self, AeadCore, AeadInPlace, AeadInPlaceDetached, Error, Key, KeyInit, KeySizeUser, -}; +pub use aead::{self, AeadCore, AeadInOut, Error, Key, KeyInit, KeySizeUser}; use crate::siv::Siv; use aead::{ - Buffer, + TagPosition, array::Array, consts::{U1, U16, U32, U64}, + inout::InOutBuf, }; use aes::{Aes128, Aes256}; use cipher::{BlockCipherEncrypt, BlockSizeUser, array::ArraySize, typenum::IsGreaterOrEqual}; @@ -206,42 +205,10 @@ where // https://tools.ietf.org/html/rfc5297#section-6 type NonceSize = NonceSize; type TagSize = U16; + const TAG_POSITION: TagPosition = TagPosition::Prefix; } -impl AeadInPlace for SivAead -where - Self: KeySizeUser, - Siv: KeyInit + KeySizeUser::KeySize>, - C: BlockSizeUser + BlockCipherEncrypt + KeyInit + KeySizeUser, - M: Mac + FixedOutputReset + KeyInit, - ::KeySize: Add, - NonceSize: ArraySize + IsGreaterOrEqual, -{ - fn encrypt_in_place( - &self, - nonce: &Array, - associated_data: &[u8], - buffer: &mut dyn Buffer, - ) -> Result<(), Error> { - // "SIV performs nonce-based authenticated encryption when a component of - // the associated data is a nonce. For purposes of interoperability the - // final component -- i.e., the string immediately preceding the - // plaintext in the vector input to S2V -- is used for the nonce." - // https://tools.ietf.org/html/rfc5297#section-3 - Siv::::new(&self.key).encrypt_in_place([associated_data, nonce.as_slice()], buffer) - } - - fn decrypt_in_place( - &self, - nonce: &Array, - associated_data: &[u8], - buffer: &mut dyn Buffer, - ) -> Result<(), Error> { - Siv::::new(&self.key).decrypt_in_place([associated_data, nonce.as_slice()], buffer) - } -} - -impl AeadInPlaceDetached for SivAead +impl AeadInOut for SivAead where Self: KeySizeUser, Siv: KeyInit + KeySizeUser::KeySize>, @@ -250,24 +217,24 @@ where ::KeySize: Add, NonceSize: ArraySize + IsGreaterOrEqual, { - fn encrypt_in_place_detached( + fn encrypt_inout_detached( &self, nonce: &Array, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, ) -> Result, Error> { Siv::::new(&self.key) - .encrypt_in_place_detached([associated_data, nonce.as_slice()], buffer) + .encrypt_inout_detached([associated_data, nonce.as_slice()], buffer) } - fn decrypt_in_place_detached( + fn decrypt_inout_detached( &self, nonce: &Array, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, tag: &Array, ) -> Result<(), Error> { - Siv::::new(&self.key).decrypt_in_place_detached( + Siv::::new(&self.key).decrypt_inout_detached( [associated_data, nonce.as_slice()], buffer, tag, diff --git a/aes-siv/src/siv.rs b/aes-siv/src/siv.rs index 7880ec2e..2f646e42 100644 --- a/aes-siv/src/siv.rs +++ b/aes-siv/src/siv.rs @@ -72,6 +72,7 @@ use crate::Tag; use aead::{ Buffer, Error, array::{Array, ArraySize, typenum::U16}, + inout::InOutBuf, }; use aes::{Aes128, Aes256}; use cipher::{ @@ -209,10 +210,10 @@ where // Make room in the buffer for the SIV tag. It needs to be prepended. buffer.extend_from_slice(Tag::default().as_slice())?; - // TODO(tarcieri): add offset param to `encrypt_in_place_detached` + // TODO(tarcieri): add offset param to `encrypt_inout_detached` buffer.as_mut().copy_within(..pt_len, IV_SIZE); - let tag = self.encrypt_in_place_detached(headers, &mut buffer.as_mut()[IV_SIZE..])?; + let tag = self.encrypt_inout_detached(headers, (&mut buffer.as_mut()[IV_SIZE..]).into())?; buffer.as_mut()[..IV_SIZE].copy_from_slice(tag.as_slice()); Ok(()) } @@ -223,17 +224,17 @@ where /// /// Returns [`Error`] if `plaintext.len()` is less than `M::OutputSize`. /// Returns [`Error`] if `headers.len()` is greater than [`MAX_HEADERS`]. - pub fn encrypt_in_place_detached( + pub fn encrypt_inout_detached( &mut self, headers: I, - plaintext: &mut [u8], + plaintext: InOutBuf<'_, '_, u8>, ) -> Result where I: IntoIterator, T: AsRef<[u8]>, { // Compute the synthetic IV for this plaintext - let siv_tag = s2v(&mut self.mac, headers, plaintext)?; + let siv_tag = s2v(&mut self.mac, headers, plaintext.get_in())?; self.xor_with_keystream(siv_tag, plaintext); Ok(siv_tag) } @@ -270,11 +271,11 @@ where } let siv_tag = Tag::try_from(&buffer.as_ref()[..IV_SIZE]).expect("tag size mismatch"); - self.decrypt_in_place_detached(headers, &mut buffer.as_mut()[IV_SIZE..], &siv_tag)?; + self.decrypt_inout_detached(headers, (&mut buffer.as_mut()[IV_SIZE..]).into(), &siv_tag)?; let pt_len = buffer.len() - IV_SIZE; - // TODO(tarcieri): add offset param to `encrypt_in_place_detached` + // TODO(tarcieri): add offset param to `encrypt_inout_detached` buffer.as_mut().copy_within(IV_SIZE.., 0); buffer.truncate(pt_len); Ok(()) @@ -286,18 +287,18 @@ where /// # Errors /// /// Returns [`Error`] if the ciphertext is not authentic - pub fn decrypt_in_place_detached( + pub fn decrypt_inout_detached( &mut self, headers: I, - ciphertext: &mut [u8], + mut ciphertext: InOutBuf<'_, '_, u8>, siv_tag: &Tag, ) -> Result<(), Error> where I: IntoIterator, T: AsRef<[u8]>, { - self.xor_with_keystream(*siv_tag, ciphertext); - let computed_siv_tag = s2v(&mut self.mac, headers, ciphertext)?; + self.xor_with_keystream(*siv_tag, ciphertext.reborrow()); + let computed_siv_tag = s2v(&mut self.mac, headers, ciphertext.get_out())?; // Note: `CtOutput` provides constant-time equality if CtOutput::::new(computed_siv_tag) == CtOutput::new(*siv_tag) { @@ -310,7 +311,7 @@ where } /// XOR the given buffer with the keystream for the given IV - fn xor_with_keystream(&mut self, mut iv: Tag, msg: &mut [u8]) { + fn xor_with_keystream(&mut self, mut iv: Tag, msg: InOutBuf<'_, '_, u8>) { // "We zero-out the top bit in each of the last two 32-bit words // of the IV before assigning it to Ctr" // — http://web.cs.ucdavis.edu/~rogaway/papers/siv.pdf @@ -318,7 +319,7 @@ where iv[12] &= 0x7f; Ctr128BE::::inner_iv_init(C::new(&self.encryption_key), &iv) - .apply_keystream_partial(msg.into()); + .apply_keystream_partial(msg); } } diff --git a/aes-siv/tests/aead.rs b/aes-siv/tests/aead.rs index ea61a96a..96a66190 100644 --- a/aes-siv/tests/aead.rs +++ b/aes-siv/tests/aead.rs @@ -32,19 +32,20 @@ macro_rules! tests { } #[test] - fn encrypt_in_place_detached() { + fn encrypt_inout_detached() { for vector in $vectors { let key = Array(*vector.key); let nonce = Array(*vector.nonce); - let mut buffer = vector.plaintext.to_vec(); + let buffer = vector.plaintext.to_vec(); + let mut buffer = aead::dev::MockBuffer::from(buffer); let cipher = <$aead>::new(&key); let tag = cipher - .encrypt_in_place_detached(&nonce, vector.aad, &mut buffer) + .encrypt_inout_detached(&nonce, vector.aad, buffer.to_in_out_buf()) .unwrap(); let (expected_tag, expected_ciphertext) = vector.ciphertext.split_at(16); assert_eq!(expected_tag, &tag[..]); - assert_eq!(expected_ciphertext, &buffer[..]); + assert_eq!(expected_ciphertext, buffer.as_ref()); } } @@ -67,18 +68,19 @@ macro_rules! tests { } #[test] - fn decrypt_in_place_detached() { + fn decrypt_inout_detached() { for vector in $vectors { let key = Array(*vector.key); let nonce = Array(*vector.nonce); let tag = Array::try_from(&vector.ciphertext[..16]).unwrap(); - let mut buffer = vector.ciphertext[16..].to_vec(); + let buffer = vector.ciphertext[16..].to_vec(); + let mut buffer = aead::dev::MockBuffer::from(buffer); <$aead>::new(&key) - .decrypt_in_place_detached(&nonce, vector.aad, &mut buffer, &tag) + .decrypt_inout_detached(&nonce, vector.aad, buffer.to_in_out_buf(), &tag) .unwrap(); - assert_eq!(vector.plaintext, buffer.as_slice()); + assert_eq!(vector.plaintext, buffer.as_ref()); } } @@ -108,7 +110,7 @@ macro_rules! tests { mod aes128cmacsivaead { use super::TestVector; use aes_siv::Aes128SivAead; - use aes_siv::aead::{Aead, AeadInPlaceDetached, KeyInit, Payload, array::Array}; + use aes_siv::aead::{Aead, AeadInOut, KeyInit, Payload, array::Array}; /// AES-128-CMAC-SIV test vectors const TEST_VECTORS: &[TestVector<[u8; 32]>] = &[TestVector { @@ -132,7 +134,7 @@ mod aes128cmacsivaead { mod aes128pmacsivaead { use super::TestVector; use aes_siv::Aes128PmacSivAead; - use aes_siv::aead::{Aead, AeadInPlaceDetached, KeyInit, Payload, array::Array}; + use aes_siv::aead::{Aead, AeadInOut, KeyInit, Payload, array::Array}; /// AES-128-PMAC-SIV test vectors const AES_128_PMAC_SIV_TEST_VECTORS: &[TestVector<[u8; 32]>] = &[TestVector { diff --git a/ascon-aead/Cargo.toml b/ascon-aead/Cargo.toml index a20e14df..556a4456 100644 --- a/ascon-aead/Cargo.toml +++ b/ascon-aead/Cargo.toml @@ -19,10 +19,11 @@ aead = { version = "0.6.0-rc.0", default-features = false } subtle = { version = "2", default-features = false } zeroize = { version = "1.6", optional = true, default-features = false, features = ["derive"] } ascon = "0.4" +inout = { version = "0.2.0-rc.4", default-features = false } [dev-dependencies] hex-literal = "0.4" -aead = { version = "0.6.0-rc.0", features = ["alloc"] } +aead = { version = "0.6.0-rc.0", features = ["alloc", "dev"] } [features] default = ["alloc", "os_rng"] diff --git a/ascon-aead/src/asconcore.rs b/ascon-aead/src/asconcore.rs index 2cd828bf..26aaba10 100644 --- a/ascon-aead/src/asconcore.rs +++ b/ascon-aead/src/asconcore.rs @@ -5,6 +5,7 @@ use aead::{ Error, array::{Array, ArraySize}, consts::U16, + inout::InOutBuf, }; use ascon::State; use subtle::ConstantTimeEq; @@ -170,63 +171,68 @@ impl<'a, P: Parameters> AsconCore<'a, P> { self.state[4] ^= 0x8000000000000000; } - fn process_encrypt_inplace(&mut self, message: &mut [u8]) { - let mut blocks = message.chunks_exact_mut(16); - for block in blocks.by_ref() { + fn process_encrypt_inout(&mut self, message: InOutBuf<'_, '_, u8>) { + let (blocks, mut last_block) = message.into_chunks::(); + + for mut block in blocks { // process full block of message - self.state[0] ^= u64_from_bytes(&block[..8]); - block[..8].copy_from_slice(&u64::to_le_bytes(self.state[0])); - self.state[1] ^= u64_from_bytes(&block[8..16]); - block[8..16].copy_from_slice(&u64::to_le_bytes(self.state[1])); + self.state[0] ^= u64_from_bytes(&block.get_in()[..8]); + block.get_out()[..8].copy_from_slice(&u64::to_le_bytes(self.state[0])); + self.state[1] ^= u64_from_bytes(&block.get_in()[8..16]); + block.get_out()[8..16].copy_from_slice(&u64::to_le_bytes(self.state[1])); self.permute_state(); } // process partial block if it exists - let mut last_block = blocks.into_remainder(); let sidx = if last_block.len() >= 8 { - self.state[0] ^= u64_from_bytes(&last_block[..8]); - last_block[..8].copy_from_slice(&u64::to_le_bytes(self.state[0])); - last_block = &mut last_block[8..]; + self.state[0] ^= u64_from_bytes(&last_block.get_in()[..8]); + last_block.get_out()[..8].copy_from_slice(&u64::to_le_bytes(self.state[0])); + (_, last_block) = last_block.split_at(8); 1 } else { 0 }; self.state[sidx] ^= pad(last_block.len()); if !last_block.is_empty() { - self.state[sidx] ^= u64_from_bytes_partial(last_block); - last_block.copy_from_slice(&u64::to_le_bytes(self.state[sidx])[0..last_block.len()]); + self.state[sidx] ^= u64_from_bytes_partial(last_block.get_in()); + let last_block_len = last_block.len(); + last_block + .get_out() + .copy_from_slice(&u64::to_le_bytes(self.state[sidx])[0..last_block_len]); } } - fn process_decrypt_inplace(&mut self, ciphertext: &mut [u8]) { - let mut blocks = ciphertext.chunks_exact_mut(16); - for block in blocks.by_ref() { + fn process_decrypt_inout(&mut self, ciphertext: InOutBuf<'_, '_, u8>) { + let (blocks, mut last_block) = ciphertext.into_chunks::(); + for mut block in blocks { // process full block of ciphertext - let cx = u64_from_bytes(&block[..8]); - block[..8].copy_from_slice(&u64::to_le_bytes(self.state[0] ^ cx)); + let cx = u64_from_bytes(&block.get_in()[..8]); + block.get_out()[..8].copy_from_slice(&u64::to_le_bytes(self.state[0] ^ cx)); self.state[0] = cx; - let cx = u64_from_bytes(&block[8..16]); - block[8..16].copy_from_slice(&u64::to_le_bytes(self.state[1] ^ cx)); + let cx = u64_from_bytes(&block.get_in()[8..16]); + block.get_out()[8..16].copy_from_slice(&u64::to_le_bytes(self.state[1] ^ cx)); self.state[1] = cx; self.permute_state(); } // process partial block if it exists - let mut last_block = blocks.into_remainder(); let sidx = if last_block.len() >= 8 { - let cx = u64_from_bytes(&last_block[..8]); - last_block[..8].copy_from_slice(&u64::to_le_bytes(self.state[0] ^ cx)); + let cx = u64_from_bytes(&last_block.get_in()[..8]); + last_block.get_out()[..8].copy_from_slice(&u64::to_le_bytes(self.state[0] ^ cx)); self.state[0] = cx; - last_block = &mut last_block[8..]; + (_, last_block) = last_block.split_at(8); 1 } else { 0 }; self.state[sidx] ^= pad(last_block.len()); if !last_block.is_empty() { - let cx = u64_from_bytes_partial(last_block); + let cx = u64_from_bytes_partial(last_block.get_in()); self.state[sidx] ^= cx; - last_block.copy_from_slice(&u64::to_le_bytes(self.state[sidx])[0..last_block.len()]); + let last_block_len = last_block.len(); + last_block + .get_out() + .copy_from_slice(&u64::to_le_bytes(self.state[sidx])[0..last_block_len]); self.state[sidx] = clear(self.state[sidx], last_block.len()) ^ cx; } } @@ -242,30 +248,30 @@ impl<'a, P: Parameters> AsconCore<'a, P> { tag } - pub(crate) fn encrypt_inplace( + pub(crate) fn encrypt_inout( &mut self, - message: &mut [u8], + message: InOutBuf<'_, '_, u8>, associated_data: &[u8], ) -> Array { self.process_associated_data(associated_data); - self.process_encrypt_inplace(message); + self.process_encrypt_inout(message); Array::from(self.process_final()) } - pub(crate) fn decrypt_inplace( + pub(crate) fn decrypt_inout( &mut self, - ciphertext: &mut [u8], + mut ciphertext: InOutBuf<'_, '_, u8>, associated_data: &[u8], expected_tag: &Array, ) -> Result<(), Error> { self.process_associated_data(associated_data); - self.process_decrypt_inplace(ciphertext); + self.process_decrypt_inout(ciphertext.reborrow()); let tag = self.process_final(); if bool::from(tag.ct_eq(expected_tag)) { Ok(()) } else { - ciphertext.fill(0); + ciphertext.get_out().fill(0); Err(Error) } } diff --git a/ascon-aead/src/lib.rs b/ascon-aead/src/lib.rs index 920292c2..49e1ebef 100644 --- a/ascon-aead/src/lib.rs +++ b/ascon-aead/src/lib.rs @@ -59,7 +59,7 @@ //! This crate has an optional `alloc` feature which can be disabled in e.g. //! microcontroller environments that don't have a heap. //! -//! The [`AeadInPlace::encrypt_in_place`] and [`AeadInPlace::decrypt_in_place`] +//! The [`AeadInOut::encrypt_in_place`] and [`AeadInOut::decrypt_in_place`] //! methods accept any type that impls the [`aead::Buffer`] trait which //! contains the plaintext for encryption or ciphertext for decryption. //! @@ -72,7 +72,7 @@ //! ``` //! # #[cfg(feature = "heapless")] { //! use ascon_aead::{AsconAead128, Key, Nonce}; -//! use ascon_aead::aead::{AeadInPlace, KeyInit}; +//! use ascon_aead::aead::{AeadInOut, KeyInit}; //! use ascon_aead::aead::heapless::Vec; //! //! let key = Key::::from_slice(b"very secret key."); @@ -105,7 +105,7 @@ pub use zeroize; pub use aead::{self, Error, Key, Nonce, Tag}; -use aead::{AeadCore, AeadInPlaceDetached, KeyInit, KeySizeUser, PostfixTagged, consts::U16}; +use aead::{AeadCore, AeadInOut, KeyInit, KeySizeUser, TagPosition, consts::U16, inout::InOutBuf}; mod asconcore; @@ -135,16 +135,15 @@ impl KeyInit for Ascon

{ impl AeadCore for Ascon

{ type NonceSize = U16; type TagSize = U16; + const TAG_POSITION: TagPosition = TagPosition::Postfix; } -impl PostfixTagged for Ascon

{} - -impl AeadInPlaceDetached for Ascon

{ - fn encrypt_in_place_detached( +impl AeadInOut for Ascon

{ + fn encrypt_inout_detached( &self, nonce: &Nonce, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, ) -> Result, Error> { if (buffer.len() as u64) .checked_add(associated_data.len() as u64) @@ -154,14 +153,14 @@ impl AeadInPlaceDetached for Ascon

{ } let mut core = AsconCore::

::new(&self.key, nonce); - Ok(core.encrypt_inplace(buffer, associated_data)) + Ok(core.encrypt_inout(buffer, associated_data)) } - fn decrypt_in_place_detached( + fn decrypt_inout_detached( &self, nonce: &Nonce, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, tag: &Tag, ) -> Result<(), Error> { if (buffer.len() as u64) @@ -172,7 +171,7 @@ impl AeadInPlaceDetached for Ascon

{ } let mut core = AsconCore::

::new(&self.key, nonce); - core.decrypt_inplace(buffer, associated_data, tag) + core.decrypt_inout(buffer, associated_data, tag) } } @@ -198,31 +197,30 @@ impl KeyInit for AsconAead128 { impl AeadCore for AsconAead128 { type NonceSize = U16; type TagSize = U16; + const TAG_POSITION: TagPosition = TagPosition::Postfix; } -impl PostfixTagged for AsconAead128 {} - -impl AeadInPlaceDetached for AsconAead128 { +impl AeadInOut for AsconAead128 { #[inline(always)] - fn encrypt_in_place_detached( + fn encrypt_inout_detached( &self, nonce: &Nonce, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, ) -> Result, Error> { self.0 - .encrypt_in_place_detached(nonce, associated_data, buffer) + .encrypt_inout_detached(nonce, associated_data, buffer) } #[inline(always)] - fn decrypt_in_place_detached( + fn decrypt_inout_detached( &self, nonce: &Nonce, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, tag: &Tag, ) -> Result<(), Error> { self.0 - .decrypt_in_place_detached(nonce, associated_data, buffer, tag) + .decrypt_inout_detached(nonce, associated_data, buffer, tag) } } diff --git a/ascon-aead/tests/kats_test.rs b/ascon-aead/tests/kats_test.rs index a364393d..dedf9341 100644 --- a/ascon-aead/tests/kats_test.rs +++ b/ascon-aead/tests/kats_test.rs @@ -3,11 +3,11 @@ use ascon_aead::{ AsconAead128, - aead::{Aead, AeadInPlaceDetached, KeyInit, Payload, Tag}, + aead::{Aead, AeadInOut, KeyInit, Payload, Tag, dev::MockBuffer}, }; use hex_literal::hex; -fn run_tv( +fn run_tv( key: &[u8], nonce: &[u8], plaintext: &[u8], @@ -40,9 +40,28 @@ fn run_tv( let bad_tag = Tag::::default(); let mut buf = ciphertext[..ciphertext.len() - bad_tag.len()].to_vec(); - let res = core.decrypt_in_place_detached(nonce, associated_data, &mut buf, &bad_tag); + let res = + core.decrypt_inout_detached(nonce, associated_data, buf.as_mut_slice().into(), &bad_tag); assert!(res.is_err()); assert!(buf.iter().all(|b| *b == 0)); + + let mut buf = MockBuffer::from(&plaintext[..ciphertext.len() - bad_tag.len()]); + let tag_encryption = core + .encrypt_inout_detached(nonce, associated_data, buf.to_in_out_buf()) + .expect("encryption failed"); + assert_eq!( + tag_encryption.as_slice(), + &ciphertext[ciphertext.len() - bad_tag.len()..] + ); + assert_eq!( + buf.as_ref(), + &ciphertext[..ciphertext.len() - bad_tag.len()] + ); + + let mut buf = MockBuffer::from(&ciphertext[..ciphertext.len() - bad_tag.len()]); + core.decrypt_inout_detached(nonce, associated_data, buf.to_in_out_buf(), &tag_encryption) + .expect("decryption failed"); + assert_eq!(buf.as_ref(), plaintext); } #[test] diff --git a/ccm/src/lib.rs b/ccm/src/lib.rs index bd51999b..a75e094f 100644 --- a/ccm/src/lib.rs +++ b/ccm/src/lib.rs @@ -42,12 +42,13 @@ //! [aead]: https://docs.rs/aead //! [1]: https://en.wikipedia.org/wiki/Authenticated_encryption -pub use aead::{self, AeadCore, AeadInPlaceDetached, Error, Key, KeyInit, KeySizeUser, consts}; +pub use aead::{self, AeadCore, AeadInOut, Error, Key, KeyInit, KeySizeUser, consts}; use aead::{ - PostfixTagged, + TagPosition, array::{Array, ArraySize, typenum::Unsigned}, consts::U16, + inout::InOutBuf, }; use cipher::{ Block, BlockCipherEncrypt, BlockSizeUser, InnerIvInit, StreamCipher, StreamCipherSeek, @@ -211,29 +212,22 @@ where { type NonceSize = N; type TagSize = M; + const TAG_POSITION: TagPosition = TagPosition::Postfix; } -impl PostfixTagged for Ccm +impl AeadInOut for Ccm where C: BlockSizeUser + BlockCipherEncrypt, M: ArraySize + TagSize, N: ArraySize + NonceSize, { -} - -impl AeadInPlaceDetached for Ccm -where - C: BlockSizeUser + BlockCipherEncrypt, - M: ArraySize + TagSize, - N: ArraySize + NonceSize, -{ - fn encrypt_in_place_detached( + fn encrypt_inout_detached( &self, nonce: &Nonce, adata: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, ) -> Result, Error> { - let mut full_tag = self.calc_mac(nonce, adata, buffer)?; + let mut full_tag = self.calc_mac(nonce, adata, buffer.get_in())?; let ext_nonce = Self::extend_nonce(nonce); // number of bytes left for counter (max 8) @@ -242,21 +236,21 @@ where if cb > 4 { let mut ctr = Ctr64BE::from_core(CtrCore::inner_iv_init(&self.cipher, &ext_nonce)); ctr.apply_keystream(&mut full_tag); - ctr.apply_keystream(buffer); + ctr.apply_keystream_inout(buffer); } else { let mut ctr = Ctr32BE::from_core(CtrCore::inner_iv_init(&self.cipher, &ext_nonce)); ctr.apply_keystream(&mut full_tag); - ctr.apply_keystream(buffer); + ctr.apply_keystream_inout(buffer); } Ok(Tag::try_from(&full_tag[..M::to_usize()]).expect("tag size mismatch")) } - fn decrypt_in_place_detached( + fn decrypt_inout_detached( &self, nonce: &Nonce, adata: &[u8], - buffer: &mut [u8], + mut buffer: InOutBuf<'_, '_, u8>, tag: &Tag, ) -> Result<(), Error> { let ext_nonce = Self::extend_nonce(nonce); @@ -266,14 +260,14 @@ where if cb > 4 { let mut ctr = Ctr64BE::from_core(CtrCore::inner_iv_init(&self.cipher, &ext_nonce)); ctr.seek(C::BlockSize::USIZE); - ctr.apply_keystream(buffer); + ctr.apply_keystream_inout(buffer.reborrow()); } else { let mut ctr = Ctr32BE::from_core(CtrCore::inner_iv_init(&self.cipher, &ext_nonce)); ctr.seek(C::BlockSize::USIZE); - ctr.apply_keystream(buffer); + ctr.apply_keystream_inout(buffer.reborrow()); } - let mut full_tag = self.calc_mac(nonce, adata, buffer)?; + let mut full_tag = self.calc_mac(nonce, adata, buffer.get_out())?; if cb > 4 { let mut ctr = Ctr64BE::from_core(CtrCore::inner_iv_init(&self.cipher, &ext_nonce)); @@ -286,7 +280,7 @@ where if full_tag[..tag.len()].ct_eq(tag).into() { Ok(()) } else { - buffer.iter_mut().for_each(|v| *v = 0); + buffer.get_out().fill(0); Err(Error) } } diff --git a/ccm/tests/mod.rs b/ccm/tests/mod.rs index 10ce7276..f4b20fb8 100644 --- a/ccm/tests/mod.rs +++ b/ccm/tests/mod.rs @@ -1,6 +1,6 @@ #![cfg(feature = "alloc")] -use aead::{Aead, AeadInPlaceDetached, KeyInit, Payload, array::Array}; +use aead::{Aead, AeadInOut, KeyInit, Payload, array::Array}; use aes::{Aes128, Aes192, Aes256}; use ccm::{ Ccm, @@ -19,11 +19,11 @@ fn test_data_len_check() { let c = Cipher::new(&key); let mut buf1 = [1; u16::MAX as usize]; - let res = c.encrypt_in_place_detached(&nonce, &[], &mut buf1); + let res = c.encrypt_inout_detached(&nonce, &[], buf1.as_mut_slice().into()); assert!(res.is_ok()); let mut buf2 = [1; u16::MAX as usize + 1]; - let res = c.encrypt_in_place_detached(&nonce, &[], &mut buf2); + let res = c.encrypt_inout_detached(&nonce, &[], buf2.as_mut_slice().into()); assert!(res.is_err()); } diff --git a/chacha20poly1305/src/cipher.rs b/chacha20poly1305/src/cipher.rs index 76bb4bf8..5c8df500 100644 --- a/chacha20poly1305/src/cipher.rs +++ b/chacha20poly1305/src/cipher.rs @@ -2,7 +2,7 @@ use ::cipher::{StreamCipher, StreamCipherSeek}; use aead::Error; -use aead::array::Array; +use aead::{array::Array, inout::InOutBuf}; use poly1305::{ Poly1305, universal_hash::{KeyInit, UniversalHash}, @@ -50,10 +50,10 @@ where } /// Encrypt the given message in-place, returning the authentication tag - pub(crate) fn encrypt_in_place_detached( + pub(crate) fn encrypt_inout_detached( mut self, associated_data: &[u8], - buffer: &mut [u8], + mut buffer: InOutBuf<'_, '_, u8>, ) -> Result { if buffer.len() / BLOCK_SIZE >= MAX_BLOCKS { return Err(Error); @@ -63,19 +63,19 @@ where // TODO(tarcieri): interleave encryption with Poly1305 // See: - self.cipher.apply_keystream(buffer); - self.mac.update_padded(buffer); + self.cipher.apply_keystream_inout(buffer.reborrow()); + self.mac.update_padded(buffer.get_out()); - self.authenticate_lengths(associated_data, buffer)?; + self.authenticate_lengths(associated_data, buffer.get_out())?; Ok(self.mac.finalize()) } /// Decrypt the given message, first authenticating ciphertext integrity /// and returning an error if it's been tampered with. - pub(crate) fn decrypt_in_place_detached( + pub(crate) fn decrypt_inout_detached( mut self, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, tag: &Tag, ) -> Result<(), Error> { if buffer.len() / BLOCK_SIZE >= MAX_BLOCKS { @@ -83,14 +83,14 @@ where } self.mac.update_padded(associated_data); - self.mac.update_padded(buffer); - self.authenticate_lengths(associated_data, buffer)?; + self.mac.update_padded(buffer.get_in()); + self.authenticate_lengths(associated_data, buffer.get_in())?; // This performs a constant-time comparison using the `subtle` crate if self.mac.verify(tag).is_ok() { // TODO(tarcieri): interleave decryption with Poly1305 // See: - self.cipher.apply_keystream(buffer); + self.cipher.apply_keystream_inout(buffer); Ok(()) } else { Err(Error) diff --git a/chacha20poly1305/src/lib.rs b/chacha20poly1305/src/lib.rs index c42e057d..d829f8a7 100644 --- a/chacha20poly1305/src/lib.rs +++ b/chacha20poly1305/src/lib.rs @@ -46,7 +46,7 @@ //! This crate has an optional `alloc` feature which can be disabled in e.g. //! microcontroller environments that don't have a heap. //! -//! The [`AeadInPlace::encrypt_in_place`] and [`AeadInPlace::decrypt_in_place`] +//! The [`AeadInOut::encrypt_in_place`] and [`AeadInOut::decrypt_in_place`] //! methods accept any type that impls the [`aead::Buffer`] trait which //! contains the plaintext for encryption or ciphertext for decryption. //! @@ -60,7 +60,7 @@ #![cfg_attr(not(all(feature = "os_rng", feature = "heapless")), doc = "```ignore")] //! # fn main() -> Result<(), Box> { //! use chacha20poly1305::{ -//! aead::{AeadCore, AeadInPlace, KeyInit, rand_core::OsRng, heapless::Vec}, +//! aead::{AeadCore, AeadInOut, KeyInit, rand_core::OsRng, heapless::Vec}, //! ChaCha20Poly1305, Nonce, //! }; //! @@ -139,14 +139,15 @@ mod cipher; -pub use aead::{self, AeadCore, AeadInPlaceDetached, Error, KeyInit, KeySizeUser, consts}; +pub use aead::{self, AeadCore, AeadInOut, Error, KeyInit, KeySizeUser, consts}; use self::cipher::Cipher; use ::cipher::{KeyIvInit, StreamCipher, StreamCipherSeek}; use aead::{ - PostfixTagged, + TagPosition, array::{Array, ArraySize}, consts::{U12, U16, U24, U32}, + inout::InOutBuf, }; use core::marker::PhantomData; @@ -245,41 +246,31 @@ where { type NonceSize = N; type TagSize = U16; + const TAG_POSITION: TagPosition = TagPosition::Postfix; } -impl PostfixTagged for ChaChaPoly1305 +impl AeadInOut for ChaChaPoly1305 where C: KeyIvInit + StreamCipher + StreamCipherSeek, N: ArraySize, { -} - -impl AeadInPlaceDetached for ChaChaPoly1305 -where - C: KeyIvInit + StreamCipher + StreamCipherSeek, - N: ArraySize, -{ - fn encrypt_in_place_detached( + fn encrypt_inout_detached( &self, nonce: &aead::Nonce, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, ) -> Result { - Cipher::new(C::new(&self.key, nonce)).encrypt_in_place_detached(associated_data, buffer) + Cipher::new(C::new(&self.key, nonce)).encrypt_inout_detached(associated_data, buffer) } - fn decrypt_in_place_detached( + fn decrypt_inout_detached( &self, nonce: &aead::Nonce, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, tag: &Tag, ) -> Result<(), Error> { - Cipher::new(C::new(&self.key, nonce)).decrypt_in_place_detached( - associated_data, - buffer, - tag, - ) + Cipher::new(C::new(&self.key, nonce)).decrypt_inout_detached(associated_data, buffer, tag) } } diff --git a/deoxys/Cargo.toml b/deoxys/Cargo.toml index 7c360207..dbf9bef8 100644 --- a/deoxys/Cargo.toml +++ b/deoxys/Cargo.toml @@ -20,6 +20,7 @@ rust-version = "1.85" [dependencies] aead = { version = "0.6.0-rc.0", default-features = false } aes = { version = "=0.9.0-pre.3", features = ["hazmat"], default-features = false } +inout = { version = "0.2.0-rc.4", default-features = false } subtle = { version = "2", default-features = false } zeroize = { version = "1", optional = true, default-features = false } diff --git a/deoxys/src/lib.rs b/deoxys/src/lib.rs index 63df0f7b..14ceac6a 100644 --- a/deoxys/src/lib.rs +++ b/deoxys/src/lib.rs @@ -62,7 +62,7 @@ //! This crate has an optional `alloc` feature which can be disabled in e.g. //! microcontroller environments that don't have a heap. //! -//! The [`AeadInPlace::encrypt_in_place`] and [`AeadInPlace::decrypt_in_place`] +//! The [`AeadInOut::encrypt_in_place`] and [`AeadInOut::decrypt_in_place`] //! methods accept any type that impls the [`aead::Buffer`] trait which //! contains the plaintext for encryption or ciphertext for decryption. //! @@ -76,7 +76,7 @@ //! # #[cfg(feature = "heapless")] //! # { //! use deoxys::{DeoxysII256, Nonce}; // Can be `DeoxysI128`, `DeoxysI256`, `DeoxysII128` of `DeoxysII256` -//! use deoxys::aead::{AeadCore, AeadInPlace, KeyInit, rand_core::OsRng, heapless::Vec}; +//! use deoxys::aead::{AeadCore, AeadInOut, KeyInit, rand_core::OsRng, heapless::Vec}; //! //! let key = DeoxysII256::generate_key().expect("generate key"); //! let cipher = DeoxysII256::new(&key); @@ -110,12 +110,13 @@ mod deoxys_bc; /// Operation modes for Deoxys. mod modes; -pub use aead::{self, AeadCore, AeadInPlaceDetached, Error, Key, KeyInit, KeySizeUser, consts}; +pub use aead::{self, AeadCore, AeadInOut, Error, Key, KeyInit, KeySizeUser, consts}; use aead::{ - PostfixTagged, + TagPosition, array::{Array, ArraySize}, consts::U16, + inout::{InOut, InOutBuf}, }; use core::marker::PhantomData; @@ -156,19 +157,19 @@ where /// Encrypts the data in place with the specified parameters /// Returns the tag - fn encrypt_in_place( + fn encrypt_inout( nonce: &Array, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, subkeys: &Array, ) -> Tag; /// Decrypts the data in place with the specified parameters /// Returns an error if the tag verification fails - fn decrypt_in_place( + fn decrypt_inout( nonce: &Array, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, tag: &Tag, subkeys: &Array, ) -> Result<(), aead::Error>; @@ -184,25 +185,23 @@ pub trait DeoxysBcType: deoxys_bc::DeoxysBcInternal { fn precompute_subkeys(key: &Array) -> Array; /// Encrypts a block of data in place. - fn encrypt_in_place( - block: &mut Block, + fn encrypt_inout( + mut block: InOut<'_, '_, Block>, tweak: &Tweak, subkeys: &Array, ) { let keys = Self::key_schedule(tweak, subkeys); - for (b, k) in block.iter_mut().zip(keys[0].iter()) { - *b ^= k; - } + block.xor_in2out(&keys[0]); for k in &keys[1..] { - aes::hazmat::cipher_round(block, k); + aes::hazmat::cipher_round(block.get_out(), k); } } /// Decrypts a block of data in place. - fn decrypt_in_place( - block: &mut Block, + fn decrypt_inout( + mut block: InOut<'_, '_, Block>, tweak: &Tweak, subkeys: &Array, ) { @@ -210,18 +209,16 @@ pub trait DeoxysBcType: deoxys_bc::DeoxysBcInternal { let r = keys.len(); - for (b, k) in block.iter_mut().zip(keys[r - 1].iter()) { - *b ^= k; - } + block.xor_in2out(&keys[r - 1]); - aes::hazmat::inv_mix_columns(block); + aes::hazmat::inv_mix_columns(block.get_out()); for k in keys[..r - 1].iter_mut().rev() { aes::hazmat::inv_mix_columns(k); - aes::hazmat::equiv_inv_cipher_round(block, k); + aes::hazmat::equiv_inv_cipher_round(block.get_out(), k); } - aes::hazmat::mix_columns(block); + aes::hazmat::mix_columns(block.get_out()); } } @@ -265,27 +262,21 @@ where { type NonceSize = M::NonceSize; type TagSize = U16; + const TAG_POSITION: TagPosition = TagPosition::Postfix; } -impl PostfixTagged for Deoxys -where - M: DeoxysMode, - B: DeoxysBcType, -{ -} - -impl AeadInPlaceDetached for Deoxys +impl AeadInOut for Deoxys where M: DeoxysMode, B: DeoxysBcType, { - fn encrypt_in_place_detached( + fn encrypt_inout_detached( &self, nonce: &Nonce, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, ) -> Result { - Ok(Tag::from(M::encrypt_in_place( + Ok(Tag::from(M::encrypt_inout( nonce, associated_data, buffer, @@ -293,14 +284,14 @@ where ))) } - fn decrypt_in_place_detached( + fn decrypt_inout_detached( &self, nonce: &Nonce, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, tag: &Tag, ) -> Result<(), Error> { - M::decrypt_in_place(nonce, associated_data, buffer, tag, &self.subkeys) + M::decrypt_inout(nonce, associated_data, buffer, tag, &self.subkeys) } } diff --git a/deoxys/src/modes.rs b/deoxys/src/modes.rs index ccb2b117..7d859606 100644 --- a/deoxys/src/modes.rs +++ b/deoxys/src/modes.rs @@ -2,6 +2,7 @@ use super::{Block, DeoxysBcType, DeoxysKey, DeoxysMode, Tag, Tweak}; use aead::{ array::Array, consts::{U8, U15, U16}, + inout::InOutBuf, }; use core::marker::PhantomData; use subtle::ConstantTimeEq; @@ -47,7 +48,7 @@ where let mut block = Block::default(); block.copy_from_slice(ad); - B::encrypt_in_place(&mut block, tweak, subkeys); + B::encrypt_inout((&mut block).into(), tweak, subkeys); for (t, b) in tag.iter_mut().zip(block.iter()) { *t ^= b; @@ -61,7 +62,7 @@ where block[ad.len()] = 0x80; - B::encrypt_in_place(&mut block, tweak, subkeys); + B::encrypt_inout((&mut block).into(), tweak, subkeys); for (t, b) in tag.iter_mut().zip(block.iter()) { *t ^= b; @@ -82,15 +83,16 @@ where { type NonceSize = U8; - fn encrypt_in_place( + fn encrypt_inout( nonce: &Array, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, subkeys: &Array, ) -> Tag { let mut tag = Tag::default(); let mut checksum = Checksum::default(); let mut tweak = Tweak::default(); + let buffer_len = buffer.len(); // Associated Data >::compute_ad_tag( @@ -112,66 +114,75 @@ where if !buffer.is_empty() { tweak[0] = (tweak[0] & 0xf) | TWEAK_M; - for (index, data) in buffer.chunks_mut(16).enumerate() { + let (data_blocks, tail) = buffer.into_chunks(); + let data_blocks_len = data_blocks.len(); + + for (index, data) in data_blocks.into_iter().enumerate() { // Copy block number let tmp = tweak[8] & 0xf0; tweak[8..].copy_from_slice(&(index as u64).to_be_bytes()); tweak[8] = (tweak[8] & 0xf) | tmp; - if data.len() == 16 { - for (c, d) in checksum.iter_mut().zip(data.iter()) { - *c ^= d; - } + for (c, d) in checksum.iter_mut().zip(data.get_in().iter()) { + *c ^= d; + } - let data: &mut Block = data.try_into().unwrap(); - B::encrypt_in_place(data, tweak.as_ref(), subkeys); - } else { - // Last block checksum - tweak[0] = (tweak[0] & 0xf) | TWEAK_M_LAST; + B::encrypt_inout(data, &tweak, subkeys); + } - let mut block = Block::default(); - block[0..data.len()].copy_from_slice(data); + let mut data = tail; + let index = data_blocks_len; + if !data.is_empty() { + // Last block, incomplete - block[data.len()] = 0x80; + // Copy block number + let tmp = tweak[8] & 0xf0; + tweak[8..].copy_from_slice(&(index as u64).to_be_bytes()); + tweak[8] = (tweak[8] & 0xf) | tmp; - for (c, d) in checksum.iter_mut().zip(block.iter()) { - *c ^= d; - } + // Last block checksum + tweak[0] = (tweak[0] & 0xf) | TWEAK_M_LAST; - block.fill(0); + let mut block = Block::default(); + block[0..data.len()].copy_from_slice(data.get_in()); - // Last block encryption - B::encrypt_in_place(&mut block, tweak.as_ref(), subkeys); + block[data.len()] = 0x80; - for (d, b) in data.iter_mut().zip(block.iter()) { - *d ^= b; - } + for (c, d) in checksum.iter_mut().zip(block.iter()) { + *c ^= d; + } - // Tag computing. - tweak[0] = (tweak[0] & 0xf) | TWEAK_CHKSUM; + block.fill(0); - let tmp = tweak[8] & 0xf0; - tweak[8..].copy_from_slice(&((index + 1) as u64).to_be_bytes()); - tweak[8] = (tweak[8] & 0xf) | tmp; + // Last block encryption + B::encrypt_inout((&mut block).into(), &tweak, subkeys); - B::encrypt_in_place(&mut checksum, tweak.as_ref(), subkeys); + data.xor_in2out((block[..data.len()]).into()); - for (t, c) in tag.iter_mut().zip(checksum.iter()) { - *t ^= c; - } + // Tag computing. + tweak[0] = (tweak[0] & 0xf) | TWEAK_CHKSUM; + + let tmp = tweak[8] & 0xf0; + tweak[8..].copy_from_slice(&((index + 1) as u64).to_be_bytes()); + tweak[8] = (tweak[8] & 0xf) | tmp; + + B::encrypt_inout((&mut checksum).into(), tweak.as_ref(), subkeys); + + for (t, c) in tag.iter_mut().zip(checksum.iter()) { + *t ^= c; } } } - if buffer.len() % 16 == 0 { + if buffer_len % 16 == 0 { // Tag computing without last block tweak[0] = (tweak[0] & 0xf) | TWEAK_TAG; let tmp = tweak[8] & 0xf0; - tweak[8..].copy_from_slice(&((buffer.len() / 16) as u64).to_be_bytes()); + tweak[8..].copy_from_slice(&((buffer_len / 16) as u64).to_be_bytes()); tweak[8] = (tweak[8] & 0xf) | tmp; - B::encrypt_in_place(&mut checksum, tweak.as_ref(), subkeys); + B::encrypt_inout((&mut checksum).into(), tweak.as_ref(), subkeys); for (t, c) in tag.iter_mut().zip(checksum.iter()) { *t ^= c; @@ -181,16 +192,17 @@ where tag } - fn decrypt_in_place( + fn decrypt_inout( nonce: &Array, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, tag: &Tag, subkeys: &Array, ) -> Result<(), aead::Error> { let mut computed_tag = Tag::default(); let mut checksum = Checksum::default(); let mut tweak = Tweak::default(); + let buffer_len = buffer.len(); // Associated Data >::compute_ad_tag( @@ -212,64 +224,71 @@ where if !buffer.is_empty() { tweak[0] = (tweak[0] & 0xf) | TWEAK_M; - for (index, data) in buffer.chunks_mut(16).enumerate() { + let (data_blocks, tail) = buffer.into_chunks(); + let data_blocks_len = data_blocks.len(); + + for (index, mut data) in data_blocks.into_iter().enumerate() { // Copy block number let tmp = tweak[8] & 0xf0; tweak[8..].copy_from_slice(&(index as u64).to_be_bytes()); tweak[8] = (tweak[8] & 0xf) | tmp; - if data.len() == 16 { - let data: &mut Block = data.try_into().unwrap(); - B::decrypt_in_place(data, tweak.as_ref(), subkeys); + B::decrypt_inout(data.reborrow(), tweak.as_ref(), subkeys); - for (c, d) in checksum.iter_mut().zip(data.iter()) { - *c ^= d; - } - } else { - // Last block checksum - tweak[0] = (tweak[0] & 0xf) | TWEAK_M_LAST; + for (c, d) in checksum.iter_mut().zip(data.get_out().iter()) { + *c ^= d; + } + } - let mut block = Block::default(); - B::encrypt_in_place(&mut block, tweak.as_ref(), subkeys); + let mut data = tail; + let index = data_blocks_len; + if !data.is_empty() { + // Copy block number + let tmp = tweak[8] & 0xf0; + tweak[8..].copy_from_slice(&(index as u64).to_be_bytes()); + tweak[8] = (tweak[8] & 0xf) | tmp; - for (d, b) in data.iter_mut().zip(block.iter()) { - *d ^= b; - } + // Last block checksum + tweak[0] = (tweak[0] & 0xf) | TWEAK_M_LAST; - block.fill(0); + let mut block = Block::default(); + B::encrypt_inout((&mut block).into(), tweak.as_ref(), subkeys); - block[0..data.len()].copy_from_slice(data); - block[data.len()] = 0x80; + data.xor_in2out((block[..data.len()]).into()); - for (c, d) in checksum.iter_mut().zip(block.iter()) { - *c ^= d; - } + block.fill(0); + + block[0..data.len()].copy_from_slice(data.get_out()); + block[data.len()] = 0x80; - // Tag computing. - tweak[0] = (tweak[0] & 0xf) | TWEAK_CHKSUM; + for (c, d) in checksum.iter_mut().zip(block.iter()) { + *c ^= d; + } - let tmp = tweak[8] & 0xf0; - tweak[8..].copy_from_slice(&((index + 1) as u64).to_be_bytes()); - tweak[8] = (tweak[8] & 0xf) | tmp; + // Tag computing. + tweak[0] = (tweak[0] & 0xf) | TWEAK_CHKSUM; - B::encrypt_in_place(&mut checksum, tweak.as_ref(), subkeys); + let tmp = tweak[8] & 0xf0; + tweak[8..].copy_from_slice(&((index + 1) as u64).to_be_bytes()); + tweak[8] = (tweak[8] & 0xf) | tmp; - for (t, c) in computed_tag.iter_mut().zip(checksum.iter()) { - *t ^= c; - } + B::encrypt_inout((&mut checksum).into(), tweak.as_ref(), subkeys); + + for (t, c) in computed_tag.iter_mut().zip(checksum.iter()) { + *t ^= c; } } } - if buffer.len() % 16 == 0 { + if buffer_len % 16 == 0 { // Tag computing without last block tweak[0] = (tweak[0] & 0xf) | TWEAK_TAG; let tmp = tweak[8] & 0xf0; - tweak[8..].copy_from_slice(&((buffer.len() / 16) as u64).to_be_bytes()); + tweak[8..].copy_from_slice(&((buffer_len / 16) as u64).to_be_bytes()); tweak[8] = (tweak[8] & 0xf) | tmp; - B::encrypt_in_place(&mut checksum, tweak.as_ref(), subkeys); + B::encrypt_inout((&mut checksum).into(), tweak.as_ref(), subkeys); for (t, c) in computed_tag.iter_mut().zip(checksum.iter()) { *t ^= c; @@ -306,7 +325,8 @@ where tweak[8..].copy_from_slice(&(index as u64).to_be_bytes()); let mut block = *data; - B::encrypt_in_place(&mut block, tweak, subkeys); + + B::encrypt_inout((&mut block).into(), tweak, subkeys); for (t, b) in tag.iter_mut().zip(block.iter()) { *t ^= b; @@ -330,7 +350,7 @@ where block[data.len()] = 0x80; - B::encrypt_in_place(&mut block, tweak, subkeys); + B::encrypt_inout((&mut block).into(), tweak, subkeys); for (t, b) in tag.iter_mut().zip(block.iter()) { *t ^= b; @@ -338,39 +358,60 @@ where } fn encrypt_decrypt_message( - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, tweak: &mut Tweak, subkeys: &Array, tag: &Tag, nonce: &Array, ) { - if !buffer.is_empty() { - tweak.copy_from_slice(tag); - tweak[0] |= 0x80; + #[inline] + fn encrypt_decrypt_block( + index: usize, + tweak: &mut Tweak, + subkeys: &Array, + nonce: &Array, + xor: F, + ) { + let index_array = (index as u64).to_be_bytes(); + + // XOR in block numbers + for (t, i) in tweak[8..].iter_mut().zip(&index_array) { + *t ^= i + } - for (index, data) in buffer.chunks_mut(16).enumerate() { - let index_array = (index as u64).to_be_bytes(); + let mut block = Block::default(); + block[1..].copy_from_slice(nonce); - // XOR in block numbers - for (t, i) in tweak[8..].iter_mut().zip(&index_array) { - *t ^= i - } + B::encrypt_inout((&mut block).into(), tweak, subkeys); - let mut block = Block::default(); - block[1..].copy_from_slice(nonce); + xor(&block); - B::encrypt_in_place(&mut block, tweak, subkeys); + // XOR out block numbers + for (t, i) in tweak[8..].iter_mut().zip(&index_array) { + *t ^= i + } + } - for (t, b) in data.iter_mut().zip(block.iter()) { - *t ^= b; - } + if buffer.is_empty() { + return; + } - // XOR out block numbers - for (t, i) in tweak[8..].iter_mut().zip(&index_array) { - *t ^= i - } - } + tweak.copy_from_slice(tag); + tweak[0] |= 0x80; + + let (blocks, tail) = buffer.into_chunks::(); + let blocks_len = blocks.len(); + for (index, mut data) in blocks.into_iter().enumerate() { + encrypt_decrypt_block::(index, tweak, subkeys, nonce, |block| { + data.xor_in2out(block) + }); } + let mut data = tail; + let index = blocks_len; + + encrypt_decrypt_block::(index, tweak, subkeys, nonce, |block| { + data.xor_in2out((block[..data.len()]).into()) + }); } } @@ -380,10 +421,10 @@ where { type NonceSize = U15; - fn encrypt_in_place( + fn encrypt_inout( nonce: &Array, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, subkeys: &Array, ) -> Tag { let mut tag = Tag::default(); @@ -398,11 +439,11 @@ where ); // Message authentication - Self::authenticate_message(buffer, &mut tweak, subkeys, &mut tag); + Self::authenticate_message(buffer.get_in(), &mut tweak, subkeys, &mut tag); tweak[0] = TWEAK_TAG; tweak[1..].copy_from_slice(nonce); - B::encrypt_in_place(&mut tag, &tweak, subkeys); + B::encrypt_inout((&mut tag).into(), &tweak, subkeys); // Message encryption Self::encrypt_decrypt_message(buffer, &mut tweak, subkeys, &tag, nonce); @@ -410,10 +451,10 @@ where tag } - fn decrypt_in_place( + fn decrypt_inout( nonce: &Array, associated_data: &[u8], - buffer: &mut [u8], + mut buffer: InOutBuf<'_, '_, u8>, tag: &Tag, subkeys: &Array, ) -> Result<(), aead::Error> { @@ -429,16 +470,16 @@ where ); // Message decryption - Self::encrypt_decrypt_message(buffer, &mut tweak, subkeys, tag, nonce); + Self::encrypt_decrypt_message(buffer.reborrow(), &mut tweak, subkeys, tag, nonce); tweak.fill(0); // Message authentication - Self::authenticate_message(buffer, &mut tweak, subkeys, &mut computed_tag); + Self::authenticate_message(buffer.get_out(), &mut tweak, subkeys, &mut computed_tag); tweak[0] = TWEAK_TAG; tweak[1..].copy_from_slice(nonce); - B::encrypt_in_place(&mut computed_tag, &tweak, subkeys); + B::encrypt_inout((&mut computed_tag).into(), &tweak, subkeys); if tag.ct_eq(&computed_tag).into() { Ok(()) diff --git a/deoxys/tests/mock_buffer.rs b/deoxys/tests/mock_buffer.rs new file mode 100644 index 00000000..d40220db --- /dev/null +++ b/deoxys/tests/mock_buffer.rs @@ -0,0 +1,82 @@ +//! this module is here to test the inout behavior which is not currently exposed. +//! it will be once we port over to the API made in RustCrypto/traits#1793. +//! +//! This is to drop once https://github.com/RustCrypto/traits/pull/1797 is made available. +//! +//! It duplicates test vectors from `tests/deoxys_i_128.rs` and provides a mock buffer backing +//! for InOut. + +use aead::{AeadInOut, array::Array, dev::MockBuffer}; +use hex_literal::hex; + +use deoxys::*; + +#[test] +fn test_deoxys_i_128_5() { + let plaintext = hex!("5a4c652cb880808707230679224b11799b5883431292973215e9bd03cf3bc32fe4"); + let mut buffer = MockBuffer::from(&plaintext[..]); + + let aad = Vec::new(); + + let key = hex!("101112131415161718191a1b1c1d1e1f"); + let key = Array(key); + + let nonce = hex!("202122232425262728292a2b2c2d2e2f"); + let nonce = Array::try_from(&nonce[..8]).unwrap(); + + let ciphertext_expected = + hex!("cded5a43d3c76e942277c2a1517530ad66037897c985305ede345903ed7585a626"); + + let tag_expected: [u8; 16] = hex!("cbf5faa6b8398c47f4278d2019161776"); + + let cipher = DeoxysI128::new(&key); + let tag: Tag = cipher + .encrypt_inout_detached(&nonce, &aad, buffer.to_in_out_buf()) + .expect("encryption failed"); + + let ciphertext = buffer.as_ref(); + assert_eq!(ciphertext, ciphertext_expected); + assert_eq!(tag, tag_expected); + + let mut buffer = MockBuffer::from(buffer.as_ref()); + cipher + .decrypt_inout_detached(&nonce, &aad, buffer.to_in_out_buf(), &tag) + .expect("decryption failed"); + + assert_eq!(&plaintext[..], buffer.as_ref()); +} + +#[test] +fn test_deoxys_ii_128_5() { + let plaintext = hex!("06ac1756eccece62bd743fa80c299f7baa3872b556130f52265919494bdc136db3"); + let mut buffer = MockBuffer::from(&plaintext[..]); + + let aad = Vec::new(); + + let key = hex!("101112131415161718191a1b1c1d1e1f"); + let key = Array(key); + + let nonce = hex!("202122232425262728292a2b2c2d2e2f"); + let nonce = Array::try_from(&nonce[..15]).unwrap(); + + let ciphertext_expected = + hex!("82bf241958b324ed053555d23315d3cc20935527fc970ff34a9f521a95e302136d"); + + let tag_expected: [u8; 16] = hex!("0eadc8612d5208c491e93005195e9769"); + + let cipher = DeoxysII128::new(&key); + let tag: Tag = cipher + .encrypt_inout_detached(&nonce, &aad, buffer.to_in_out_buf()) + .expect("encryption failed"); + + let ciphertext = buffer.as_ref(); + assert_eq!(ciphertext, ciphertext_expected); + assert_eq!(tag, tag_expected); + + let mut buffer = MockBuffer::from(buffer.as_ref()); + cipher + .decrypt_inout_detached(&nonce, &aad, buffer.to_in_out_buf(), &tag) + .expect("decryption failed"); + + assert_eq!(&plaintext[..], buffer.as_ref()); +} diff --git a/eax/src/lib.rs b/eax/src/lib.rs index c4d6cf03..1abc7c64 100644 --- a/eax/src/lib.rs +++ b/eax/src/lib.rs @@ -38,7 +38,7 @@ //! This crate has an optional `alloc` feature which can be disabled in e.g. //! microcontroller environments that don't have a heap. //! -//! The [`AeadInPlace::encrypt_in_place`] and [`AeadInPlace::decrypt_in_place`] +//! The [`AeadInOut::encrypt_in_place`] and [`AeadInOut::decrypt_in_place`] //! methods accept any type that impls the [`aead::Buffer`] trait which //! contains the plaintext for encryption or ciphertext for decryption. //! @@ -56,7 +56,7 @@ //! use eax::aead::{ //! array::Array, //! heapless::Vec, -//! AeadCore, AeadInPlace, KeyInit, rand_core::OsRng +//! AeadCore, AeadInOut, KeyInit, rand_core::OsRng //! }; //! //! pub type Aes256Eax = Eax; @@ -97,7 +97,7 @@ //! # { //! use aes::Aes256; //! use eax::Eax; -//! use eax::aead::{AeadInPlaceDetached, KeyInit, array::Array}; +//! use eax::aead::{AeadInOut, KeyInit, array::Array}; //! use eax::aead::heapless::Vec; //! use eax::aead::consts::{U8, U128}; //! @@ -110,7 +110,7 @@ //! buffer.extend_from_slice(b"plaintext message"); //! //! // Encrypt `buffer` in-place, replacing the plaintext contents with ciphertext -//! let tag = cipher.encrypt_in_place_detached(nonce, b"", &mut buffer).expect("encryption failure!"); +//! let tag = cipher.encrypt_inout_detached(nonce, b"", buffer.as_mut_slice().into()).expect("encryption failure!"); //! //! // The tag has only 8 bytes, compared to the usual 16 bytes //! assert_eq!(tag.len(), 8); @@ -119,15 +119,15 @@ //! assert_ne!(&buffer, b"plaintext message"); //! //! // Decrypt `buffer` in-place, replacing its ciphertext context with the original plaintext -//! cipher.decrypt_in_place_detached(nonce, b"", &mut buffer, &tag).expect("decryption failure!"); +//! cipher.decrypt_inout_detached(nonce, b"", buffer.as_mut_slice().into(), &tag).expect("decryption failure!"); //! assert_eq!(&buffer, b"plaintext message"); //! # } //! ``` -pub use aead::{self, AeadCore, AeadInPlaceDetached, Error, Key, KeyInit, KeySizeUser}; +pub use aead::{self, AeadCore, AeadInOut, Error, Key, KeyInit, KeySizeUser}; pub use cipher; -use aead::PostfixTagged; +use aead::{TagPosition, inout::InOutBuf}; use cipher::{ BlockCipherEncrypt, BlockSizeUser, InnerIvInit, StreamCipherCore, array::Array, consts::U16, crypto_common::OutputSizeUser, typenum::Unsigned, @@ -210,25 +210,19 @@ where { type NonceSize = Cipher::BlockSize; type TagSize = M; + const TAG_POSITION: TagPosition = TagPosition::Postfix; } -impl PostfixTagged for Eax +impl AeadInOut for Eax where Cipher: BlockSizeUser + BlockCipherEncrypt + Clone + KeyInit, M: TagSize, { -} - -impl AeadInPlaceDetached for Eax -where - Cipher: BlockSizeUser + BlockCipherEncrypt + Clone + KeyInit, - M: TagSize, -{ - fn encrypt_in_place_detached( + fn encrypt_inout_detached( &self, nonce: &Nonce, associated_data: &[u8], - buffer: &mut [u8], + mut buffer: InOutBuf<'_, '_, u8>, ) -> Result, Error> { if buffer.len() as u64 > P_MAX || associated_data.len() as u64 > A_MAX { return Err(Error); @@ -247,10 +241,10 @@ where // 3. enc ← CTR(M) using n as iv Ctr128BE::::inner_iv_init(Cipher::new(&self.key), &n) - .apply_keystream_partial(buffer.into()); + .apply_keystream_partial(buffer.reborrow()); // 4. c ← OMAC(2 || enc) - let c = Self::cmac_with_iv(&self.key, 2, buffer); + let c = Self::cmac_with_iv(&self.key, 2, buffer.get_out()); // 5. tag ← n ^ h ^ c // (^ means xor) @@ -267,11 +261,11 @@ where Ok(tag) } - fn decrypt_in_place_detached( + fn decrypt_inout_detached( &self, nonce: &Nonce, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, tag: &Tag, ) -> Result<(), Error> { if buffer.len() as u64 > C_MAX || associated_data.len() as u64 > A_MAX { @@ -285,7 +279,7 @@ where let h = Self::cmac_with_iv(&self.key, 1, associated_data); // 4. c ← OMAC(2 || enc) - let c = Self::cmac_with_iv(&self.key, 2, buffer); + let c = Self::cmac_with_iv(&self.key, 2, buffer.get_in()); // 5. tag ← n ^ h ^ c // (^ means xor) @@ -305,7 +299,7 @@ where if expected_tag.ct_eq(tag).into() { // Decrypt Ctr128BE::::inner_iv_init(Cipher::new(&self.key), &n) - .apply_keystream_partial(buffer.into()); + .apply_keystream_partial(buffer); Ok(()) } else { diff --git a/ocb3/src/lib.rs b/ocb3/src/lib.rs index a6808ff9..34fa5c4f 100644 --- a/ocb3/src/lib.rs +++ b/ocb3/src/lib.rs @@ -5,7 +5,7 @@ html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" )] -#![deny(unsafe_code)] +//#![deny(unsafe_code)] #![warn(missing_docs, rust_2018_idioms)] /// Constants used, reexported for convenience. @@ -14,17 +14,21 @@ pub mod consts { } pub use aead::{ - self, AeadCore, AeadInPlaceDetached, Error, KeyInit, KeySizeUser, + self, AeadCore, AeadInOut, Error, KeyInit, KeySizeUser, array::{Array, AssocArraySize}, }; -use aead::{PostfixTagged, array::ArraySize}; +use aead::{ + TagPosition, + array::ArraySize, + inout::{InOut, InOutBuf}, +}; use cipher::{ BlockCipherDecrypt, BlockCipherEncrypt, BlockSizeUser, - consts::{U12, U16}, + consts::{U2, U12, U16}, typenum::Unsigned, }; -use core::marker::PhantomData; +use core::{marker::PhantomData, ops::Mul}; use dbl::Dbl; use subtle::ConstantTimeEq; @@ -55,7 +59,9 @@ pub type Nonce = Array; /// OCB3 tag pub type Tag = Array; -pub(crate) type Block = Array; +type BlockSize = U16; +pub(crate) type Block = Array; +type DoubleBlock = Array>::Output>; mod sealed { use aead::array::{ @@ -168,6 +174,7 @@ where { type NonceSize = NonceSize; type TagSize = TagSize; + const TAG_POSITION: TagPosition = TagPosition::Postfix; } impl From for Ocb3 @@ -190,54 +197,47 @@ where } } -impl PostfixTagged for Ocb3 +impl AeadInOut for Ocb3 where Cipher: BlockSizeUser + BlockCipherEncrypt + BlockCipherDecrypt, NonceSize: sealed::NonceSizes, TagSize: sealed::TagSizes, { -} - -impl AeadInPlaceDetached for Ocb3 -where - Cipher: BlockSizeUser + BlockCipherEncrypt + BlockCipherDecrypt, - NonceSize: sealed::NonceSizes, - TagSize: sealed::TagSizes, -{ - fn encrypt_in_place_detached( + fn encrypt_inout_detached( &self, nonce: &Nonce, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, ) -> aead::Result> { if (buffer.len() > P_MAX) || (associated_data.len() > A_MAX) { unimplemented!() } // First, try to process many blocks at once. - let (processed_bytes, mut offset_i, mut checksum_i) = self.wide_encrypt(nonce, buffer); + let (tail, index, mut offset_i, mut checksum_i) = self.wide_encrypt(nonce, buffer); - let mut i = (processed_bytes / 16) + 1; + let mut i = index; // Then, process the remaining blocks. - for p_i in Block::slice_as_chunks_mut(&mut buffer[processed_bytes..]).0 { + let (blocks, mut tail): (InOutBuf<'_, '_, Block>, _) = tail.into_chunks(); + + for p_i in blocks { // offset_i = offset_{i-1} xor L_{ntz(i)} inplace_xor(&mut offset_i, &self.ll[ntz(i)]); // checksum_i = checksum_{i-1} xor p_i - inplace_xor(&mut checksum_i, p_i); + inplace_xor(&mut checksum_i, p_i.get_in()); // c_i = offset_i xor ENCIPHER(K, p_i xor offset_i) - let c_i = p_i; - inplace_xor(c_i, &offset_i); - self.cipher.encrypt_block(c_i); - inplace_xor(c_i, &offset_i); + let mut c_i = p_i; + c_i.xor_in2out(&offset_i); + self.cipher.encrypt_block(c_i.get_out()); + inplace_xor(c_i.get_out(), &offset_i); i += 1; } // Process any partial blocks. - if (buffer.len() % 16) != 0 { - let processed_bytes = (i - 1) * 16; - let remaining_bytes = buffer.len() - processed_bytes; + if !tail.is_empty() { + let remaining_bytes = tail.len(); // offset_* = offset_m xor L_* inplace_xor(&mut offset_i, &self.ll_star); @@ -247,15 +247,13 @@ where self.cipher.encrypt_block(&mut pad); // checksum_* = checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*))) let checksum_rhs = &mut [0u8; 16]; - checksum_rhs[..remaining_bytes].copy_from_slice(&buffer[processed_bytes..]); + checksum_rhs[..remaining_bytes].copy_from_slice(tail.get_in()); checksum_rhs[remaining_bytes] = 0b1000_0000; inplace_xor(&mut checksum_i, checksum_rhs.as_ref()); // C_* = P_* xor Pad[1..bitlen(P_*)] - let p_star = &mut buffer[processed_bytes..]; + let p_star = tail.get_out(); let pad = &mut pad[..p_star.len()]; - for (aa, bb) in p_star.iter_mut().zip(pad) { - *aa ^= *bb; - } + tail.xor_in2out(pad); } let tag = self.compute_tag(associated_data, &mut checksum_i, &offset_i); @@ -263,14 +261,14 @@ where Ok(tag) } - fn decrypt_in_place_detached( + fn decrypt_inout_detached( &self, nonce: &Nonce, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, tag: &aead::Tag, ) -> aead::Result<()> { - let expected_tag = self.decrypt_in_place_return_tag(nonce, associated_data, buffer); + let expected_tag = self.decrypt_inout_return_tag(nonce, associated_data, buffer); if expected_tag.ct_eq(tag).into() { Ok(()) } else { @@ -286,41 +284,40 @@ where TagSize: sealed::TagSizes, { /// Decrypts in place and returns expected tag. - pub(crate) fn decrypt_in_place_return_tag( + pub(crate) fn decrypt_inout_return_tag( &self, nonce: &Nonce, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, ) -> aead::Tag { if (buffer.len() > C_MAX) || (associated_data.len() > A_MAX) { unimplemented!() } // First, try to process many blocks at once. - let (processed_bytes, mut offset_i, mut checksum_i) = self.wide_decrypt(nonce, buffer); + let (tail, index, mut offset_i, mut checksum_i) = self.wide_decrypt(nonce, buffer); - let mut i = (processed_bytes / 16) + 1; + let mut i = index; // Then, process the remaining blocks. - let (blocks, _remaining) = Block::slice_as_chunks_mut(&mut buffer[processed_bytes..]); + let (blocks, mut tail): (InOutBuf<'_, '_, Block>, _) = tail.into_chunks(); for c_i in blocks { // offset_i = offset_{i-1} xor L_{ntz(i)} inplace_xor(&mut offset_i, &self.ll[ntz(i)]); // p_i = offset_i xor DECIPHER(K, c_i xor offset_i) - let p_i = c_i; - inplace_xor(p_i, &offset_i); - self.cipher.decrypt_block(p_i); - inplace_xor(p_i, &offset_i); + let mut p_i = c_i; + p_i.xor_in2out(&offset_i); + self.cipher.decrypt_block(p_i.get_out()); + inplace_xor(p_i.get_out(), &offset_i); // checksum_i = checksum_{i-1} xor p_i - inplace_xor(&mut checksum_i, p_i); + inplace_xor(&mut checksum_i, p_i.get_out()); i += 1; } // Process any partial blocks. - if (buffer.len() % 16) != 0 { - let processed_bytes = (i - 1) * 16; - let remaining_bytes = buffer.len() - processed_bytes; + if !tail.is_empty() { + let remaining_bytes = tail.len(); // offset_* = offset_m xor L_* inplace_xor(&mut offset_i, &self.ll_star); @@ -329,14 +326,12 @@ where inplace_xor(&mut pad, &offset_i); self.cipher.encrypt_block(&mut pad); // P_* = C_* xor Pad[1..bitlen(C_*)] - let c_star = &mut buffer[processed_bytes..]; + let c_star = tail.get_in(); let pad = &mut pad[..c_star.len()]; - for (aa, bb) in c_star.iter_mut().zip(pad) { - *aa ^= *bb; - } + tail.xor_in2out(pad); // checksum_* = checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*))) let checksum_rhs = &mut [0u8; 16]; - checksum_rhs[..remaining_bytes].copy_from_slice(&buffer[processed_bytes..]); + checksum_rhs[..remaining_bytes].copy_from_slice(tail.get_out()); checksum_rhs[remaining_bytes] = 0b1000_0000; inplace_xor(&mut checksum_i, checksum_rhs.as_ref()); } @@ -347,81 +342,85 @@ where /// Encrypts plaintext in groups of two. /// /// Adapted from https://www.cs.ucdavis.edu/~rogaway/ocb/news/code/ocb.c - fn wide_encrypt(&self, nonce: &Nonce, buffer: &mut [u8]) -> (usize, Block, Block) { + fn wide_encrypt<'i, 'o>( + &self, + nonce: &Nonce, + buffer: InOutBuf<'i, 'o, u8>, + ) -> (InOutBuf<'i, 'o, u8>, usize, Block, Block) { const WIDTH: usize = 2; let mut i = 1; let mut offset_i = [Block::default(); WIDTH]; - offset_i[offset_i.len() - 1] = initial_offset(&self.cipher, nonce, TagSize::to_u32()); + offset_i[1] = initial_offset(&self.cipher, nonce, TagSize::to_u32()); let mut checksum_i = Block::default(); - for wide_blocks in buffer.chunks_exact_mut(::Size::USIZE * WIDTH) { - let p_i = split_into_two_blocks(wide_blocks); + let (wide_blocks, tail): (InOutBuf<'_, '_, DoubleBlock>, _) = buffer.into_chunks(); + for wide_block in wide_blocks.into_iter() { + let mut p_i = split_into_two_blocks(wide_block); // checksum_i = checksum_{i-1} xor p_i for p_ij in &p_i { - inplace_xor(&mut checksum_i, p_ij); + inplace_xor(&mut checksum_i, p_ij.get_in()); } // offset_i = offset_{i-1} xor L_{ntz(i)} - offset_i[0] = offset_i[offset_i.len() - 1]; + offset_i[0] = offset_i[1]; inplace_xor(&mut offset_i[0], &self.ll[ntz(i)]); - for j in 1..p_i.len() { - offset_i[j] = offset_i[j - 1]; - inplace_xor(&mut offset_i[j], &self.ll[ntz(i + j)]); - } + offset_i[1] = offset_i[0]; + inplace_xor(&mut offset_i[1], &self.ll[ntz(i + 1)]); // c_i = offset_i xor ENCIPHER(K, p_i xor offset_i) for j in 0..p_i.len() { - inplace_xor(p_i[j], &offset_i[j]); - self.cipher.encrypt_block(p_i[j]); - inplace_xor(p_i[j], &offset_i[j]) + p_i[j].xor_in2out(&offset_i[j]); + self.cipher.encrypt_block(p_i[j].get_out()); + inplace_xor(p_i[j].get_out(), &offset_i[j]); } i += WIDTH; } - let processed_bytes = (buffer.len() / (WIDTH * 16)) * (WIDTH * 16); - - (processed_bytes, offset_i[offset_i.len() - 1], checksum_i) + (tail, i, offset_i[offset_i.len() - 1], checksum_i) } /// Decrypts plaintext in groups of two. /// /// Adapted from https://www.cs.ucdavis.edu/~rogaway/ocb/news/code/ocb.c - fn wide_decrypt(&self, nonce: &Nonce, buffer: &mut [u8]) -> (usize, Block, Block) { + fn wide_decrypt<'i, 'o>( + &self, + nonce: &Nonce, + buffer: InOutBuf<'i, 'o, u8>, + ) -> (InOutBuf<'i, 'o, u8>, usize, Block, Block) { const WIDTH: usize = 2; let mut i = 1; let mut offset_i = [Block::default(); WIDTH]; - offset_i[offset_i.len() - 1] = initial_offset(&self.cipher, nonce, TagSize::to_u32()); + offset_i[1] = initial_offset(&self.cipher, nonce, TagSize::to_u32()); let mut checksum_i = Block::default(); - for wide_blocks in buffer.chunks_exact_mut(16 * WIDTH) { - let c_i = split_into_two_blocks(wide_blocks); + + let (wide_blocks, tail): (InOutBuf<'_, '_, DoubleBlock>, _) = buffer.into_chunks(); + for wide_block in wide_blocks.into_iter() { + let mut c_i = split_into_two_blocks(wide_block); // offset_i = offset_{i-1} xor L_{ntz(i)} - offset_i[0] = offset_i[offset_i.len() - 1]; + offset_i[0] = offset_i[1]; inplace_xor(&mut offset_i[0], &self.ll[ntz(i)]); - for j in 1..c_i.len() { - offset_i[j] = offset_i[j - 1]; - inplace_xor(&mut offset_i[j], &self.ll[ntz(i + j)]); - } + offset_i[1] = offset_i[0]; + inplace_xor(&mut offset_i[1], &self.ll[ntz(i + 1)]); // p_i = offset_i xor DECIPHER(K, c_i xor offset_i) // checksum_i = checksum_{i-1} xor p_i for j in 0..c_i.len() { - inplace_xor(c_i[j], &offset_i[j]); - self.cipher.decrypt_block(c_i[j]); - inplace_xor(c_i[j], &offset_i[j]); - inplace_xor(&mut checksum_i, c_i[j]); + c_i[j].xor_in2out(&offset_i[j]); + self.cipher.decrypt_block(c_i[j].get_out()); + inplace_xor(c_i[j].get_out(), &offset_i[j]); + inplace_xor(&mut checksum_i, c_i[j].get_out()); } i += WIDTH; } - let processed_bytes = (buffer.len() / (WIDTH * 16)) * (WIDTH * 16); - (processed_bytes, offset_i[offset_i.len() - 1], checksum_i) + (tail, i, offset_i[offset_i.len() - 1], checksum_i) } /// Computes HASH function defined in https://www.rfc-editor.org/rfc/rfc7253.html#section-4.1 @@ -580,11 +579,20 @@ pub(crate) fn ntz(n: usize) -> usize { } #[inline] -pub(crate) fn split_into_two_blocks(two_blocks: &mut [u8]) -> [&mut Block; 2] { - const BLOCK_SIZE: usize = 16; - debug_assert_eq!(two_blocks.len(), BLOCK_SIZE * 2); - let (b0, b1) = two_blocks.split_at_mut(BLOCK_SIZE); - [b0.try_into().unwrap(), b1.try_into().unwrap()] +pub(crate) fn split_into_two_blocks<'i, 'o>( + two_blocks: InOut<'i, 'o, DoubleBlock>, +) -> [InOut<'i, 'o, Block>; 2] { + let (input, output) = two_blocks.into_raw(); + + let (bi0, bi1) = unsafe { input.as_ref() } + .unwrap() + .split_at(BlockSize::USIZE); + let (bi0, bi1): (&Block, &Block) = (bi0.try_into().unwrap(), bi1.try_into().unwrap()); + let (bo0, bo1) = unsafe { output.as_mut() } + .unwrap() + .split_at_mut(BlockSize::USIZE); + let (bo0, bo1): (&mut Block, &mut Block) = (bo0.try_into().unwrap(), bo1.try_into().unwrap()); + [InOut::from((bi0, bo0)), InOut::from((bi1, bo1))] } #[cfg(test)] diff --git a/ocb3/tests/kats.rs b/ocb3/tests/kats.rs index 7181c5c9..1b30c726 100644 --- a/ocb3/tests/kats.rs +++ b/ocb3/tests/kats.rs @@ -1,7 +1,7 @@ #![allow(non_snake_case)] use aead::{ - AeadInPlaceDetached, KeyInit, + AeadInOut, KeyInit, consts::{U8, U12}, }; use aes::{Aes128, Aes192, Aes256}; @@ -38,7 +38,11 @@ macro_rules! rfc7253_wider_variety { let N = num2str96(3 * i + 1); let mut buffer = S.clone(); let tag = ocb - .encrypt_in_place_detached(N.as_slice().try_into().unwrap(), &S, &mut buffer) + .encrypt_inout_detached( + N.as_slice().try_into().unwrap(), + &S, + buffer.as_mut_slice().into(), + ) .unwrap(); ciphertext.append(&mut buffer); ciphertext.append(&mut tag.as_slice().to_vec()); @@ -48,7 +52,11 @@ macro_rules! rfc7253_wider_variety { let N = num2str96(3 * i + 2); let mut buffer = S.clone(); let tag = ocb - .encrypt_in_place_detached(N.as_slice().try_into().unwrap(), &[], &mut buffer) + .encrypt_inout_detached( + N.as_slice().try_into().unwrap(), + &[], + buffer.as_mut_slice().into(), + ) .unwrap(); ciphertext.append(&mut buffer); ciphertext.append(&mut tag.as_slice().to_vec()); @@ -57,7 +65,7 @@ macro_rules! rfc7253_wider_variety { // C = C || OCB-ENCRYPT(K,N,S,) let N = num2str96(3 * i + 3); let tag = ocb - .encrypt_in_place_detached(N.as_slice().try_into().unwrap(), &S, &mut []) + .encrypt_inout_detached(N.as_slice().try_into().unwrap(), &S, (&mut [][..]).into()) .unwrap(); ciphertext.append(&mut tag.as_slice().to_vec()); } @@ -75,7 +83,11 @@ macro_rules! rfc7253_wider_variety { // Output : OCB-ENCRYPT(K,N,C,) let N = num2str96(385); let tag = ocb - .encrypt_in_place_detached(N.as_slice().try_into().unwrap(), &ciphertext, &mut []) + .encrypt_inout_detached( + N.as_slice().try_into().unwrap(), + &ciphertext, + (&mut [][..]).into(), + ) .unwrap(); assert_eq!(tag.as_slice(), hex!($expected)) diff --git a/xaes-256-gcm/src/lib.rs b/xaes-256-gcm/src/lib.rs index a89ff81e..d36c8fc3 100644 --- a/xaes-256-gcm/src/lib.rs +++ b/xaes-256-gcm/src/lib.rs @@ -56,7 +56,7 @@ pub use aes_gcm; use core::ops::{Div, Mul}; use aead::{ - AeadCore, AeadInPlaceDetached, Error, KeyInit, KeySizeUser, PostfixTagged, array::Array, + AeadCore, AeadInOut, Error, KeyInit, KeySizeUser, TagPosition, array::Array, inout::InOutBuf, }; use aes::Aes256; use aes_gcm::Aes256Gcm; @@ -96,6 +96,7 @@ pub const C_MAX: u64 = (1 << 36) + 16; impl AeadCore for Xaes256Gcm { type NonceSize = NonceSize; type TagSize = TagSize; + const TAG_POSITION: TagPosition = TagPosition::Postfix; } impl KeySizeUser for Xaes256Gcm { @@ -126,14 +127,12 @@ impl KeyInit for Xaes256Gcm { } } -impl PostfixTagged for Xaes256Gcm {} - -impl AeadInPlaceDetached for Xaes256Gcm { - fn encrypt_in_place_detached( +impl AeadInOut for Xaes256Gcm { + fn encrypt_inout_detached( &self, nonce: &Nonce, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, ) -> Result { if buffer.len() as u64 > P_MAX || associated_data.len() as u64 > A_MAX { return Err(Error); @@ -141,14 +140,14 @@ impl AeadInPlaceDetached for Xaes256Gcm { let (n1, n) = nonce.split_ref::<>::Output>(); let k = self.derive_key(n1); - Aes256Gcm::new(&k).encrypt_in_place_detached(n, associated_data, buffer) + Aes256Gcm::new(&k).encrypt_inout_detached(n, associated_data, buffer) } - fn decrypt_in_place_detached( + fn decrypt_inout_detached( &self, nonce: &Nonce, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, tag: &Tag, ) -> Result<(), Error> { if buffer.len() as u64 > C_MAX || associated_data.len() as u64 > A_MAX { @@ -157,7 +156,7 @@ impl AeadInPlaceDetached for Xaes256Gcm { let (n1, n) = nonce.split_ref::<>::Output>(); let k = self.derive_key(n1); - Aes256Gcm::new(&k).decrypt_in_place_detached(n, associated_data, buffer, tag) + Aes256Gcm::new(&k).decrypt_inout_detached(n, associated_data, buffer, tag) } } diff --git a/xaes-256-gcm/tests/xaes256gcm.rs b/xaes-256-gcm/tests/xaes256gcm.rs index 1bb04ce1..62b85d7e 100644 --- a/xaes-256-gcm/tests/xaes256gcm.rs +++ b/xaes-256-gcm/tests/xaes256gcm.rs @@ -4,7 +4,7 @@ #[path = "../../aes-gcm/tests/common/mod.rs"] mod common; -use aes_gcm::aead::{Aead, AeadInPlaceDetached, KeyInit, Payload, array::Array}; +use aes_gcm::aead::{Aead, AeadInOut, KeyInit, Payload, array::Array}; use common::TestVector; use hex_literal::hex; use xaes_256_gcm::Xaes256Gcm;