Skip to content

Commit

Permalink
ocb3: restrict minimum NonceSize to U6 (#593)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
tarcieri committed Mar 27, 2024
1 parent c0e9ae4 commit d2b664b
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 22 deletions.
3 changes: 2 additions & 1 deletion ocb3/README.md
Expand Up @@ -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]

Expand Down
50 changes: 29 additions & 21 deletions ocb3/src/lib.rs
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -56,11 +59,16 @@ pub type Nonce<NonceSize> = GenericArray<u8, NonceSize>;
pub type Tag<TagSize> = GenericArray<u8, TagSize>;

/// 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: <https://eprint.iacr.org/2023/326.pdf>.
/// - `TagSize`: max of 16-bytes, default and recommended size of 16-bytes.
#[derive(Clone)]
pub struct Ocb3<Cipher, NonceSize = U12, TagSize = U16>
where
NonceSize: ArrayLength<u8> + IsLessOrEqual<U15>,
TagSize: ArrayLength<u8> + IsLessOrEqual<U16>,
NonceSize: ArrayLength<u8> + IsGreaterOrEqual<U6> + IsLessOrEqual<U15>,
TagSize: ArrayLength<u8> + IsGreater<U0> + IsLessOrEqual<U16>,
{
cipher: Cipher,
nonce_size: PhantomData<NonceSize>,
Expand All @@ -79,17 +87,17 @@ type Sum = GenericArray<u8, SumSize>;
impl<Cipher, NonceSize, TagSize> KeySizeUser for Ocb3<Cipher, NonceSize, TagSize>
where
Cipher: KeySizeUser,
TagSize: ArrayLength<u8> + IsLessOrEqual<U16>,
NonceSize: ArrayLength<u8> + IsLessOrEqual<U15>,
TagSize: ArrayLength<u8> + IsGreater<U0> + IsLessOrEqual<U16>,
NonceSize: ArrayLength<u8> + IsGreaterOrEqual<U6> + IsLessOrEqual<U15>,
{
type KeySize = Cipher::KeySize;
}

impl<Cipher, NonceSize, TagSize> KeyInit for Ocb3<Cipher, NonceSize, TagSize>
where
Cipher: BlockSizeUser<BlockSize = U16> + BlockEncrypt + KeyInit + BlockDecrypt,
TagSize: ArrayLength<u8> + IsLessOrEqual<U16>,
NonceSize: ArrayLength<u8> + IsLessOrEqual<U15>,
TagSize: ArrayLength<u8> + IsGreater<U0> + IsLessOrEqual<U16>,
NonceSize: ArrayLength<u8> + IsGreaterOrEqual<U6> + IsLessOrEqual<U15>,
{
fn new(key: &aead::Key<Self>) -> Self {
Cipher::new(key).into()
Expand All @@ -98,8 +106,8 @@ where

impl<Cipher, NonceSize, TagSize> AeadCore for Ocb3<Cipher, NonceSize, TagSize>
where
NonceSize: ArrayLength<u8> + IsLessOrEqual<U15>,
TagSize: ArrayLength<u8> + IsLessOrEqual<U16>,
NonceSize: ArrayLength<u8> + IsGreaterOrEqual<U6> + IsLessOrEqual<U15>,
TagSize: ArrayLength<u8> + IsGreater<U0> + IsLessOrEqual<U16>,
{
type NonceSize = NonceSize;
type TagSize = TagSize;
Expand All @@ -109,8 +117,8 @@ where
impl<Cipher, NonceSize, TagSize> From<Cipher> for Ocb3<Cipher, NonceSize, TagSize>
where
Cipher: BlockSizeUser<BlockSize = U16> + BlockEncrypt + BlockDecrypt,
TagSize: ArrayLength<u8> + IsLessOrEqual<U16>,
NonceSize: ArrayLength<u8> + IsLessOrEqual<U15>,
TagSize: ArrayLength<u8> + IsGreater<U0> + IsLessOrEqual<U16>,
NonceSize: ArrayLength<u8> + IsGreaterOrEqual<U6> + IsLessOrEqual<U15>,
{
fn from(cipher: Cipher) -> Self {
let (ll_star, ll_dollar, ll) = key_dependent_variables(&cipher);
Expand Down Expand Up @@ -149,8 +157,8 @@ fn key_dependent_variables<Cipher: BlockSizeUser<BlockSize = U16> + BlockEncrypt
impl<Cipher, NonceSize, TagSize> AeadInPlace for Ocb3<Cipher, NonceSize, TagSize>
where
Cipher: BlockSizeUser<BlockSize = U16> + BlockEncrypt + BlockDecrypt,
TagSize: ArrayLength<u8> + IsLessOrEqual<U16>,
NonceSize: ArrayLength<u8> + IsLessOrEqual<U15>,
TagSize: ArrayLength<u8> + IsGreater<U0> + IsLessOrEqual<U16>,
NonceSize: ArrayLength<u8> + IsGreaterOrEqual<U6> + IsLessOrEqual<U15>,
{
fn encrypt_in_place_detached(
&self,
Expand Down Expand Up @@ -231,8 +239,8 @@ where
impl<Cipher, NonceSize, TagSize> Ocb3<Cipher, NonceSize, TagSize>
where
Cipher: BlockSizeUser<BlockSize = U16> + BlockEncrypt + BlockDecrypt,
TagSize: ArrayLength<u8> + IsLessOrEqual<U16>,
NonceSize: ArrayLength<u8> + IsLessOrEqual<U15>,
TagSize: ArrayLength<u8> + IsGreater<U0> + IsLessOrEqual<U16>,
NonceSize: ArrayLength<u8> + IsGreaterOrEqual<U6> + IsLessOrEqual<U15>,
{
/// Decrypts in place and returns expected tag.
pub(crate) fn decrypt_in_place_return_tag(
Expand Down Expand Up @@ -381,7 +389,7 @@ where
/// in https://www.rfc-editor.org/rfc/rfc7253.html#section-4.2
fn nonce_dependent_variables<
Cipher: BlockSizeUser<BlockSize = U16> + BlockEncrypt,
NonceSize: ArrayLength<u8> + IsLessOrEqual<U15>,
NonceSize: ArrayLength<u8> + IsGreaterOrEqual<U6> + IsLessOrEqual<U15>,
>(
cipher: &Cipher,
nn: &Nonce<NonceSize>,
Expand Down Expand Up @@ -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<BlockSize = U16> + BlockEncrypt,
NonceSize: ArrayLength<u8> + IsLessOrEqual<U15>,
NonceSize: ArrayLength<u8> + IsGreaterOrEqual<U6> + IsLessOrEqual<U15>,
>(
cipher: &Cipher,
nn: &Nonce<NonceSize>,
Expand All @@ -439,8 +447,8 @@ fn initial_offset<
impl<Cipher, NonceSize, TagSize> Ocb3<Cipher, NonceSize, TagSize>
where
Cipher: BlockSizeUser<BlockSize = U16> + BlockEncrypt,
TagSize: ArrayLength<u8> + IsLessOrEqual<U16>,
NonceSize: ArrayLength<u8> + IsLessOrEqual<U15>,
TagSize: ArrayLength<u8> + IsGreater<U0> + IsLessOrEqual<U16>,
NonceSize: ArrayLength<u8> + IsGreaterOrEqual<U6> + IsLessOrEqual<U15>,
{
/// Computes HASH function defined in https://www.rfc-editor.org/rfc/rfc7253.html#section-4.1
fn hash(&self, associated_data: &[u8]) -> Sum {
Expand Down

0 comments on commit d2b664b

Please sign in to comment.