From d2b664b66e79c6922f85d1aece10c7585026a6ca Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Wed, 27 Mar 2024 07:41:56 -0600 Subject: [PATCH] ocb3: restrict minimum `NonceSize` to `U6` (#593) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on the recommendations of the following paper, which describes an attack against OCB3 mode: https://eprint.iacr.org/2023/326.pdf > In the case of OCB3, it is easy to fix the algorithm’s specification > in order to avoid the weakness and abide to the full assumptions of > the security proof. If the description is unchanged, the requirement > N ≥ 6 must become an absolute requirement. Furthermore, this restricts the minimum tag size to 1-byte, up from the former 0-bytes. This is a questionable choice of minimum but reflects the wording in the RFC: > The TAGLEN parameter specifies the length of authentication tag used > by OCB and may be any value up to 128 --- ocb3/README.md | 3 ++- ocb3/src/lib.rs | 50 ++++++++++++++++++++++++++++--------------------- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/ocb3/README.md b/ocb3/README.md index a7c94016..ea905899 100644 --- a/ocb3/README.md +++ b/ocb3/README.md @@ -7,7 +7,8 @@ [![Project Chat][chat-image]][chat-link] [![Build Status][build-image]][build-link] -Pure Rust implementation of **OCB3** ([RFC 7253][rfc7253])[Authenticated Encryption with Associated Data (AEAD)][aead] cipher. +Pure Rust implementation of the Offset Codebook Mode v3 (OCB3) +[Authenticated Encryption with Associated Data (AEAD)][aead] cipher as described in [RFC7253]. [Documentation][docs-link] diff --git a/ocb3/src/lib.rs b/ocb3/src/lib.rs index 56f6889e..07bbd056 100644 --- a/ocb3/src/lib.rs +++ b/ocb3/src/lib.rs @@ -10,7 +10,7 @@ /// Constants used, reexported for convenience. pub mod consts { - pub use cipher::consts::{U0, U12, U15, U16}; + pub use cipher::consts::{U0, U12, U15, U16, U6}; } mod util; @@ -20,9 +20,12 @@ pub use aead::{ }; use crate::util::{double, inplace_xor, ntz, Block}; -use aead::generic_array::{typenum::IsLessOrEqual, ArrayLength}; +use aead::generic_array::{ + typenum::{IsGreater, IsGreaterOrEqual, IsLessOrEqual}, + ArrayLength, +}; use cipher::{ - consts::{U0, U12, U15, U16}, + consts::{U0, U12, U15, U16, U6}, BlockDecrypt, BlockEncrypt, BlockSizeUser, }; use core::marker::PhantomData; @@ -56,11 +59,16 @@ pub type Nonce = GenericArray; pub type Tag = GenericArray; /// OCB3: generic over a block cipher implementation, nonce size, and tag size. +/// +/// - `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. #[derive(Clone)] pub struct Ocb3 where - NonceSize: ArrayLength + IsLessOrEqual, - TagSize: ArrayLength + IsLessOrEqual, + NonceSize: ArrayLength + IsGreaterOrEqual + IsLessOrEqual, + TagSize: ArrayLength + IsGreater + IsLessOrEqual, { cipher: Cipher, nonce_size: PhantomData, @@ -79,8 +87,8 @@ type Sum = GenericArray; impl KeySizeUser for Ocb3 where Cipher: KeySizeUser, - TagSize: ArrayLength + IsLessOrEqual, - NonceSize: ArrayLength + IsLessOrEqual, + TagSize: ArrayLength + IsGreater + IsLessOrEqual, + NonceSize: ArrayLength + IsGreaterOrEqual + IsLessOrEqual, { type KeySize = Cipher::KeySize; } @@ -88,8 +96,8 @@ where impl KeyInit for Ocb3 where Cipher: BlockSizeUser + BlockEncrypt + KeyInit + BlockDecrypt, - TagSize: ArrayLength + IsLessOrEqual, - NonceSize: ArrayLength + IsLessOrEqual, + TagSize: ArrayLength + IsGreater + IsLessOrEqual, + NonceSize: ArrayLength + IsGreaterOrEqual + IsLessOrEqual, { fn new(key: &aead::Key) -> Self { Cipher::new(key).into() @@ -98,8 +106,8 @@ where impl AeadCore for Ocb3 where - NonceSize: ArrayLength + IsLessOrEqual, - TagSize: ArrayLength + IsLessOrEqual, + NonceSize: ArrayLength + IsGreaterOrEqual + IsLessOrEqual, + TagSize: ArrayLength + IsGreater + IsLessOrEqual, { type NonceSize = NonceSize; type TagSize = TagSize; @@ -109,8 +117,8 @@ where impl From for Ocb3 where Cipher: BlockSizeUser + BlockEncrypt + BlockDecrypt, - TagSize: ArrayLength + IsLessOrEqual, - NonceSize: ArrayLength + IsLessOrEqual, + TagSize: ArrayLength + IsGreater + IsLessOrEqual, + NonceSize: ArrayLength + IsGreaterOrEqual + IsLessOrEqual, { fn from(cipher: Cipher) -> Self { let (ll_star, ll_dollar, ll) = key_dependent_variables(&cipher); @@ -149,8 +157,8 @@ fn key_dependent_variables + BlockEncrypt impl AeadInPlace for Ocb3 where Cipher: BlockSizeUser + BlockEncrypt + BlockDecrypt, - TagSize: ArrayLength + IsLessOrEqual, - NonceSize: ArrayLength + IsLessOrEqual, + TagSize: ArrayLength + IsGreater + IsLessOrEqual, + NonceSize: ArrayLength + IsGreaterOrEqual + IsLessOrEqual, { fn encrypt_in_place_detached( &self, @@ -231,8 +239,8 @@ where impl Ocb3 where Cipher: BlockSizeUser + BlockEncrypt + BlockDecrypt, - TagSize: ArrayLength + IsLessOrEqual, - NonceSize: ArrayLength + IsLessOrEqual, + TagSize: ArrayLength + IsGreater + IsLessOrEqual, + NonceSize: ArrayLength + IsGreaterOrEqual + IsLessOrEqual, { /// Decrypts in place and returns expected tag. pub(crate) fn decrypt_in_place_return_tag( @@ -381,7 +389,7 @@ where /// in https://www.rfc-editor.org/rfc/rfc7253.html#section-4.2 fn nonce_dependent_variables< Cipher: BlockSizeUser + BlockEncrypt, - NonceSize: ArrayLength + IsLessOrEqual, + NonceSize: ArrayLength + IsGreaterOrEqual + IsLessOrEqual, >( cipher: &Cipher, nn: &Nonce, @@ -420,7 +428,7 @@ fn nonce_dependent_variables< /// in https://www.rfc-editor.org/rfc/rfc7253.html#section-4.2 fn initial_offset< Cipher: BlockSizeUser + BlockEncrypt, - NonceSize: ArrayLength + IsLessOrEqual, + NonceSize: ArrayLength + IsGreaterOrEqual + IsLessOrEqual, >( cipher: &Cipher, nn: &Nonce, @@ -439,8 +447,8 @@ fn initial_offset< impl Ocb3 where Cipher: BlockSizeUser + BlockEncrypt, - TagSize: ArrayLength + IsLessOrEqual, - NonceSize: ArrayLength + IsLessOrEqual, + TagSize: ArrayLength + IsGreater + IsLessOrEqual, + NonceSize: ArrayLength + IsGreaterOrEqual + IsLessOrEqual, { /// Computes HASH function defined in https://www.rfc-editor.org/rfc/rfc7253.html#section-4.1 fn hash(&self, associated_data: &[u8]) -> Sum {