Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ocb3: restrict minimum NonceSize to U6 #593

Merged
merged 1 commit into from
Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion ocb3/README.md
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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>,
Copy link
Member

@newpavlov newpavlov Mar 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you also need to add bounds like GrEq<NonceSize, U6>: NonZero,, otherwise it will have no effect. Same with IslessOrEqual. IIRC the current bounds only state that you can compare against the number and nothing about comparison result.

Plus it's worth to add compilation failure tests for unsupported sizes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's an example case where that bound is required?

Copy link
Member

@newpavlov newpavlov Mar 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC with the current bound you still can use U5 for NonceSize, same for U16.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be worth to add sealed TagSizes/NonceSizes traits to simplify public bounds.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can prepare a quick PR to amend this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We had those before although removed them in #590, though the requirements have gotten more complex since then. Still, it's a bounded range, and if we can express it properly with typenum it will be easier to eventually move to const generics.

{
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