diff --git a/Cargo.lock b/Cargo.lock index 4b45a1b9..c9e6333b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -336,6 +336,7 @@ dependencies = [ "aes", "cipher", "ctr", + "dbl", "hex-literal", "subtle", "zeroize", diff --git a/ocb3/Cargo.toml b/ocb3/Cargo.toml index c5948184..124477d0 100644 --- a/ocb3/Cargo.toml +++ b/ocb3/Cargo.toml @@ -19,6 +19,7 @@ rust-version = "1.72" aead = { version = "=0.6.0-pre.0", default-features = false } cipher = "=0.5.0-pre.4" ctr = "=0.10.0-pre" +dbl = "=0.4.0-pre.4" subtle = { version = "2", default-features = false } zeroize = { version = "1", optional = true, default-features = false } diff --git a/ocb3/src/lib.rs b/ocb3/src/lib.rs index cfa17a01..a61775e4 100644 --- a/ocb3/src/lib.rs +++ b/ocb3/src/lib.rs @@ -13,20 +13,19 @@ pub mod consts { pub use cipher::consts::{U0, U12, U15, U16, U6}; } -mod util; - pub use aead::{ self, array::{Array, AssocArraySize}, AeadCore, AeadInPlace, Error, KeyInit, KeySizeUser, }; -use crate::util::{double, inplace_xor, ntz, Block}; +use aead::array::ArraySize; use cipher::{ consts::{U0, U12, U16}, BlockCipherDecrypt, BlockCipherEncrypt, BlockSizeUser, Unsigned, }; use core::marker::PhantomData; +use dbl::Dbl; use subtle::ConstantTimeEq; /// Number of L values to be precomputed. Precomputing m values, allows @@ -56,6 +55,8 @@ pub type Nonce = Array; /// OCB3 tag pub type Tag = Array; +pub(crate) type Block = Array; + mod sealed { use aead::array::{ typenum::{GrEq, IsGreaterOrEqual, IsLessOrEqual, LeEq, NonZero, U15, U16, U6}, @@ -202,13 +203,13 @@ fn key_dependent_variables + BlockCipherE let mut zeros = [0u8; 16]; let ll_star = Block::from_mut_slice(&mut zeros); cipher.encrypt_block(ll_star); - let ll_dollar = double(ll_star); + let ll_dollar = ll_star.dbl(); let mut ll = [Block::default(); L_TABLE_SIZE]; let mut ll_i = ll_dollar; #[allow(clippy::needless_range_loop)] for i in 0..L_TABLE_SIZE { - ll_i = double(&ll_i); + ll_i = ll_i.dbl(); ll[i] = ll_i } (*ll_star, ll_dollar, ll) @@ -366,7 +367,6 @@ where /// Adapted from https://www.cs.ucdavis.edu/~rogaway/ocb/news/code/ocb.c fn wide_encrypt(&self, nonce: &Nonce, buffer: &mut [u8]) -> (usize, Block, Block) { const WIDTH: usize = 2; - let split_into_blocks = crate::util::split_into_two_blocks; let mut i = 1; @@ -374,7 +374,7 @@ where offset_i[offset_i.len() - 1] = initial_offset(&self.cipher, nonce, TagSize::to_u32()); let mut checksum_i = Block::default(); for wide_blocks in buffer.chunks_exact_mut(::Size::USIZE * WIDTH) { - let p_i = split_into_blocks(wide_blocks); + let p_i = split_into_two_blocks(wide_blocks); // checksum_i = checksum_{i-1} xor p_i for p_ij in &p_i { @@ -409,7 +409,6 @@ where /// Adapted from https://www.cs.ucdavis.edu/~rogaway/ocb/news/code/ocb.c fn wide_decrypt(&self, nonce: &Nonce, buffer: &mut [u8]) -> (usize, Block, Block) { const WIDTH: usize = 2; - let split_into_blocks = crate::util::split_into_two_blocks; let mut i = 1; @@ -417,7 +416,7 @@ where offset_i[offset_i.len() - 1] = initial_offset(&self.cipher, nonce, TagSize::to_u32()); let mut checksum_i = Block::default(); for wide_blocks in buffer.chunks_exact_mut(16 * WIDTH) { - let c_i = split_into_blocks(wide_blocks); + let c_i = split_into_two_blocks(wide_blocks); // offset_i = offset_{i-1} xor L_{ntz(i)} offset_i[0] = offset_i[offset_i.len() - 1]; @@ -504,6 +503,33 @@ fn initial_offset< offset.to_be_bytes().into() } +#[inline] +pub(crate) fn inplace_xor(a: &mut Array, b: &Array) +where + U: ArraySize, + T: core::ops::BitXor + Copy, +{ + for (aa, bb) in a.as_mut_slice().iter_mut().zip(b.as_slice()) { + *aa = *aa ^ *bb; + } +} + +/// Counts the number of non-trailing zeros in the binary representation. +/// +/// Defined in https://www.rfc-editor.org/rfc/rfc7253.html#section-2 +#[inline] +pub(crate) fn ntz(n: usize) -> usize { + n.trailing_zeros().try_into().unwrap() +} + +#[inline] +pub(crate) fn split_into_two_blocks(two_blocks: &mut [u8]) -> [&mut Block; 2] { + const BLOCK_SIZE: usize = 16; + debug_assert_eq!(two_blocks.len(), BLOCK_SIZE * 2); + let (b0, b1) = two_blocks.split_at_mut(BLOCK_SIZE); + [b0.try_into().unwrap(), b1.try_into().unwrap()] +} + impl Ocb3 where Cipher: BlockSizeUser + BlockCipherEncrypt, @@ -570,15 +596,16 @@ where #[cfg(test)] mod tests { use super::*; + use dbl::Dbl; use hex_literal::hex; #[test] fn double_basic_test() { let zero = Block::from(hex!("00000000000000000000000000000000")); - assert_eq!(zero, double(&zero)); + assert_eq!(zero, zero.dbl()); let one = Block::from(hex!("00000000000000000000000000000001")); let two = Block::from(hex!("00000000000000000000000000000002")); - assert_eq!(two, double(&one)); + assert_eq!(two, one.dbl()); } #[test] diff --git a/ocb3/src/util.rs b/ocb3/src/util.rs deleted file mode 100644 index e90a6d05..00000000 --- a/ocb3/src/util.rs +++ /dev/null @@ -1,48 +0,0 @@ -use aead::{ - array::{Array, ArraySize}, - consts::U16, -}; - -const BLOCK_SIZE: usize = 16; -pub(crate) type Block = Array; - -#[inline] -pub(crate) fn inplace_xor(a: &mut Array, b: &Array) -where - U: ArraySize, - T: core::ops::BitXor + Copy, -{ - for (aa, bb) in a.as_mut_slice().iter_mut().zip(b.as_slice()) { - *aa = *aa ^ *bb; - } -} - -/// Doubles a block, in GF(2^128). -/// -/// Adapted from https://github.com/RustCrypto/universal-hashes/blob/9b0ac5d1/polyval/src/mulx.rs#L5-L18 -#[inline] -pub(crate) fn double(block: &Block) -> Block { - let mut v = u128::from_be_bytes((*block).into()); - let v_hi = v >> 127; - - // If v_hi = 0, return (v << 1) - // If v_hi = 1, return (v << 1) xor (0b0...010000111) - v <<= 1; - v ^= v_hi ^ (v_hi << 1) ^ (v_hi << 2) ^ (v_hi << 7); - v.to_be_bytes().into() -} - -/// Counts the number of non-trailing zeros in the binary representation. -/// -/// Defined in https://www.rfc-editor.org/rfc/rfc7253.html#section-2 -#[inline] -pub(crate) fn ntz(n: usize) -> usize { - n.trailing_zeros().try_into().unwrap() -} - -#[inline] -pub(crate) fn split_into_two_blocks(two_blocks: &mut [u8]) -> [&mut Block; 2] { - debug_assert_eq!(two_blocks.len(), BLOCK_SIZE * 2); - let (b0, b1) = two_blocks.split_at_mut(BLOCK_SIZE); - [b0.try_into().unwrap(), b1.try_into().unwrap()] -}