From 6c3b85004d4fa59637eb7bc3b040d5954228ac03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Mon, 23 Sep 2024 19:34:01 +0300 Subject: [PATCH 1/3] aead: extract STREAM implementation into `aead-stream` --- Cargo.lock | 2 +- aead/Cargo.toml | 1 - aead/src/lib.rs | 1 - aead/src/stream.rs | 236 +-------------------------------------------- 4 files changed, 4 insertions(+), 236 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cebf88f69..b348962b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -496,7 +496,7 @@ dependencies = [ [[package]] name = "elliptic-curve" -version = "0.14.0-rc.0" +version = "0.14.0-rc.1" dependencies = [ "base16ct", "base64ct", diff --git a/aead/Cargo.toml b/aead/Cargo.toml index ab3b5e79d..3c9aa01d7 100644 --- a/aead/Cargo.toml +++ b/aead/Cargo.toml @@ -31,7 +31,6 @@ std = ["alloc", "crypto-common/std"] dev = ["blobby"] getrandom = ["crypto-common/getrandom"] rand_core = ["crypto-common/rand_core"] -stream = [] [package.metadata.docs.rs] all-features = true diff --git a/aead/src/lib.rs b/aead/src/lib.rs index 74ea85353..468b06762 100644 --- a/aead/src/lib.rs +++ b/aead/src/lib.rs @@ -22,7 +22,6 @@ extern crate std; #[cfg(feature = "dev")] pub mod dev; -#[cfg(feature = "stream")] pub mod stream; pub use crypto_common::{ diff --git a/aead/src/stream.rs b/aead/src/stream.rs index 7f735fb2a..c9c1eb0cb 100644 --- a/aead/src/stream.rs +++ b/aead/src/stream.rs @@ -1,43 +1,14 @@ //! Streaming AEAD support. //! -//! Implementation of the STREAM online authenticated encryption construction -//! as described in the paper -//! [Online Authenticated-Encryption and its Nonce-Reuse Misuse-Resistance][1]. +//! See the [`aead-stream`] crate for a generic implementation of the STREAM construction. //! -//! ## About -//! -//! The STREAM construction supports encrypting/decrypting sequences of AEAD -//! message segments, which is useful in cases where the overall message is too -//! large to fit in a single buffer and needs to be processed incrementally. -//! -//! STREAM defends against reordering and truncation attacks which are common -//! in naive schemes which attempt to provide these properties, and is proven -//! to meet the security definition of "nonce-based online authenticated -//! encryption" (nOAE) as given in the aforementioned paper. -//! -//! ## Diagram -//! -//! ![STREAM Diagram](https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/img/AEADs/rogaway-stream.svg) -//! -//! Legend: -//! -//! - 𝐄k: AEAD encryption under key `k` -//! - 𝐌: message -//! - 𝐍: nonce -//! - 𝐀: additional associated data -//! - 𝐂: ciphertext -//! - 𝜏: MAC tag -//! -//! [1]: https://eprint.iacr.org/2015/189.pdf +//! [`aead-stream`]: https://docs.rs/aead-stream #![allow(clippy::upper_case_acronyms)] use crate::{AeadCore, AeadInPlace, Buffer, Error, Key, KeyInit, Result}; use core::ops::{AddAssign, Sub}; -use crypto_common::array::{ - typenum::{Unsigned, U4, U5}, - Array, ArraySize, -}; +use crypto_common::array::{typenum::Unsigned, Array, ArraySize}; #[cfg(feature = "alloc")] use {crate::Payload, alloc::vec::Vec}; @@ -50,22 +21,6 @@ pub type Nonce = Array>; pub type NonceSize = <::NonceSize as Sub<>::NonceOverhead>>::Output; -/// STREAM encryptor instantiated with [`StreamBE32`] as the underlying -/// STREAM primitive. -pub type EncryptorBE32 = Encryptor>; - -/// STREAM decryptor instantiated with [`StreamBE32`] as the underlying -/// STREAM primitive. -pub type DecryptorBE32 = Decryptor>; - -/// STREAM encryptor instantiated with [`StreamLE31`] as the underlying -/// STREAM primitive. -pub type EncryptorLE31 = Encryptor>; - -/// STREAM decryptor instantiated with [`StreamLE31`] as the underlying -/// STREAM primitive. -pub type DecryptorLE31 = Decryptor>; - /// Create a new STREAM from the provided AEAD. pub trait NewStream: StreamPrimitive where @@ -354,188 +309,3 @@ impl_stream_object!( "decrypt", "𝒟 STREAM decryptor" ); - -/// The original "Rogaway-flavored" STREAM as described in the paper -/// [Online Authenticated-Encryption and its Nonce-Reuse Misuse-Resistance][1]. -/// -/// Uses a 32-bit big endian counter and 1-byte "last block" flag stored as -/// the last 5-bytes of the AEAD nonce. -/// -/// [1]: https://eprint.iacr.org/2015/189.pdf -#[derive(Debug)] -pub struct StreamBE32 -where - A: AeadInPlace, - A::NonceSize: Sub, - <::NonceSize as Sub>::Output: ArraySize, -{ - /// Underlying AEAD cipher - aead: A, - - /// Nonce (sans STREAM overhead) - nonce: Nonce, -} - -impl NewStream for StreamBE32 -where - A: AeadInPlace, - A::NonceSize: Sub, - <::NonceSize as Sub>::Output: ArraySize, -{ - fn from_aead(aead: A, nonce: &Nonce) -> Self { - Self { - aead, - nonce: nonce.clone(), - } - } -} - -impl StreamPrimitive for StreamBE32 -where - A: AeadInPlace, - A::NonceSize: Sub, - <::NonceSize as Sub>::Output: ArraySize, -{ - type NonceOverhead = U5; - type Counter = u32; - const COUNTER_INCR: u32 = 1; - const COUNTER_MAX: u32 = u32::MAX; - - fn encrypt_in_place( - &self, - position: u32, - last_block: bool, - associated_data: &[u8], - buffer: &mut dyn Buffer, - ) -> Result<()> { - let nonce = self.aead_nonce(position, last_block); - self.aead.encrypt_in_place(&nonce, associated_data, buffer) - } - - fn decrypt_in_place( - &self, - position: Self::Counter, - last_block: bool, - associated_data: &[u8], - buffer: &mut dyn Buffer, - ) -> Result<()> { - let nonce = self.aead_nonce(position, last_block); - self.aead.decrypt_in_place(&nonce, associated_data, buffer) - } -} - -impl StreamBE32 -where - A: AeadInPlace, - A::NonceSize: Sub, - <::NonceSize as Sub>::Output: ArraySize, -{ - /// Compute the full AEAD nonce including the STREAM counter and last - /// block flag. - fn aead_nonce(&self, position: u32, last_block: bool) -> crate::Nonce { - let mut result = Array::default(); - - // TODO(tarcieri): use `generic_array::sequence::Concat` (or const generics) - let (prefix, tail) = result.split_at_mut(NonceSize::::to_usize()); - prefix.copy_from_slice(&self.nonce); - - let (counter, flag) = tail.split_at_mut(4); - counter.copy_from_slice(&position.to_be_bytes()); - flag[0] = last_block as u8; - - result - } -} - -/// STREAM as instantiated with a 31-bit little endian counter and 1-bit -/// "last block" flag stored as the most significant bit of the counter -/// when interpreted as a 32-bit integer. -/// -/// The 31-bit + 1-bit value is stored as the last 4 bytes of the AEAD nonce. -#[derive(Debug)] -pub struct StreamLE31 -where - A: AeadInPlace, - A::NonceSize: Sub, - <::NonceSize as Sub>::Output: ArraySize, -{ - /// Underlying AEAD cipher - aead: A, - - /// Nonce (sans STREAM overhead) - nonce: Nonce, -} - -impl NewStream for StreamLE31 -where - A: AeadInPlace, - A::NonceSize: Sub, - <::NonceSize as Sub>::Output: ArraySize, -{ - fn from_aead(aead: A, nonce: &Nonce) -> Self { - Self { - aead, - nonce: nonce.clone(), - } - } -} - -impl StreamPrimitive for StreamLE31 -where - A: AeadInPlace, - A::NonceSize: Sub, - <::NonceSize as Sub>::Output: ArraySize, -{ - type NonceOverhead = U4; - type Counter = u32; - const COUNTER_INCR: u32 = 1; - const COUNTER_MAX: u32 = 0xfff_ffff; - - fn encrypt_in_place( - &self, - position: u32, - last_block: bool, - associated_data: &[u8], - buffer: &mut dyn Buffer, - ) -> Result<()> { - let nonce = self.aead_nonce(position, last_block)?; - self.aead.encrypt_in_place(&nonce, associated_data, buffer) - } - - fn decrypt_in_place( - &self, - position: Self::Counter, - last_block: bool, - associated_data: &[u8], - buffer: &mut dyn Buffer, - ) -> Result<()> { - let nonce = self.aead_nonce(position, last_block)?; - self.aead.decrypt_in_place(&nonce, associated_data, buffer) - } -} - -impl StreamLE31 -where - A: AeadInPlace, - A::NonceSize: Sub, - <::NonceSize as Sub>::Output: ArraySize, -{ - /// Compute the full AEAD nonce including the STREAM counter and last - /// block flag. - fn aead_nonce(&self, position: u32, last_block: bool) -> Result> { - if position > Self::COUNTER_MAX { - return Err(Error); - } - - let mut result = Array::default(); - - // TODO(tarcieri): use `generic_array::sequence::Concat` (or const generics) - let (prefix, tail) = result.split_at_mut(NonceSize::::to_usize()); - prefix.copy_from_slice(&self.nonce); - - let position_with_flag = position | ((last_block as u32) << 31); - tail.copy_from_slice(&position_with_flag.to_le_bytes()); - - Ok(result) - } -} From 3a81b6135ebeea4fcf2beecc435c43ad08e41a8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Mon, 23 Sep 2024 19:39:09 +0300 Subject: [PATCH 2/3] Fix warning --- aead/src/stream.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aead/src/stream.rs b/aead/src/stream.rs index c9c1eb0cb..5ee90c5f8 100644 --- a/aead/src/stream.rs +++ b/aead/src/stream.rs @@ -8,10 +8,10 @@ use crate::{AeadCore, AeadInPlace, Buffer, Error, Key, KeyInit, Result}; use core::ops::{AddAssign, Sub}; -use crypto_common::array::{typenum::Unsigned, Array, ArraySize}; +use crypto_common::array::{Array, ArraySize}; #[cfg(feature = "alloc")] -use {crate::Payload, alloc::vec::Vec}; +use {crate::Payload, alloc::vec::Vec, crypto_common::array::typenum::Unsigned}; /// Nonce as used by a given AEAD construction and STREAM primitive. pub type Nonce = Array>; From abdd927c6b52606ff8ba701d8bffa913241a6fff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Mon, 23 Sep 2024 19:42:38 +0300 Subject: [PATCH 3/3] Fix CI config --- .github/workflows/aead.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/aead.yml b/.github/workflows/aead.yml index 462108e7a..11f47906c 100644 --- a/.github/workflows/aead.yml +++ b/.github/workflows/aead.yml @@ -40,7 +40,6 @@ jobs: - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features bytes - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features heapless - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features rand_core - - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features stream # TODO(tarcieri): re-enable after next `crypto-common` release # minimal-versions: