From 01fcf4cd2f4b9d657dfdf493e7c8a137d3975360 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Wed, 27 Mar 2024 17:20:25 +0300 Subject: [PATCH] ocb3: fix nonce and tag size bounds (#595) --- ocb3/README.md | 1 - ocb3/src/lib.rs | 78 ++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 68 insertions(+), 11 deletions(-) diff --git a/ocb3/README.md b/ocb3/README.md index ea905899..ea0fdd8d 100644 --- a/ocb3/README.md +++ b/ocb3/README.md @@ -33,7 +33,6 @@ let plaintext = cipher.decrypt(&nonce, ciphertext.as_ref()).unwrap(); assert_eq!(&plaintext, b"plaintext message"); ``` - ## Security Notes No security audits of this crate have ever been performed, and it has not been thoroughly assessed to ensure its operation is constant-time on common CPU architectures. diff --git a/ocb3/src/lib.rs b/ocb3/src/lib.rs index 07bbd056..ed141f36 100644 --- a/ocb3/src/lib.rs +++ b/ocb3/src/lib.rs @@ -21,7 +21,7 @@ pub use aead::{ use crate::util::{double, inplace_xor, ntz, Block}; use aead::generic_array::{ - typenum::{IsGreater, IsGreaterOrEqual, IsLessOrEqual}, + typenum::{GrEq, IsGreaterOrEqual, IsLessOrEqual, LeEq, NonZero}, ArrayLength, }; use cipher::{ @@ -63,12 +63,49 @@ pub type Tag = GenericArray; /// - `NonceSize`: max of 15-bytes, default and recommended size of 12-bytes (96-bits). /// We further restrict the minimum nonce size to 6-bytes to prevent an attack described in /// the following paper: . -/// - `TagSize`: max of 16-bytes, default and recommended size of 16-bytes. +/// - `TagSize`: non-zero, max of 16-bytes, default and recommended size of 16-bytes. +/// +/// Compilation will fail if the size conditions are not satisfied: +/// +/// ```rust,compile_fail +/// # use aes::Aes128; +/// # use ocb3::{aead::{consts::U5, KeyInit}, Ocb3}; +/// # let key = [42; 16].into(); +/// // Invalid nonce size equal to 5 bytes +/// let cipher = Ocb3::::new(&key); +/// ``` +/// +/// ```rust,compile_fail +/// # use aes::Aes128; +/// # use ocb3::{aead::{consts::U16, KeyInit}, Ocb3}; +/// # let key = [42; 16].into(); +/// // Invalid nonce size equal to 16 bytes +/// let cipher = Ocb3::::new(&key); +/// ``` +/// +/// ```rust,compile_fail +/// # use aes::Aes128; +/// # use ocb3::{aead::{consts::{U12, U0}, KeyInit}, Ocb3}; +/// # let key = [42; 16].into(); +/// // Invalid tag size equal to 0 bytes +/// let cipher = Ocb3::::new(&key); +/// ``` +/// +/// ```rust,compile_fail +/// # use aes::Aes128; +/// # use ocb3::{aead::{consts::{U12, U20}, KeyInit}, Ocb3}; +/// # let key = [42; 16].into(); +/// // Invalid tag size equal to 20 bytes +/// let cipher = Ocb3::::new(&key); +/// ``` #[derive(Clone)] pub struct Ocb3 where NonceSize: ArrayLength + IsGreaterOrEqual + IsLessOrEqual, - TagSize: ArrayLength + IsGreater + IsLessOrEqual, + TagSize: ArrayLength + NonZero + IsLessOrEqual, + GrEq: NonZero, + LeEq: NonZero, + LeEq: NonZero, { cipher: Cipher, nonce_size: PhantomData, @@ -87,8 +124,11 @@ type Sum = GenericArray; impl KeySizeUser for Ocb3 where Cipher: KeySizeUser, - TagSize: ArrayLength + IsGreater + IsLessOrEqual, NonceSize: ArrayLength + IsGreaterOrEqual + IsLessOrEqual, + TagSize: ArrayLength + NonZero + IsLessOrEqual, + GrEq: NonZero, + LeEq: NonZero, + LeEq: NonZero, { type KeySize = Cipher::KeySize; } @@ -96,8 +136,11 @@ where impl KeyInit for Ocb3 where Cipher: BlockSizeUser + BlockEncrypt + KeyInit + BlockDecrypt, - TagSize: ArrayLength + IsGreater + IsLessOrEqual, NonceSize: ArrayLength + IsGreaterOrEqual + IsLessOrEqual, + TagSize: ArrayLength + NonZero + IsLessOrEqual, + GrEq: NonZero, + LeEq: NonZero, + LeEq: NonZero, { fn new(key: &aead::Key) -> Self { Cipher::new(key).into() @@ -107,7 +150,10 @@ where impl AeadCore for Ocb3 where NonceSize: ArrayLength + IsGreaterOrEqual + IsLessOrEqual, - TagSize: ArrayLength + IsGreater + IsLessOrEqual, + TagSize: ArrayLength + NonZero + IsLessOrEqual, + GrEq: NonZero, + LeEq: NonZero, + LeEq: NonZero, { type NonceSize = NonceSize; type TagSize = TagSize; @@ -117,8 +163,11 @@ where impl From for Ocb3 where Cipher: BlockSizeUser + BlockEncrypt + BlockDecrypt, - TagSize: ArrayLength + IsGreater + IsLessOrEqual, NonceSize: ArrayLength + IsGreaterOrEqual + IsLessOrEqual, + TagSize: ArrayLength + NonZero + IsLessOrEqual, + GrEq: NonZero, + LeEq: NonZero, + LeEq: NonZero, { fn from(cipher: Cipher) -> Self { let (ll_star, ll_dollar, ll) = key_dependent_variables(&cipher); @@ -157,8 +206,11 @@ fn key_dependent_variables + BlockEncrypt impl AeadInPlace for Ocb3 where Cipher: BlockSizeUser + BlockEncrypt + BlockDecrypt, - TagSize: ArrayLength + IsGreater + IsLessOrEqual, NonceSize: ArrayLength + IsGreaterOrEqual + IsLessOrEqual, + TagSize: ArrayLength + NonZero + IsLessOrEqual, + GrEq: NonZero, + LeEq: NonZero, + LeEq: NonZero, { fn encrypt_in_place_detached( &self, @@ -239,8 +291,11 @@ where impl Ocb3 where Cipher: BlockSizeUser + BlockEncrypt + BlockDecrypt, - TagSize: ArrayLength + IsGreater + IsLessOrEqual, NonceSize: ArrayLength + IsGreaterOrEqual + IsLessOrEqual, + TagSize: ArrayLength + NonZero + IsLessOrEqual, + GrEq: NonZero, + LeEq: NonZero, + LeEq: NonZero, { /// Decrypts in place and returns expected tag. pub(crate) fn decrypt_in_place_return_tag( @@ -447,8 +502,11 @@ fn initial_offset< impl Ocb3 where Cipher: BlockSizeUser + BlockEncrypt, - TagSize: ArrayLength + IsGreater + IsLessOrEqual, NonceSize: ArrayLength + IsGreaterOrEqual + IsLessOrEqual, + TagSize: ArrayLength + NonZero + IsLessOrEqual, + GrEq: NonZero, + LeEq: NonZero, + LeEq: NonZero, { /// Computes HASH function defined in https://www.rfc-editor.org/rfc/rfc7253.html#section-4.1 fn hash(&self, associated_data: &[u8]) -> Sum {