From 784ddf1c676a2987a8ab68bbb8f106b8e3d96fb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Mon, 30 Aug 2021 15:44:22 +0300 Subject: [PATCH 01/63] new crate versions, including cipher v0.4 --- Cargo.lock | 33 +- Cargo.toml | 4 + cipher/Cargo.toml | 11 +- cipher/src/block.rs | 490 +++++++++++++++++++---------- cipher/src/dev/block.rs | 115 ++++--- cipher/src/dev/stream.rs | 16 +- cipher/src/errors.rs | 53 +--- cipher/src/lib.rs | 130 ++------ cipher/src/mode.rs | 42 --- cipher/src/mode_wrapper.rs | 194 ------------ cipher/src/stream.rs | 124 +++++--- cipher/src/stream_core.rs | 64 ++++ cipher/src/stream_wrapper.rs | 116 +++++++ crypto-common/Cargo.toml | 6 +- crypto-common/src/core_api.rs | 25 +- crypto-common/src/init.rs | 182 +++++++++++ crypto-common/src/lib.rs | 36 ++- crypto-mac/Cargo.toml | 5 +- crypto-mac/src/core_api.rs | 8 +- crypto-mac/src/lib.rs | 70 ++++- digest/Cargo.toml | 6 +- digest/src/core_api.rs | 13 +- digest/src/core_api/ct_variable.rs | 13 +- digest/src/core_api/xof_reader.rs | 6 +- digest/src/lib.rs | 10 +- 25 files changed, 1045 insertions(+), 727 deletions(-) delete mode 100644 cipher/src/mode.rs delete mode 100644 cipher/src/mode_wrapper.rs create mode 100644 cipher/src/stream_core.rs create mode 100644 cipher/src/stream_wrapper.rs create mode 100644 crypto-common/src/init.rs diff --git a/Cargo.lock b/Cargo.lock index f2713aac4..1fefce199 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -66,19 +66,18 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.10.0-pre.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4b13c429c0b48d55a541108e23c7795eb821ee65b50c2f719f4f7fc5a022dcf" +version = "0.10.0" +source = "git+https://github.com/RustCrypto/utils?branch=pad_error#6b7199fb78dba025deb1e4f46bdaf10ee812341e" dependencies = [ "block-padding", "generic-array", + "inout", ] [[package]] name = "block-padding" -version = "0.3.0-pre" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3992d179d1dd2fa87869057217d43cf88ad31d4e44738d159a5a6caafdf63ae6" +version = "0.3.0" +source = "git+https://github.com/RustCrypto/utils?branch=pad_error#6b7199fb78dba025deb1e4f46bdaf10ee812341e" dependencies = [ "generic-array", ] @@ -106,13 +105,12 @@ dependencies = [ [[package]] name = "cipher" -version = "0.4.0-pre" +version = "0.4.0" dependencies = [ "blobby", - "block-buffer 0.10.0-pre.4", + "block-buffer 0.10.0", "crypto-common", "generic-array", - "rand_core", ] [[package]] @@ -158,10 +156,11 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.1.0-pre" +version = "0.1.0" dependencies = [ - "block-buffer 0.10.0-pre.4", + "block-buffer 0.10.0", "generic-array", + "rand_core", ] [[package]] @@ -179,7 +178,7 @@ name = "crypto-mac" version = "0.12.0-pre" dependencies = [ "blobby", - "cipher 0.4.0-pre", + "cipher 0.4.0", "crypto-common", "generic-array", "rand_core", @@ -206,7 +205,7 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.0-pre.3" +version = "0.10.0" dependencies = [ "blobby", "crypto-common", @@ -305,6 +304,14 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21e4590e13640f19f249fe3e4eca5113bc4289f2497710378190e7f4bd96f45b" +[[package]] +name = "inout" +version = "0.1.0" +source = "git+https://github.com/RustCrypto/utils?branch=pad_error#6b7199fb78dba025deb1e4f46bdaf10ee812341e" +dependencies = [ + "generic-array", +] + [[package]] name = "itoa" version = "0.4.7" diff --git a/Cargo.toml b/Cargo.toml index ebf9e0985..72bbfd15b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,7 @@ members = [ "signature/async", "universal-hash", ] + +[patch.crates-io] +block-buffer = { git = "https://github.com/RustCrypto/utils", branch = "pad_error" } +inout = { git = "https://github.com/RustCrypto/utils", branch = "pad_error" } diff --git a/cipher/Cargo.toml b/cipher/Cargo.toml index 017e3c028..3fd9135f7 100644 --- a/cipher/Cargo.toml +++ b/cipher/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cipher" description = "Traits for describing block ciphers and stream ciphers" -version = "0.4.0-pre" +version = "0.4.0" authors = ["RustCrypto Developers"] license = "MIT OR Apache-2.0" readme = "README.md" @@ -13,17 +13,14 @@ categories = ["cryptography", "no-std"] [dependencies] generic-array = "0.14" -crypto-common = { version = "=0.1.0-pre", path = "../crypto-common" } +crypto-common = { version = "0.1", path = "../crypto-common" } +block-buffer = { version = "0.10.0", features = ["block-padding", "inout"] } # optional dependencies -block-buffer = { version = "=0.10.0-pre.4", features = ["block-padding"], optional = true } blobby = { version = "0.3", optional = true } -rand_core = { version = "0.6", optional = true } [features] -default = ["mode_wrapper"] -std = ["crypto-common/std", "rand_core/std"] -mode_wrapper = ["block-buffer"] +std = ["crypto-common/std"] dev = ["blobby"] [package.metadata.docs.rs] diff --git a/cipher/src/block.rs b/cipher/src/block.rs index 1769c782e..8ab24c605 100644 --- a/cipher/src/block.rs +++ b/cipher/src/block.rs @@ -10,228 +10,398 @@ //! [2]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation //! [3]: https://en.wikipedia.org/wiki/Symmetric-key_algorithm -use crate::errors::InvalidLength; -use crate::{FromKey, FromKeyNonce}; -use core::convert::TryInto; -use generic_array::{typenum::Unsigned, ArrayLength, GenericArray}; +use block_buffer::inout::{InOut, InOutBuf, InSrc, InTmpOutBuf, NotEqualError}; +use generic_array::typenum::U1; -/// Key for an algorithm that implements [`FromKey`]. -pub type BlockCipherKey = GenericArray::KeySize>; +pub use crypto_common::{Block, BlockUser}; -/// Block on which a [`BlockCipher`] operates. -pub type Block = GenericArray::BlockSize>; - -/// Block on which a [`BlockCipher`] operates in parallel. -pub type ParBlocks = GenericArray, ::ParBlocks>; - -/// Trait which marks a type as being a block cipher. -pub trait BlockCipher { - /// Size of the block in bytes - type BlockSize: ArrayLength; - - /// Number of blocks which can be processed in parallel by - /// cipher implementation - type ParBlocks: ArrayLength>; -} +/// Marker trait for block ciphers. +pub trait BlockCipher: BlockUser {} /// Encrypt-only functionality for block ciphers. -pub trait BlockEncrypt: BlockCipher { - /// Encrypt block in-place - fn encrypt_block(&self, block: &mut Block); +pub trait BlockEncrypt: BlockUser { + /// Encrypt single `inout` block. + fn encrypt_block_inout(&self, block: InOut<'_, Block>); + + /// Encrypt `inout` blocks with given pre and post hooks. + fn encrypt_blocks_with_pre( + &self, + blocks: InOutBuf<'_, Block>, + pre_fn: impl FnMut(InTmpOutBuf<'_, Block>) -> InSrc, + post_fn: impl FnMut(InTmpOutBuf<'_, Block>), + ) { + blocks.process_chunks::( + self, + pre_fn, + post_fn, + |state, mut chunk| state.encrypt_block_inout(chunk.get(0)), + |state, mut chunk| state.encrypt_block_inout(chunk.get(0)), + ) + } - /// Encrypt several blocks in parallel using instruction level parallelism - /// if possible. - /// - /// If `ParBlocks` equals to 1 it's equivalent to `encrypt_block`. + /// Encrypt single block in-place. #[inline] - fn encrypt_par_blocks(&self, blocks: &mut ParBlocks) { - for block in blocks.iter_mut() { - self.encrypt_block(block); - } + fn encrypt_block(&self, block: &mut Block) { + self.encrypt_block_inout(block.into()) } - /// Encrypt a slice of blocks, leveraging parallelism when available. + /// Encrypt single block block-to-block, i.e. encrypt + /// block from `in_block` and write result to `out_block`. #[inline] - fn encrypt_blocks(&self, mut blocks: &mut [Block]) { - let pb = Self::ParBlocks::to_usize(); - - if pb > 1 { - let mut iter = blocks.chunks_exact_mut(pb); + fn encrypt_block_b2b(&self, in_block: &Block, out_block: &mut Block) { + self.encrypt_block_inout((in_block, out_block).into()) + } - for chunk in &mut iter { - self.encrypt_par_blocks(chunk.try_into().unwrap()) - } + /// Encrypt `inout` blocks with given post hook. + fn encrypt_blocks_inout( + &self, + blocks: InOutBuf<'_, Block>, + post_fn: impl FnMut(InTmpOutBuf<'_, Block>), + ) { + self.encrypt_blocks_with_pre(blocks, |_| InSrc::In, post_fn) + } - blocks = iter.into_remainder(); - } + /// Encrypt blocks in-place with given post hook. + fn encrypt_blocks(&self, blocks: &mut [Block], mut post_fn: impl FnMut(&[Block])) { + self.encrypt_blocks_with_pre( + blocks.into(), + |_| InSrc::In, + |mut buf| { + buf.copy_tmp2out(); + post_fn(buf.get_out()); + }, + ) + } - for block in blocks { - self.encrypt_block(block); - } + /// Encrypt blocks buffer-to-buffer with given post hook. + /// + /// Returns [`NotEqualError`] if provided `in_blocks` and `out_blocks` + /// have different lengths. + fn encrypt_blocks_b2b( + &self, + in_blocks: &[Block], + out_blocks: &mut [Block], + mut post_fn: impl FnMut(&[Block]), + ) -> Result<(), NotEqualError> { + self.encrypt_blocks_with_pre( + InOutBuf::new(in_blocks, out_blocks)?, + |_| InSrc::In, + |mut buf| { + buf.copy_tmp2out(); + post_fn(buf.get_out()); + }, + ); + Ok(()) } } /// Decrypt-only functionality for block ciphers. -pub trait BlockDecrypt: BlockCipher { - /// Decrypt block in-place - fn decrypt_block(&self, block: &mut Block); +pub trait BlockDecrypt: BlockUser { + /// Decrypt single `inout` block. + fn decrypt_block_inout(&self, block: InOut<'_, Block>); + + /// Decrypt `inout` blocks with given pre and post hooks. + fn decrypt_blocks_with_pre( + &self, + blocks: InOutBuf<'_, Block>, + pre_fn: impl FnMut(InTmpOutBuf<'_, Block>) -> InSrc, + post_fn: impl FnMut(InTmpOutBuf<'_, Block>), + ) { + blocks.process_chunks::( + self, + pre_fn, + post_fn, + |state, mut chunk| state.decrypt_block_inout(chunk.get(0)), + |state, mut chunk| state.decrypt_block_inout(chunk.get(0)), + ) + } - /// Decrypt several blocks in parallel using instruction level parallelism - /// if possible. - /// - /// If `ParBlocks` equals to 1 it's equivalent to `decrypt_block`. + /// Decrypt single block in-place. #[inline] - fn decrypt_par_blocks(&self, blocks: &mut ParBlocks) { - for block in blocks.iter_mut() { - self.decrypt_block(block); - } + fn decrypt_block(&self, block: &mut Block) { + self.decrypt_block_inout(block.into()) } - /// Decrypt a slice of blocks, leveraging parallelism when available. + /// Decrypt single block block-to-block, i.e. encrypt + /// block from `in_block` and write result to `out_block`. #[inline] - fn decrypt_blocks(&self, mut blocks: &mut [Block]) { - let pb = Self::ParBlocks::to_usize(); - - if pb > 1 { - let mut iter = blocks.chunks_exact_mut(pb); - - for chunk in &mut iter { - self.decrypt_par_blocks(chunk.try_into().unwrap()) - } + fn decrypt_block_b2b(&self, in_block: &Block, out_block: &mut Block) { + self.decrypt_block_inout((in_block, out_block).into()) + } - blocks = iter.into_remainder(); - } + /// Decrypt `inout` blocks with given post hook. + fn decrypt_blocks_inout( + &self, + blocks: InOutBuf<'_, Block>, + post_fn: impl FnMut(InTmpOutBuf<'_, Block>), + ) { + self.decrypt_blocks_with_pre(blocks, |_| InSrc::In, post_fn) + } - for block in blocks { - self.decrypt_block(block); - } + /// Decrypt blocks in-place with given post hook. + fn decrypt_blocks(&self, blocks: &mut [Block], mut post_fn: impl FnMut(&[Block])) { + self.decrypt_blocks_with_pre( + blocks.into(), + |_| InSrc::In, + |mut buf| { + buf.copy_tmp2out(); + post_fn(buf.get_out()); + }, + ) } -} -/// Encrypt-only functionality for block ciphers with mutable access to `self`. -/// -/// The main use case for this trait is hardware encryption engines which -/// require `&mut self` access to an underlying hardware peripheral. -pub trait BlockEncryptMut: BlockCipher { - /// Encrypt block in-place - fn encrypt_block_mut(&mut self, block: &mut Block); + /// Decrypt blocks buffer-to-buffer with given post hook. + /// + /// Returns [`NotEqualError`] if provided `in_blocks` and `out_blocks` + /// have different lengths. + fn decrypt_blocks_b2b( + &self, + in_blocks: &[Block], + out_blocks: &mut [Block], + mut post_fn: impl FnMut(&[Block]), + ) -> Result<(), NotEqualError> { + self.decrypt_blocks_with_pre( + InOutBuf::new(in_blocks, out_blocks)?, + |_| InSrc::In, + |mut buf| { + buf.copy_tmp2out(); + post_fn(buf.get_out()); + }, + ); + Ok(()) + } } -/// Decrypt-only functionality for block ciphers with mutable access to `self`. +/// Encrypt-only functionality for block ciphers and modes with mutable access to `self`. /// -/// The main use case for this trait is hardware encryption engines which -/// require `&mut self` access to an underlying hardware peripheral. -pub trait BlockDecryptMut: BlockCipher { - /// Decrypt block in-place - fn decrypt_block_mut(&mut self, block: &mut Block); -} +/// The main use case for this trait is blocks modes, but it also can be used +/// for hardware cryptographic engines which require `&mut self` access to an +/// underlying hardware peripheral. +pub trait BlockEncryptMut: BlockUser { + /// Encrypt single `inout` block. + fn encrypt_block_inout_mut(&mut self, block: InOut<'_, Block>); + + /// Encrypt `inout` blocks with given pre and post hooks. + fn encrypt_blocks_with_pre_mut( + &mut self, + blocks: InOutBuf<'_, Block>, + pre_fn: impl FnMut(InTmpOutBuf<'_, Block>) -> InSrc, + post_fn: impl FnMut(InTmpOutBuf<'_, Block>), + ) { + blocks.process_chunks::( + self, + pre_fn, + post_fn, + |state, mut chunk| state.encrypt_block_inout_mut(chunk.get(0)), + |state, mut chunk| state.encrypt_block_inout_mut(chunk.get(0)), + ) + } -impl BlockEncryptMut for Alg { + /// Encrypt block in-place. + #[inline] fn encrypt_block_mut(&mut self, block: &mut Block) { - self.encrypt_block(block); + self.encrypt_block_inout_mut(block.into()) } -} -impl BlockDecryptMut for Alg { - fn decrypt_block_mut(&mut self, block: &mut Block) { - self.decrypt_block(block); + /// Encrypt single block block-to-block, i.e. encrypt + /// block from `in_block` and write result to `out_block`. + #[inline] + fn encrypt_block_b2b_mut(&mut self, in_block: &Block, out_block: &mut Block) { + self.encrypt_block_inout_mut((in_block, out_block).into()) } -} -// Impls of block cipher traits for reference types + /// Encrypt `inout` blocks with given post hook. + fn encrypt_blocks_inout_mut( + &mut self, + blocks: InOutBuf<'_, Block>, + post_fn: impl FnMut(InTmpOutBuf<'_, Block>), + ) { + self.encrypt_blocks_with_pre_mut(blocks, |_| InSrc::In, post_fn) + } + + /// Encrypt blocks in-place with given post hook. + fn encrypt_blocks_mut( + &mut self, + blocks: &mut [Block], + mut post_fn: impl FnMut(&[Block]), + ) { + self.encrypt_blocks_with_pre_mut( + blocks.into(), + |_| InSrc::In, + |mut buf| { + buf.copy_tmp2out(); + post_fn(buf.get_out()); + }, + ) + } -impl BlockCipher for &Alg { - type BlockSize = Alg::BlockSize; - type ParBlocks = Alg::ParBlocks; + /// Encrypt blocks buffer-to-buffer with given post hook. + /// + /// Returns [`NotEqualError`] if provided `in_blocks` and `out_blocks` + /// have different lengths. + fn decrypt_blocks_b2b_mut( + &mut self, + in_blocks: &[Block], + out_blocks: &mut [Block], + mut post_fn: impl FnMut(&[Block]), + ) -> Result<(), NotEqualError> { + self.encrypt_blocks_with_pre_mut( + InOutBuf::new(in_blocks, out_blocks)?, + |_| InSrc::In, + |mut buf| { + buf.copy_tmp2out(); + post_fn(buf.get_out()); + }, + ); + Ok(()) + } } -impl BlockEncrypt for &Alg { - #[inline] - fn encrypt_block(&self, block: &mut Block) { - Alg::encrypt_block(self, block); +/// Decrypt-only functionality for block ciphers and modes with mutable access to `self`. +/// +/// The main use case for this trait is blocks modes, but it also can be used +/// for hardware cryptographic engines which require `&mut self` access to an +/// underlying hardware peripheral. +pub trait BlockDecryptMut: BlockUser { + /// Decrypt single `inout` block. + fn decrypt_block_inout_mut(&mut self, block: InOut<'_, Block>); + + /// Decrypt `inout` blocks with given pre and post hooks. + fn decrypt_blocks_with_pre_mut( + &mut self, + blocks: InOutBuf<'_, Block>, + pre_fn: impl FnMut(InTmpOutBuf<'_, Block>) -> InSrc, + post_fn: impl FnMut(InTmpOutBuf<'_, Block>), + ) { + blocks.process_chunks::( + self, + pre_fn, + post_fn, + |state, mut chunk| state.decrypt_block_inout_mut(chunk.get(0)), + |state, mut chunk| state.decrypt_block_inout_mut(chunk.get(0)), + ) } + /// Decrypt single block in-place. #[inline] - fn encrypt_par_blocks(&self, blocks: &mut ParBlocks) { - Alg::encrypt_par_blocks(self, blocks); + fn decrypt_block_mut(&mut self, block: &mut Block) { + self.decrypt_block_inout_mut(block.into()) } + /// Decrypt single block block-to-block, i.e. encrypt + /// block from `in_block` and write result to `out_block`. #[inline] - fn encrypt_blocks(&self, blocks: &mut [Block]) { - Alg::encrypt_blocks(self, blocks); + fn decrypt_block_b2b_mut(&mut self, in_block: &Block, out_block: &mut Block) { + self.decrypt_block_inout_mut((in_block, out_block).into()) } -} -impl BlockDecrypt for &Alg { - #[inline] - fn decrypt_block(&self, block: &mut Block) { - Alg::decrypt_block(self, block); + /// Decrypt `inout` blocks with given post hook. + fn decrypt_blocks_inout_mut( + &mut self, + blocks: InOutBuf<'_, Block>, + post_fn: impl FnMut(InTmpOutBuf<'_, Block>), + ) { + self.decrypt_blocks_with_pre_mut(blocks, |_| InSrc::In, post_fn) } - #[inline] - fn decrypt_par_blocks(&self, blocks: &mut ParBlocks) { - Alg::decrypt_par_blocks(self, blocks); + /// Decrypt blocks in-place with given post hook. + fn decrypt_blocks_mut( + &mut self, + blocks: &mut [Block], + mut post_fn: impl FnMut(&[Block]), + ) { + self.decrypt_blocks_with_pre_mut( + blocks.into(), + |_| InSrc::In, + |mut buf| { + buf.copy_tmp2out(); + post_fn(buf.get_out()); + }, + ) } - #[inline] - fn decrypt_blocks(&self, blocks: &mut [Block]) { - Alg::decrypt_blocks(self, blocks); + /// Decrypt blocks buffer-to-buffer with given post hook. + /// + /// Returns [`NotEqualError`] if provided `in_blocks` and `out_blocks` + /// have different lengths. + fn decrypt_blocks_b2b_mut( + &mut self, + in_blocks: &[Block], + out_blocks: &mut [Block], + mut post_fn: impl FnMut(&[Block]), + ) -> Result<(), NotEqualError> { + self.decrypt_blocks_with_pre_mut( + InOutBuf::new(in_blocks, out_blocks)?, + |_| InSrc::In, + |mut buf| { + buf.copy_tmp2out(); + post_fn(buf.get_out()); + }, + ); + Ok(()) } } -/// Trait for types which can be initialized from a block cipher. -pub trait FromBlockCipher { - /// Block cipher used for initialization. - type BlockCipher: BlockCipher; +impl BlockEncryptMut for Alg { + #[inline] + fn encrypt_block_inout_mut(&mut self, block: InOut<'_, Block>) { + self.encrypt_block_inout(block) + } - /// Initialize instance from block cipher. - fn from_block_cipher(cipher: Self::BlockCipher) -> Self; + fn encrypt_blocks_with_pre_mut( + &mut self, + blocks: InOutBuf<'_, Block>, + pre_fn: impl FnMut(InTmpOutBuf<'_, Block>) -> InSrc, + post_fn: impl FnMut(InTmpOutBuf<'_, Block>), + ) { + self.encrypt_blocks_with_pre(blocks, pre_fn, post_fn) + } } -/// Trait for types which can be initialized from a block cipher and nonce. -pub trait FromBlockCipherNonce { - /// Block cipher used for initialization. - type BlockCipher: BlockCipher; - /// Nonce size in bytes. - type NonceSize: ArrayLength; - - /// Initialize instance from block cipher and nonce. - fn from_block_cipher_nonce( - cipher: Self::BlockCipher, - nonce: &GenericArray, - ) -> Self; +impl BlockDecryptMut for Alg { + #[inline] + fn decrypt_block_inout_mut(&mut self, block: InOut<'_, Block>) { + self.decrypt_block_inout(block) + } + + fn decrypt_blocks_with_pre_mut( + &mut self, + blocks: InOutBuf<'_, Block>, + pre_fn: impl FnMut(InTmpOutBuf<'_, Block>) -> InSrc, + post_fn: impl FnMut(InTmpOutBuf<'_, Block>), + ) { + self.decrypt_blocks_with_pre(blocks, pre_fn, post_fn) + } } -impl FromKeyNonce for T -where - T: FromBlockCipherNonce, - T::BlockCipher: FromKey, -{ - type KeySize = ::KeySize; - type NonceSize = T::NonceSize; +impl BlockEncrypt for &Alg { + #[inline] + fn encrypt_block_inout(&self, block: InOut<'_, Block>) { + Alg::encrypt_block_inout(self, block) + } - fn new( - key: &GenericArray, - nonce: &GenericArray, - ) -> Self { - Self::from_block_cipher_nonce(T::BlockCipher::new(key), nonce) + fn encrypt_blocks_with_pre( + &self, + blocks: InOutBuf<'_, Block>, + pre_fn: impl FnMut(InTmpOutBuf<'_, Block>) -> InSrc, + post_fn: impl FnMut(InTmpOutBuf<'_, Block>), + ) { + Alg::encrypt_blocks_with_pre(self, blocks, pre_fn, post_fn) } } -impl FromKey for T -where - T: FromBlockCipher, - T::BlockCipher: FromKey, -{ - type KeySize = ::KeySize; - - fn new(key: &GenericArray) -> Self { - Self::from_block_cipher(T::BlockCipher::new(key)) +impl BlockDecrypt for &Alg { + #[inline] + fn decrypt_block_inout(&self, block: InOut<'_, Block>) { + Alg::decrypt_block_inout(self, block) } - fn new_from_slice(key: &[u8]) -> Result { - T::BlockCipher::new_from_slice(key) - .map_err(|_| InvalidLength) - .map(Self::from_block_cipher) + fn decrypt_blocks_with_pre( + &self, + blocks: InOutBuf<'_, Block>, + pre_fn: impl FnMut(InTmpOutBuf<'_, Block>) -> InSrc, + post_fn: impl FnMut(InTmpOutBuf<'_, Block>), + ) { + Alg::decrypt_blocks_with_pre(self, blocks, pre_fn, post_fn) } } diff --git a/cipher/src/dev/block.rs b/cipher/src/dev/block.rs index fc53b9435..414748848 100644 --- a/cipher/src/dev/block.rs +++ b/cipher/src/dev/block.rs @@ -11,19 +11,19 @@ macro_rules! block_cipher_test { fn $name() { use cipher::generic_array::{typenum::Unsigned, GenericArray}; use cipher::{ - blobby::Blob3Iterator, BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher, + blobby::Blob3Iterator, BlockDecryptMut, BlockEncryptMut, BlockUser, KeyInit, }; fn run_test(key: &[u8], pt: &[u8], ct: &[u8]) -> bool { - let state = <$cipher as NewBlockCipher>::new_from_slice(key).unwrap(); + let mut state = <$cipher as KeyInit>::new_from_slice(key).unwrap(); let mut block = GenericArray::clone_from_slice(pt); - state.encrypt_block(&mut block); + state.encrypt_block_mut(&mut block); if ct != block.as_slice() { return false; } - state.decrypt_block(&mut block); + state.decrypt_block_mut(&mut block); if pt != block.as_slice() { return false; } @@ -32,15 +32,12 @@ macro_rules! block_cipher_test { } fn run_par_test(key: &[u8], pt: &[u8]) -> bool { - type ParBlocks = <$cipher as BlockCipher>::ParBlocks; - type BlockSize = <$cipher as BlockCipher>::BlockSize; - type Block = GenericArray; - type ParBlock = GenericArray; + type Block = cipher::Block<$cipher>; - let state = <$cipher as NewBlockCipher>::new_from_slice(key).unwrap(); + let mut state = <$cipher as KeyInit>::new_from_slice(key).unwrap(); let block = Block::clone_from_slice(pt); - let mut blocks1 = ParBlock::default(); + let mut blocks1 = vec![block; 101]; for (i, b) in blocks1.iter_mut().enumerate() { *b = block; b[0] = b[0].wrapping_add(i as u8); @@ -49,9 +46,9 @@ macro_rules! block_cipher_test { // check that `encrypt_blocks` and `encrypt_block` // result in the same ciphertext - state.encrypt_blocks(&mut blocks1); + state.encrypt_blocks_mut(&mut blocks1, |_| {}); for b in blocks2.iter_mut() { - state.encrypt_block(b); + state.encrypt_block_mut(b); } if blocks1 != blocks2 { return false; @@ -59,9 +56,9 @@ macro_rules! block_cipher_test { // check that `encrypt_blocks` and `encrypt_block` // result in the same plaintext - state.decrypt_blocks(&mut blocks1); + state.decrypt_blocks_mut(&mut blocks1, |_| {}); for b in blocks2.iter_mut() { - state.decrypt_block(b); + state.decrypt_block_mut(b); } if blocks1 != blocks2 { return false; @@ -70,7 +67,6 @@ macro_rules! block_cipher_test { true } - let pb = <$cipher as BlockCipher>::ParBlocks::to_usize(); let data = include_bytes!(concat!("data/", $test_name, ".blb")); for (i, row) in Blob3Iterator::new(data).unwrap().enumerate() { let [key, pt, ct] = row.unwrap(); @@ -86,58 +82,91 @@ macro_rules! block_cipher_test { } // test parallel blocks encryption/decryption - if pb != 1 { - if !run_par_test(key, pt) { - panic!( - "\n\ - Failed parallel test №{}\n\ - key:\t{:?}\n\ - plaintext:\t{:?}\n\ - ciphertext:\t{:?}\n", - i, key, pt, ct, - ); - } + if !run_par_test(key, pt) { + panic!( + "\n\ + Failed parallel test №{}\n\ + key:\t{:?}\n\ + plaintext:\t{:?}\n\ + ciphertext:\t{:?}\n", + i, key, pt, ct, + ); } } - // test if cipher can be cloned - let key = Default::default(); - let _ = <$cipher as NewBlockCipher>::new(&key).clone(); } }; } -/// Define block cipher benchmark +/// Define block encryptor benchmark #[macro_export] #[cfg_attr(docsrs, doc(cfg(feature = "dev")))] -macro_rules! block_cipher_bench { - ($cipher:path, $key_len:expr) => { - extern crate test; - - use cipher::{BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher}; - use test::Bencher; - +macro_rules! block_encryptor_bench { + ($cipher:path, $block_name:ident, $blocks_name:ident $(,)? ) => { #[bench] - pub fn encrypt(bh: &mut Bencher) { - let state = <$cipher>::new_from_slice(&[1u8; $key_len]).unwrap(); + pub fn $block_name(bh: &mut test::Bencher) { + use cipher::{BlockEncryptMut, KeyInit}; + + let key = Default::default(); + let mut cipher = test::black_box(<$cipher>::new(&key)); let mut block = Default::default(); bh.iter(|| { - state.encrypt_block(&mut block); + cipher.encrypt_block_mut(&mut block); test::black_box(&block); }); bh.bytes = block.len() as u64; } #[bench] - pub fn decrypt(bh: &mut Bencher) { - let state = <$cipher>::new_from_slice(&[1u8; $key_len]).unwrap(); + pub fn $blocks_name(bh: &mut test::Bencher) { + use cipher::{BlockEncryptMut, KeyInit}; + + let key = Default::default(); + let mut cipher = test::black_box(<$cipher>::new(&key)); + let mut blocks = vec![Default::default(); 16 * 1024]; + + bh.iter(|| { + cipher.encrypt_blocks_mut(&mut blocks, |_| {}); + test::black_box(&blocks); + }); + bh.bytes = (blocks.len() * blocks[0].len()) as u64; + } + }; +} + +/// Define block decryptor benchmark +#[macro_export] +#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] +macro_rules! block_decryptor_bench { + ($cipher:path, $block_name:ident, $blocks_name:ident $(,)? ) => { + #[bench] + pub fn $block_name(bh: &mut test::Bencher) { + use cipher::{BlockEncryptMut, KeyInit}; + + let key = Default::default(); + let mut cipher = test::black_box(<$cipher>::new(&key)); let mut block = Default::default(); bh.iter(|| { - state.decrypt_block(&mut block); + cipher.encrypt_block_mut(&mut block); test::black_box(&block); }); bh.bytes = block.len() as u64; } + + #[bench] + pub fn $blocks_name(bh: &mut test::Bencher) { + use cipher::{BlockEncryptMut, KeyInit}; + + let key = Default::default(); + let mut cipher = test::black_box(<$cipher>::new(&key)); + let mut blocks = vec![Default::default(); 16 * 1024]; + + bh.iter(|| { + cipher.encrypt_blocks_mut(&mut blocks, |_| {}); + test::black_box(&blocks); + }); + bh.bytes = (blocks.len() * blocks[0].len()) as u64; + } }; } diff --git a/cipher/src/dev/stream.rs b/cipher/src/dev/stream.rs index 43757ffa1..01526a308 100644 --- a/cipher/src/dev/stream.rs +++ b/cipher/src/dev/stream.rs @@ -8,7 +8,7 @@ macro_rules! stream_cipher_test { #[test] fn $name() { use cipher::generic_array::GenericArray; - use cipher::{blobby::Blob4Iterator, NewCipher, StreamCipher}; + use cipher::{blobby::Blob4Iterator, KeyIvInit, StreamCipher}; let data = include_bytes!(concat!("data/", $test_name, ".blb")); for (i, row) in Blob4Iterator::new(data).unwrap().enumerate() { @@ -18,7 +18,7 @@ macro_rules! stream_cipher_test { let mut mode = <$cipher>::new_from_slices(key, iv).unwrap(); let mut pt = pt.to_vec(); for chunk in pt.chunks_mut(chunk_n) { - mode.apply_keystream(chunk); + mode.apply_keystream_inplace(chunk); } if pt != &ct[..] { panic!( @@ -44,7 +44,7 @@ macro_rules! stream_cipher_seek_test { #[test] fn $name() { use cipher::generic_array::GenericArray; - use cipher::{NewCipher, StreamCipher, StreamCipherSeek}; + use cipher::{KeyIvInit, StreamCipher, StreamCipherSeek}; fn get_cipher() -> $cipher { <$cipher>::new(&Default::default(), &Default::default()) @@ -53,7 +53,7 @@ macro_rules! stream_cipher_seek_test { const MAX_SEEK: usize = 512; let mut ct = [0u8; MAX_SEEK]; - get_cipher().apply_keystream(&mut ct[..]); + get_cipher().apply_keystream_inplace(&mut ct[..]); for n in 0..MAX_SEEK { let mut cipher = get_cipher(); @@ -61,7 +61,7 @@ macro_rules! stream_cipher_seek_test { cipher.seek(n); assert_eq!(cipher.current_pos::(), n); let mut buf = [0u8; MAX_SEEK]; - cipher.apply_keystream(&mut buf[n..]); + cipher.apply_keystream_inplace(&mut buf[n..]); assert_eq!(cipher.current_pos::(), MAX_SEEK); assert_eq!(&buf[n..], &ct[n..]); } @@ -72,12 +72,12 @@ macro_rules! stream_cipher_seek_test { let mut buf = [0u8; MAX_CHUNK]; let mut cipher = get_cipher(); assert_eq!(cipher.current_pos::(), 0); - cipher.apply_keystream(&mut []); + cipher.apply_keystream_inplace(&mut []); assert_eq!(cipher.current_pos::(), 0); for n in 1..MAX_CHUNK { assert_eq!(cipher.current_pos::(), 0); for m in 1.. { - cipher.apply_keystream(&mut buf[..n]); + cipher.apply_keystream_inplace(&mut buf[..n]); assert_eq!(cipher.current_pos::(), n * m); if n * m > MAX_LEN { break; @@ -97,7 +97,7 @@ macro_rules! stream_cipher_async_test { #[test] fn $name() { use cipher::generic_array::GenericArray; - use cipher::{blobby::Blob4Iterator, AsyncStreamCipher, NewCipher}; + use cipher::{blobby::Blob4Iterator, AsyncStreamCipher, KeyIvInit}; fn run_test( key: &[u8], diff --git a/cipher/src/errors.rs b/cipher/src/errors.rs index 644495e80..acd2f488a 100644 --- a/cipher/src/errors.rs +++ b/cipher/src/errors.rs @@ -2,18 +2,23 @@ use core::fmt; -/// The error type returned when stream cipher has reached the end of a keystream. +/// This error is returned by the [`StreamCipher`][crate::stream::StreamCipher] +/// trait methods. +/// +/// Usually it's used in cases when stream cipher has reached the end +/// of a keystream, but also can be used if lengths of provided input +/// and output buffers are not equal. #[derive(Copy, Clone, Debug)] -pub struct LoopError; +pub struct StreamCipherError; -impl fmt::Display for LoopError { +impl fmt::Display for StreamCipherError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { f.write_str("Loop Error") } } #[cfg(feature = "std")] -impl std::error::Error for LoopError {} +impl std::error::Error for StreamCipherError {} /// The error type returned when a cipher position can not be represented /// by the requested type. @@ -26,45 +31,11 @@ impl fmt::Display for OverflowError { } } -impl From for LoopError { - fn from(_: OverflowError) -> LoopError { - LoopError +impl From for StreamCipherError { + fn from(_: OverflowError) -> StreamCipherError { + StreamCipherError } } #[cfg(feature = "std")] impl std::error::Error for OverflowError {} - -/// The error type returned when key and/or nonce used in the [`FromKey`] -/// and [`FromKeyNonce`] slice-based methods had an invalid length. -/// -/// [`FromKey`]: crate::FromKey -/// [`FromKeyNonce`]: crate::FromKeyNonce -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub struct InvalidLength; - -impl fmt::Display for InvalidLength { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - f.write_str("Invalid Length") - } -} - -#[cfg(feature = "std")] -impl std::error::Error for InvalidLength {} - -/// The error type returned by the [`BlockModeEncryptWrapper`] and -/// [`BlockModeDecryptWrapper`] types. -/// -/// [`BlockModeEncryptWrapper`]: crate::BlockModeEncryptWrapper -/// [`BlockModeDecryptWrapper`]: crate::BlockModeDecryptWrapper -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub struct BlockModeError; - -impl fmt::Display for BlockModeError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - f.write_str("Invalid Length") - } -} - -#[cfg(feature = "std")] -impl std::error::Error for BlockModeError {} diff --git a/cipher/src/lib.rs b/cipher/src/lib.rs index 4a9a3ebe1..9ab175c0a 100644 --- a/cipher/src/lib.rs +++ b/cipher/src/lib.rs @@ -1,8 +1,9 @@ //! This crate defines a set of traits which describe the functionality of -//! [block ciphers][1] and [stream ciphers][2]. +//! [block ciphers][1], [block modes][2], and [stream ciphers][3]. //! //! [1]: https://en.wikipedia.org/wiki/Block_cipher -//! [2]: https://en.wikipedia.org/wiki/Stream_cipher +//! [2]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation +//! [3]: https://en.wikipedia.org/wiki/Stream_cipher #![no_std] #![cfg_attr(docsrs, feature(doc_cfg))] @@ -13,127 +14,32 @@ #![forbid(unsafe_code)] #![warn(missing_docs, rust_2018_idioms)] +pub use crypto_common; + #[cfg(feature = "std")] extern crate std; -#[cfg(feature = "rand_core")] -#[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] -pub use rand_core; - #[cfg(feature = "dev")] pub use blobby; +pub use block_buffer::inout; + mod block; #[cfg(feature = "dev")] mod dev; -pub mod errors; -mod mode; +mod errors; mod stream; +mod stream_core; +mod stream_wrapper; -#[cfg(feature = "mode_wrapper")] -mod mode_wrapper; - -pub use crate::{block::*, mode::*, stream::*}; +pub use crate::{block::*, errors::*, stream::*, stream_core::*, stream_wrapper::*}; +pub use crypto_common::{ + Block, InnerIvInit, InvalidLength, Iv, IvUser, Key, KeyInit, KeyIvInit, KeyUser, +}; pub use generic_array::{self, typenum::consts}; -#[cfg(feature = "mode_wrapper")] -pub use mode_wrapper::{BlockModeDecryptWrapper, BlockModeEncryptWrapper}; - -use crate::errors::InvalidLength; -use generic_array::{typenum::Unsigned, ArrayLength, GenericArray}; -#[cfg(feature = "rand_core")] -use rand_core::{CryptoRng, RngCore}; - -// note: ideally the following traits would be defined in the `crypto-common` crate, -// but it would make impossible the generic impls over `T: FromBlockCipher(Nonce)` -// in the `block` module, see the following link for proposal to change it: -// https://internals.rust-lang.org/t/14125 - -/// Trait for types which can be created from key and nonce. -pub trait FromKeyNonce: Sized { - /// Key size in bytes. - type KeySize: ArrayLength; - - /// Nonce size in bytes. - type NonceSize: ArrayLength; - - /// Create new value from fixed length key and nonce. - fn new( - key: &GenericArray, - nonce: &GenericArray, - ) -> Self; - - /// Create new value from variable length key and nonce. - #[inline] - fn new_from_slices(key: &[u8], nonce: &[u8]) -> Result { - let kl = Self::KeySize::to_usize(); - let nl = Self::NonceSize::to_usize(); - if key.len() != kl || nonce.len() != nl { - Err(InvalidLength) - } else { - let key = GenericArray::from_slice(key); - let nonce = GenericArray::from_slice(nonce); - Ok(Self::new(key, nonce)) - } - } - - /// Generate a random key using the provided [`CryptoRng`]. - #[cfg(feature = "rand_core")] - #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] - #[inline] - fn generate_key(mut rng: impl CryptoRng + RngCore) -> GenericArray { - let mut key = GenericArray::::default(); - rng.fill_bytes(&mut key); - key - } - - /// Generate a random nonce using the provided [`CryptoRng`]. - #[cfg(feature = "rand_core")] - #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] - #[inline] - fn generate_nonce(mut rng: impl CryptoRng + RngCore) -> GenericArray { - let mut nonce = GenericArray::::default(); - rng.fill_bytes(&mut nonce); - nonce - } - - /// Generate random key and nonce using the provided [`CryptoRng`]. - #[cfg(feature = "rand_core")] - #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] - #[inline] - fn generate_key_nonce( - mut rng: impl CryptoRng + RngCore, - ) -> ( - GenericArray, - GenericArray, - ) { - (Self::generate_key(&mut rng), Self::generate_nonce(&mut rng)) - } -} - -/// Trait for types which can be created from key. -pub trait FromKey: Sized { - /// Key size in bytes. - type KeySize: ArrayLength; - - /// Create new value from fixed size key. - fn new(key: &GenericArray) -> Self; - - /// Create new value from variable size key. - fn new_from_slice(key: &[u8]) -> Result { - if key.len() != Self::KeySize::to_usize() { - Err(InvalidLength) - } else { - Ok(Self::new(GenericArray::from_slice(key))) - } - } - /// Generate a random key using the provided [`CryptoRng`]. - #[cfg(feature = "rand_core")] - #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] - #[inline] - fn generate_key(mut rng: impl CryptoRng + RngCore) -> GenericArray { - let mut key = GenericArray::::default(); - rng.fill_bytes(&mut key); - key - } +/// Trait for loading current IV state. +pub trait IvState: crypto_common::IvUser { + /// Returns current IV state. + fn iv_state(&self) -> Iv; } diff --git a/cipher/src/mode.rs b/cipher/src/mode.rs deleted file mode 100644 index 336f50cfa..000000000 --- a/cipher/src/mode.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::{BlockCipher, FromKeyNonce}; -use generic_array::{ArrayLength, GenericArray}; - -/// Trait for types which implement a block cipher [mode of operation][1]. -/// -/// [1]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation -pub trait BlockMode { - /// Size of the block in bytes - type BlockSize: ArrayLength; -} - -/// Trait for a block cipher mode of operation block-level encryptor. -/// -/// This trait operates only on blocks, for convinient slice-based methods with padding -/// see the [`BlockModeEncryptWrapper`][crate::BlockModeEncryptWrapper] type. -pub trait BlockModeEncrypt: BlockMode { - /// Encrypt blocks of data. - fn encrypt_blocks(&mut self, blocks: &mut [GenericArray]); -} - -/// Trait for a block cipher mode of operation block-level decryptor. -/// -/// This trait operates only on blocks, for convinient slice-based methods with padding -/// see the [`BlockModeDecryptWrapper`][crate::BlockModeDecryptWrapper] type. -pub trait BlockModeDecrypt: BlockMode { - /// Decrypt blocks of data. - fn decrypt_blocks(&mut self, blocks: &mut [GenericArray]); -} - -/// Trait for a block mode, used to obtain the current state in the form of an IV -/// that can initialize a BlockMode later and resume the original operation. -/// -/// The IV value SHOULD be used for resuming operations only and MUST NOT be -/// exposed to attackers. Failing to comply with this requirement breaks -/// unpredictability and opens attack venues (see e.g. [1], sec. 3.6.2). -/// -/// [1]: https://www.cs.umd.edu/~jkatz/imc.html -pub trait BlockModeIvState: FromKeyNonce { - /// Returns the IV needed to process the following block. This value MUST - /// NOT be exposed to attackers. - fn iv_state(&self) -> GenericArray; -} diff --git a/cipher/src/mode_wrapper.rs b/cipher/src/mode_wrapper.rs deleted file mode 100644 index 36f379c3e..000000000 --- a/cipher/src/mode_wrapper.rs +++ /dev/null @@ -1,194 +0,0 @@ -//! Convinience wrapper around types which implement `BlockMode`. - -use crate::errors::BlockModeError; -use crate::{BlockModeDecrypt, BlockModeEncrypt, FromBlockCipherNonce}; -use block_buffer::{block_padding::Padding, BlockBuffer, LazyBlockBuffer}; -use core::{marker::PhantomData, slice::from_mut}; -use generic_array::{typenum::Unsigned, GenericArray}; - -/// Convinience wrapper around the [`BlockModeEncrypt`] trait, which handles -/// data buffering and provides slice-based methods. -pub struct BlockModeEncryptWrapper> { - inner: M, - buffer: BlockBuffer, - _p: PhantomData

, -} - -impl FromBlockCipherNonce for BlockModeEncryptWrapper -where - M: BlockModeEncrypt + FromBlockCipherNonce, - P: Padding, -{ - type BlockCipher = M::BlockCipher; - type NonceSize = M::NonceSize; - - fn from_block_cipher_nonce( - cipher: Self::BlockCipher, - nonce: &GenericArray, - ) -> Self { - Self { - inner: M::from_block_cipher_nonce(cipher, nonce), - buffer: Default::default(), - _p: Default::default(), - } - } -} - -impl BlockModeEncryptWrapper -where - M: BlockModeEncrypt, - P: Padding, -{ - /// Encrypt part of a plaintext. - /// - /// This mehthod MUST be used in conjuction with the [`encrypt_final`][Self::encrypt_final] method, - /// otherwise plaintext will not be properly padded and may be truncated. - /// - /// The method encrypts plaintext in `data`, writes the resulting plaintext - /// into `out_buf`, and returns it in the `Ok` variant. If a whole message - /// can not be processed, it caches plaintext leftovers into inner buffer - /// for future use. - /// - /// It's recommended for `out_buf` to be at least one block longer than - /// `data`, otherwise the method can return `Err(BlockModeError)` if there is - /// not enough space for encrypted blocks. - #[inline] - pub fn encrypt_part<'a>( - &mut self, - plaintext: &[u8], - out_buf: &'a mut [u8], - ) -> Result<&'a [u8], BlockModeError> { - let Self { inner, buffer, .. } = self; - buffer - .block_mode_processing(plaintext, out_buf, |blocks| inner.encrypt_blocks(blocks)) - .map_err(|_| BlockModeError) - } - - /// Pad and encrypt plaintext. - /// - /// The method pads `plaintext` and encrypts it writing the resulting - /// ciphertext into `out_buf`. - /// - /// It's recommended for `out_buf` to be at least one block longer than - /// `data`, otherwise the method can return `Err(BlockModeError)` if there is - /// not enough space for encrypted blocks. - #[inline] - pub fn encrypt_final<'a>( - mut self, - plaintext: &[u8], - out_buf: &'a mut [u8], - ) -> Result<&'a [u8], BlockModeError> { - let Self { inner, buffer, .. } = &mut self; - let res_len = buffer - .block_mode_processing(plaintext, out_buf, |blocks| inner.encrypt_blocks(blocks)) - .map_err(|_| BlockModeError)? - .len(); - let final_block = buffer.pad_with::

(); - inner.encrypt_blocks(from_mut(final_block)); - - let bs = M::BlockSize::USIZE; - let final_len = res_len.checked_add(bs).ok_or(BlockModeError)?; - let buf = out_buf.get_mut(..final_len).ok_or(BlockModeError)?; - // note: even though `buf[t..]` and `buf[res_len..]` are guaranteed to be - // equivalent, compiler generates a panic branch for the latter. - let t = final_len - bs; - debug_assert_eq!(t, res_len); - buf[t..].copy_from_slice(final_block); - Ok(buf) - } -} - -/// Convinience wrapper around the [`BlockModeDecrypt`] trait, which handles -/// data buffering and provides slice-based methods. -pub struct BlockModeDecryptWrapper> { - inner: M, - buffer: LazyBlockBuffer, - _p: PhantomData

, -} - -impl FromBlockCipherNonce for BlockModeDecryptWrapper -where - M: BlockModeDecrypt + FromBlockCipherNonce, - P: Padding, -{ - type BlockCipher = M::BlockCipher; - type NonceSize = M::NonceSize; - - fn from_block_cipher_nonce( - cipher: Self::BlockCipher, - nonce: &GenericArray, - ) -> Self { - Self { - inner: M::from_block_cipher_nonce(cipher, nonce), - buffer: Default::default(), - _p: Default::default(), - } - } -} - -impl BlockModeDecryptWrapper -where - M: BlockModeDecrypt, - P: Padding, -{ - /// Decrypt part of a ciphertext. - /// - /// This mehthod MUST be used in conjuction with the [`decrypt_final`] method, - /// otherwise plaintext will not be properly padded and may be truncated. - /// - /// The method decrypts `ciphertext`, writes the resulting plaintext - /// into `out_buf`, and returns it in the `Ok` variant. If a whole message - /// can not be processed, it caches ciphertext leftovers into inner buffer - /// for future use. - /// - /// It's recommended for `out_buf` to be at least one block longer than - /// `data`, otherwise the method can return `Err(BlockModeError)` if there is - /// not enough space for encrypted blocks. - /// - /// [`decrypt_final`]: Self::decrypt_final - #[inline] - pub fn decrypt_part<'a>( - &mut self, - ciphertext: &[u8], - out_buf: &'a mut [u8], - ) -> Result<&'a [u8], BlockModeError> { - let Self { inner, buffer, .. } = self; - buffer - .block_mode_processing(ciphertext, out_buf, |blocks| inner.decrypt_blocks(blocks)) - .map_err(|_| BlockModeError) - } - - /// Pad and decrypt plaintext. - /// - /// The method decrypts ciphertext, writes the resulting plaintext into - /// into `out_buf`, and unpads it. - /// - /// It's recommended for `out_buf` to be at least one block longer than - /// `data`, otherwise the method can return `Err(BlockModeError)` if there is - /// not enough space for encrypted blocks. - #[inline] - pub fn decrypt_final<'a>( - mut self, - ciphertext: &[u8], - out_buf: &'a mut [u8], - ) -> Result<&'a [u8], BlockModeError> { - let Self { inner, buffer, .. } = &mut self; - let res_len = buffer - .block_mode_processing(ciphertext, out_buf, |blocks| inner.decrypt_blocks(blocks)) - .map_err(|_| BlockModeError)? - .len(); - let final_block = buffer.get_full_block().ok_or(BlockModeError)?; - inner.decrypt_blocks(from_mut(final_block)); - let tail = P::unpad(final_block).map_err(|_| BlockModeError)?; - - let tail_len = tail.len(); - let final_len = res_len.checked_add(tail_len).ok_or(BlockModeError)?; - let buf = out_buf.get_mut(..final_len).ok_or(BlockModeError)?; - // note: even though `buf[t..]` and `buf[res_len..]` are guaranteed to be - // equivalent, compiler generates a panic branch for the latter. - let t = final_len - tail_len; - debug_assert_eq!(t, res_len); - buf[t..].copy_from_slice(tail); - Ok(buf) - } -} diff --git a/cipher/src/stream.rs b/cipher/src/stream.rs index e33dd15a1..bee396eb1 100644 --- a/cipher/src/stream.rs +++ b/cipher/src/stream.rs @@ -3,48 +3,80 @@ //! See [RustCrypto/stream-ciphers](https://github.com/RustCrypto/stream-ciphers) //! for ciphers implementation. -use crate::errors::{LoopError, OverflowError}; -use core::convert::{TryFrom, TryInto}; +use crate::errors::{OverflowError, StreamCipherError}; +use crate::stream_core::Counter; +use block_buffer::inout::InOutBuf; /// Synchronous stream cipher core trait. pub trait StreamCipher { - /// Apply keystream to the data. + /// Apply keystream to data behind `buf` and return explicit result. /// - /// It will XOR generated keystream with the data, which can be both - /// encryption and decryption. + /// If end of the keystream will be achieved with the given data length, + /// method will return [`StreamCipherError`] without modifying provided `data`. + fn try_apply_keystream(&mut self, buf: InOutBuf<'_, u8>) -> Result<(), StreamCipherError>; + + /// Apply keystream to `inout` data. + /// + /// It will XOR generated keystream with the data behind `in` pointer + /// and will write result to `out` pointer. /// /// # Panics /// If end of the keystream will be reached with the given data length, /// method will panic without modifying the provided `data`. #[inline] - fn apply_keystream(&mut self, data: &mut [u8]) { - self.try_apply_keystream(data).unwrap(); + fn apply_keystream_inout(&mut self, buf: InOutBuf<'_, u8>) { + self.try_apply_keystream(buf).unwrap(); } - /// Apply keystream to the data, but return an error if end of a keystream - /// will be reached. + /// Apply keystream to data in-place. /// - /// If end of the keystream will be achieved with the given data length, - /// method will return `Err(LoopError)` without modifying provided `data`. - fn try_apply_keystream(&mut self, data: &mut [u8]) -> Result<(), LoopError>; + /// It will XOR generated keystream with `data` and will write result + /// to the same buffer. + /// + /// # Panics + /// If end of the keystream will be reached with the given data length, + /// method will panic without modifying the provided `data`. + #[inline] + fn apply_keystream(&mut self, buf: &mut [u8]) { + self.try_apply_keystream(buf.into()).unwrap(); + } + + /// Apply keystream to data buffer-to-buffer. + /// + /// It will XOR generated keystream with data from the `input` buffer + /// and will write result to the `output` buffer. + /// + /// Returns [`StreamCipherError`] if provided `in_blocks` and `out_blocks` + /// have different lengths or if end of the keystream will be reached with + /// the given input data length. + #[inline] + fn apply_keystream_b2b( + &mut self, + input: &[u8], + output: &mut [u8], + ) -> Result<(), StreamCipherError> { + InOutBuf::new(input, output) + .map_err(|_| StreamCipherError) + .and_then(|buf| self.try_apply_keystream(buf)) + } } /// Trait for seekable stream ciphers. /// /// Methods of this trait are generic over the [`SeekNum`] trait, which is -/// implemented for primitive numeric types, i.e.: `i/u8`, `i/u16`, `i/u32`, -/// `i/u64`, `i/u128`, and `i/usize`. +/// implemented for primitive numeric types, i.e.: `i32`, `u32`, `u64`, +/// `u128`, and `usize`. pub trait StreamCipherSeek { /// Try to get current keystream position /// - /// Returns [`LoopError`] if position can not be represented by type `T` + /// Returns [`StreamCipherError`] if position can not be represented by type `T` fn try_current_pos(&self) -> Result; /// Try to seek to the given position /// - /// Returns [`LoopError`] if provided position value is bigger than + /// Returns [`StreamCipherError`] if provided position value is bigger than /// keystream length. - fn try_seek(&mut self, pos: T) -> Result<(), LoopError>; + fn try_seek(&mut self, pos: T) -> Result<(), StreamCipherError>; /// Get current keystream position /// @@ -63,72 +95,74 @@ pub trait StreamCipherSeek { } } -/// Asynchronous stream cipher core trait. +/// Asynchronous stream cipher. pub trait AsyncStreamCipher { /// Encrypt data in place. - fn encrypt(&mut self, data: &mut [u8]); + fn encrypt_inout(&mut self, buf: InOutBuf<'_, u8>); /// Decrypt data in place. - fn decrypt(&mut self, data: &mut [u8]); + fn decrypt_inout(&mut self, buf: InOutBuf<'_, u8>); } impl StreamCipher for &mut C { #[inline] - fn apply_keystream(&mut self, data: &mut [u8]) { - C::apply_keystream(self, data); + fn apply_keystream_inout(&mut self, buf: InOutBuf<'_, u8>) { + C::apply_keystream_inout(self, buf); + } + + #[inline] + fn try_apply_keystream(&mut self, buf: InOutBuf<'_, u8>) -> Result<(), StreamCipherError> { + C::try_apply_keystream(self, buf) + } +} + +impl AsyncStreamCipher for &mut C { + #[inline] + fn encrypt_inout(&mut self, buf: InOutBuf<'_, u8>) { + C::encrypt_inout(self, buf); } #[inline] - fn try_apply_keystream(&mut self, data: &mut [u8]) -> Result<(), LoopError> { - C::try_apply_keystream(self, data) + fn decrypt_inout(&mut self, buf: InOutBuf<'_, u8>) { + C::decrypt_inout(self, buf); } } /// Trait implemented for numeric types which can be used with the /// [`StreamCipherSeek`] trait. /// -/// This trait is implemented for primitive numeric types, i.e. `i/u8`, -/// `u16`, `u32`, `u64`, `u128`, `usize`, and `i32`. It is not intended -/// to be implemented in third-party crates. -#[rustfmt::skip] -pub trait SeekNum: - Sized - + TryInto + TryFrom + TryInto + TryFrom - + TryInto + TryFrom + TryInto + TryFrom - + TryInto + TryFrom + TryInto + TryFrom - + TryInto + TryFrom + TryInto + TryFrom - + TryInto + TryFrom + TryInto + TryFrom - + TryInto + TryFrom + TryInto + TryFrom -{ +/// This trait is implemented for `i32`, `u32`, `u64`, `u128`, and `usize`. +/// It is not intended to be implemented in third-party crates. +pub trait SeekNum: Sized { /// Try to get position for block number `block`, byte position inside /// block `byte`, and block size `bs`. - fn from_block_byte(block: T, byte: u8, bs: u8) -> Result; + fn from_block_byte(block: T, byte: usize, bs: usize) + -> Result; /// Try to get block number and bytes position for given block size `bs`. - #[allow(clippy::wrong_self_convention)] - fn to_block_byte(self, bs: u8) -> Result<(T, u8), OverflowError>; + fn into_block_byte(self, bs: usize) -> Result<(T, usize), OverflowError>; } macro_rules! impl_seek_num { {$($t:ty )*} => { $( impl SeekNum for $t { - fn from_block_byte>(block: T, byte: u8, bs: u8) -> Result { + fn from_block_byte(block: T, byte: usize, bs: usize) -> Result { debug_assert!(byte < bs); - let block = block.try_into().map_err(|_| OverflowError)?; + let block: Self = block.try_into().map_err(|_| OverflowError)?; let pos = block.checked_mul(bs as Self).ok_or(OverflowError)? + (byte as Self); Ok(pos) } - fn to_block_byte>(self, bs: u8) -> Result<(T, u8), OverflowError> { + fn into_block_byte(self, bs: usize) -> Result<(T, usize), OverflowError> { let bs = bs as Self; let byte = self % bs; let block = T::try_from(self/bs).map_err(|_| OverflowError)?; - Ok((block, byte as u8)) + Ok((block, byte as usize)) } } )* }; } -impl_seek_num! { u8 u16 u32 u64 u128 usize i32 } +impl_seek_num! { i32 u32 u64 u128 usize } diff --git a/cipher/src/stream_core.rs b/cipher/src/stream_core.rs new file mode 100644 index 000000000..0a6407896 --- /dev/null +++ b/cipher/src/stream_core.rs @@ -0,0 +1,64 @@ +use crate::{BlockDecryptMut, BlockEncryptMut}; +use block_buffer::inout::InOutBuf; +use core::convert::{TryFrom, TryInto}; +use crypto_common::{Block, BlockUser}; + +/// Marker trait for block-level asynchronous stream ciphers +pub trait AsyncStreamCipherCore: BlockEncryptMut + BlockDecryptMut {} + +/// Block-level synchronous stream ciphers. +pub trait StreamCipherCore: BlockUser { + /// Return number of remaining blocks before cipher wraps around. + /// + /// Returns `None` if number of remaining blocks can not be computed + /// (e.g. in ciphers based on the sponge construction) or it's too big + /// to fit to `usize`. + fn remaining_blocks(&self) -> Option; + + /// Apply keystream blocks with pre and post callbacks using + /// parallel block processing if possible. + fn apply_keystream_blocks( + &mut self, + blocks: InOutBuf<'_, Block>, + pre_fn: impl FnMut(&[Block]), + post_fn: impl FnMut(&[Block]), + ); +} + +// note: unfortunately currently we can not write blanket impls of +// `BlockEncryptMut` and `BlockDecryptMut` for `StreamCipherCore` + +/// Counter type usable with [`StreamCipherCore`]. +pub trait Counter: + TryFrom + + TryFrom + + TryFrom + + TryFrom + + TryFrom + + TryInto + + TryInto + + TryInto + + TryInto + + TryInto +{ +} + +/// Block-level seeking trait for stream ciphers. +pub trait StreamCipherSeekCore: StreamCipherCore { + /// Counter type used inside stream cipher. + type Counter: Counter; + + /// Get current block position. + fn get_block_pos(&self) -> Self::Counter; + + /// Set block position. + fn set_block_pos(&mut self, pos: Self::Counter); +} + +macro_rules! impl_counter { + {$($t:ty )*} => { + $( impl Counter for $t { } )* + }; +} + +impl_counter! { u32 u64 u128 } diff --git a/cipher/src/stream_wrapper.rs b/cipher/src/stream_wrapper.rs new file mode 100644 index 000000000..468c67af6 --- /dev/null +++ b/cipher/src/stream_wrapper.rs @@ -0,0 +1,116 @@ +use crate::{ + errors::StreamCipherError, AsyncStreamCipher, AsyncStreamCipherCore, OverflowError, SeekNum, + StreamCipher, StreamCipherCore, StreamCipherSeek, StreamCipherSeekCore, +}; +use block_buffer::{inout::InOutBuf, BlockBuffer}; +use crypto_common::{BlockUser, InnerIvInit, InnerUser, Iv, IvUser}; +use generic_array::typenum::Unsigned; + +/// Wrapper around [`StreamCipherCore`] implementations. +/// +/// It handles data buffering and implements the slice-based traits. +#[derive(Clone, Default)] +pub struct StreamCipherCoreWrapper { + core: T, + buffer: BlockBuffer, +} + +impl StreamCipherCoreWrapper { + /// Get reference to core. + pub fn get_core(&self) -> &T { + &self.core + } + + /// Split wrapper into core and buffer. + pub fn into_inner(self) -> (T, BlockBuffer) { + (self.core, self.buffer) + } + + /// Create wrapper from core and buffer. + pub fn from_inner(core: T, buffer: BlockBuffer) -> Self { + Self { core, buffer } + } +} + +impl StreamCipher for StreamCipherCoreWrapper { + #[inline] + fn try_apply_keystream(&mut self, data: InOutBuf<'_, u8>) -> Result<(), StreamCipherError> { + if let Some(rem_blocks) = self.core.remaining_blocks() { + let bytes = if self.buffer.get_pos() == 0 { + data.len() + } else { + data.len() - self.buffer.remaining() + }; + let bs = T::BlockSize::USIZE; + let blocks = if bytes % bs == 0 { + bytes / bs + } else { + bytes / bs + 1 + }; + if blocks > rem_blocks { + return Err(StreamCipherError); + } + } + + let Self { core, buffer } = self; + buffer.xor_data(data, |blocks| { + core.apply_keystream_blocks(blocks, |_| {}, |_| {}) + }); + + Ok(()) + } +} + +impl AsyncStreamCipher for StreamCipherCoreWrapper { + #[inline] + fn encrypt_inout(&mut self, data: InOutBuf<'_, u8>) { + let Self { core, buffer } = self; + buffer.xor_data(data, |blocks| core.encrypt_blocks_inout_mut(blocks, |_| {})); + } + + #[inline] + fn decrypt_inout(&mut self, data: InOutBuf<'_, u8>) { + let Self { core, buffer } = self; + buffer.xor_data(data, |blocks| core.decrypt_blocks_inout_mut(blocks, |_| {})); + } +} + +impl StreamCipherSeek for StreamCipherCoreWrapper { + fn try_current_pos(&self) -> Result { + let Self { core, buffer } = self; + let bs = T::BlockSize::USIZE; + SN::from_block_byte(core.get_block_pos(), buffer.get_pos(), bs) + } + + fn try_seek(&mut self, pos: SN) -> Result<(), StreamCipherError> { + let Self { core, buffer } = self; + let bs = T::BlockSize::USIZE; + let (block_pos, byte_pos) = pos.into_block_byte(bs)?; + core.set_block_pos(block_pos); + let mut block = Default::default(); + if byte_pos != 0 { + let buf = InOutBuf::from_mut(&mut block); + core.apply_keystream_blocks(buf, |_| {}, |_| {}); + } + buffer.set(block, byte_pos); + Ok(()) + } +} + +impl IvUser for StreamCipherCoreWrapper { + type IvSize = T::IvSize; +} + +impl InnerUser for StreamCipherCoreWrapper { + type Inner = T::Inner; +} + +impl InnerIvInit for StreamCipherCoreWrapper { + #[inline] + fn inner_iv_init(cipher: Self::Inner, iv: &Iv) -> Self { + Self { + core: T::inner_iv_init(cipher, iv), + buffer: Default::default(), + } + } +} diff --git a/crypto-common/Cargo.toml b/crypto-common/Cargo.toml index 3fa429be3..28d9ffee5 100644 --- a/crypto-common/Cargo.toml +++ b/crypto-common/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "crypto-common" description = "Common cryptographic traits" -version = "0.1.0-pre" +version = "0.1.0" authors = ["RustCrypto Developers"] license = "MIT OR Apache-2.0" readme = "README.md" @@ -13,9 +13,9 @@ categories = ["cryptography", "no-std"] [dependencies] generic-array = "0.14" -block-buffer = { version = "0.10.0-pre.2", optional = true } +block-buffer = "0.10.0" +rand_core = { version = "0.6", optional = true } [features] block-padding = ["block-buffer/block-padding"] -core-api = ["block-buffer"] std = [] diff --git a/crypto-common/src/core_api.rs b/crypto-common/src/core_api.rs index 7def7a076..0818acb1d 100644 --- a/crypto-common/src/core_api.rs +++ b/crypto-common/src/core_api.rs @@ -1,25 +1,19 @@ //! Low-level core API traits. -use super::{FixedOutput, FixedOutputReset, Reset, Update}; +use super::{Block, BlockUser, FixedOutput, FixedOutputReset, KeyInit, KeyUser, Reset, Update}; use block_buffer::DigestBuffer; use core::fmt; use generic_array::{ArrayLength, GenericArray}; /// Trait for types which consume data in blocks. -#[cfg(feature = "core-api")] -#[cfg_attr(docsrs, doc(cfg(feature = "core-api")))] -pub trait UpdateCore { - /// Block size in bytes. - type BlockSize: ArrayLength; +pub trait UpdateCore: BlockUser { /// Block buffer type over which value operates. type Buffer: DigestBuffer; /// Update state using the provided data blocks. - fn update_blocks(&mut self, blocks: &[GenericArray]); + fn update_blocks(&mut self, blocks: &[Block]); } /// Core trait for hash functions with fixed output size. -#[cfg(feature = "core-api")] -#[cfg_attr(docsrs, doc(cfg(feature = "core-api")))] pub trait FixedOutputCore: UpdateCore { /// Size of result in bytes. type OutputSize: ArrayLength; @@ -76,6 +70,19 @@ impl CoreWrapper { } } +impl KeyUser for CoreWrapper { + type KeySize = T::KeySize; +} + +impl KeyInit for CoreWrapper { + fn new(key: &GenericArray) -> Self { + Self { + core: T::new(key), + buffer: Default::default(), + } + } +} + impl fmt::Debug for CoreWrapper { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { T::write_alg_name(f)?; diff --git a/crypto-common/src/init.rs b/crypto-common/src/init.rs new file mode 100644 index 000000000..f1bf06970 --- /dev/null +++ b/crypto-common/src/init.rs @@ -0,0 +1,182 @@ +//! Traits related to types initialization. + +use core::fmt; +use generic_array::{typenum::Unsigned, ArrayLength, GenericArray}; +#[cfg(feature = "rand_core")] +use rand_core::{CryptoRng, RngCore}; + +/// Key used by [`KeyUser`] implementors. +pub type Key = GenericArray::KeySize>; +/// Initialization vector (nonce) used by [`IvUser`] implementors. +pub type Iv = GenericArray::IvSize>; + +/// Trait for types which use key for initialization. +/// +/// Generally it's used indirectly via [`KeyInit`] or [`KeyIvInit`]. +pub trait KeyUser { + /// Key size in bytes. + type KeySize: ArrayLength; + + /// Generate random key using the provided [`CryptoRng`]. + #[cfg(feature = "rand_core")] + #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] + #[inline] + fn generate_key(mut rng: impl CryptoRng + RngCore) -> Key { + let mut key = Key::::default(); + rng.fill_bytes(&mut key); + key + } +} + +/// Trait for types which use initialization vector (nonce) for initialization. +/// +/// Generally it's used indirectly via [`KeyIvInit`] or [`InnerIvInit`]. +pub trait IvUser { + /// Initialization vector size in bytes. + type IvSize: ArrayLength; + + /// Generate random IV using the provided [`CryptoRng`]. + #[cfg(feature = "rand_core")] + #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] + #[inline] + fn generate_iv(mut rng: impl CryptoRng + RngCore) -> Iv { + let mut iv = Iv::::default(); + rng.fill_bytes(&mut iv); + iv + } +} + +/// Trait for types which use another type for initialization. +/// +/// Generally it's used indirectly via [`InnerInit`] or [`InnerIvInit`]. +pub trait InnerUser { + /// Inner type. + type Inner; +} + +/// Trait for types which can be initialized from key. +pub trait KeyInit: KeyUser + Sized { + /// Create new value from fixed size key. + fn new(key: &Key) -> Self; + + /// Create new value from variable size key. + fn new_from_slice(key: &[u8]) -> Result { + if key.len() != Self::KeySize::to_usize() { + Err(InvalidLength) + } else { + Ok(Self::new(GenericArray::from_slice(key))) + } + } +} + +/// Trait for types which can be initialized from key and +/// initialization vector (nonce). +pub trait KeyIvInit: KeyUser + IvUser + Sized { + /// Create new value from fixed length key and nonce. + fn new(key: &Key, iv: &Iv) -> Self; + + /// Create new value from variable length key and nonce. + #[inline] + fn new_from_slices(key: &[u8], iv: &[u8]) -> Result { + let kl = Self::KeySize::to_usize(); + let nl = Self::IvSize::to_usize(); + if key.len() != kl || iv.len() != nl { + Err(InvalidLength) + } else { + let key = GenericArray::from_slice(key); + let iv = GenericArray::from_slice(iv); + Ok(Self::new(key, iv)) + } + } + + /// Generate random key and nonce using the provided [`CryptoRng`]. + #[cfg(feature = "rand_core")] + #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] + #[inline] + fn generate_key_iv(mut rng: impl CryptoRng + RngCore) -> (Key, Iv) { + (Self::generate_key(&mut rng), Self::generate_iv(&mut rng)) + } +} + +/// Types which can be initialized from another type (usually block ciphers). +/// +/// Usually used for initializing types from block ciphers. +pub trait InnerInit: InnerUser + Sized { + /// Initialize value from the `inner`. + fn inner_init(inner: Self::Inner) -> Self; +} + +/// Types which can be initialized from another type and additional initialization +/// vector/nonce. +/// +/// Usually used for initializing types from block ciphers. +pub trait InnerIvInit: InnerUser + IvUser + Sized { + /// Initialize value using `inner` and `iv` array. + fn inner_iv_init(inner: Self::Inner, iv: &GenericArray) -> Self; + + /// Initialize value using `inner` and `iv` slice. + fn inner_iv_slice_init(inner: Self::Inner, iv: &[u8]) -> Result { + if iv.len() != Self::IvSize::to_usize() { + Err(InvalidLength) + } else { + Ok(Self::inner_iv_init(inner, GenericArray::from_slice(iv))) + } + } +} + +impl KeyUser for T +where + T: InnerUser, + T::Inner: KeyUser, +{ + type KeySize = ::KeySize; +} + +impl KeyIvInit for T +where + T: InnerIvInit, + T::Inner: KeyInit, +{ + #[inline] + fn new(key: &Key, iv: &Iv) -> Self { + Self::inner_iv_init(T::Inner::new(key), iv) + } + + #[inline] + fn new_from_slices(key: &[u8], iv: &[u8]) -> Result { + T::Inner::new_from_slice(key).and_then(|i| T::inner_iv_slice_init(i, iv)) + } +} + +impl KeyInit for T +where + T: InnerInit, + T::Inner: KeyInit, +{ + #[inline] + fn new(key: &Key) -> Self { + Self::inner_init(T::Inner::new(key)) + } + + #[inline] + fn new_from_slice(key: &[u8]) -> Result { + T::Inner::new_from_slice(key) + .map_err(|_| InvalidLength) + .map(Self::inner_init) + } +} + +/// The error type returned when key and/or IV used in the [`KeyInit`], +/// [`KeyIvInit`], and [`InnerIvInit`] slice-based methods had +/// an invalid length. +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub struct InvalidLength; + +impl fmt::Display for InvalidLength { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str("Invalid Length") + } +} + +#[cfg(feature = "std")] +impl std::error::Error for InvalidLength {} diff --git a/crypto-common/src/lib.rs b/crypto-common/src/lib.rs index 5869bc677..c32a38b56 100644 --- a/crypto-common/src/lib.rs +++ b/crypto-common/src/lib.rs @@ -12,17 +12,33 @@ #[cfg(feature = "std")] extern crate std; -use generic_array::{ArrayLength, GenericArray}; +use generic_array::{ + typenum::{type_operators::IsLess, U256}, + ArrayLength, GenericArray, +}; -#[cfg(feature = "core-api")] -#[cfg_attr(docsrs, doc(cfg(feature = "core-api")))] pub use block_buffer; -#[cfg(feature = "core-api")] -#[cfg_attr(docsrs, doc(cfg(feature = "core-api")))] -pub mod core_api; +mod core_api; +mod init; -/// Trait for types which consume data. +pub use core_api::*; +pub use init::*; + +/// Block on which [`BlockUser`] implementors operate. +pub type Block = GenericArray::BlockSize>; + +/// Types which process data in blocks. +pub trait BlockUser { + /// Size of the block in bytes. + type BlockSize: ArrayLength + IsLess; +} + +impl BlockUser for &Alg { + type BlockSize = Alg::BlockSize; +} + +/// Trait which allows consumption of data. pub trait Update { /// Update state using the provided data. fn update(&mut self, data: &[u8]); @@ -46,7 +62,7 @@ pub trait FixedOutput: Sized { } /// Trait for types which return fixed-sized result after finalization and reset -/// values into its initial state. +/// state into its initial value. pub trait FixedOutputReset: FixedOutput + Reset { /// Write result into provided array and reset value to its initial state. fn finalize_into_reset(&mut self, out: &mut GenericArray); @@ -60,8 +76,8 @@ pub trait FixedOutputReset: FixedOutput + Reset { } } -/// Trait for resetting values to initial state. +/// Trait resetting of state to its initial value. pub trait Reset { - /// Reset value to its initial state. + /// Reset state to its initial value. fn reset(&mut self); } diff --git a/crypto-mac/Cargo.toml b/crypto-mac/Cargo.toml index 725f75fa4..52e7f0943 100644 --- a/crypto-mac/Cargo.toml +++ b/crypto-mac/Cargo.toml @@ -13,8 +13,8 @@ categories = ["cryptography", "no-std"] [dependencies] generic-array = "0.14" -crypto-common = { version = "=0.1.0-pre", path = "../crypto-common" } -cipher = { version = "=0.4.0-pre", path = "../cipher" } +crypto-common = { version = "0.1", path = "../crypto-common" } +cipher = { version = "0.4", path = "../cipher" } subtle = { version = "=2.4", default-features = false } blobby = { version = "0.3", optional = true } @@ -22,7 +22,6 @@ rand_core = { version = "0.6", optional = true } [features] dev = ["blobby"] -core-api = ["crypto-common/core-api"] std = ["crypto-common/std", "rand_core/std"] [package.metadata.docs.rs] diff --git a/crypto-mac/src/core_api.rs b/crypto-mac/src/core_api.rs index 7f7e6a6ec..d7d158590 100644 --- a/crypto-mac/src/core_api.rs +++ b/crypto-mac/src/core_api.rs @@ -1,2 +1,8 @@ //! Low-level core API traits. -pub use crypto_common::core_api::{AlgorithmName, CoreWrapper, FixedOutputCore, UpdateCore}; +use crypto_common::KeyInit; +pub use crypto_common::{AlgorithmName, CoreWrapper, FixedOutputCore, UpdateCore}; + +/// Marker trait for MAC algorithms. +pub trait MacCore: UpdateCore + FixedOutputCore {} + +impl super::Mac for CoreWrapper {} diff --git a/crypto-mac/src/lib.rs b/crypto-mac/src/lib.rs index e5e2f2ba7..152225ef4 100644 --- a/crypto-mac/src/lib.rs +++ b/crypto-mac/src/lib.rs @@ -19,38 +19,40 @@ pub use rand_core; #[cfg(feature = "cipher")] pub use cipher; -#[cfg(feature = "cipher")] -use cipher::{BlockCipher, NewBlockCipher}; #[cfg(feature = "dev")] #[cfg_attr(docsrs, doc(cfg(feature = "dev")))] pub mod dev; -#[cfg(feature = "core-api")] -#[cfg_attr(docsrs, doc(cfg(feature = "core-api")))] pub mod core_api; -pub use cipher::{errors::InvalidLength, FromKey}; -pub use crypto_common::{FixedOutput, FixedOutputReset, Reset, Update}; -pub use generic_array::{self, typenum::consts}; +pub use crypto_common::{ + FixedOutput, FixedOutputReset, InvalidLength, Key, KeyInit, Reset, Update, +}; +pub use generic_array::{ + self, + typenum::{consts, Unsigned}, +}; use core::fmt; use generic_array::GenericArray; use subtle::{Choice, ConstantTimeEq}; -/// Key for an algorithm that implements [`FromKey`]. -pub type Key = GenericArray::KeySize>; +/// Tag bytes generated by a MAC algorithm `M`. +pub type TagBytes = GenericArray::OutputSize>; /// Convinience super-trait covering functionality of Message Authentication algorithms. -pub trait Mac: FromKey + Update + FixedOutput { +pub trait Mac: KeyInit + Update + FixedOutput { /// Obtain the result of a [`Mac`] computation as a [`Output`] and consume /// [`Mac`] instance. + #[inline] fn finalize(self) -> Output { Output::new(self.finalize_fixed()) } /// Obtain the result of a [`Mac`] computation as a [`Output`] and reset /// [`Mac`] instance. + #[inline] fn finalize_reset(&mut self) -> Output where Self: FixedOutputReset, @@ -59,8 +61,9 @@ pub trait Mac: FromKey + Update + FixedOutput { } /// Check if tag/code value is correct for the processed input. + #[inline] fn verify(self, tag: &[u8]) -> Result<(), MacError> { - let choice = self.finalize().bytes.ct_eq(tag); + let choice = self.finalize_fixed().ct_eq(tag); if choice.unwrap_u8() == 1 { Ok(()) @@ -68,20 +71,55 @@ pub trait Mac: FromKey + Update + FixedOutput { Err(MacError) } } -} -impl Mac for T {} + /// Check if a tag/code truncated from right side (i.e. `tag[..n]`) + /// is correct for the processed input. + /// + /// Returns `MacError` if `tag` is empty. + fn verify_truncated_right(self, tag: &[u8]) -> Result<(), MacError> { + let n = tag.len(); + if n == 0 || n > Self::OutputSize::USIZE { + return Err(MacError); + } + let choice = self.finalize_fixed()[..n].ct_eq(tag); + + if choice.unwrap_u8() == 1 { + Ok(()) + } else { + Err(MacError) + } + } + + /// Check if a tag/code truncated from left side (i.e. `tag[n..]`) + /// is correct for the processed input. + /// + /// Returns `MacError` if `tag` is not valid or empty. + fn verify_truncated_left(self, tag: &[u8]) -> Result<(), MacError> { + let n = tag.len(); + if n == 0 || n > Self::OutputSize::USIZE { + return Err(MacError); + } + let m = Self::OutputSize::USIZE - n; + let choice = self.finalize_fixed()[m..].ct_eq(tag); + + if choice.unwrap_u8() == 1 { + Ok(()) + } else { + Err(MacError) + } + } +} /// [`Output`] is a thin wrapper around bytes array which provides a safe `Eq` /// implementation that runs in a fixed time. #[derive(Clone)] pub struct Output { - bytes: GenericArray, + bytes: TagBytes, } impl Output { /// Create a new MAC [`Output`]. - pub fn new(bytes: GenericArray) -> Output { + pub fn new(bytes: TagBytes) -> Output { Output { bytes } } @@ -90,7 +128,7 @@ impl Output { /// Be very careful using this method, since incorrect use of the tag value /// may permit timing attacks which defeat the security provided by the /// [`Mac`] trait. - pub fn into_bytes(self) -> GenericArray { + pub fn into_bytes(self) -> TagBytes { self.bytes } } diff --git a/digest/Cargo.toml b/digest/Cargo.toml index 61852b9d9..38aeea0b7 100644 --- a/digest/Cargo.toml +++ b/digest/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "digest" description = "Traits for cryptographic hash functions" -version = "0.10.0-pre.3" +version = "0.10.0" authors = ["RustCrypto Developers"] license = "MIT OR Apache-2.0" readme = "README.md" @@ -13,15 +13,15 @@ categories = ["cryptography", "no-std"] [dependencies] generic-array = "0.14" -crypto-common = { version = "=0.1.0-pre", path = "../crypto-common" } +crypto-common = { version = "0.1", path = "../crypto-common" } blobby = { version = "0.3", optional = true } [features] +default = ["block-padding"] alloc = [] std = ["alloc", "crypto-common/std"] dev = ["blobby"] -core-api = ["crypto-common/core-api"] block-padding = ["crypto-common/block-padding"] [package.metadata.docs.rs] diff --git a/digest/src/core_api.rs b/digest/src/core_api.rs index 63e573d33..fe40e34a1 100644 --- a/digest/src/core_api.rs +++ b/digest/src/core_api.rs @@ -5,9 +5,11 @@ //! higher-level traits. use crate::InvalidOutputSize; use crate::{ExtendableOutput, Reset}; -use generic_array::{ArrayLength, GenericArray}; +use generic_array::ArrayLength; -pub use crypto_common::core_api::{AlgorithmName, CoreWrapper, FixedOutputCore, UpdateCore}; +pub use crypto_common::{ + AlgorithmName, Block, BlockUser, CoreWrapper, FixedOutputCore, UpdateCore, +}; mod ct_variable; mod rt_variable; @@ -28,12 +30,9 @@ pub trait ExtendableOutputCore: UpdateCore { } /// Core reader trait for extendable-output function (XOF) result. -pub trait XofReaderCore { - /// Block size in bytes. - type BlockSize: ArrayLength; - +pub trait XofReaderCore: BlockUser { /// Read next XOF block. - fn read_block(&mut self) -> GenericArray; + fn read_block(&mut self) -> Block; } /// Core trait for hash functions with variable output size. diff --git a/digest/src/core_api/ct_variable.rs b/digest/src/core_api/ct_variable.rs index 11474326f..52bc53c67 100644 --- a/digest/src/core_api/ct_variable.rs +++ b/digest/src/core_api/ct_variable.rs @@ -1,5 +1,6 @@ use super::{AlgorithmName, FixedOutputCore, Reset, UpdateCore, VariableOutputCore}; use core::{fmt, marker::PhantomData}; +use crypto_common::{Block, BlockUser}; use generic_array::{ typenum::{IsLessOrEqual, LeEq, NonZero}, ArrayLength, GenericArray, @@ -18,17 +19,25 @@ where _out: PhantomData, } -impl UpdateCore for CtVariableCoreWrapper +impl BlockUser for CtVariableCoreWrapper where T: VariableOutputCore, OutSize: ArrayLength + IsLessOrEqual, LeEq: NonZero, { type BlockSize = T::BlockSize; +} + +impl UpdateCore for CtVariableCoreWrapper +where + T: VariableOutputCore, + OutSize: ArrayLength + IsLessOrEqual, + LeEq: NonZero, +{ type Buffer = T::Buffer; #[inline] - fn update_blocks(&mut self, blocks: &[GenericArray]) { + fn update_blocks(&mut self, blocks: &[Block]) { self.inner.update_blocks(blocks); } } diff --git a/digest/src/core_api/xof_reader.rs b/digest/src/core_api/xof_reader.rs index 5d7b83520..e3468e07f 100644 --- a/digest/src/core_api/xof_reader.rs +++ b/digest/src/core_api/xof_reader.rs @@ -23,7 +23,11 @@ impl XofReader for XofReaderCoreWrapper { #[inline] fn read(&mut self, buffer: &mut [u8]) { let Self { core, buffer: buf } = self; - buf.set_data(buffer, || core.read_block()); + buf.set_data(buffer, |blocks| { + for block in blocks { + *block = core.read_block(); + } + }); } } diff --git a/digest/src/lib.rs b/digest/src/lib.rs index 2991ded68..3d07d5967 100644 --- a/digest/src/lib.rs +++ b/digest/src/lib.rs @@ -46,22 +46,18 @@ use alloc::boxed::Box; #[cfg_attr(docsrs, doc(cfg(feature = "dev")))] pub mod dev; -#[cfg(feature = "core-api")] -#[cfg_attr(docsrs, doc(cfg(feature = "core-api")))] pub mod core_api; mod digest; mod dyn_digest; -pub use crate::digest::{Digest, Output}; use core::fmt; -#[cfg(feature = "core-api")] -#[cfg_attr(docsrs, doc(cfg(feature = "core-api")))] + +pub use crate::digest::{Digest, Output}; pub use crypto_common::block_buffer; +pub use crypto_common::{FixedOutput, FixedOutputReset, Reset, Update}; pub use dyn_digest::{DynDigest, InvalidBufferLength}; pub use generic_array::{self, typenum::consts, GenericArray}; -pub use crypto_common::{FixedOutput, FixedOutputReset, Reset, Update}; - /// Trait for describing readers which are used to extract extendable output /// from XOF (extendable-output function) result. pub trait XofReader { From dc5109f7c96f9b6b81ce7aac3a355b8a5ee9652e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Mon, 30 Aug 2021 16:29:39 +0300 Subject: [PATCH 02/63] fix tests --- .github/workflows/crypto-common.yml | 1 - .github/workflows/crypto-mac.yml | 1 - .github/workflows/digest.yml | 1 - cipher/Cargo.toml | 1 + 4 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/crypto-common.yml b/.github/workflows/crypto-common.yml index 84963aaae..2d9ef1349 100644 --- a/.github/workflows/crypto-common.yml +++ b/.github/workflows/crypto-common.yml @@ -51,6 +51,5 @@ jobs: toolchain: ${{ matrix.rust }} - run: cargo check --all-features - run: cargo test - - run: cargo test --features core-api - run: cargo test --features std - run: cargo test --all-features diff --git a/.github/workflows/crypto-mac.yml b/.github/workflows/crypto-mac.yml index 15caa59ed..a769aa4ae 100644 --- a/.github/workflows/crypto-mac.yml +++ b/.github/workflows/crypto-mac.yml @@ -53,7 +53,6 @@ jobs: toolchain: ${{ matrix.rust }} - run: cargo check --all-features - run: cargo test - - run: cargo test --features core-api - run: cargo test --features dev - run: cargo test --features std - run: cargo test --all-features diff --git a/.github/workflows/digest.yml b/.github/workflows/digest.yml index da00f2b12..516d8ad80 100644 --- a/.github/workflows/digest.yml +++ b/.github/workflows/digest.yml @@ -51,7 +51,6 @@ jobs: toolchain: ${{ matrix.rust }} - run: cargo check --all-features - run: cargo test --release - - run: cargo test --features core-api --release - run: cargo test --features dev --release - run: cargo test --features alloc --release - run: cargo test --features std --release diff --git a/cipher/Cargo.toml b/cipher/Cargo.toml index 3fd9135f7..94f9ae3ae 100644 --- a/cipher/Cargo.toml +++ b/cipher/Cargo.toml @@ -21,6 +21,7 @@ blobby = { version = "0.3", optional = true } [features] std = ["crypto-common/std"] +rand_core = ["crypto-common/rand_core"] dev = ["blobby"] [package.metadata.docs.rs] From 991ec33a1d20f7a3baf8376f208ef0ebeb87db98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Mon, 30 Aug 2021 18:27:43 +0300 Subject: [PATCH 03/63] add StreamCipherCore::apply_keystream_partial method --- cipher/src/stream_core.rs | 26 ++++++++++++++++++++++++-- crypto-common/src/lib.rs | 2 +- crypto/Cargo.toml | 2 +- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/cipher/src/stream_core.rs b/cipher/src/stream_core.rs index 0a6407896..b99e0ff51 100644 --- a/cipher/src/stream_core.rs +++ b/cipher/src/stream_core.rs @@ -1,5 +1,5 @@ use crate::{BlockDecryptMut, BlockEncryptMut}; -use block_buffer::inout::InOutBuf; +use block_buffer::{generic_array::typenum::Unsigned, inout::InOutBuf}; use core::convert::{TryFrom, TryInto}; use crypto_common::{Block, BlockUser}; @@ -7,7 +7,7 @@ use crypto_common::{Block, BlockUser}; pub trait AsyncStreamCipherCore: BlockEncryptMut + BlockDecryptMut {} /// Block-level synchronous stream ciphers. -pub trait StreamCipherCore: BlockUser { +pub trait StreamCipherCore: BlockUser + Sized { /// Return number of remaining blocks before cipher wraps around. /// /// Returns `None` if number of remaining blocks can not be computed @@ -17,12 +17,34 @@ pub trait StreamCipherCore: BlockUser { /// Apply keystream blocks with pre and post callbacks using /// parallel block processing if possible. + /// + /// WARNING: this method does not check number of remaining blocks! fn apply_keystream_blocks( &mut self, blocks: InOutBuf<'_, Block>, pre_fn: impl FnMut(&[Block]), post_fn: impl FnMut(&[Block]), ); + + /// Apply keystream to data not divided into blocks. + /// + /// Consumes cipher since it may consume final keystream block only + /// partially. + /// + /// WARNING: this method does not check number of remaining blocks! + fn apply_keystream_partial(mut self, mut buf: InOutBuf<'_, u8>) { + if buf.len() > Self::BlockSize::USIZE { + let (blocks, tail) = buf.into_chunks(); + self.apply_keystream_blocks(blocks, |_| {}, |_| {}); + buf = tail; + } + let n = buf.len(); + let mut block = Block::::default(); + block[..n].copy_from_slice(buf.get_in()); + let mut t = InOutBuf::from_mut(&mut block); + self.apply_keystream_blocks(t.reborrow(), |_| {}, |_| {}); + buf.get_out().copy_from_slice(&block[..n]); + } } // note: unfortunately currently we can not write blanket impls of diff --git a/crypto-common/src/lib.rs b/crypto-common/src/lib.rs index c32a38b56..05fbd913a 100644 --- a/crypto-common/src/lib.rs +++ b/crypto-common/src/lib.rs @@ -31,7 +31,7 @@ pub type Block = GenericArray::BlockSize>; /// Types which process data in blocks. pub trait BlockUser { /// Size of the block in bytes. - type BlockSize: ArrayLength + IsLess; + type BlockSize: ArrayLength + IsLess + 'static; } impl BlockUser for &Alg { diff --git a/crypto/Cargo.toml b/crypto/Cargo.toml index 46f8c370d..be08125a9 100644 --- a/crypto/Cargo.toml +++ b/crypto/Cargo.toml @@ -21,7 +21,7 @@ elliptic-curve = { version = "0.10", optional = true, path = "../elliptic-curve" mac = { version = "0.11", package = "crypto-mac", optional = true } password-hash = { version = "0.3", optional = true, path = "../password-hash" } signature = { version = "1.3.0", optional = true, default-features = false, path = "../signature" } -universal-hash = { version = "0.4", optional = true, path = "../universal-hash" } +universal-hash = { version = "0.4", optional = true } [features] std = [ From 4ac95d4a1461a13b65e37403adc860f7a36e1311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Mon, 30 Aug 2021 18:29:38 +0300 Subject: [PATCH 04/63] return immideately in apply_keystream_partial if tail is empty --- cipher/src/stream_core.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cipher/src/stream_core.rs b/cipher/src/stream_core.rs index b99e0ff51..bea813e73 100644 --- a/cipher/src/stream_core.rs +++ b/cipher/src/stream_core.rs @@ -39,6 +39,9 @@ pub trait StreamCipherCore: BlockUser + Sized { buf = tail; } let n = buf.len(); + if n == 0 { + return; + } let mut block = Block::::default(); block[..n].copy_from_slice(buf.get_in()); let mut t = InOutBuf::from_mut(&mut block); From e4de63930d01991f40930979295c64798472f9e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Mon, 30 Aug 2021 19:54:08 +0300 Subject: [PATCH 05/63] migrate universal-hash --- Cargo.lock | 14 +- crypto-common/Cargo.toml | 1 + .../src/{core_api.rs => core_wrapper.rs} | 56 ++----- crypto-common/src/ct_output.rs | 50 ++++++ crypto-common/src/lib.rs | 66 ++++++-- crypto-mac/Cargo.toml | 3 +- crypto-mac/src/lib.rs | 95 ++++-------- universal-hash/Cargo.toml | 4 +- universal-hash/src/lib.rs | 142 +++++------------- 9 files changed, 195 insertions(+), 236 deletions(-) rename crypto-common/src/{core_api.rs => core_wrapper.rs} (61%) create mode 100644 crypto-common/src/ct_output.rs diff --git a/Cargo.lock b/Cargo.lock index 1fefce199..08c2a3d98 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -139,7 +139,7 @@ dependencies = [ "elliptic-curve", "password-hash", "signature", - "universal-hash", + "universal-hash 0.4.1", ] [[package]] @@ -161,6 +161,7 @@ dependencies = [ "block-buffer 0.10.0", "generic-array", "rand_core", + "subtle", ] [[package]] @@ -182,7 +183,6 @@ dependencies = [ "crypto-common", "generic-array", "rand_core", - "subtle", ] [[package]] @@ -515,11 +515,21 @@ checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "universal-hash" version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" dependencies = [ "generic-array", "subtle", ] +[[package]] +name = "universal-hash" +version = "0.5.0" +dependencies = [ + "crypto-common", + "generic-array", +] + [[package]] name = "version_check" version = "0.9.3" diff --git a/crypto-common/Cargo.toml b/crypto-common/Cargo.toml index 28d9ffee5..8622823c2 100644 --- a/crypto-common/Cargo.toml +++ b/crypto-common/Cargo.toml @@ -15,6 +15,7 @@ categories = ["cryptography", "no-std"] generic-array = "0.14" block-buffer = "0.10.0" rand_core = { version = "0.6", optional = true } +subtle = { version = "=2.4", default-features = false, optional = true } [features] block-padding = ["block-buffer/block-padding"] diff --git a/crypto-common/src/core_api.rs b/crypto-common/src/core_wrapper.rs similarity index 61% rename from crypto-common/src/core_api.rs rename to crypto-common/src/core_wrapper.rs index 0818acb1d..0be093d29 100644 --- a/crypto-common/src/core_api.rs +++ b/crypto-common/src/core_wrapper.rs @@ -1,48 +1,22 @@ //! Low-level core API traits. -use super::{Block, BlockUser, FixedOutput, FixedOutputReset, KeyInit, KeyUser, Reset, Update}; +use super::{ + AlgorithmName, BufferUser, FixedOutput, FixedOutputCore, FixedOutputReset, KeyInit, KeyUser, + OutputUser, Reset, Update, UpdateCore, +}; use block_buffer::DigestBuffer; use core::fmt; -use generic_array::{ArrayLength, GenericArray}; - -/// Trait for types which consume data in blocks. -pub trait UpdateCore: BlockUser { - /// Block buffer type over which value operates. - type Buffer: DigestBuffer; - - /// Update state using the provided data blocks. - fn update_blocks(&mut self, blocks: &[Block]); -} - -/// Core trait for hash functions with fixed output size. -pub trait FixedOutputCore: UpdateCore { - /// Size of result in bytes. - type OutputSize: ArrayLength; - - /// Finalize state using remaining data stored in the provided block buffer, - /// write result into provided array using and leave value in a dirty state. - fn finalize_fixed_core( - &mut self, - buffer: &mut Self::Buffer, - out: &mut GenericArray, - ); -} - -/// Trait which stores algorithm name constant, used in `Debug` implementations. -pub trait AlgorithmName { - /// Write algorithm name into `f`. - fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result; -} +use generic_array::GenericArray; /// Wrapper around [`UpdateCore`] implementations. /// /// It handles data buffering and implements the slice-based traits. #[derive(Clone, Default)] -pub struct CoreWrapper { +pub struct CoreWrapper { core: T, buffer: T::Buffer, } -impl CoreWrapper { +impl CoreWrapper { /// Create new wrapper from `core`. #[inline] pub fn from_core(core: T) -> Self { @@ -58,7 +32,7 @@ impl CoreWrapper { } } -impl CoreWrapper { +impl CoreWrapper { /// Apply function to core and buffer, return its result, /// and reset core and buffer. pub fn apply_reset(&mut self, mut f: impl FnMut(&mut T, &mut T::Buffer) -> V) -> V { @@ -70,11 +44,11 @@ impl CoreWrapper { } } -impl KeyUser for CoreWrapper { +impl KeyUser for CoreWrapper { type KeySize = T::KeySize; } -impl KeyInit for CoreWrapper { +impl KeyInit for CoreWrapper { fn new(key: &GenericArray) -> Self { Self { core: T::new(key), @@ -83,14 +57,14 @@ impl KeyInit for CoreWrapper { } } -impl fmt::Debug for CoreWrapper { +impl fmt::Debug for CoreWrapper { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { T::write_alg_name(f)?; f.write_str(" { .. }") } } -impl Reset for CoreWrapper { +impl Reset for CoreWrapper { #[inline] fn reset(&mut self) { self.core.reset(); @@ -98,7 +72,7 @@ impl Reset for CoreWrapper { } } -impl Update for CoreWrapper { +impl Update for CoreWrapper { #[inline] fn update(&mut self, input: &[u8]) { let Self { core, buffer } = self; @@ -106,9 +80,11 @@ impl Update for CoreWrapper { } } -impl FixedOutput for CoreWrapper { +impl OutputUser for CoreWrapper { type OutputSize = D::OutputSize; +} +impl FixedOutput for CoreWrapper { #[inline] fn finalize_into(mut self, out: &mut GenericArray) { let Self { core, buffer } = &mut self; diff --git a/crypto-common/src/ct_output.rs b/crypto-common/src/ct_output.rs new file mode 100644 index 000000000..bf8e4f28a --- /dev/null +++ b/crypto-common/src/ct_output.rs @@ -0,0 +1,50 @@ +use super::{FixedOutput, Output}; +use subtle::{Choice, ConstantTimeEq}; + +/// Fixed size output value which provides a safe [`Eq`] implementation that +/// runs in constant time. +/// +/// It is useful for implementing Message Authentication Codes (MACs). +#[derive(Clone)] +#[cfg_attr(docsrs, doc(cfg(feature = "subtle")))] +pub struct CtOutput { + bytes: Output, +} + +impl CtOutput { + /// Create a new [`CtOutput`] value. + pub fn new(bytes: Output) -> Self { + Self { bytes } + } + + /// Get the inner [`Output`] array this type wraps. + pub fn into_bytes(self) -> Output { + self.bytes + } +} + +impl From> for CtOutput { + fn from(bytes: Output) -> Self { + Self { bytes } + } +} + +impl<'a, T: FixedOutput> From<&'a Output> for CtOutput { + fn from(bytes: &'a Output) -> Self { + bytes.clone().into() + } +} + +impl ConstantTimeEq for CtOutput { + fn ct_eq(&self, other: &Self) -> Choice { + self.bytes.ct_eq(&other.bytes) + } +} + +impl PartialEq for CtOutput { + fn eq(&self, x: &CtOutput) -> bool { + self.ct_eq(x).unwrap_u8() == 1 + } +} + +impl Eq for CtOutput {} diff --git a/crypto-common/src/lib.rs b/crypto-common/src/lib.rs index 05fbd913a..e15372196 100644 --- a/crypto-common/src/lib.rs +++ b/crypto-common/src/lib.rs @@ -12,22 +12,34 @@ #[cfg(feature = "std")] extern crate std; +use block_buffer::DigestBuffer; +use core::fmt; use generic_array::{ typenum::{type_operators::IsLess, U256}, ArrayLength, GenericArray, }; pub use block_buffer; +#[cfg(feature = "subtle")] +#[cfg_attr(docsrs, doc(cfg(feature = "subtle")))] +pub use subtle; -mod core_api; +mod core_wrapper; +#[cfg(feature = "subtle")] +mod ct_output; mod init; -pub use core_api::*; +pub use core_wrapper::*; +#[cfg(feature = "subtle")] +pub use ct_output::CtOutput; pub use init::*; /// Block on which [`BlockUser`] implementors operate. pub type Block = GenericArray::BlockSize>; +/// Output array of [`FixedOutput`] implementors. +pub type Output = GenericArray::OutputSize>; + /// Types which process data in blocks. pub trait BlockUser { /// Size of the block in bytes. @@ -38,38 +50,41 @@ impl BlockUser for &Alg { type BlockSize = Alg::BlockSize; } -/// Trait which allows consumption of data. +/// Types which return data with the given size. +pub trait OutputUser { + /// Size of the output in bytes. + type OutputSize: ArrayLength + 'static; +} + +/// Types which consume data with byte granularity. pub trait Update { /// Update state using the provided data. fn update(&mut self, data: &[u8]); } -/// Trait for types which return fixed-sized result after finalization. -pub trait FixedOutput: Sized { - /// Size of result in bytes. - type OutputSize: ArrayLength; - +/// Types which return fixed-sized result after finalization. +pub trait FixedOutput: OutputUser + Sized { /// Consume value and write result into provided array. - fn finalize_into(self, out: &mut GenericArray); + fn finalize_into(self, out: &mut Output); /// Retrieve result and consume the hasher instance. #[inline] - fn finalize_fixed(self) -> GenericArray { + fn finalize_fixed(self) -> Output { let mut out = Default::default(); self.finalize_into(&mut out); out } } -/// Trait for types which return fixed-sized result after finalization and reset +/// Types which return fixed-sized result after finalization and reset /// state into its initial value. pub trait FixedOutputReset: FixedOutput + Reset { /// Write result into provided array and reset value to its initial state. - fn finalize_into_reset(&mut self, out: &mut GenericArray); + fn finalize_into_reset(&mut self, out: &mut Output); /// Retrieve result and reset the hasher instance. #[inline] - fn finalize_fixed_reset(&mut self) -> GenericArray { + fn finalize_fixed_reset(&mut self) -> Output { let mut out = Default::default(); self.finalize_into_reset(&mut out); out @@ -81,3 +96,28 @@ pub trait Reset { /// Reset state to its initial value. fn reset(&mut self); } + +/// Trait for types which consume data in blocks. +pub trait UpdateCore: BlockUser { + /// Update state using the provided data blocks. + fn update_blocks(&mut self, blocks: &[Block]); +} + +/// Trait for types which use [`DigestBuffer`] functionality. +pub trait BufferUser: BlockUser { + /// Block buffer type over which value operates. + type Buffer: DigestBuffer; +} + +/// Core trait for hash functions with fixed output size. +pub trait FixedOutputCore: UpdateCore + BufferUser + OutputUser { + /// Finalize state using remaining data stored in the provided block buffer, + /// write result into provided array using and leave value in a dirty state. + fn finalize_fixed_core(&mut self, buffer: &mut Self::Buffer, out: &mut Output); +} + +/// Trait which stores algorithm name constant, used in `Debug` implementations. +pub trait AlgorithmName { + /// Write algorithm name into `f`. + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result; +} diff --git a/crypto-mac/Cargo.toml b/crypto-mac/Cargo.toml index 52e7f0943..1980a8f73 100644 --- a/crypto-mac/Cargo.toml +++ b/crypto-mac/Cargo.toml @@ -13,9 +13,8 @@ categories = ["cryptography", "no-std"] [dependencies] generic-array = "0.14" -crypto-common = { version = "0.1", path = "../crypto-common" } +crypto-common = { version = "0.1", features = ["subtle"], path = "../crypto-common" } cipher = { version = "0.4", path = "../cipher" } -subtle = { version = "=2.4", default-features = false } blobby = { version = "0.3", optional = true } rand_core = { version = "0.6", optional = true } diff --git a/crypto-mac/src/lib.rs b/crypto-mac/src/lib.rs index 152225ef4..0ad0491b4 100644 --- a/crypto-mac/src/lib.rs +++ b/crypto-mac/src/lib.rs @@ -26,78 +26,71 @@ pub mod dev; pub mod core_api; +use core::fmt; pub use crypto_common::{ - FixedOutput, FixedOutputReset, InvalidLength, Key, KeyInit, Reset, Update, + subtle::ConstantTimeEq, CtOutput, FixedOutput, FixedOutputReset, InvalidLength, Key, KeyInit, + Output, Reset, Update, }; pub use generic_array::{ self, typenum::{consts, Unsigned}, }; -use core::fmt; -use generic_array::GenericArray; -use subtle::{Choice, ConstantTimeEq}; - -/// Tag bytes generated by a MAC algorithm `M`. -pub type TagBytes = GenericArray::OutputSize>; - /// Convinience super-trait covering functionality of Message Authentication algorithms. pub trait Mac: KeyInit + Update + FixedOutput { - /// Obtain the result of a [`Mac`] computation as a [`Output`] and consume + /// Obtain the result of a [`Mac`] computation as a [`CtOutput`] and consume /// [`Mac`] instance. #[inline] - fn finalize(self) -> Output { - Output::new(self.finalize_fixed()) + fn finalize(self) -> CtOutput { + CtOutput::new(self.finalize_fixed()) } - /// Obtain the result of a [`Mac`] computation as a [`Output`] and reset + /// Obtain the result of a [`Mac`] computation as a [`CtOutput`] and reset /// [`Mac`] instance. #[inline] - fn finalize_reset(&mut self) -> Output + fn finalize_reset(&mut self) -> CtOutput where Self: FixedOutputReset, { - Output::new(self.finalize_fixed_reset()) + CtOutput::new(self.finalize_fixed_reset()) } /// Check if tag/code value is correct for the processed input. #[inline] - fn verify(self, tag: &[u8]) -> Result<(), MacError> { - let choice = self.finalize_fixed().ct_eq(tag); - - if choice.unwrap_u8() == 1 { + fn verify(self, other: &Output) -> Result<(), Error> { + if self.finalize() == other.into() { Ok(()) } else { - Err(MacError) + Err(Error) } } /// Check if a tag/code truncated from right side (i.e. `tag[..n]`) /// is correct for the processed input. /// - /// Returns `MacError` if `tag` is empty. - fn verify_truncated_right(self, tag: &[u8]) -> Result<(), MacError> { + /// Returns `Error` if `tag` is empty. + fn verify_truncated_right(self, tag: &[u8]) -> Result<(), Error> { let n = tag.len(); if n == 0 || n > Self::OutputSize::USIZE { - return Err(MacError); + return Err(Error); } let choice = self.finalize_fixed()[..n].ct_eq(tag); if choice.unwrap_u8() == 1 { Ok(()) } else { - Err(MacError) + Err(Error) } } /// Check if a tag/code truncated from left side (i.e. `tag[n..]`) /// is correct for the processed input. /// - /// Returns `MacError` if `tag` is not valid or empty. - fn verify_truncated_left(self, tag: &[u8]) -> Result<(), MacError> { + /// Returns `Error` if `tag` is not valid or empty. + fn verify_truncated_left(self, tag: &[u8]) -> Result<(), Error> { let n = tag.len(); if n == 0 || n > Self::OutputSize::USIZE { - return Err(MacError); + return Err(Error); } let m = Self::OutputSize::USIZE - n; let choice = self.finalize_fixed()[m..].ct_eq(tag); @@ -105,57 +98,21 @@ pub trait Mac: KeyInit + Update + FixedOutput { if choice.unwrap_u8() == 1 { Ok(()) } else { - Err(MacError) + Err(Error) } } } -/// [`Output`] is a thin wrapper around bytes array which provides a safe `Eq` -/// implementation that runs in a fixed time. -#[derive(Clone)] -pub struct Output { - bytes: TagBytes, -} - -impl Output { - /// Create a new MAC [`Output`]. - pub fn new(bytes: TagBytes) -> Output { - Output { bytes } - } - - /// Get the MAC tag/code value as a byte array. - /// - /// Be very careful using this method, since incorrect use of the tag value - /// may permit timing attacks which defeat the security provided by the - /// [`Mac`] trait. - pub fn into_bytes(self) -> TagBytes { - self.bytes - } -} - -impl ConstantTimeEq for Output { - fn ct_eq(&self, other: &Self) -> Choice { - self.bytes.ct_eq(&other.bytes) - } -} - -impl PartialEq for Output { - fn eq(&self, x: &Output) -> bool { - self.ct_eq(x).unwrap_u8() == 1 - } -} - -impl Eq for Output {} - -/// Error type for signaling failed MAC verification +/// Error type for when the [`Output`] of a [`Mac`] +/// is not equal to the expected value. #[derive(Default, Debug, Copy, Clone, Eq, PartialEq)] -pub struct MacError; +pub struct Error; -impl fmt::Display for MacError { +impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("failed MAC verification") + f.write_str("MAC output mismatch") } } #[cfg(feature = "std")] -impl std::error::Error for MacError {} +impl std::error::Error for Error {} diff --git a/universal-hash/Cargo.toml b/universal-hash/Cargo.toml index 2c15823ef..7e4b65718 100644 --- a/universal-hash/Cargo.toml +++ b/universal-hash/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "universal-hash" -version = "0.4.1" # Also update html_root_url in lib.rs when bumping this +version = "0.5.0" # Also update html_root_url in lib.rs when bumping this authors = ["RustCrypto Developers"] license = "MIT OR Apache-2.0" description = "Trait for universal hash functions" @@ -13,7 +13,7 @@ edition = "2018" [dependencies] generic-array = "0.14" -subtle = { version = "=2.4", default-features = false } +crypto-common = { version = "0.1", features = ["subtle"], path = "../crypto-common" } [features] std = [] diff --git a/universal-hash/src/lib.rs b/universal-hash/src/lib.rs index dc802c815..3330fce9d 100644 --- a/universal-hash/src/lib.rs +++ b/universal-hash/src/lib.rs @@ -18,11 +18,10 @@ //! [Universal Hash Functions]: https://en.wikipedia.org/wiki/Universal_hashing #![no_std] -#![forbid(unsafe_code)] #![doc( html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg", html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg", - html_root_url = "https://docs.rs/universal-hash/0.4.1" + html_root_url = "https://docs.rs/universal-hash/0.5.0" )] #![warn(missing_docs, rust_2018_idioms)] @@ -31,34 +30,17 @@ extern crate std; pub use generic_array::{self, typenum::consts}; -use generic_array::typenum::Unsigned; -use generic_array::{ArrayLength, GenericArray}; -use subtle::{Choice, ConstantTimeEq}; +use core::slice; +use generic_array::{typenum::Unsigned, GenericArray}; -/// Keys to a [`UniversalHash`]. -pub type Key = GenericArray::KeySize>; - -/// Blocks are inputs to a [`UniversalHash`]. -pub type Block = GenericArray::BlockSize>; - -/// Instantiate a [`UniversalHash`] algorithm. -pub trait NewUniversalHash: Sized { - /// Size of the key for the universal hash function. - type KeySize: ArrayLength; - - /// Instantiate a universal hash function with the given key. - fn new(key: &Key) -> Self; -} +pub use crypto_common::{ + Block, BlockUser, CtOutput, FixedOutput, FixedOutputReset, Key, KeyInit, KeyUser, Output, + Reset, UpdateCore, +}; /// The [`UniversalHash`] trait defines a generic interface for universal hash /// functions. -pub trait UniversalHash: Clone { - /// Size of the inputs to and outputs from the universal hash function - type BlockSize: ArrayLength; - - /// Input a block into the universal hash function - fn update(&mut self, block: &Block); - +pub trait UniversalHash: KeyInit + UpdateCore + FixedOutput { /// Input data into the universal hash function. If the length of the /// data is not a multiple of the block size, the remaining data is /// padded with zeroes up to the `BlockSize`. @@ -66,39 +48,45 @@ pub trait UniversalHash: Clone { /// This approach is frequently used by AEAD modes which use /// Message Authentication Codes (MACs) based on universal hashing. fn update_padded(&mut self, data: &[u8]) { - let mut chunks = data.chunks_exact(Self::BlockSize::to_usize()); - - for chunk in &mut chunks { - self.update(GenericArray::from_slice(chunk)); - } - - let rem = chunks.remainder(); - - if !rem.is_empty() { + // TODO: replace with `array_chunks` on migration to const generics + let (blocks, tail) = unsafe { + let blocks_len = data.len() / Self::BlockSize::USIZE; + let tail_start = Self::BlockSize::USIZE * blocks_len; + let tail_len = data.len() - tail_start; + ( + slice::from_raw_parts(data.as_ptr() as *const Block, blocks_len), + slice::from_raw_parts(data.as_ptr().add(tail_start), tail_len), + ) + }; + + self.update_blocks(blocks); + + if !tail.is_empty() { let mut padded_block = GenericArray::default(); - padded_block[..rem.len()].copy_from_slice(rem); - self.update(&padded_block); + padded_block[..tail.len()].copy_from_slice(tail); + self.update_blocks(slice::from_ref(&padded_block)); } } - /// Reset [`UniversalHash`] instance. - fn reset(&mut self); - /// Obtain the [`Output`] of a [`UniversalHash`] function and consume it. - fn finalize(self) -> Output; + fn finalize(self) -> CtOutput { + CtOutput::new(self.finalize_fixed()) + } /// Obtain the [`Output`] of a [`UniversalHash`] computation and reset it back /// to its initial state. - fn finalize_reset(&mut self) -> Output { - let res = self.clone().finalize(); - self.reset(); - res + #[inline] + fn finalize_reset(&mut self) -> CtOutput + where + Self: FixedOutputReset, + { + CtOutput::new(self.finalize_fixed_reset()) } /// Verify the [`UniversalHash`] of the processed input matches a given [`Output`]. /// This is useful when constructing Message Authentication Codes (MACs) /// from universal hash functions. - fn verify(self, other: &Block) -> Result<(), Error> { + fn verify(self, other: &Output) -> Result<(), Error> { if self.finalize() == other.into() { Ok(()) } else { @@ -107,68 +95,6 @@ pub trait UniversalHash: Clone { } } -/// Outputs of universal hash functions which are a thin wrapper around a -/// byte array. Provides a safe [`Eq`] implementation that runs in constant time, -/// which is useful for implementing Message Authentication Codes (MACs) based -/// on universal hashing. -#[derive(Clone)] -pub struct Output { - bytes: GenericArray, -} - -impl Output -where - U: UniversalHash, -{ - /// Create a new [`Output`] block. - pub fn new(bytes: Block) -> Output { - Output { bytes } - } - - /// Get the inner [`GenericArray`] this type wraps - pub fn into_bytes(self) -> Block { - self.bytes - } -} - -impl From> for Output -where - U: UniversalHash, -{ - fn from(bytes: Block) -> Self { - Output { bytes } - } -} - -impl<'a, U> From<&'a Block> for Output -where - U: UniversalHash, -{ - fn from(bytes: &'a Block) -> Self { - bytes.clone().into() - } -} - -impl ConstantTimeEq for Output -where - U: UniversalHash, -{ - fn ct_eq(&self, other: &Self) -> Choice { - self.bytes.ct_eq(&other.bytes) - } -} - -impl PartialEq for Output -where - U: UniversalHash, -{ - fn eq(&self, x: &Output) -> bool { - self.ct_eq(x).unwrap_u8() == 1 - } -} - -impl Eq for Output {} - /// Error type for when the [`Output`] of a [`UniversalHash`] /// is not equal to the expected value. #[derive(Default, Debug, Copy, Clone, Eq, PartialEq)] From 9d1322ca239b741bb42810d21d8496440b55d461 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Mon, 30 Aug 2021 19:56:55 +0300 Subject: [PATCH 06/63] crypto-common: doc updates --- crypto-common/src/init.rs | 11 +++++------ crypto-common/src/lib.rs | 6 +++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/crypto-common/src/init.rs b/crypto-common/src/init.rs index f1bf06970..6a5f84cf9 100644 --- a/crypto-common/src/init.rs +++ b/crypto-common/src/init.rs @@ -10,7 +10,7 @@ pub type Key = GenericArray::KeySize>; /// Initialization vector (nonce) used by [`IvUser`] implementors. pub type Iv = GenericArray::IvSize>; -/// Trait for types which use key for initialization. +/// Types which use key for initialization. /// /// Generally it's used indirectly via [`KeyInit`] or [`KeyIvInit`]. pub trait KeyUser { @@ -28,7 +28,7 @@ pub trait KeyUser { } } -/// Trait for types which use initialization vector (nonce) for initialization. +/// Types which use initialization vector (nonce) for initialization. /// /// Generally it's used indirectly via [`KeyIvInit`] or [`InnerIvInit`]. pub trait IvUser { @@ -46,7 +46,7 @@ pub trait IvUser { } } -/// Trait for types which use another type for initialization. +/// Types which use another type for initialization. /// /// Generally it's used indirectly via [`InnerInit`] or [`InnerIvInit`]. pub trait InnerUser { @@ -54,7 +54,7 @@ pub trait InnerUser { type Inner; } -/// Trait for types which can be initialized from key. +/// Types which can be initialized from key. pub trait KeyInit: KeyUser + Sized { /// Create new value from fixed size key. fn new(key: &Key) -> Self; @@ -69,8 +69,7 @@ pub trait KeyInit: KeyUser + Sized { } } -/// Trait for types which can be initialized from key and -/// initialization vector (nonce). +/// Types which can be initialized from key and initialization vector (nonce). pub trait KeyIvInit: KeyUser + IvUser + Sized { /// Create new value from fixed length key and nonce. fn new(key: &Key, iv: &Iv) -> Self; diff --git a/crypto-common/src/lib.rs b/crypto-common/src/lib.rs index e15372196..4e04def9a 100644 --- a/crypto-common/src/lib.rs +++ b/crypto-common/src/lib.rs @@ -91,19 +91,19 @@ pub trait FixedOutputReset: FixedOutput + Reset { } } -/// Trait resetting of state to its initial value. +/// Resettable types. pub trait Reset { /// Reset state to its initial value. fn reset(&mut self); } -/// Trait for types which consume data in blocks. +/// Types which consume data in blocks. pub trait UpdateCore: BlockUser { /// Update state using the provided data blocks. fn update_blocks(&mut self, blocks: &[Block]); } -/// Trait for types which use [`DigestBuffer`] functionality. +/// Types which use [`DigestBuffer`] functionality. pub trait BufferUser: BlockUser { /// Block buffer type over which value operates. type Buffer: DigestBuffer; From 46feeb5e84d97f6f538256f77f72722c75c84178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Mon, 30 Aug 2021 20:01:13 +0300 Subject: [PATCH 07/63] crypto-common: fix wrapper bound --- crypto-common/src/core_wrapper.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto-common/src/core_wrapper.rs b/crypto-common/src/core_wrapper.rs index 0be093d29..2e877dc62 100644 --- a/crypto-common/src/core_wrapper.rs +++ b/crypto-common/src/core_wrapper.rs @@ -101,7 +101,7 @@ impl FixedOutputReset for CoreWrapper { #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl std::io::Write for CoreWrapper { +impl std::io::Write for CoreWrapper { #[inline] fn write(&mut self, buf: &[u8]) -> std::io::Result { Update::update(self, buf); From 22d7c94ee453d20ecf4b6dba9c86ba7939bee775 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Wed, 1 Sep 2021 14:18:52 +0300 Subject: [PATCH 08/63] fix digest --- crypto-common/src/core_wrapper.rs | 6 +++--- crypto-common/src/lib.rs | 10 +++++----- digest/src/core_api.rs | 6 +++--- digest/src/core_api/ct_variable.rs | 24 +++++++++++++++++++----- digest/src/digest.rs | 3 ++- digest/src/dyn_digest.rs | 5 +++-- 6 files changed, 35 insertions(+), 19 deletions(-) diff --git a/crypto-common/src/core_wrapper.rs b/crypto-common/src/core_wrapper.rs index 2e877dc62..15d3a6a28 100644 --- a/crypto-common/src/core_wrapper.rs +++ b/crypto-common/src/core_wrapper.rs @@ -1,7 +1,7 @@ //! Low-level core API traits. use super::{ AlgorithmName, BufferUser, FixedOutput, FixedOutputCore, FixedOutputReset, KeyInit, KeyUser, - OutputUser, Reset, Update, UpdateCore, + OutputSizeUser, Reset, Update, UpdateCore, }; use block_buffer::DigestBuffer; use core::fmt; @@ -11,7 +11,7 @@ use generic_array::GenericArray; /// /// It handles data buffering and implements the slice-based traits. #[derive(Clone, Default)] -pub struct CoreWrapper { +pub struct CoreWrapper { core: T, buffer: T::Buffer, } @@ -80,7 +80,7 @@ impl Update for CoreWrapper { } } -impl OutputUser for CoreWrapper { +impl OutputSizeUser for CoreWrapper { type OutputSize = D::OutputSize; } diff --git a/crypto-common/src/lib.rs b/crypto-common/src/lib.rs index 4e04def9a..1668f9e81 100644 --- a/crypto-common/src/lib.rs +++ b/crypto-common/src/lib.rs @@ -37,8 +37,8 @@ pub use init::*; /// Block on which [`BlockUser`] implementors operate. pub type Block = GenericArray::BlockSize>; -/// Output array of [`FixedOutput`] implementors. -pub type Output = GenericArray::OutputSize>; +/// Output array of [`OutputSizeUser`] implementors. +pub type Output = GenericArray::OutputSize>; /// Types which process data in blocks. pub trait BlockUser { @@ -51,7 +51,7 @@ impl BlockUser for &Alg { } /// Types which return data with the given size. -pub trait OutputUser { +pub trait OutputSizeUser { /// Size of the output in bytes. type OutputSize: ArrayLength + 'static; } @@ -63,7 +63,7 @@ pub trait Update { } /// Types which return fixed-sized result after finalization. -pub trait FixedOutput: OutputUser + Sized { +pub trait FixedOutput: OutputSizeUser + Sized { /// Consume value and write result into provided array. fn finalize_into(self, out: &mut Output); @@ -110,7 +110,7 @@ pub trait BufferUser: BlockUser { } /// Core trait for hash functions with fixed output size. -pub trait FixedOutputCore: UpdateCore + BufferUser + OutputUser { +pub trait FixedOutputCore: UpdateCore + BufferUser + OutputSizeUser { /// Finalize state using remaining data stored in the provided block buffer, /// write result into provided array using and leave value in a dirty state. fn finalize_fixed_core(&mut self, buffer: &mut Self::Buffer, out: &mut Output); diff --git a/digest/src/core_api.rs b/digest/src/core_api.rs index fe40e34a1..b12f04c0c 100644 --- a/digest/src/core_api.rs +++ b/digest/src/core_api.rs @@ -8,7 +8,7 @@ use crate::{ExtendableOutput, Reset}; use generic_array::ArrayLength; pub use crypto_common::{ - AlgorithmName, Block, BlockUser, CoreWrapper, FixedOutputCore, UpdateCore, + AlgorithmName, Block, BlockUser, BufferUser, CoreWrapper, FixedOutputCore, UpdateCore, }; mod ct_variable; @@ -20,7 +20,7 @@ pub use rt_variable::RtVariableCoreWrapper; pub use xof_reader::XofReaderCoreWrapper; /// Core trait for hash functions with extendable (XOF) output size. -pub trait ExtendableOutputCore: UpdateCore { +pub trait ExtendableOutputCore: UpdateCore + BufferUser { /// XOF reader core state. type ReaderCore: XofReaderCore; @@ -36,7 +36,7 @@ pub trait XofReaderCore: BlockUser { } /// Core trait for hash functions with variable output size. -pub trait VariableOutputCore: UpdateCore + Sized { +pub trait VariableOutputCore: UpdateCore + BufferUser + Sized { /// Maximum output size. type MaxOutputSize: ArrayLength; diff --git a/digest/src/core_api/ct_variable.rs b/digest/src/core_api/ct_variable.rs index 52bc53c67..5e8ddbd3e 100644 --- a/digest/src/core_api/ct_variable.rs +++ b/digest/src/core_api/ct_variable.rs @@ -1,6 +1,6 @@ use super::{AlgorithmName, FixedOutputCore, Reset, UpdateCore, VariableOutputCore}; use core::{fmt, marker::PhantomData}; -use crypto_common::{Block, BlockUser}; +use crypto_common::{Block, BlockUser, BufferUser, OutputSizeUser}; use generic_array::{ typenum::{IsLessOrEqual, LeEq, NonZero}, ArrayLength, GenericArray, @@ -34,22 +34,36 @@ where OutSize: ArrayLength + IsLessOrEqual, LeEq: NonZero, { - type Buffer = T::Buffer; - #[inline] fn update_blocks(&mut self, blocks: &[Block]) { self.inner.update_blocks(blocks); } } -impl FixedOutputCore for CtVariableCoreWrapper +impl OutputSizeUser for CtVariableCoreWrapper where T: VariableOutputCore, - OutSize: ArrayLength + IsLessOrEqual, + OutSize: ArrayLength + IsLessOrEqual + 'static, LeEq: NonZero, { type OutputSize = OutSize; +} + +impl BufferUser for CtVariableCoreWrapper +where + T: VariableOutputCore, + OutSize: ArrayLength + IsLessOrEqual, + LeEq: NonZero, +{ + type Buffer = T::Buffer; +} +impl FixedOutputCore for CtVariableCoreWrapper +where + T: VariableOutputCore, + OutSize: ArrayLength + IsLessOrEqual + 'static, + LeEq: NonZero, +{ #[inline] fn finalize_fixed_core( &mut self, diff --git a/digest/src/digest.rs b/digest/src/digest.rs index 7c277c9a6..9b42fc37c 100644 --- a/digest/src/digest.rs +++ b/digest/src/digest.rs @@ -1,4 +1,5 @@ use super::{FixedOutput, FixedOutputReset, Update}; +use crypto_common::OutputSizeUser; use generic_array::typenum::Unsigned; use generic_array::{ArrayLength, GenericArray}; @@ -45,7 +46,7 @@ pub trait Digest { } impl Digest for D { - type OutputSize = ::OutputSize; + type OutputSize = ::OutputSize; #[inline] fn new() -> Self { diff --git a/digest/src/dyn_digest.rs b/digest/src/dyn_digest.rs index ecafe7945..0e1d3fab3 100644 --- a/digest/src/dyn_digest.rs +++ b/digest/src/dyn_digest.rs @@ -1,5 +1,6 @@ -use super::{FixedOutput, FixedOutputReset, Reset, Update}; +use super::{FixedOutputReset, Reset, Update}; use core::fmt; +use crypto_common::OutputSizeUser; use generic_array::{typenum::Unsigned, GenericArray}; #[cfg(feature = "alloc")] @@ -92,7 +93,7 @@ impl DynDigest for D { } fn output_size(&self) -> usize { - ::OutputSize::to_usize() + ::OutputSize::to_usize() } #[cfg(feature = "alloc")] From 8f488e755cb24d3bf243368c37018e852469a8c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Wed, 1 Sep 2021 14:27:15 +0300 Subject: [PATCH 09/63] digest: re-export OutputSizeUser in core_api --- digest/src/core_api.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/digest/src/core_api.rs b/digest/src/core_api.rs index b12f04c0c..6816cc64f 100644 --- a/digest/src/core_api.rs +++ b/digest/src/core_api.rs @@ -8,7 +8,8 @@ use crate::{ExtendableOutput, Reset}; use generic_array::ArrayLength; pub use crypto_common::{ - AlgorithmName, Block, BlockUser, BufferUser, CoreWrapper, FixedOutputCore, UpdateCore, + AlgorithmName, Block, BlockUser, BufferUser, CoreWrapper, FixedOutputCore, OutputSizeUser, + UpdateCore, }; mod ct_variable; From bd0fa5914346208cfd98c531135abd97d6b698e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Wed, 1 Sep 2021 15:37:47 +0300 Subject: [PATCH 10/63] digest: re-export Reset in core_api --- digest/src/core_api.rs | 5 ++--- digest/src/core_api/ct_variable.rs | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/digest/src/core_api.rs b/digest/src/core_api.rs index 6816cc64f..9e4fce441 100644 --- a/digest/src/core_api.rs +++ b/digest/src/core_api.rs @@ -3,13 +3,12 @@ //! Usage of traits in this module in user code is discouraged. Instead use //! core algorithm wrapped by the wrapper types, which implement the //! higher-level traits. -use crate::InvalidOutputSize; -use crate::{ExtendableOutput, Reset}; +use crate::{ExtendableOutput, InvalidOutputSize}; use generic_array::ArrayLength; pub use crypto_common::{ AlgorithmName, Block, BlockUser, BufferUser, CoreWrapper, FixedOutputCore, OutputSizeUser, - UpdateCore, + UpdateCore, Reset, }; mod ct_variable; diff --git a/digest/src/core_api/ct_variable.rs b/digest/src/core_api/ct_variable.rs index 5e8ddbd3e..bda15a5e1 100644 --- a/digest/src/core_api/ct_variable.rs +++ b/digest/src/core_api/ct_variable.rs @@ -85,7 +85,7 @@ where fn default() -> Self { Self { inner: T::new(OutSize::USIZE).unwrap(), - _out: Default::default(), + _out: PhantomData, } } } From 27743f63fc84fbf5580cfe25be10b419b33c108f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Wed, 1 Sep 2021 19:23:32 +0300 Subject: [PATCH 11/63] fmt --- digest/src/core_api.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/digest/src/core_api.rs b/digest/src/core_api.rs index 9e4fce441..7998a7816 100644 --- a/digest/src/core_api.rs +++ b/digest/src/core_api.rs @@ -8,7 +8,7 @@ use generic_array::ArrayLength; pub use crypto_common::{ AlgorithmName, Block, BlockUser, BufferUser, CoreWrapper, FixedOutputCore, OutputSizeUser, - UpdateCore, Reset, + Reset, UpdateCore, }; mod ct_variable; From 815cb3931fbdfeaa8339139e6a2c358de6d0d354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Mon, 6 Sep 2021 21:30:53 +0300 Subject: [PATCH 12/63] implement InnerInit for StreamCipherCoreWrapper --- cipher/src/stream_wrapper.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/cipher/src/stream_wrapper.rs b/cipher/src/stream_wrapper.rs index 468c67af6..0d00d2cb1 100644 --- a/cipher/src/stream_wrapper.rs +++ b/cipher/src/stream_wrapper.rs @@ -3,7 +3,7 @@ use crate::{ StreamCipher, StreamCipherCore, StreamCipherSeek, StreamCipherSeekCore, }; use block_buffer::{inout::InOutBuf, BlockBuffer}; -use crypto_common::{BlockUser, InnerIvInit, InnerUser, Iv, IvUser}; +use crypto_common::{BlockUser, InnerUser, InnerInit}; use generic_array::typenum::Unsigned; /// Wrapper around [`StreamCipherCore`] implementations. @@ -97,19 +97,15 @@ impl StreamCipherSeek for StreamCipherCoreWrapper { } } -impl IvUser for StreamCipherCoreWrapper { - type IvSize = T::IvSize; +impl InnerUser for StreamCipherCoreWrapper { + type Inner = T; } -impl InnerUser for StreamCipherCoreWrapper { - type Inner = T::Inner; -} - -impl InnerIvInit for StreamCipherCoreWrapper { +impl InnerInit for StreamCipherCoreWrapper { #[inline] - fn inner_iv_init(cipher: Self::Inner, iv: &Iv) -> Self { + fn inner_init(core: T) -> Self { Self { - core: T::inner_iv_init(cipher, iv), + core, buffer: Default::default(), } } From 149df98337bc41ac014c20dd4d1889a1094c9138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Wed, 8 Sep 2021 15:02:25 +0300 Subject: [PATCH 13/63] do not implement InnerInit for StreamCipherCoreWrapper --- cipher/src/stream_wrapper.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/cipher/src/stream_wrapper.rs b/cipher/src/stream_wrapper.rs index 0d00d2cb1..4aa91075d 100644 --- a/cipher/src/stream_wrapper.rs +++ b/cipher/src/stream_wrapper.rs @@ -3,7 +3,7 @@ use crate::{ StreamCipher, StreamCipherCore, StreamCipherSeek, StreamCipherSeekCore, }; use block_buffer::{inout::InOutBuf, BlockBuffer}; -use crypto_common::{BlockUser, InnerUser, InnerInit}; +use crypto_common::{BlockUser, KeyIvInit, Key, Iv, KeyUser, IvUser}; use generic_array::typenum::Unsigned; /// Wrapper around [`StreamCipherCore`] implementations. @@ -97,15 +97,23 @@ impl StreamCipherSeek for StreamCipherCoreWrapper { } } -impl InnerUser for StreamCipherCoreWrapper { - type Inner = T; +// ideally we would only implement the InitInner trait and everythin else +// would be handled by blanket impls, but unfortunately it will not work +// properly without mutually exclusive traits + +impl KeyUser for StreamCipherCoreWrapper { + type KeySize = T::KeySize; +} + +impl IvUser for StreamCipherCoreWrapper { + type IvSize = T::IvSize; } -impl InnerInit for StreamCipherCoreWrapper { +impl KeyIvInit for StreamCipherCoreWrapper { #[inline] - fn inner_init(core: T) -> Self { + fn new(key: &Key, iv: &Iv) -> Self { Self { - core, + core: T::new(key, iv), buffer: Default::default(), } } From a00ef4fa605a35fafc9827b612e97a5ecec62cfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Wed, 8 Sep 2021 18:54:12 +0300 Subject: [PATCH 14/63] add comment about blanket impl --- crypto-common/src/init.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/crypto-common/src/init.rs b/crypto-common/src/init.rs index 6a5f84cf9..802f7152f 100644 --- a/crypto-common/src/init.rs +++ b/crypto-common/src/init.rs @@ -165,6 +165,28 @@ where } } +// Unfortunately this blanket impl is impossible without mutually +// exclusive traits, see: https://github.com/rust-lang/rfcs/issues/1053 +/* +impl KeyIvInit for T +where + T: InnerInit, + T::Inner: KeyIvInit, +{ + #[inline] + fn new(key: &Key, iv: &Iv) -> Self { + Self::inner_init(T::Inner::new(key, iv)) + } + + #[inline] + fn new_from_slices(key: &[u8], iv: &[u8]) -> Result { + T::Inner::new_from_slice(key) + .map_err(|_| InvalidLength) + .map(Self::inner_init) + } +} +*/ + /// The error type returned when key and/or IV used in the [`KeyInit`], /// [`KeyIvInit`], and [`InnerIvInit`] slice-based methods had /// an invalid length. From 8c38ade50c074fe9ac9ca5985c2d3f85cc82a584 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Wed, 8 Sep 2021 18:55:53 +0300 Subject: [PATCH 15/63] add blanket impl KeyInit for stream wrapper --- cipher/src/stream_wrapper.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/cipher/src/stream_wrapper.rs b/cipher/src/stream_wrapper.rs index 4aa91075d..146e26e64 100644 --- a/cipher/src/stream_wrapper.rs +++ b/cipher/src/stream_wrapper.rs @@ -3,7 +3,7 @@ use crate::{ StreamCipher, StreamCipherCore, StreamCipherSeek, StreamCipherSeekCore, }; use block_buffer::{inout::InOutBuf, BlockBuffer}; -use crypto_common::{BlockUser, KeyIvInit, Key, Iv, KeyUser, IvUser}; +use crypto_common::{BlockUser, KeyIvInit, Key, Iv, KeyUser, IvUser, KeyInit}; use generic_array::typenum::Unsigned; /// Wrapper around [`StreamCipherCore`] implementations. @@ -101,11 +101,11 @@ impl StreamCipherSeek for StreamCipherCoreWrapper { // would be handled by blanket impls, but unfortunately it will not work // properly without mutually exclusive traits -impl KeyUser for StreamCipherCoreWrapper { +impl KeyUser for StreamCipherCoreWrapper { type KeySize = T::KeySize; } -impl IvUser for StreamCipherCoreWrapper { +impl IvUser for StreamCipherCoreWrapper { type IvSize = T::IvSize; } @@ -118,3 +118,13 @@ impl KeyIvInit for StreamCipherCoreWrapper { } } } + +impl KeyInit for StreamCipherCoreWrapper { + #[inline] + fn new(key: &Key) -> Self { + Self { + core: T::new(key), + buffer: Default::default(), + } + } +} From 67da8b460ef42ab6ae53df5373b710e6d2f63961 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Mon, 13 Sep 2021 20:57:59 +0300 Subject: [PATCH 16/63] crypto-common update --- crypto-common/src/core_wrapper.rs | 18 +++---- crypto-common/src/ct_output.rs | 2 +- crypto-common/src/init.rs | 84 +++++++----------------------- crypto-common/src/lib.rs | 51 +++++------------- crypto-common/src/users.rs | 86 +++++++++++++++++++++++++++++++ 5 files changed, 127 insertions(+), 114 deletions(-) create mode 100644 crypto-common/src/users.rs diff --git a/crypto-common/src/core_wrapper.rs b/crypto-common/src/core_wrapper.rs index 15d3a6a28..8e4becb05 100644 --- a/crypto-common/src/core_wrapper.rs +++ b/crypto-common/src/core_wrapper.rs @@ -1,13 +1,13 @@ //! Low-level core API traits. use super::{ - AlgorithmName, BufferUser, FixedOutput, FixedOutputCore, FixedOutputReset, KeyInit, KeyUser, - OutputSizeUser, Reset, Update, UpdateCore, + AlgorithmName, BufferUser, FixedOutput, FixedOutputCore, FixedOutputReset, KeyInit, + KeySizeUser, OutputSizeUser, Reset, Update, UpdateCore, }; use block_buffer::DigestBuffer; use core::fmt; use generic_array::GenericArray; -/// Wrapper around [`UpdateCore`] implementations. +/// Wrapper around [`BufferUser`]. /// /// It handles data buffering and implements the slice-based traits. #[derive(Clone, Default)] @@ -16,7 +16,7 @@ pub struct CoreWrapper { buffer: T::Buffer, } -impl CoreWrapper { +impl CoreWrapper { /// Create new wrapper from `core`. #[inline] pub fn from_core(core: T) -> Self { @@ -32,7 +32,7 @@ impl CoreWrapper { } } -impl CoreWrapper { +impl CoreWrapper { /// Apply function to core and buffer, return its result, /// and reset core and buffer. pub fn apply_reset(&mut self, mut f: impl FnMut(&mut T, &mut T::Buffer) -> V) -> V { @@ -44,11 +44,11 @@ impl CoreWrapper { } } -impl KeyUser for CoreWrapper { +impl KeySizeUser for CoreWrapper { type KeySize = T::KeySize; } -impl KeyInit for CoreWrapper { +impl KeyInit for CoreWrapper { fn new(key: &GenericArray) -> Self { Self { core: T::new(key), @@ -57,14 +57,14 @@ impl KeyInit for CoreWrapper { } } -impl fmt::Debug for CoreWrapper { +impl fmt::Debug for CoreWrapper { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { T::write_alg_name(f)?; f.write_str(" { .. }") } } -impl Reset for CoreWrapper { +impl Reset for CoreWrapper { #[inline] fn reset(&mut self) { self.core.reset(); diff --git a/crypto-common/src/ct_output.rs b/crypto-common/src/ct_output.rs index bf8e4f28a..7a94f1a0f 100644 --- a/crypto-common/src/ct_output.rs +++ b/crypto-common/src/ct_output.rs @@ -7,7 +7,7 @@ use subtle::{Choice, ConstantTimeEq}; /// It is useful for implementing Message Authentication Codes (MACs). #[derive(Clone)] #[cfg_attr(docsrs, doc(cfg(feature = "subtle")))] -pub struct CtOutput { +pub struct CtOutput { bytes: Output, } diff --git a/crypto-common/src/init.rs b/crypto-common/src/init.rs index 802f7152f..518ce3e58 100644 --- a/crypto-common/src/init.rs +++ b/crypto-common/src/init.rs @@ -1,61 +1,13 @@ //! Traits related to types initialization. +use crate::users::{InnerUser, Iv, IvSizeUser, Key, KeySizeUser}; use core::fmt; -use generic_array::{typenum::Unsigned, ArrayLength, GenericArray}; +use generic_array::typenum::Unsigned; #[cfg(feature = "rand_core")] use rand_core::{CryptoRng, RngCore}; -/// Key used by [`KeyUser`] implementors. -pub type Key = GenericArray::KeySize>; -/// Initialization vector (nonce) used by [`IvUser`] implementors. -pub type Iv = GenericArray::IvSize>; - -/// Types which use key for initialization. -/// -/// Generally it's used indirectly via [`KeyInit`] or [`KeyIvInit`]. -pub trait KeyUser { - /// Key size in bytes. - type KeySize: ArrayLength; - - /// Generate random key using the provided [`CryptoRng`]. - #[cfg(feature = "rand_core")] - #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] - #[inline] - fn generate_key(mut rng: impl CryptoRng + RngCore) -> Key { - let mut key = Key::::default(); - rng.fill_bytes(&mut key); - key - } -} - -/// Types which use initialization vector (nonce) for initialization. -/// -/// Generally it's used indirectly via [`KeyIvInit`] or [`InnerIvInit`]. -pub trait IvUser { - /// Initialization vector size in bytes. - type IvSize: ArrayLength; - - /// Generate random IV using the provided [`CryptoRng`]. - #[cfg(feature = "rand_core")] - #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] - #[inline] - fn generate_iv(mut rng: impl CryptoRng + RngCore) -> Iv { - let mut iv = Iv::::default(); - rng.fill_bytes(&mut iv); - iv - } -} - -/// Types which use another type for initialization. -/// -/// Generally it's used indirectly via [`InnerInit`] or [`InnerIvInit`]. -pub trait InnerUser { - /// Inner type. - type Inner; -} - /// Types which can be initialized from key. -pub trait KeyInit: KeyUser + Sized { +pub trait KeyInit: KeySizeUser + Sized { /// Create new value from fixed size key. fn new(key: &Key) -> Self; @@ -64,27 +16,28 @@ pub trait KeyInit: KeyUser + Sized { if key.len() != Self::KeySize::to_usize() { Err(InvalidLength) } else { - Ok(Self::new(GenericArray::from_slice(key))) + Ok(Self::new(Key::::from_slice(key))) } } } /// Types which can be initialized from key and initialization vector (nonce). -pub trait KeyIvInit: KeyUser + IvUser + Sized { +pub trait KeyIvInit: KeySizeUser + IvSizeUser + Sized { /// Create new value from fixed length key and nonce. fn new(key: &Key, iv: &Iv) -> Self; /// Create new value from variable length key and nonce. #[inline] fn new_from_slices(key: &[u8], iv: &[u8]) -> Result { - let kl = Self::KeySize::to_usize(); - let nl = Self::IvSize::to_usize(); - if key.len() != kl || iv.len() != nl { + let key_len = Self::KeySize::USIZE; + let iv_len = Self::IvSize::USIZE; + if key.len() != key_len || iv.len() != iv_len { Err(InvalidLength) } else { - let key = GenericArray::from_slice(key); - let iv = GenericArray::from_slice(iv); - Ok(Self::new(key, iv)) + Ok(Self::new( + Key::::from_slice(key), + Iv::::from_slice(iv), + )) } } @@ -109,26 +62,26 @@ pub trait InnerInit: InnerUser + Sized { /// vector/nonce. /// /// Usually used for initializing types from block ciphers. -pub trait InnerIvInit: InnerUser + IvUser + Sized { +pub trait InnerIvInit: InnerUser + IvSizeUser + Sized { /// Initialize value using `inner` and `iv` array. - fn inner_iv_init(inner: Self::Inner, iv: &GenericArray) -> Self; + fn inner_iv_init(inner: Self::Inner, iv: &Iv) -> Self; /// Initialize value using `inner` and `iv` slice. fn inner_iv_slice_init(inner: Self::Inner, iv: &[u8]) -> Result { if iv.len() != Self::IvSize::to_usize() { Err(InvalidLength) } else { - Ok(Self::inner_iv_init(inner, GenericArray::from_slice(iv))) + Ok(Self::inner_iv_init(inner, Iv::::from_slice(iv))) } } } -impl KeyUser for T +impl KeySizeUser for T where T: InnerUser, - T::Inner: KeyUser, + T::Inner: KeySizeUser, { - type KeySize = ::KeySize; + type KeySize = ::KeySize; } impl KeyIvInit for T @@ -167,6 +120,7 @@ where // Unfortunately this blanket impl is impossible without mutually // exclusive traits, see: https://github.com/rust-lang/rfcs/issues/1053 +// ot at the very least without: https://github.com/rust-lang/rust/issues/20400 /* impl KeyIvInit for T where diff --git a/crypto-common/src/lib.rs b/crypto-common/src/lib.rs index 1668f9e81..7afc5abfa 100644 --- a/crypto-common/src/lib.rs +++ b/crypto-common/src/lib.rs @@ -12,12 +12,7 @@ #[cfg(feature = "std")] extern crate std; -use block_buffer::DigestBuffer; use core::fmt; -use generic_array::{ - typenum::{type_operators::IsLess, U256}, - ArrayLength, GenericArray, -}; pub use block_buffer; #[cfg(feature = "subtle")] @@ -25,36 +20,20 @@ pub use block_buffer; pub use subtle; mod core_wrapper; -#[cfg(feature = "subtle")] -mod ct_output; mod init; +mod users; + +pub use core_wrapper::CoreWrapper; +pub use init::{InnerInit, InnerIvInit, InvalidLength, KeyInit, KeyIvInit}; +pub use users::{ + Block, BlockSizeUser, BufferUser, InnerUser, Iv, IvSizeUser, Key, KeySizeUser, Output, + OutputSizeUser, +}; -pub use core_wrapper::*; +#[cfg(feature = "subtle")] +mod ct_output; #[cfg(feature = "subtle")] pub use ct_output::CtOutput; -pub use init::*; - -/// Block on which [`BlockUser`] implementors operate. -pub type Block = GenericArray::BlockSize>; - -/// Output array of [`OutputSizeUser`] implementors. -pub type Output = GenericArray::OutputSize>; - -/// Types which process data in blocks. -pub trait BlockUser { - /// Size of the block in bytes. - type BlockSize: ArrayLength + IsLess + 'static; -} - -impl BlockUser for &Alg { - type BlockSize = Alg::BlockSize; -} - -/// Types which return data with the given size. -pub trait OutputSizeUser { - /// Size of the output in bytes. - type OutputSize: ArrayLength + 'static; -} /// Types which consume data with byte granularity. pub trait Update { @@ -98,21 +77,15 @@ pub trait Reset { } /// Types which consume data in blocks. -pub trait UpdateCore: BlockUser { +pub trait UpdateCore: BlockSizeUser { /// Update state using the provided data blocks. fn update_blocks(&mut self, blocks: &[Block]); } -/// Types which use [`DigestBuffer`] functionality. -pub trait BufferUser: BlockUser { - /// Block buffer type over which value operates. - type Buffer: DigestBuffer; -} - /// Core trait for hash functions with fixed output size. pub trait FixedOutputCore: UpdateCore + BufferUser + OutputSizeUser { /// Finalize state using remaining data stored in the provided block buffer, - /// write result into provided array using and leave value in a dirty state. + /// write result into provided array and leave `self` in a dirty state. fn finalize_fixed_core(&mut self, buffer: &mut Self::Buffer, out: &mut Output); } diff --git a/crypto-common/src/users.rs b/crypto-common/src/users.rs new file mode 100644 index 000000000..6af82b7be --- /dev/null +++ b/crypto-common/src/users.rs @@ -0,0 +1,86 @@ +use block_buffer::DigestBuffer; +use generic_array::{ + typenum::{type_operators::IsLess, U256}, + ArrayLength, GenericArray, +}; +#[cfg(feature = "rand_core")] +use rand_core::{CryptoRng, RngCore}; + +/// Block on which [`BlockUser`] implementors operate. +pub type Block = GenericArray::BlockSize>; +/// Output array of [`OutputSizeUser`] implementors. +pub type Output = GenericArray::OutputSize>; +/// Key used by [`KeyUser`] implementors. +pub type Key = GenericArray::KeySize>; +/// Initialization vector (nonce) used by [`IvUser`] implementors. +pub type Iv = GenericArray::IvSize>; + +/// Types which process data in blocks. +pub trait BlockSizeUser { + /// Size of the block in bytes. + type BlockSize: ArrayLength + IsLess + 'static; +} + +impl BlockSizeUser for &T { + type BlockSize = T::BlockSize; +} + +impl BlockSizeUser for &mut T { + type BlockSize = T::BlockSize; +} + +/// Types which return data with the given size. +pub trait OutputSizeUser { + /// Size of the output in bytes. + type OutputSize: ArrayLength + 'static; +} + +/// Types which use key for initialization. +/// +/// Generally it's used indirectly via [`KeyInit`] or [`KeyIvInit`]. +pub trait KeySizeUser { + /// Key size in bytes. + type KeySize: ArrayLength + 'static; + + /// Generate random key using the provided [`CryptoRng`]. + #[cfg(feature = "rand_core")] + #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] + #[inline] + fn generate_key(mut rng: impl CryptoRng + RngCore) -> Key { + let mut key = Key::::default(); + rng.fill_bytes(&mut key); + key + } +} + +/// Types which use initialization vector (nonce) for initialization. +/// +/// Generally it's used indirectly via [`KeyIvInit`] or [`InnerIvInit`]. +pub trait IvSizeUser { + /// Initialization vector size in bytes. + type IvSize: ArrayLength + 'static; + + /// Generate random IV using the provided [`CryptoRng`]. + #[cfg(feature = "rand_core")] + #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] + #[inline] + fn generate_iv(mut rng: impl CryptoRng + RngCore) -> Iv { + let mut iv = Iv::::default(); + rng.fill_bytes(&mut iv); + iv + } +} + +/// Types which use another type for initialization. +/// +/// Generally it's used indirectly via [`InnerInit`] or [`InnerIvInit`]. +pub trait InnerUser { + /// Inner type. + type Inner; +} + +/// Types which use [`DigestBuffer`] functionality. +pub trait BufferUser: BlockSizeUser { + /// Block buffer type over which value operates. + type Buffer: DigestBuffer; +} From 19923a10692c154f1e0cabb6a9d9a718c71b080d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Mon, 13 Sep 2021 21:05:59 +0300 Subject: [PATCH 17/63] cipher update --- cipher/src/block.rs | 12 ++++++------ cipher/src/lib.rs | 4 ++-- cipher/src/stream_core.rs | 14 ++++++++++---- cipher/src/stream_wrapper.rs | 14 +++++++------- 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/cipher/src/block.rs b/cipher/src/block.rs index 8ab24c605..24e74a336 100644 --- a/cipher/src/block.rs +++ b/cipher/src/block.rs @@ -13,13 +13,13 @@ use block_buffer::inout::{InOut, InOutBuf, InSrc, InTmpOutBuf, NotEqualError}; use generic_array::typenum::U1; -pub use crypto_common::{Block, BlockUser}; +pub use crypto_common::{Block, BlockSizeUser}; /// Marker trait for block ciphers. -pub trait BlockCipher: BlockUser {} +pub trait BlockCipher: BlockSizeUser {} /// Encrypt-only functionality for block ciphers. -pub trait BlockEncrypt: BlockUser { +pub trait BlockEncrypt: BlockSizeUser { /// Encrypt single `inout` block. fn encrypt_block_inout(&self, block: InOut<'_, Block>); @@ -96,7 +96,7 @@ pub trait BlockEncrypt: BlockUser { } /// Decrypt-only functionality for block ciphers. -pub trait BlockDecrypt: BlockUser { +pub trait BlockDecrypt: BlockSizeUser { /// Decrypt single `inout` block. fn decrypt_block_inout(&self, block: InOut<'_, Block>); @@ -177,7 +177,7 @@ pub trait BlockDecrypt: BlockUser { /// The main use case for this trait is blocks modes, but it also can be used /// for hardware cryptographic engines which require `&mut self` access to an /// underlying hardware peripheral. -pub trait BlockEncryptMut: BlockUser { +pub trait BlockEncryptMut: BlockSizeUser { /// Encrypt single `inout` block. fn encrypt_block_inout_mut(&mut self, block: InOut<'_, Block>); @@ -262,7 +262,7 @@ pub trait BlockEncryptMut: BlockUser { /// The main use case for this trait is blocks modes, but it also can be used /// for hardware cryptographic engines which require `&mut self` access to an /// underlying hardware peripheral. -pub trait BlockDecryptMut: BlockUser { +pub trait BlockDecryptMut: BlockSizeUser { /// Decrypt single `inout` block. fn decrypt_block_inout_mut(&mut self, block: InOut<'_, Block>); diff --git a/cipher/src/lib.rs b/cipher/src/lib.rs index 9ab175c0a..80465cea4 100644 --- a/cipher/src/lib.rs +++ b/cipher/src/lib.rs @@ -34,12 +34,12 @@ mod stream_wrapper; pub use crate::{block::*, errors::*, stream::*, stream_core::*, stream_wrapper::*}; pub use crypto_common::{ - Block, InnerIvInit, InvalidLength, Iv, IvUser, Key, KeyInit, KeyIvInit, KeyUser, + Block, InnerIvInit, InvalidLength, Iv, IvSizeUser, Key, KeyInit, KeyIvInit, KeySizeUser, }; pub use generic_array::{self, typenum::consts}; /// Trait for loading current IV state. -pub trait IvState: crypto_common::IvUser { +pub trait IvState: IvSizeUser { /// Returns current IV state. fn iv_state(&self) -> Iv; } diff --git a/cipher/src/stream_core.rs b/cipher/src/stream_core.rs index bea813e73..78062b133 100644 --- a/cipher/src/stream_core.rs +++ b/cipher/src/stream_core.rs @@ -1,13 +1,13 @@ use crate::{BlockDecryptMut, BlockEncryptMut}; use block_buffer::{generic_array::typenum::Unsigned, inout::InOutBuf}; use core::convert::{TryFrom, TryInto}; -use crypto_common::{Block, BlockUser}; +use crypto_common::{Block, BlockSizeUser}; /// Marker trait for block-level asynchronous stream ciphers pub trait AsyncStreamCipherCore: BlockEncryptMut + BlockDecryptMut {} /// Block-level synchronous stream ciphers. -pub trait StreamCipherCore: BlockUser + Sized { +pub trait StreamCipherCore: BlockSizeUser + Sized { /// Return number of remaining blocks before cipher wraps around. /// /// Returns `None` if number of remaining blocks can not be computed @@ -50,10 +50,16 @@ pub trait StreamCipherCore: BlockUser + Sized { } } -// note: unfortunately currently we can not write blanket impls of -// `BlockEncryptMut` and `BlockDecryptMut` for `StreamCipherCore` +// note: unfortunately, currently we can not write blanket impls of +// `BlockEncryptMut` and `BlockDecryptMut` for `T: StreamCipherCore` +// since it requires mutually exlusive traits, see: +// https://github.com/rust-lang/rfcs/issues/1053 /// Counter type usable with [`StreamCipherCore`]. +/// +/// This trait is implemented for `i32`, `u32`, `u64`, `u128`, and `usize`. +/// It's not intended to be implemented in third-party crates, but doing so +/// is not forbidden. pub trait Counter: TryFrom + TryFrom diff --git a/cipher/src/stream_wrapper.rs b/cipher/src/stream_wrapper.rs index 146e26e64..88ca27c70 100644 --- a/cipher/src/stream_wrapper.rs +++ b/cipher/src/stream_wrapper.rs @@ -3,19 +3,19 @@ use crate::{ StreamCipher, StreamCipherCore, StreamCipherSeek, StreamCipherSeekCore, }; use block_buffer::{inout::InOutBuf, BlockBuffer}; -use crypto_common::{BlockUser, KeyIvInit, Key, Iv, KeyUser, IvUser, KeyInit}; +use crypto_common::{BlockSizeUser, KeyIvInit, Key, Iv, KeySizeUser, IvSizeUser, KeyInit}; use generic_array::typenum::Unsigned; /// Wrapper around [`StreamCipherCore`] implementations. /// /// It handles data buffering and implements the slice-based traits. #[derive(Clone, Default)] -pub struct StreamCipherCoreWrapper { +pub struct StreamCipherCoreWrapper { core: T, buffer: BlockBuffer, } -impl StreamCipherCoreWrapper { +impl StreamCipherCoreWrapper { /// Get reference to core. pub fn get_core(&self) -> &T { &self.core @@ -101,15 +101,15 @@ impl StreamCipherSeek for StreamCipherCoreWrapper { // would be handled by blanket impls, but unfortunately it will not work // properly without mutually exclusive traits -impl KeyUser for StreamCipherCoreWrapper { +impl KeySizeUser for StreamCipherCoreWrapper { type KeySize = T::KeySize; } -impl IvUser for StreamCipherCoreWrapper { +impl IvSizeUser for StreamCipherCoreWrapper { type IvSize = T::IvSize; } -impl KeyIvInit for StreamCipherCoreWrapper { +impl KeyIvInit for StreamCipherCoreWrapper { #[inline] fn new(key: &Key, iv: &Iv) -> Self { Self { @@ -119,7 +119,7 @@ impl KeyIvInit for StreamCipherCoreWrapper { } } -impl KeyInit for StreamCipherCoreWrapper { +impl KeyInit for StreamCipherCoreWrapper { #[inline] fn new(key: &Key) -> Self { Self { From 714daa26881b15a6b55f23db6f65dab912564ac0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Mon, 13 Sep 2021 21:06:18 +0300 Subject: [PATCH 18/63] fmt --- cipher/src/stream_wrapper.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cipher/src/stream_wrapper.rs b/cipher/src/stream_wrapper.rs index 88ca27c70..7d7f9e874 100644 --- a/cipher/src/stream_wrapper.rs +++ b/cipher/src/stream_wrapper.rs @@ -3,7 +3,7 @@ use crate::{ StreamCipher, StreamCipherCore, StreamCipherSeek, StreamCipherSeekCore, }; use block_buffer::{inout::InOutBuf, BlockBuffer}; -use crypto_common::{BlockSizeUser, KeyIvInit, Key, Iv, KeySizeUser, IvSizeUser, KeyInit}; +use crypto_common::{BlockSizeUser, Iv, IvSizeUser, Key, KeyInit, KeyIvInit, KeySizeUser}; use generic_array::typenum::Unsigned; /// Wrapper around [`StreamCipherCore`] implementations. From 89f5bf225e0299a521b17de2dbf2e86e8cb71b46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Mon, 13 Sep 2021 21:29:10 +0300 Subject: [PATCH 19/63] update strem_wrapper note --- cipher/src/stream_wrapper.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cipher/src/stream_wrapper.rs b/cipher/src/stream_wrapper.rs index 7d7f9e874..095a3b768 100644 --- a/cipher/src/stream_wrapper.rs +++ b/cipher/src/stream_wrapper.rs @@ -97,9 +97,10 @@ impl StreamCipherSeek for StreamCipherCoreWrapper { } } -// ideally we would only implement the InitInner trait and everythin else -// would be handled by blanket impls, but unfortunately it will not work -// properly without mutually exclusive traits +// Note: ideally we would only implement the InitInner trait and everything +// else would be handled by blanket impls, but unfortunately it will +// not work properly without mutually exclusive traits, see: +// https://github.com/rust-lang/rfcs/issues/1053 impl KeySizeUser for StreamCipherCoreWrapper { type KeySize = T::KeySize; From 5b55e13c1948f4e006f22811c763cc943cdd81cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Mon, 13 Sep 2021 21:30:08 +0300 Subject: [PATCH 20/63] fix ct_output --- crypto-common/src/ct_output.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crypto-common/src/ct_output.rs b/crypto-common/src/ct_output.rs index 7a94f1a0f..242c19383 100644 --- a/crypto-common/src/ct_output.rs +++ b/crypto-common/src/ct_output.rs @@ -1,4 +1,4 @@ -use super::{FixedOutput, Output}; +use super::{OutputSizeUser, Output}; use subtle::{Choice, ConstantTimeEq}; /// Fixed size output value which provides a safe [`Eq`] implementation that @@ -11,7 +11,7 @@ pub struct CtOutput { bytes: Output, } -impl CtOutput { +impl CtOutput { /// Create a new [`CtOutput`] value. pub fn new(bytes: Output) -> Self { Self { bytes } @@ -23,28 +23,28 @@ impl CtOutput { } } -impl From> for CtOutput { +impl From> for CtOutput { fn from(bytes: Output) -> Self { Self { bytes } } } -impl<'a, T: FixedOutput> From<&'a Output> for CtOutput { +impl<'a, T: OutputSizeUser> From<&'a Output> for CtOutput { fn from(bytes: &'a Output) -> Self { bytes.clone().into() } } -impl ConstantTimeEq for CtOutput { +impl ConstantTimeEq for CtOutput { fn ct_eq(&self, other: &Self) -> Choice { self.bytes.ct_eq(&other.bytes) } } -impl PartialEq for CtOutput { +impl PartialEq for CtOutput { fn eq(&self, x: &CtOutput) -> bool { self.ct_eq(x).unwrap_u8() == 1 } } -impl Eq for CtOutput {} +impl Eq for CtOutput {} From 1c59f8ac7b1da23301b3de32683456ae274eac72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Mon, 13 Sep 2021 21:30:48 +0300 Subject: [PATCH 21/63] fix ct_output --- crypto-common/src/ct_output.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto-common/src/ct_output.rs b/crypto-common/src/ct_output.rs index 242c19383..e4e1be885 100644 --- a/crypto-common/src/ct_output.rs +++ b/crypto-common/src/ct_output.rs @@ -1,4 +1,4 @@ -use super::{OutputSizeUser, Output}; +use super::{Output, OutputSizeUser}; use subtle::{Choice, ConstantTimeEq}; /// Fixed size output value which provides a safe [`Eq`] implementation that From 7e25b1fdb1ff671cd36a860655224a5c51cee179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Mon, 13 Sep 2021 21:34:13 +0300 Subject: [PATCH 22/63] fix digest --- digest/src/core_api.rs | 4 ++-- digest/src/core_api/ct_variable.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/digest/src/core_api.rs b/digest/src/core_api.rs index 7998a7816..8f83015ea 100644 --- a/digest/src/core_api.rs +++ b/digest/src/core_api.rs @@ -7,7 +7,7 @@ use crate::{ExtendableOutput, InvalidOutputSize}; use generic_array::ArrayLength; pub use crypto_common::{ - AlgorithmName, Block, BlockUser, BufferUser, CoreWrapper, FixedOutputCore, OutputSizeUser, + AlgorithmName, Block, BlockSizeUser, BufferUser, CoreWrapper, FixedOutputCore, OutputSizeUser, Reset, UpdateCore, }; @@ -30,7 +30,7 @@ pub trait ExtendableOutputCore: UpdateCore + BufferUser { } /// Core reader trait for extendable-output function (XOF) result. -pub trait XofReaderCore: BlockUser { +pub trait XofReaderCore: BlockSizeUser { /// Read next XOF block. fn read_block(&mut self) -> Block; } diff --git a/digest/src/core_api/ct_variable.rs b/digest/src/core_api/ct_variable.rs index bda15a5e1..75f3babbb 100644 --- a/digest/src/core_api/ct_variable.rs +++ b/digest/src/core_api/ct_variable.rs @@ -1,6 +1,6 @@ use super::{AlgorithmName, FixedOutputCore, Reset, UpdateCore, VariableOutputCore}; use core::{fmt, marker::PhantomData}; -use crypto_common::{Block, BlockUser, BufferUser, OutputSizeUser}; +use crypto_common::{Block, BlockSizeUser, BufferUser, OutputSizeUser}; use generic_array::{ typenum::{IsLessOrEqual, LeEq, NonZero}, ArrayLength, GenericArray, @@ -19,7 +19,7 @@ where _out: PhantomData, } -impl BlockUser for CtVariableCoreWrapper +impl BlockSizeUser for CtVariableCoreWrapper where T: VariableOutputCore, OutSize: ArrayLength + IsLessOrEqual, From e1e3090a6fd683138e50e4862c9b9a214e27aa17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Mon, 13 Sep 2021 21:39:24 +0300 Subject: [PATCH 23/63] fix universal-hash --- universal-hash/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/universal-hash/src/lib.rs b/universal-hash/src/lib.rs index 3330fce9d..ed558ac8b 100644 --- a/universal-hash/src/lib.rs +++ b/universal-hash/src/lib.rs @@ -34,8 +34,8 @@ use core::slice; use generic_array::{typenum::Unsigned, GenericArray}; pub use crypto_common::{ - Block, BlockUser, CtOutput, FixedOutput, FixedOutputReset, Key, KeyInit, KeyUser, Output, - Reset, UpdateCore, + Block, BlockSizeUser, CtOutput, FixedOutput, FixedOutputReset, Key, KeyInit, KeySizeUser, + Output, Reset, UpdateCore, }; /// The [`UniversalHash`] trait defines a generic interface for universal hash From 545885e6526375477b4498cca7a8349cde4045b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Mon, 13 Sep 2021 22:09:24 +0300 Subject: [PATCH 24/63] cipher: fix dev module --- cipher/src/dev/block.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cipher/src/dev/block.rs b/cipher/src/dev/block.rs index 414748848..fec627d97 100644 --- a/cipher/src/dev/block.rs +++ b/cipher/src/dev/block.rs @@ -11,7 +11,7 @@ macro_rules! block_cipher_test { fn $name() { use cipher::generic_array::{typenum::Unsigned, GenericArray}; use cipher::{ - blobby::Blob3Iterator, BlockDecryptMut, BlockEncryptMut, BlockUser, KeyInit, + blobby::Blob3Iterator, BlockDecryptMut, BlockEncryptMut, BlockSizeUser, KeyInit, }; fn run_test(key: &[u8], pt: &[u8], ct: &[u8]) -> bool { From 5cca342554f21af26e943edc08fc3c327665849e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Wed, 15 Sep 2021 17:30:52 +0300 Subject: [PATCH 25/63] fix stream cipher test macros --- cipher/src/dev/stream.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cipher/src/dev/stream.rs b/cipher/src/dev/stream.rs index 01526a308..1339697e9 100644 --- a/cipher/src/dev/stream.rs +++ b/cipher/src/dev/stream.rs @@ -18,7 +18,7 @@ macro_rules! stream_cipher_test { let mut mode = <$cipher>::new_from_slices(key, iv).unwrap(); let mut pt = pt.to_vec(); for chunk in pt.chunks_mut(chunk_n) { - mode.apply_keystream_inplace(chunk); + mode.apply_keystream(chunk); } if pt != &ct[..] { panic!( @@ -53,7 +53,7 @@ macro_rules! stream_cipher_seek_test { const MAX_SEEK: usize = 512; let mut ct = [0u8; MAX_SEEK]; - get_cipher().apply_keystream_inplace(&mut ct[..]); + get_cipher().apply_keystream(&mut ct[..]); for n in 0..MAX_SEEK { let mut cipher = get_cipher(); @@ -61,7 +61,7 @@ macro_rules! stream_cipher_seek_test { cipher.seek(n); assert_eq!(cipher.current_pos::(), n); let mut buf = [0u8; MAX_SEEK]; - cipher.apply_keystream_inplace(&mut buf[n..]); + cipher.apply_keystream(&mut buf[n..]); assert_eq!(cipher.current_pos::(), MAX_SEEK); assert_eq!(&buf[n..], &ct[n..]); } @@ -72,12 +72,12 @@ macro_rules! stream_cipher_seek_test { let mut buf = [0u8; MAX_CHUNK]; let mut cipher = get_cipher(); assert_eq!(cipher.current_pos::(), 0); - cipher.apply_keystream_inplace(&mut []); + cipher.apply_keystream(&mut []); assert_eq!(cipher.current_pos::(), 0); for n in 1..MAX_CHUNK { assert_eq!(cipher.current_pos::(), 0); for m in 1.. { - cipher.apply_keystream_inplace(&mut buf[..n]); + cipher.apply_keystream(&mut buf[..n]); assert_eq!(cipher.current_pos::(), n * m); if n * m > MAX_LEN { break; From f93dace438e0ab2d9bd6e4e2c9d4dc5ab2e935c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Wed, 15 Sep 2021 17:53:24 +0300 Subject: [PATCH 26/63] fix SeekNum impl --- cipher/src/stream.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cipher/src/stream.rs b/cipher/src/stream.rs index bee396eb1..ae728f47b 100644 --- a/cipher/src/stream.rs +++ b/cipher/src/stream.rs @@ -149,7 +149,10 @@ macro_rules! impl_seek_num { impl SeekNum for $t { fn from_block_byte(block: T, byte: usize, bs: usize) -> Result { debug_assert!(byte < bs); - let block: Self = block.try_into().map_err(|_| OverflowError)?; + let mut block: Self = block.try_into().map_err(|_| OverflowError)?; + if byte != 0 { + block -= 1; + } let pos = block.checked_mul(bs as Self).ok_or(OverflowError)? + (byte as Self); Ok(pos) } From 6cde8298210c1771ca41df14d7e843282770297b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Wed, 15 Sep 2021 17:59:40 +0300 Subject: [PATCH 27/63] fix benches --- cipher/src/dev/stream.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cipher/src/dev/stream.rs b/cipher/src/dev/stream.rs index 1339697e9..a89d4763d 100644 --- a/cipher/src/dev/stream.rs +++ b/cipher/src/dev/stream.rs @@ -172,7 +172,7 @@ macro_rules! stream_cipher_sync_bench { ($cipher:path) => { extern crate test; - use cipher::{generic_array::GenericArray, NewCipher, StreamCipher}; + use cipher::{generic_array::GenericArray, KeyIvInit, StreamCipher}; use test::Bencher; #[inline(never)] @@ -224,7 +224,7 @@ macro_rules! stream_cipher_async_bench { ($cipher:path) => { extern crate test; - use cipher::{generic_array::GenericArray, AsyncStreamCipher, NewCipher}; + use cipher::{generic_array::GenericArray, AsyncStreamCipher, KeyIvInit}; use test::Bencher; #[inline(never)] From 8809473b872242efb7bc15775706fe3f97db5ed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Wed, 15 Sep 2021 21:56:22 +0300 Subject: [PATCH 28/63] cipher re-export block-buffer --- cipher/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/cipher/src/lib.rs b/cipher/src/lib.rs index 80465cea4..5b262212e 100644 --- a/cipher/src/lib.rs +++ b/cipher/src/lib.rs @@ -22,6 +22,7 @@ extern crate std; #[cfg(feature = "dev")] pub use blobby; +pub use block_buffer; pub use block_buffer::inout; mod block; From 8f9d86c2e1939b814e86906b363b8a5f3c9ecaab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Tue, 21 Sep 2021 16:11:52 +0300 Subject: [PATCH 29/63] remove restriction on BlockSize --- crypto-common/src/users.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/crypto-common/src/users.rs b/crypto-common/src/users.rs index 6af82b7be..644911f16 100644 --- a/crypto-common/src/users.rs +++ b/crypto-common/src/users.rs @@ -1,8 +1,5 @@ use block_buffer::DigestBuffer; -use generic_array::{ - typenum::{type_operators::IsLess, U256}, - ArrayLength, GenericArray, -}; +use generic_array::{ArrayLength, GenericArray}; #[cfg(feature = "rand_core")] use rand_core::{CryptoRng, RngCore}; @@ -18,7 +15,7 @@ pub type Iv = GenericArray::IvSize>; /// Types which process data in blocks. pub trait BlockSizeUser { /// Size of the block in bytes. - type BlockSize: ArrayLength + IsLess + 'static; + type BlockSize: ArrayLength + 'static; } impl BlockSizeUser for &T { From 5ff8e4f2e5a345e870cbf94be2e802c15d7776cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Tue, 21 Sep 2021 18:48:31 +0300 Subject: [PATCH 30/63] add encrypt/decrypt methods to AsyncStreamCipher --- cipher/src/stream.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/cipher/src/stream.rs b/cipher/src/stream.rs index ae728f47b..781d5049d 100644 --- a/cipher/src/stream.rs +++ b/cipher/src/stream.rs @@ -97,11 +97,21 @@ pub trait StreamCipherSeek { /// Asynchronous stream cipher. pub trait AsyncStreamCipher { - /// Encrypt data in place. + /// Encrypt data using `InOutBuf`. fn encrypt_inout(&mut self, buf: InOutBuf<'_, u8>); - /// Decrypt data in place. + /// Decrypt data using `InOutBuf`. fn decrypt_inout(&mut self, buf: InOutBuf<'_, u8>); + + /// Encrypt data in place. + fn encrypt(&mut self, buf: &mut [u8]) { + self.encrypt_inout(buf.into()); + } + + /// Decrypt data in place. + fn decrypt(&mut self, buf: &mut [u8]) { + self.decrypt_inout(buf.into()); + } } impl StreamCipher for &mut C { From 6dd2d0279c55b0069c0c8121167a5111d3c0bcc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Tue, 21 Sep 2021 19:10:26 +0300 Subject: [PATCH 31/63] fix stream wrapper --- Cargo.lock | 6 ++--- cipher/src/stream_wrapper.rs | 48 ++++++++++++++++++++++++------------ 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 08c2a3d98..b8ba56ebb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -67,7 +67,7 @@ dependencies = [ [[package]] name = "block-buffer" version = "0.10.0" -source = "git+https://github.com/RustCrypto/utils?branch=pad_error#6b7199fb78dba025deb1e4f46bdaf10ee812341e" +source = "git+https://github.com/RustCrypto/utils?branch=pad_error#6bd6ade2bc6db1f168f853e2c4a7ed16d623df41" dependencies = [ "block-padding", "generic-array", @@ -77,7 +77,7 @@ dependencies = [ [[package]] name = "block-padding" version = "0.3.0" -source = "git+https://github.com/RustCrypto/utils?branch=pad_error#6b7199fb78dba025deb1e4f46bdaf10ee812341e" +source = "git+https://github.com/RustCrypto/utils?branch=pad_error#6bd6ade2bc6db1f168f853e2c4a7ed16d623df41" dependencies = [ "generic-array", ] @@ -307,7 +307,7 @@ checksum = "21e4590e13640f19f249fe3e4eca5113bc4289f2497710378190e7f4bd96f45b" [[package]] name = "inout" version = "0.1.0" -source = "git+https://github.com/RustCrypto/utils?branch=pad_error#6b7199fb78dba025deb1e4f46bdaf10ee812341e" +source = "git+https://github.com/RustCrypto/utils?branch=pad_error#6bd6ade2bc6db1f168f853e2c4a7ed16d623df41" dependencies = [ "generic-array", ] diff --git a/cipher/src/stream_wrapper.rs b/cipher/src/stream_wrapper.rs index 095a3b768..ef13d0b5d 100644 --- a/cipher/src/stream_wrapper.rs +++ b/cipher/src/stream_wrapper.rs @@ -32,25 +32,41 @@ impl StreamCipherCoreWrapper { } } -impl StreamCipher for StreamCipherCoreWrapper { - #[inline] - fn try_apply_keystream(&mut self, data: InOutBuf<'_, u8>) -> Result<(), StreamCipherError> { - if let Some(rem_blocks) = self.core.remaining_blocks() { - let bytes = if self.buffer.get_pos() == 0 { - data.len() +impl StreamCipherCoreWrapper { + fn check_remaining(&self, dlen: usize) -> Result<(), StreamCipherError> { + let rem_blocks = match self.core.remaining_blocks() { + Some(v) => v, + None => return Ok(()), + }; + + let bytes = if self.buffer.get_pos() == 0 { + dlen + } else { + let rem = self.buffer.remaining(); + if dlen > rem { + dlen - rem } else { - data.len() - self.buffer.remaining() - }; - let bs = T::BlockSize::USIZE; - let blocks = if bytes % bs == 0 { - bytes / bs - } else { - bytes / bs + 1 - }; - if blocks > rem_blocks { - return Err(StreamCipherError); + return Ok(()); } + }; + let bs = T::BlockSize::USIZE; + let blocks = if bytes % bs == 0 { + bytes / bs + } else { + bytes / bs + 1 + }; + if blocks > rem_blocks { + Err(StreamCipherError) + } else { + Ok(()) } + } +} + +impl StreamCipher for StreamCipherCoreWrapper { + #[inline] + fn try_apply_keystream(&mut self, data: InOutBuf<'_, u8>) -> Result<(), StreamCipherError> { + self.check_remaining(data.len())?; let Self { core, buffer } = self; buffer.xor_data(data, |blocks| { From 4c5c3b781e4f64834404b0c2ab3c6dfe376f2ae5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Tue, 21 Sep 2021 20:30:32 +0300 Subject: [PATCH 32/63] change async stream cipher --- cipher/src/stream.rs | 67 +++++++++++++++++++----------------- cipher/src/stream_core.rs | 4 --- cipher/src/stream_wrapper.rs | 16 +-------- 3 files changed, 37 insertions(+), 50 deletions(-) diff --git a/cipher/src/stream.rs b/cipher/src/stream.rs index 781d5049d..7f4fa7d8b 100644 --- a/cipher/src/stream.rs +++ b/cipher/src/stream.rs @@ -5,8 +5,44 @@ use crate::errors::{OverflowError, StreamCipherError}; use crate::stream_core::Counter; +use crate::{Block, BlockDecryptMut, BlockEncryptMut}; use block_buffer::inout::InOutBuf; +/// Marker trait for block-level asynchronous stream ciphers +pub trait AsyncStreamCipher: BlockEncryptMut + BlockDecryptMut + Sized { + /// Encrypt data using `InOutBuf`. + fn encrypt_inout(mut self, data: InOutBuf<'_, u8>) { + let (blocks, tail) = data.into_chunks(); + self.encrypt_blocks_inout_mut(blocks, |_| {}); + let mut block = Block::::default(); + let n = tail.len(); + block[..n].copy_from_slice(tail.get_in()); + self.encrypt_block_mut(&mut block); + tail.get_out().copy_from_slice(&block[..n]); + } + + /// Decrypt data using `InOutBuf`. + fn decrypt_inout(mut self, data: InOutBuf<'_, u8>) { + let (blocks, tail) = data.into_chunks(); + self.decrypt_blocks_inout_mut(blocks, |_| {}); + let mut block = Block::::default(); + let n = tail.len(); + block[..n].copy_from_slice(tail.get_in()); + self.decrypt_block_mut(&mut block); + tail.get_out().copy_from_slice(&block[..n]); + } + + /// Encrypt data in place. + fn encrypt(self, buf: &mut [u8]) { + self.encrypt_inout(buf.into()); + } + + /// Decrypt data in place. + fn decrypt(self, buf: &mut [u8]) { + self.decrypt_inout(buf.into()); + } +} + /// Synchronous stream cipher core trait. pub trait StreamCipher { /// Apply keystream to data behind `buf` and return explicit result. @@ -95,25 +131,6 @@ pub trait StreamCipherSeek { } } -/// Asynchronous stream cipher. -pub trait AsyncStreamCipher { - /// Encrypt data using `InOutBuf`. - fn encrypt_inout(&mut self, buf: InOutBuf<'_, u8>); - - /// Decrypt data using `InOutBuf`. - fn decrypt_inout(&mut self, buf: InOutBuf<'_, u8>); - - /// Encrypt data in place. - fn encrypt(&mut self, buf: &mut [u8]) { - self.encrypt_inout(buf.into()); - } - - /// Decrypt data in place. - fn decrypt(&mut self, buf: &mut [u8]) { - self.decrypt_inout(buf.into()); - } -} - impl StreamCipher for &mut C { #[inline] fn apply_keystream_inout(&mut self, buf: InOutBuf<'_, u8>) { @@ -126,18 +143,6 @@ impl StreamCipher for &mut C { } } -impl AsyncStreamCipher for &mut C { - #[inline] - fn encrypt_inout(&mut self, buf: InOutBuf<'_, u8>) { - C::encrypt_inout(self, buf); - } - - #[inline] - fn decrypt_inout(&mut self, buf: InOutBuf<'_, u8>) { - C::decrypt_inout(self, buf); - } -} - /// Trait implemented for numeric types which can be used with the /// [`StreamCipherSeek`] trait. /// diff --git a/cipher/src/stream_core.rs b/cipher/src/stream_core.rs index 78062b133..c0522a1ff 100644 --- a/cipher/src/stream_core.rs +++ b/cipher/src/stream_core.rs @@ -1,11 +1,7 @@ -use crate::{BlockDecryptMut, BlockEncryptMut}; use block_buffer::{generic_array::typenum::Unsigned, inout::InOutBuf}; use core::convert::{TryFrom, TryInto}; use crypto_common::{Block, BlockSizeUser}; -/// Marker trait for block-level asynchronous stream ciphers -pub trait AsyncStreamCipherCore: BlockEncryptMut + BlockDecryptMut {} - /// Block-level synchronous stream ciphers. pub trait StreamCipherCore: BlockSizeUser + Sized { /// Return number of remaining blocks before cipher wraps around. diff --git a/cipher/src/stream_wrapper.rs b/cipher/src/stream_wrapper.rs index ef13d0b5d..c4aabc9c9 100644 --- a/cipher/src/stream_wrapper.rs +++ b/cipher/src/stream_wrapper.rs @@ -1,5 +1,5 @@ use crate::{ - errors::StreamCipherError, AsyncStreamCipher, AsyncStreamCipherCore, OverflowError, SeekNum, + errors::StreamCipherError, OverflowError, SeekNum, StreamCipher, StreamCipherCore, StreamCipherSeek, StreamCipherSeekCore, }; use block_buffer::{inout::InOutBuf, BlockBuffer}; @@ -77,20 +77,6 @@ impl StreamCipher for StreamCipherCoreWrapper { } } -impl AsyncStreamCipher for StreamCipherCoreWrapper { - #[inline] - fn encrypt_inout(&mut self, data: InOutBuf<'_, u8>) { - let Self { core, buffer } = self; - buffer.xor_data(data, |blocks| core.encrypt_blocks_inout_mut(blocks, |_| {})); - } - - #[inline] - fn decrypt_inout(&mut self, data: InOutBuf<'_, u8>) { - let Self { core, buffer } = self; - buffer.xor_data(data, |blocks| core.decrypt_blocks_inout_mut(blocks, |_| {})); - } -} - impl StreamCipherSeek for StreamCipherCoreWrapper { fn try_current_pos(&self) -> Result { let Self { core, buffer } = self; From f6559dbfbd20740d3232bc835a5cbf9451602d56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Tue, 21 Sep 2021 21:04:54 +0300 Subject: [PATCH 33/63] async stream cipher fix --- cipher/src/stream.rs | 48 +++++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/cipher/src/stream.rs b/cipher/src/stream.rs index 7f4fa7d8b..7373c0342 100644 --- a/cipher/src/stream.rs +++ b/cipher/src/stream.rs @@ -11,35 +11,59 @@ use block_buffer::inout::InOutBuf; /// Marker trait for block-level asynchronous stream ciphers pub trait AsyncStreamCipher: BlockEncryptMut + BlockDecryptMut + Sized { /// Encrypt data using `InOutBuf`. - fn encrypt_inout(mut self, data: InOutBuf<'_, u8>) { + fn encrypt_inout( + mut self, + data: InOutBuf<'_, u8>, + mut post_fn: impl FnMut(&[Block]), + ) { let (blocks, tail) = data.into_chunks(); - self.encrypt_blocks_inout_mut(blocks, |_| {}); + self.encrypt_blocks_inout_mut( + blocks, + |mut buf| { + buf.copy_tmp2out(); + post_fn(buf.get_out()); + }, + ); let mut block = Block::::default(); let n = tail.len(); - block[..n].copy_from_slice(tail.get_in()); - self.encrypt_block_mut(&mut block); - tail.get_out().copy_from_slice(&block[..n]); + if n != 0 { + block[..n].copy_from_slice(tail.get_in()); + self.encrypt_block_mut(&mut block); + tail.get_out().copy_from_slice(&block[..n]); + } } /// Decrypt data using `InOutBuf`. - fn decrypt_inout(mut self, data: InOutBuf<'_, u8>) { + fn decrypt_inout( + mut self, + data: InOutBuf<'_, u8>, + mut post_fn: impl FnMut(&[Block]), + ) { let (blocks, tail) = data.into_chunks(); - self.decrypt_blocks_inout_mut(blocks, |_| {}); + self.decrypt_blocks_inout_mut( + blocks, + |mut buf| { + buf.copy_tmp2out(); + post_fn(buf.get_out()); + }, + ); let mut block = Block::::default(); let n = tail.len(); - block[..n].copy_from_slice(tail.get_in()); - self.decrypt_block_mut(&mut block); - tail.get_out().copy_from_slice(&block[..n]); + if n != 0 { + block[..n].copy_from_slice(tail.get_in()); + self.decrypt_block_mut(&mut block); + tail.get_out().copy_from_slice(&block[..n]); + } } /// Encrypt data in place. fn encrypt(self, buf: &mut [u8]) { - self.encrypt_inout(buf.into()); + self.encrypt_inout(buf.into(), |_| {}); } /// Decrypt data in place. fn decrypt(self, buf: &mut [u8]) { - self.decrypt_inout(buf.into()); + self.decrypt_inout(buf.into(), |_| {}); } } From dce3879b52c2f8d40bfe70fb164812c96631ec43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Wed, 20 Oct 2021 18:11:53 +0300 Subject: [PATCH 34/63] temporary depend on inout directly --- Cargo.lock | 109 +++++++++++++++++++++++--------------- cipher/Cargo.toml | 4 +- cipher/src/block.rs | 2 +- cipher/src/lib.rs | 6 +-- cipher/src/stream.rs | 2 +- cipher/src/stream_core.rs | 3 +- 6 files changed, 77 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b8ba56ebb..d4d80187d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -33,9 +33,9 @@ dependencies = [ [[package]] name = "base64ct" -version = "1.0.1" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b" +checksum = "e6b4d9b1225d28d360ec6a231d65af1fd99a2a095154c8040689617290569c5c" [[package]] name = "bitvec" @@ -67,17 +67,16 @@ dependencies = [ [[package]] name = "block-buffer" version = "0.10.0" -source = "git+https://github.com/RustCrypto/utils?branch=pad_error#6bd6ade2bc6db1f168f853e2c4a7ed16d623df41" +source = "git+https://github.com/RustCrypto/utils?branch=pad_error#c3b7bf938b88f227b4a9349373f4657c457306aa" dependencies = [ "block-padding", "generic-array", - "inout", ] [[package]] name = "block-padding" version = "0.3.0" -source = "git+https://github.com/RustCrypto/utils?branch=pad_error#6bd6ade2bc6db1f168f853e2c4a7ed16d623df41" +source = "git+https://github.com/RustCrypto/utils?branch=pad_error#c3b7bf938b88f227b4a9349373f4657c457306aa" dependencies = [ "generic-array", ] @@ -111,13 +110,14 @@ dependencies = [ "block-buffer 0.10.0", "crypto-common", "generic-array", + "inout", ] [[package]] name = "const-oid" -version = "0.6.0" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c32f031ea41b4291d695026c023b95d59db2d8a2c7640800ed56bc8f510f22" +checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b" [[package]] name = "cpufeatures" @@ -144,9 +144,9 @@ dependencies = [ [[package]] name = "crypto-bigint" -version = "0.2.4" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc209804a22c34a98fe26a32d997ac64d4284816f65cf1a529c4e31a256218a0" +checksum = "f83bd3bb4314701c568e340cd8cf78c975aa0ca79e03d3f6d1677d5b0c9c0c03" dependencies = [ "generic-array", "rand_core", @@ -187,9 +187,9 @@ dependencies = [ [[package]] name = "der" -version = "0.4.0" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f215f706081a44cb702c71c39a52c05da637822e9c1645a50b7202689e982d" +checksum = "28e98c534e9c8a0483aa01d6f6913bc063de254311bd267c9cf535e9b70e15b2" dependencies = [ "const-oid", ] @@ -290,11 +290,12 @@ dependencies = [ [[package]] name = "heapless" -version = "0.7.5" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50530280e9a947b192e3a30a9d7bcead527b22da30ff7cbd334233d820aaf82a" +checksum = "fe65ef062f1af5b1b189842b0bc45bd671c38e1d22c6aa22e6ada03d01026d53" dependencies = [ "hash32", + "spin", "stable_deref_trait", ] @@ -307,22 +308,31 @@ checksum = "21e4590e13640f19f249fe3e4eca5113bc4289f2497710378190e7f4bd96f45b" [[package]] name = "inout" version = "0.1.0" -source = "git+https://github.com/RustCrypto/utils?branch=pad_error#6bd6ade2bc6db1f168f853e2c4a7ed16d623df41" +source = "git+https://github.com/RustCrypto/utils?branch=pad_error#c3b7bf938b88f227b4a9349373f4657c457306aa" dependencies = [ "generic-array", ] [[package]] name = "itoa" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "libc" -version = "0.2.101" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" +checksum = "7b2f96d100e1cf1929e7719b7edb3b90ab5298072638fccd77be9ce942ecdfce" + +[[package]] +name = "lock_api" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +dependencies = [ + "scopeguard", +] [[package]] name = "opaque-debug" @@ -341,18 +351,18 @@ dependencies = [ [[package]] name = "pem-rfc7468" -version = "0.2.0" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fe90c78c9a17442665a41a1a45dcd24bbab0e1794748edc19b27fffb146c13" +checksum = "8f22eb0e3c593294a99e9ff4b24cf6b752d43f193aa4415fe5077c159996d497" dependencies = [ "base64ct", ] [[package]] name = "pkcs8" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbee84ed13e44dd82689fa18348a49934fa79cc774a344c42fc9b301c71b140a" +checksum = "ee3ef9b64d26bad0536099c816c6734379e45bbd5f14798def6809e5cc350447" dependencies = [ "der", "pem-rfc7468", @@ -362,18 +372,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.28" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" +checksum = "edc3358ebc67bc8b7fa0c007f945b0b18226f78437d61bec735a9eb96b61ee70" dependencies = [ "unicode-xid", ] [[package]] name = "quote" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" dependencies = [ "proc-macro2", ] @@ -399,17 +409,23 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "serde" -version = "1.0.129" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1f72836d2aa753853178eda473a3b9d8e4eefdaf20523b919677e6de489f8f1" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" [[package]] name = "serde_json" -version = "1.0.66" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "336b10da19a12ad094b59d870ebde26a45402e5b470add4b5fd03c5048a32127" +checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" dependencies = [ "itoa", "ryu", @@ -418,9 +434,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.9.6" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9204c41a1597a8c5af23c82d1c921cb01ec0a4c59e07a9c7306062829a3903f3" +checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" dependencies = [ "block-buffer 0.9.0", "cfg-if", @@ -450,11 +466,20 @@ dependencies = [ "synstructure", ] +[[package]] +name = "spin" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "511254be0c5bcf062b019a6c89c01a664aa359ded62f78aa72c6fc137c0590e5" +dependencies = [ + "lock_api", +] + [[package]] name = "spki" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "987637c5ae6b3121aba9d513f869bd2bff11c4cc086c22473befd6649c0bd521" +checksum = "5c01a0c15da1b0b0e1494112e7af814a678fec9bd157881b49beac661e9b6f32" dependencies = [ "der", ] @@ -473,9 +498,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.74" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" +checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194" dependencies = [ "proc-macro2", "quote", @@ -484,9 +509,9 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.12.5" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "474aaa926faa1603c40b7885a9eaea29b444d1cb2850cb7c0e37bb1a4182f4fa" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ "proc-macro2", "quote", @@ -502,9 +527,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "typenum" -version = "1.13.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" +checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" [[package]] name = "unicode-xid" @@ -553,6 +578,6 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "377db0846015f7ae377174787dd452e1c5f5a9050bc6f954911d01f116daa0cd" +checksum = "bf68b08513768deaa790264a7fac27a58cbf2705cfcdc9448362229217d7e970" diff --git a/cipher/Cargo.toml b/cipher/Cargo.toml index 94f9ae3ae..cebdafc60 100644 --- a/cipher/Cargo.toml +++ b/cipher/Cargo.toml @@ -14,7 +14,9 @@ categories = ["cryptography", "no-std"] [dependencies] generic-array = "0.14" crypto-common = { version = "0.1", path = "../crypto-common" } -block-buffer = { version = "0.10.0", features = ["block-padding", "inout"] } +block-buffer = { version = "0.10.0", features = ["block-padding"] } +# TODO: remove and use re-import from block-buffer +inout = "0.1" # optional dependencies blobby = { version = "0.3", optional = true } diff --git a/cipher/src/block.rs b/cipher/src/block.rs index 24e74a336..56dcca0f9 100644 --- a/cipher/src/block.rs +++ b/cipher/src/block.rs @@ -10,7 +10,7 @@ //! [2]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation //! [3]: https://en.wikipedia.org/wiki/Symmetric-key_algorithm -use block_buffer::inout::{InOut, InOutBuf, InSrc, InTmpOutBuf, NotEqualError}; +use inout::{InOut, InOutBuf, InSrc, InTmpOutBuf, NotEqualError}; use generic_array::typenum::U1; pub use crypto_common::{Block, BlockSizeUser}; diff --git a/cipher/src/lib.rs b/cipher/src/lib.rs index 5b262212e..65336f051 100644 --- a/cipher/src/lib.rs +++ b/cipher/src/lib.rs @@ -23,7 +23,7 @@ extern crate std; pub use blobby; pub use block_buffer; -pub use block_buffer::inout; +// pub use block_buffer::inout; mod block; #[cfg(feature = "dev")] @@ -31,9 +31,9 @@ mod dev; mod errors; mod stream; mod stream_core; -mod stream_wrapper; +// mod stream_wrapper; -pub use crate::{block::*, errors::*, stream::*, stream_core::*, stream_wrapper::*}; +pub use crate::{block::*, errors::*, stream::*, stream_core::*};//, stream_wrapper::*}; pub use crypto_common::{ Block, InnerIvInit, InvalidLength, Iv, IvSizeUser, Key, KeyInit, KeyIvInit, KeySizeUser, }; diff --git a/cipher/src/stream.rs b/cipher/src/stream.rs index 7373c0342..abde5e25f 100644 --- a/cipher/src/stream.rs +++ b/cipher/src/stream.rs @@ -6,7 +6,7 @@ use crate::errors::{OverflowError, StreamCipherError}; use crate::stream_core::Counter; use crate::{Block, BlockDecryptMut, BlockEncryptMut}; -use block_buffer::inout::InOutBuf; +use inout::InOutBuf; /// Marker trait for block-level asynchronous stream ciphers pub trait AsyncStreamCipher: BlockEncryptMut + BlockDecryptMut + Sized { diff --git a/cipher/src/stream_core.rs b/cipher/src/stream_core.rs index c0522a1ff..e43666467 100644 --- a/cipher/src/stream_core.rs +++ b/cipher/src/stream_core.rs @@ -1,4 +1,5 @@ -use block_buffer::{generic_array::typenum::Unsigned, inout::InOutBuf}; +use block_buffer::{generic_array::typenum::Unsigned}; +use inout::InOutBuf; use core::convert::{TryFrom, TryInto}; use crypto_common::{Block, BlockSizeUser}; From 034d4f5494e211b06152c85fd5050e021ad4dbc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Wed, 20 Oct 2021 18:33:10 +0300 Subject: [PATCH 35/63] add inline attributes --- crypto-common/src/ct_output.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crypto-common/src/ct_output.rs b/crypto-common/src/ct_output.rs index e4e1be885..1cc16e870 100644 --- a/crypto-common/src/ct_output.rs +++ b/crypto-common/src/ct_output.rs @@ -13,35 +13,41 @@ pub struct CtOutput { impl CtOutput { /// Create a new [`CtOutput`] value. + #[inline(always)] pub fn new(bytes: Output) -> Self { Self { bytes } } /// Get the inner [`Output`] array this type wraps. + #[inline(always)] pub fn into_bytes(self) -> Output { self.bytes } } impl From> for CtOutput { + #[inline(always)] fn from(bytes: Output) -> Self { Self { bytes } } } impl<'a, T: OutputSizeUser> From<&'a Output> for CtOutput { + #[inline(always)] fn from(bytes: &'a Output) -> Self { bytes.clone().into() } } impl ConstantTimeEq for CtOutput { + #[inline(always)] fn ct_eq(&self, other: &Self) -> Choice { self.bytes.ct_eq(&other.bytes) } } impl PartialEq for CtOutput { + #[inline(always)] fn eq(&self, x: &CtOutput) -> bool { self.ct_eq(x).unwrap_u8() == 1 } From a96a2c74cf8c0ae0bc351bf0587a918743b47598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Wed, 20 Oct 2021 18:57:38 +0300 Subject: [PATCH 36/63] crypto-mac: remove cipher dependency --- Cargo.lock | 1 - crypto-mac/Cargo.toml | 1 - crypto-mac/src/lib.rs | 3 --- 3 files changed, 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d4d80187d..223d5e563 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -179,7 +179,6 @@ name = "crypto-mac" version = "0.12.0-pre" dependencies = [ "blobby", - "cipher 0.4.0", "crypto-common", "generic-array", "rand_core", diff --git a/crypto-mac/Cargo.toml b/crypto-mac/Cargo.toml index 1980a8f73..19b2e3014 100644 --- a/crypto-mac/Cargo.toml +++ b/crypto-mac/Cargo.toml @@ -14,7 +14,6 @@ categories = ["cryptography", "no-std"] [dependencies] generic-array = "0.14" crypto-common = { version = "0.1", features = ["subtle"], path = "../crypto-common" } -cipher = { version = "0.4", path = "../cipher" } blobby = { version = "0.3", optional = true } rand_core = { version = "0.6", optional = true } diff --git a/crypto-mac/src/lib.rs b/crypto-mac/src/lib.rs index 0ad0491b4..b9dc48ea7 100644 --- a/crypto-mac/src/lib.rs +++ b/crypto-mac/src/lib.rs @@ -17,9 +17,6 @@ extern crate std; #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] pub use rand_core; -#[cfg(feature = "cipher")] -pub use cipher; - #[cfg(feature = "dev")] #[cfg_attr(docsrs, doc(cfg(feature = "dev")))] pub mod dev; From bbf60078825d70add995293732f7d59fe59ea154 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Wed, 20 Oct 2021 19:06:05 +0300 Subject: [PATCH 37/63] change re-imports --- crypto-mac/src/lib.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/crypto-mac/src/lib.rs b/crypto-mac/src/lib.rs index b9dc48ea7..028874769 100644 --- a/crypto-mac/src/lib.rs +++ b/crypto-mac/src/lib.rs @@ -17,20 +17,24 @@ extern crate std; #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] pub use rand_core; +pub use crypto_common; +pub use generic_array; + #[cfg(feature = "dev")] #[cfg_attr(docsrs, doc(cfg(feature = "dev")))] pub mod dev; pub mod core_api; -use core::fmt; pub use crypto_common::{ - subtle::ConstantTimeEq, CtOutput, FixedOutput, FixedOutputReset, InvalidLength, Key, KeyInit, - Output, Reset, Update, + CtOutput, InvalidLength, Key, KeyInit, Reset, Update, }; -pub use generic_array::{ - self, - typenum::{consts, Unsigned}, +pub use generic_array::typenum::consts; + +use core::fmt; +use generic_array::typenum::Unsigned; +use crypto_common::{ + subtle::ConstantTimeEq, FixedOutput, FixedOutputReset, Output, }; /// Convinience super-trait covering functionality of Message Authentication algorithms. From 76ee00409686abdf6e64c6ecf17dd5e9178ea156 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Fri, 22 Oct 2021 14:12:33 +0300 Subject: [PATCH 38/63] fix typo --- crypto-common/src/init.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto-common/src/init.rs b/crypto-common/src/init.rs index 518ce3e58..b1e550c9e 100644 --- a/crypto-common/src/init.rs +++ b/crypto-common/src/init.rs @@ -120,7 +120,7 @@ where // Unfortunately this blanket impl is impossible without mutually // exclusive traits, see: https://github.com/rust-lang/rfcs/issues/1053 -// ot at the very least without: https://github.com/rust-lang/rust/issues/20400 +// or at the very least without: https://github.com/rust-lang/rust/issues/20400 /* impl KeyIvInit for T where From 4dd62b5d586b823d7d806db9a980f15510d41c98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Fri, 22 Oct 2021 14:17:12 +0300 Subject: [PATCH 39/63] move generate methods to the init traits --- crypto-common/src/init.rs | 40 ++++++++++++++++++++++++++++++++++++++ crypto-common/src/users.rs | 22 --------------------- 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/crypto-common/src/init.rs b/crypto-common/src/init.rs index b1e550c9e..dbb6924af 100644 --- a/crypto-common/src/init.rs +++ b/crypto-common/src/init.rs @@ -19,6 +19,16 @@ pub trait KeyInit: KeySizeUser + Sized { Ok(Self::new(Key::::from_slice(key))) } } + + /// Generate random key using the provided [`CryptoRng`]. + #[cfg(feature = "rand_core")] + #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] + #[inline] + fn generate_key(mut rng: impl CryptoRng + RngCore) -> Key { + let mut key = Key::::default(); + rng.fill_bytes(&mut key); + key + } } /// Types which can be initialized from key and initialization vector (nonce). @@ -41,6 +51,26 @@ pub trait KeyIvInit: KeySizeUser + IvSizeUser + Sized { } } + /// Generate random key using the provided [`CryptoRng`]. + #[cfg(feature = "rand_core")] + #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] + #[inline] + fn generate_key(mut rng: impl CryptoRng + RngCore) -> Key { + let mut key = Key::::default(); + rng.fill_bytes(&mut key); + key + } + + /// Generate random IV using the provided [`CryptoRng`]. + #[cfg(feature = "rand_core")] + #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] + #[inline] + fn generate_iv(mut rng: impl CryptoRng + RngCore) -> Iv { + let mut iv = Iv::::default(); + rng.fill_bytes(&mut iv); + iv + } + /// Generate random key and nonce using the provided [`CryptoRng`]. #[cfg(feature = "rand_core")] #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] @@ -74,6 +104,16 @@ pub trait InnerIvInit: InnerUser + IvSizeUser + Sized { Ok(Self::inner_iv_init(inner, Iv::::from_slice(iv))) } } + + /// Generate random IV using the provided [`CryptoRng`]. + #[cfg(feature = "rand_core")] + #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] + #[inline] + fn generate_iv(mut rng: impl CryptoRng + RngCore) -> Iv { + let mut iv = Iv::::default(); + rng.fill_bytes(&mut iv); + iv + } } impl KeySizeUser for T diff --git a/crypto-common/src/users.rs b/crypto-common/src/users.rs index 644911f16..557bae834 100644 --- a/crypto-common/src/users.rs +++ b/crypto-common/src/users.rs @@ -1,7 +1,5 @@ use block_buffer::DigestBuffer; use generic_array::{ArrayLength, GenericArray}; -#[cfg(feature = "rand_core")] -use rand_core::{CryptoRng, RngCore}; /// Block on which [`BlockUser`] implementors operate. pub type Block = GenericArray::BlockSize>; @@ -38,16 +36,6 @@ pub trait OutputSizeUser { pub trait KeySizeUser { /// Key size in bytes. type KeySize: ArrayLength + 'static; - - /// Generate random key using the provided [`CryptoRng`]. - #[cfg(feature = "rand_core")] - #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] - #[inline] - fn generate_key(mut rng: impl CryptoRng + RngCore) -> Key { - let mut key = Key::::default(); - rng.fill_bytes(&mut key); - key - } } /// Types which use initialization vector (nonce) for initialization. @@ -56,16 +44,6 @@ pub trait KeySizeUser { pub trait IvSizeUser { /// Initialization vector size in bytes. type IvSize: ArrayLength + 'static; - - /// Generate random IV using the provided [`CryptoRng`]. - #[cfg(feature = "rand_core")] - #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] - #[inline] - fn generate_iv(mut rng: impl CryptoRng + RngCore) -> Iv { - let mut iv = Iv::::default(); - rng.fill_bytes(&mut iv); - iv - } } /// Types which use another type for initialization. From d32157322e1aff5169e59a8be6ba4048b04be52b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Fri, 22 Oct 2021 21:02:40 +0300 Subject: [PATCH 40/63] merge crypto-mac into digest --- Cargo.lock | 26 +- Cargo.toml | 2 - crypto-common/Cargo.toml | 3 - crypto-common/src/ct_output.rs | 56 ---- crypto-common/src/init.rs | 197 ------------ crypto-common/src/lib.rs | 291 ++++++++++++++---- crypto-common/src/users.rs | 61 ---- crypto-mac/CHANGELOG.md | 104 ------- crypto-mac/Cargo.toml | 27 -- crypto-mac/LICENSE-APACHE | 201 ------------ crypto-mac/LICENSE-MIT | 25 -- crypto-mac/README.md | 59 ---- crypto-mac/src/core_api.rs | 8 - crypto-mac/src/dev.rs | 148 --------- crypto-mac/src/lib.rs | 119 ------- digest/Cargo.toml | 9 +- digest/src/core_api.rs | 54 ++-- digest/src/core_api/ct_variable.rs | 24 +- digest/src/core_api/rt_variable.rs | 10 +- .../src/core_api/wrapper.rs | 59 ++-- digest/src/core_api/xof_reader.rs | 2 +- digest/src/digest.rs | 149 ++++++++- digest/src/lib.rs | 80 +++-- digest/src/mac.rs | 182 +++++++++++ 24 files changed, 717 insertions(+), 1179 deletions(-) delete mode 100644 crypto-common/src/ct_output.rs delete mode 100644 crypto-common/src/init.rs delete mode 100644 crypto-common/src/users.rs delete mode 100644 crypto-mac/CHANGELOG.md delete mode 100644 crypto-mac/Cargo.toml delete mode 100644 crypto-mac/LICENSE-APACHE delete mode 100644 crypto-mac/LICENSE-MIT delete mode 100644 crypto-mac/README.md delete mode 100644 crypto-mac/src/core_api.rs delete mode 100644 crypto-mac/src/dev.rs delete mode 100644 crypto-mac/src/lib.rs rename crypto-common/src/core_wrapper.rs => digest/src/core_api/wrapper.rs (64%) create mode 100644 digest/src/mac.rs diff --git a/Cargo.lock b/Cargo.lock index 223d5e563..fedb82044 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -134,12 +134,12 @@ version = "0.3.0" dependencies = [ "aead", "cipher 0.3.0", - "crypto-mac 0.11.1", + "crypto-mac", "digest 0.9.0", "elliptic-curve", "password-hash", "signature", - "universal-hash 0.4.1", + "universal-hash", ] [[package]] @@ -158,10 +158,8 @@ dependencies = [ name = "crypto-common" version = "0.1.0" dependencies = [ - "block-buffer 0.10.0", "generic-array", "rand_core", - "subtle", ] [[package]] @@ -174,16 +172,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "crypto-mac" -version = "0.12.0-pre" -dependencies = [ - "blobby", - "crypto-common", - "generic-array", - "rand_core", -] - [[package]] name = "der" version = "0.4.4" @@ -207,8 +195,10 @@ name = "digest" version = "0.10.0" dependencies = [ "blobby", + "block-buffer 0.10.0", "crypto-common", "generic-array", + "subtle", ] [[package]] @@ -546,14 +536,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "universal-hash" -version = "0.5.0" -dependencies = [ - "crypto-common", - "generic-array", -] - [[package]] name = "version_check" version = "0.9.3" diff --git a/Cargo.toml b/Cargo.toml index 72bbfd15b..78fa89c1a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,14 +3,12 @@ members = [ "aead", "cipher", "crypto-common", - "crypto-mac", "crypto", "digest", "elliptic-curve", "password-hash", "signature", "signature/async", - "universal-hash", ] [patch.crates-io] diff --git a/crypto-common/Cargo.toml b/crypto-common/Cargo.toml index 8622823c2..b38f4bb9d 100644 --- a/crypto-common/Cargo.toml +++ b/crypto-common/Cargo.toml @@ -13,10 +13,7 @@ categories = ["cryptography", "no-std"] [dependencies] generic-array = "0.14" -block-buffer = "0.10.0" rand_core = { version = "0.6", optional = true } -subtle = { version = "=2.4", default-features = false, optional = true } [features] -block-padding = ["block-buffer/block-padding"] std = [] diff --git a/crypto-common/src/ct_output.rs b/crypto-common/src/ct_output.rs deleted file mode 100644 index 1cc16e870..000000000 --- a/crypto-common/src/ct_output.rs +++ /dev/null @@ -1,56 +0,0 @@ -use super::{Output, OutputSizeUser}; -use subtle::{Choice, ConstantTimeEq}; - -/// Fixed size output value which provides a safe [`Eq`] implementation that -/// runs in constant time. -/// -/// It is useful for implementing Message Authentication Codes (MACs). -#[derive(Clone)] -#[cfg_attr(docsrs, doc(cfg(feature = "subtle")))] -pub struct CtOutput { - bytes: Output, -} - -impl CtOutput { - /// Create a new [`CtOutput`] value. - #[inline(always)] - pub fn new(bytes: Output) -> Self { - Self { bytes } - } - - /// Get the inner [`Output`] array this type wraps. - #[inline(always)] - pub fn into_bytes(self) -> Output { - self.bytes - } -} - -impl From> for CtOutput { - #[inline(always)] - fn from(bytes: Output) -> Self { - Self { bytes } - } -} - -impl<'a, T: OutputSizeUser> From<&'a Output> for CtOutput { - #[inline(always)] - fn from(bytes: &'a Output) -> Self { - bytes.clone().into() - } -} - -impl ConstantTimeEq for CtOutput { - #[inline(always)] - fn ct_eq(&self, other: &Self) -> Choice { - self.bytes.ct_eq(&other.bytes) - } -} - -impl PartialEq for CtOutput { - #[inline(always)] - fn eq(&self, x: &CtOutput) -> bool { - self.ct_eq(x).unwrap_u8() == 1 - } -} - -impl Eq for CtOutput {} diff --git a/crypto-common/src/init.rs b/crypto-common/src/init.rs deleted file mode 100644 index dbb6924af..000000000 --- a/crypto-common/src/init.rs +++ /dev/null @@ -1,197 +0,0 @@ -//! Traits related to types initialization. - -use crate::users::{InnerUser, Iv, IvSizeUser, Key, KeySizeUser}; -use core::fmt; -use generic_array::typenum::Unsigned; -#[cfg(feature = "rand_core")] -use rand_core::{CryptoRng, RngCore}; - -/// Types which can be initialized from key. -pub trait KeyInit: KeySizeUser + Sized { - /// Create new value from fixed size key. - fn new(key: &Key) -> Self; - - /// Create new value from variable size key. - fn new_from_slice(key: &[u8]) -> Result { - if key.len() != Self::KeySize::to_usize() { - Err(InvalidLength) - } else { - Ok(Self::new(Key::::from_slice(key))) - } - } - - /// Generate random key using the provided [`CryptoRng`]. - #[cfg(feature = "rand_core")] - #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] - #[inline] - fn generate_key(mut rng: impl CryptoRng + RngCore) -> Key { - let mut key = Key::::default(); - rng.fill_bytes(&mut key); - key - } -} - -/// Types which can be initialized from key and initialization vector (nonce). -pub trait KeyIvInit: KeySizeUser + IvSizeUser + Sized { - /// Create new value from fixed length key and nonce. - fn new(key: &Key, iv: &Iv) -> Self; - - /// Create new value from variable length key and nonce. - #[inline] - fn new_from_slices(key: &[u8], iv: &[u8]) -> Result { - let key_len = Self::KeySize::USIZE; - let iv_len = Self::IvSize::USIZE; - if key.len() != key_len || iv.len() != iv_len { - Err(InvalidLength) - } else { - Ok(Self::new( - Key::::from_slice(key), - Iv::::from_slice(iv), - )) - } - } - - /// Generate random key using the provided [`CryptoRng`]. - #[cfg(feature = "rand_core")] - #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] - #[inline] - fn generate_key(mut rng: impl CryptoRng + RngCore) -> Key { - let mut key = Key::::default(); - rng.fill_bytes(&mut key); - key - } - - /// Generate random IV using the provided [`CryptoRng`]. - #[cfg(feature = "rand_core")] - #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] - #[inline] - fn generate_iv(mut rng: impl CryptoRng + RngCore) -> Iv { - let mut iv = Iv::::default(); - rng.fill_bytes(&mut iv); - iv - } - - /// Generate random key and nonce using the provided [`CryptoRng`]. - #[cfg(feature = "rand_core")] - #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] - #[inline] - fn generate_key_iv(mut rng: impl CryptoRng + RngCore) -> (Key, Iv) { - (Self::generate_key(&mut rng), Self::generate_iv(&mut rng)) - } -} - -/// Types which can be initialized from another type (usually block ciphers). -/// -/// Usually used for initializing types from block ciphers. -pub trait InnerInit: InnerUser + Sized { - /// Initialize value from the `inner`. - fn inner_init(inner: Self::Inner) -> Self; -} - -/// Types which can be initialized from another type and additional initialization -/// vector/nonce. -/// -/// Usually used for initializing types from block ciphers. -pub trait InnerIvInit: InnerUser + IvSizeUser + Sized { - /// Initialize value using `inner` and `iv` array. - fn inner_iv_init(inner: Self::Inner, iv: &Iv) -> Self; - - /// Initialize value using `inner` and `iv` slice. - fn inner_iv_slice_init(inner: Self::Inner, iv: &[u8]) -> Result { - if iv.len() != Self::IvSize::to_usize() { - Err(InvalidLength) - } else { - Ok(Self::inner_iv_init(inner, Iv::::from_slice(iv))) - } - } - - /// Generate random IV using the provided [`CryptoRng`]. - #[cfg(feature = "rand_core")] - #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] - #[inline] - fn generate_iv(mut rng: impl CryptoRng + RngCore) -> Iv { - let mut iv = Iv::::default(); - rng.fill_bytes(&mut iv); - iv - } -} - -impl KeySizeUser for T -where - T: InnerUser, - T::Inner: KeySizeUser, -{ - type KeySize = ::KeySize; -} - -impl KeyIvInit for T -where - T: InnerIvInit, - T::Inner: KeyInit, -{ - #[inline] - fn new(key: &Key, iv: &Iv) -> Self { - Self::inner_iv_init(T::Inner::new(key), iv) - } - - #[inline] - fn new_from_slices(key: &[u8], iv: &[u8]) -> Result { - T::Inner::new_from_slice(key).and_then(|i| T::inner_iv_slice_init(i, iv)) - } -} - -impl KeyInit for T -where - T: InnerInit, - T::Inner: KeyInit, -{ - #[inline] - fn new(key: &Key) -> Self { - Self::inner_init(T::Inner::new(key)) - } - - #[inline] - fn new_from_slice(key: &[u8]) -> Result { - T::Inner::new_from_slice(key) - .map_err(|_| InvalidLength) - .map(Self::inner_init) - } -} - -// Unfortunately this blanket impl is impossible without mutually -// exclusive traits, see: https://github.com/rust-lang/rfcs/issues/1053 -// or at the very least without: https://github.com/rust-lang/rust/issues/20400 -/* -impl KeyIvInit for T -where - T: InnerInit, - T::Inner: KeyIvInit, -{ - #[inline] - fn new(key: &Key, iv: &Iv) -> Self { - Self::inner_init(T::Inner::new(key, iv)) - } - - #[inline] - fn new_from_slices(key: &[u8], iv: &[u8]) -> Result { - T::Inner::new_from_slice(key) - .map_err(|_| InvalidLength) - .map(Self::inner_init) - } -} -*/ - -/// The error type returned when key and/or IV used in the [`KeyInit`], -/// [`KeyIvInit`], and [`InnerIvInit`] slice-based methods had -/// an invalid length. -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub struct InvalidLength; - -impl fmt::Display for InvalidLength { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - f.write_str("Invalid Length") - } -} - -#[cfg(feature = "std")] -impl std::error::Error for InvalidLength {} diff --git a/crypto-common/src/lib.rs b/crypto-common/src/lib.rs index 7afc5abfa..a11626d37 100644 --- a/crypto-common/src/lib.rs +++ b/crypto-common/src/lib.rs @@ -13,84 +13,261 @@ extern crate std; use core::fmt; +use generic_array::{typenum::Unsigned, ArrayLength, GenericArray}; +#[cfg(feature = "rand_core")] +use rand_core::{CryptoRng, RngCore}; -pub use block_buffer; -#[cfg(feature = "subtle")] -#[cfg_attr(docsrs, doc(cfg(feature = "subtle")))] -pub use subtle; +/// Block on which [`BlockSizeUser`] implementors operate. +pub type Block = GenericArray::BlockSize>; +/// Output array of [`OutputSizeUser`] implementors. +pub type Output = GenericArray::OutputSize>; +/// Key used by [`KeySizeUser`] implementors. +pub type Key = GenericArray::KeySize>; +/// Initialization vector (nonce) used by [`IvSizeUser`] implementors. +pub type Iv = GenericArray::IvSize>; -mod core_wrapper; -mod init; -mod users; +/// Types which process data in blocks. +pub trait BlockSizeUser { + /// Size of the block in bytes. + type BlockSize: ArrayLength + 'static; +} -pub use core_wrapper::CoreWrapper; -pub use init::{InnerInit, InnerIvInit, InvalidLength, KeyInit, KeyIvInit}; -pub use users::{ - Block, BlockSizeUser, BufferUser, InnerUser, Iv, IvSizeUser, Key, KeySizeUser, Output, - OutputSizeUser, -}; +impl BlockSizeUser for &T { + type BlockSize = T::BlockSize; +} -#[cfg(feature = "subtle")] -mod ct_output; -#[cfg(feature = "subtle")] -pub use ct_output::CtOutput; +impl BlockSizeUser for &mut T { + type BlockSize = T::BlockSize; +} + +/// Types which return data with the given size. +pub trait OutputSizeUser { + /// Size of the output in bytes. + type OutputSize: ArrayLength + 'static; +} + +/// Types which use key for initialization. +/// +/// Generally it's used indirectly via [`KeyInit`] or [`KeyIvInit`]. +pub trait KeySizeUser { + /// Key size in bytes. + type KeySize: ArrayLength + 'static; +} + +/// Types which use initialization vector (nonce) for initialization. +/// +/// Generally it's used indirectly via [`KeyIvInit`] or [`InnerIvInit`]. +pub trait IvSizeUser { + /// Initialization vector size in bytes. + type IvSize: ArrayLength + 'static; +} -/// Types which consume data with byte granularity. -pub trait Update { - /// Update state using the provided data. - fn update(&mut self, data: &[u8]); +/// Types which use another type for initialization. +/// +/// Generally it's used indirectly via [`InnerInit`] or [`InnerIvInit`]. +pub trait InnerUser { + /// Inner type. + type Inner; } -/// Types which return fixed-sized result after finalization. -pub trait FixedOutput: OutputSizeUser + Sized { - /// Consume value and write result into provided array. - fn finalize_into(self, out: &mut Output); +/// Resettable types. +pub trait Reset { + /// Reset state to its initial value. + fn reset(&mut self); +} - /// Retrieve result and consume the hasher instance. +/// Trait which stores algorithm name constant, used in `Debug` implementations. +pub trait AlgorithmName { + /// Write algorithm name into `f`. + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result; +} + +/// Types which can be initialized from key. +pub trait KeyInit: KeySizeUser + Sized { + /// Create new value from fixed size key. + fn new(key: &Key) -> Self; + + /// Create new value from variable size key. + fn new_from_slice(key: &[u8]) -> Result { + if key.len() != Self::KeySize::to_usize() { + Err(InvalidLength) + } else { + Ok(Self::new(Key::::from_slice(key))) + } + } + + /// Generate random key using the provided [`CryptoRng`]. + #[cfg(feature = "rand_core")] + #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] #[inline] - fn finalize_fixed(self) -> Output { - let mut out = Default::default(); - self.finalize_into(&mut out); - out + fn generate_key(mut rng: impl CryptoRng + RngCore) -> Key { + let mut key = Key::::default(); + rng.fill_bytes(&mut key); + key } } -/// Types which return fixed-sized result after finalization and reset -/// state into its initial value. -pub trait FixedOutputReset: FixedOutput + Reset { - /// Write result into provided array and reset value to its initial state. - fn finalize_into_reset(&mut self, out: &mut Output); +/// Types which can be initialized from key and initialization vector (nonce). +pub trait KeyIvInit: KeySizeUser + IvSizeUser + Sized { + /// Create new value from fixed length key and nonce. + fn new(key: &Key, iv: &Iv) -> Self; - /// Retrieve result and reset the hasher instance. + /// Create new value from variable length key and nonce. #[inline] - fn finalize_fixed_reset(&mut self) -> Output { - let mut out = Default::default(); - self.finalize_into_reset(&mut out); - out + fn new_from_slices(key: &[u8], iv: &[u8]) -> Result { + let key_len = Self::KeySize::USIZE; + let iv_len = Self::IvSize::USIZE; + if key.len() != key_len || iv.len() != iv_len { + Err(InvalidLength) + } else { + Ok(Self::new( + Key::::from_slice(key), + Iv::::from_slice(iv), + )) + } + } + + /// Generate random key using the provided [`CryptoRng`]. + #[cfg(feature = "rand_core")] + #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] + #[inline] + fn generate_key(mut rng: impl CryptoRng + RngCore) -> Key { + let mut key = Key::::default(); + rng.fill_bytes(&mut key); + key + } + + /// Generate random IV using the provided [`CryptoRng`]. + #[cfg(feature = "rand_core")] + #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] + #[inline] + fn generate_iv(mut rng: impl CryptoRng + RngCore) -> Iv { + let mut iv = Iv::::default(); + rng.fill_bytes(&mut iv); + iv + } + + /// Generate random key and nonce using the provided [`CryptoRng`]. + #[cfg(feature = "rand_core")] + #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] + #[inline] + fn generate_key_iv(mut rng: impl CryptoRng + RngCore) -> (Key, Iv) { + (Self::generate_key(&mut rng), Self::generate_iv(&mut rng)) } } -/// Resettable types. -pub trait Reset { - /// Reset state to its initial value. - fn reset(&mut self); +/// Types which can be initialized from another type (usually block ciphers). +/// +/// Usually used for initializing types from block ciphers. +pub trait InnerInit: InnerUser + Sized { + /// Initialize value from the `inner`. + fn inner_init(inner: Self::Inner) -> Self; } -/// Types which consume data in blocks. -pub trait UpdateCore: BlockSizeUser { - /// Update state using the provided data blocks. - fn update_blocks(&mut self, blocks: &[Block]); +/// Types which can be initialized from another type and additional initialization +/// vector/nonce. +/// +/// Usually used for initializing types from block ciphers. +pub trait InnerIvInit: InnerUser + IvSizeUser + Sized { + /// Initialize value using `inner` and `iv` array. + fn inner_iv_init(inner: Self::Inner, iv: &Iv) -> Self; + + /// Initialize value using `inner` and `iv` slice. + fn inner_iv_slice_init(inner: Self::Inner, iv: &[u8]) -> Result { + if iv.len() != Self::IvSize::to_usize() { + Err(InvalidLength) + } else { + Ok(Self::inner_iv_init(inner, Iv::::from_slice(iv))) + } + } + + /// Generate random IV using the provided [`CryptoRng`]. + #[cfg(feature = "rand_core")] + #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] + #[inline] + fn generate_iv(mut rng: impl CryptoRng + RngCore) -> Iv { + let mut iv = Iv::::default(); + rng.fill_bytes(&mut iv); + iv + } } -/// Core trait for hash functions with fixed output size. -pub trait FixedOutputCore: UpdateCore + BufferUser + OutputSizeUser { - /// Finalize state using remaining data stored in the provided block buffer, - /// write result into provided array and leave `self` in a dirty state. - fn finalize_fixed_core(&mut self, buffer: &mut Self::Buffer, out: &mut Output); +impl KeySizeUser for T +where + T: InnerUser, + T::Inner: KeySizeUser, +{ + type KeySize = ::KeySize; } -/// Trait which stores algorithm name constant, used in `Debug` implementations. -pub trait AlgorithmName { - /// Write algorithm name into `f`. - fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result; +impl KeyIvInit for T +where + T: InnerIvInit, + T::Inner: KeyInit, +{ + #[inline] + fn new(key: &Key, iv: &Iv) -> Self { + Self::inner_iv_init(T::Inner::new(key), iv) + } + + #[inline] + fn new_from_slices(key: &[u8], iv: &[u8]) -> Result { + T::Inner::new_from_slice(key).and_then(|i| T::inner_iv_slice_init(i, iv)) + } } + +impl KeyInit for T +where + T: InnerInit, + T::Inner: KeyInit, +{ + #[inline] + fn new(key: &Key) -> Self { + Self::inner_init(T::Inner::new(key)) + } + + #[inline] + fn new_from_slice(key: &[u8]) -> Result { + T::Inner::new_from_slice(key) + .map_err(|_| InvalidLength) + .map(Self::inner_init) + } +} + +// Unfortunately this blanket impl is impossible without mutually +// exclusive traits, see: https://github.com/rust-lang/rfcs/issues/1053 +// or at the very least without: https://github.com/rust-lang/rust/issues/20400 +/* +impl KeyIvInit for T +where + T: InnerInit, + T::Inner: KeyIvInit, +{ + #[inline] + fn new(key: &Key, iv: &Iv) -> Self { + Self::inner_init(T::Inner::new(key, iv)) + } + + #[inline] + fn new_from_slices(key: &[u8], iv: &[u8]) -> Result { + T::Inner::new_from_slice(key) + .map_err(|_| InvalidLength) + .map(Self::inner_init) + } +} +*/ + +/// The error type returned when key and/or IV used in the [`KeyInit`], +/// [`KeyIvInit`], and [`InnerIvInit`] slice-based methods had +/// an invalid length. +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub struct InvalidLength; + +impl fmt::Display for InvalidLength { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + f.write_str("Invalid Length") + } +} + +#[cfg(feature = "std")] +impl std::error::Error for InvalidLength {} diff --git a/crypto-common/src/users.rs b/crypto-common/src/users.rs deleted file mode 100644 index 557bae834..000000000 --- a/crypto-common/src/users.rs +++ /dev/null @@ -1,61 +0,0 @@ -use block_buffer::DigestBuffer; -use generic_array::{ArrayLength, GenericArray}; - -/// Block on which [`BlockUser`] implementors operate. -pub type Block = GenericArray::BlockSize>; -/// Output array of [`OutputSizeUser`] implementors. -pub type Output = GenericArray::OutputSize>; -/// Key used by [`KeyUser`] implementors. -pub type Key = GenericArray::KeySize>; -/// Initialization vector (nonce) used by [`IvUser`] implementors. -pub type Iv = GenericArray::IvSize>; - -/// Types which process data in blocks. -pub trait BlockSizeUser { - /// Size of the block in bytes. - type BlockSize: ArrayLength + 'static; -} - -impl BlockSizeUser for &T { - type BlockSize = T::BlockSize; -} - -impl BlockSizeUser for &mut T { - type BlockSize = T::BlockSize; -} - -/// Types which return data with the given size. -pub trait OutputSizeUser { - /// Size of the output in bytes. - type OutputSize: ArrayLength + 'static; -} - -/// Types which use key for initialization. -/// -/// Generally it's used indirectly via [`KeyInit`] or [`KeyIvInit`]. -pub trait KeySizeUser { - /// Key size in bytes. - type KeySize: ArrayLength + 'static; -} - -/// Types which use initialization vector (nonce) for initialization. -/// -/// Generally it's used indirectly via [`KeyIvInit`] or [`InnerIvInit`]. -pub trait IvSizeUser { - /// Initialization vector size in bytes. - type IvSize: ArrayLength + 'static; -} - -/// Types which use another type for initialization. -/// -/// Generally it's used indirectly via [`InnerInit`] or [`InnerIvInit`]. -pub trait InnerUser { - /// Inner type. - type Inner; -} - -/// Types which use [`DigestBuffer`] functionality. -pub trait BufferUser: BlockSizeUser { - /// Block buffer type over which value operates. - type Buffer: DigestBuffer; -} diff --git a/crypto-mac/CHANGELOG.md b/crypto-mac/CHANGELOG.md deleted file mode 100644 index 7488081b1..000000000 --- a/crypto-mac/CHANGELOG.md +++ /dev/null @@ -1,104 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [Unreleased] -### Added -- Re-export `rand_core` ([#683]) - -[#683]: https://github.com/RustCrypto/traits/pull/683 - -## 0.11.1 (2021-07-20) -### Changed -- Pin `subtle` dependency to v2.4 ([#691]) - -[#691]: https://github.com/RustCrypto/traits/pull/691 - -## 0.11.0 (2021-04-28) -### Added -- `generate_key` method to `New*` trait ([#513]) - -### Changed -- Renamed `new_var` to `new_from_slice` ([#442]) -- Bump `cipher` dependency to v0.3 ([#621]) - -[#442]: https://github.com/RustCrypto/traits/pull/442 -[#513]: https://github.com/RustCrypto/traits/pull/513 -[#621]: https://github.com/RustCrypto/traits/pull/621 - -## 0.10.1 (2021-07-20) -### Changed -- Pin `subtle` dependency to v2.4 ([#690]) - -[#690]: https://github.com/RustCrypto/traits/pull/690 - -## 0.10.0 (2020-10-15) -### Changed -- Replace `block-cipher` crate with new `cipher` crate ([#337], [#338]) - -[#338]: https://github.com/RustCrypto/traits/pull/338 -[#337]: https://github.com/RustCrypto/traits/pull/337 - -## 0.9.1 (2020-08-12) -### Added -- Re-export the `block-cipher` crate ([#257]) - -[#257]: https://github.com/RustCrypto/traits/pull/257 - -## 0.9.0 (2020-08-10) -### Added -- `FromBlockCipher` trait and blanket implementation of the `NewMac` trait -for it ([#217]) - -### Changed -- Updated test vectors storage to `blobby v0.3` ([#217]) - -### Removed -- `impl_write!` macro ([#217]) - -[#217]: https://github.com/RustCrypto/traits/pull/217 - -## 0.8.0 (2020-06-04) -### Added -- `impl_write!` macro ([#134]) - -### Changed -- Bump `generic-array` dependency to v0.14 ([#144]) -- Split `Mac` initialization into `NewMac` trait ([#133]) -- Rename `MacResult` => `Output`, `code` => `into_bytes` ([#114]) -- Rename `Input::input` to `Update::update` ([#111]) -- Update to 2018 edition ([#108]) -- Bump `subtle` dependency from v1.0 to v2.0 ([#33]) - -[#144]: https://github.com/RustCrypto/traits/pull/95 -[#134]: https://github.com/RustCrypto/traits/pull/134 -[#133]: https://github.com/RustCrypto/traits/pull/133 -[#114]: https://github.com/RustCrypto/traits/pull/114 -[#111]: https://github.com/RustCrypto/traits/pull/111 -[#108]: https://github.com/RustCrypto/traits/pull/108 -[#33]: https://github.com/RustCrypto/traits/pull/33 - -## 0.7.0 (2018-10-01) - -## 0.6.2 (2018-06-21) - -## 0.6.1 (2018-06-20) - -## 0.6.0 (2017-11-26) - -## 0.5.2 (2017-11-20) - -## 0.5.1 (2017-11-15) - -## 0.5.0 (2017-11-14) - -## 0.4.0 (2017-06-12) - -## 0.3.0 (2017-05-14) - -## 0.2.0 (2017-05-14) - -## 0.1.0 (2016-10-14) diff --git a/crypto-mac/Cargo.toml b/crypto-mac/Cargo.toml deleted file mode 100644 index 19b2e3014..000000000 --- a/crypto-mac/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "crypto-mac" -description = "Trait for Message Authentication Code (MAC) algorithms" -version = "0.12.0-pre" # Also update html_root_url in lib.rs when bumping this -authors = ["RustCrypto Developers"] -license = "MIT OR Apache-2.0" -readme = "README.md" -edition = "2018" -documentation = "https://docs.rs/crypto-mac" -repository = "https://github.com/RustCrypto/traits" -keywords = ["crypto", "mac"] -categories = ["cryptography", "no-std"] - -[dependencies] -generic-array = "0.14" -crypto-common = { version = "0.1", features = ["subtle"], path = "../crypto-common" } - -blobby = { version = "0.3", optional = true } -rand_core = { version = "0.6", optional = true } - -[features] -dev = ["blobby"] -std = ["crypto-common/std", "rand_core/std"] - -[package.metadata.docs.rs] -all-features = true -rustdoc-args = ["--cfg", "docsrs"] diff --git a/crypto-mac/LICENSE-APACHE b/crypto-mac/LICENSE-APACHE deleted file mode 100644 index 78173fa2e..000000000 --- a/crypto-mac/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/crypto-mac/LICENSE-MIT b/crypto-mac/LICENSE-MIT deleted file mode 100644 index 8dcb85b30..000000000 --- a/crypto-mac/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2017 Artyom Pavlov - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/crypto-mac/README.md b/crypto-mac/README.md deleted file mode 100644 index 889d6c244..000000000 --- a/crypto-mac/README.md +++ /dev/null @@ -1,59 +0,0 @@ -# RustCrypto: Message Authentication Code Traits - -[![crate][crate-image]][crate-link] -[![Docs][docs-image]][docs-link] -![Apache2/MIT licensed][license-image] -![Rust Version][rustc-image] -[![Project Chat][chat-image]][chat-link] -[![Build Status][build-image]][build-link] - -Traits for [Message Authentication Code] (MAC) algorithms. - -See [RustCrypto/MACs] for implementations which use this trait. - -[Documentation][docs-link] - -## Minimum Supported Rust Version - -Rust **1.41** or higher. - -Minimum supported Rust version can be changed in the future, but it will be -done with a minor version bump. - -## SemVer Policy - -- All on-by-default features of this library are covered by SemVer -- MSRV is considered exempt from SemVer as noted above - -## License - -Licensed under either of: - - * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) - * [MIT license](http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall be -dual licensed as above, without any additional terms or conditions. - -[//]: # (badges) - -[crate-image]: https://img.shields.io/crates/v/crypto-mac.svg -[crate-link]: https://crates.io/crates/crypto-mac -[docs-image]: https://docs.rs/crypto-mac/badge.svg -[docs-link]: https://docs.rs/crypto-mac/ -[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg -[rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg -[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg -[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260044-MACs -[build-image]: https://github.com/RustCrypto/traits/workflows/crypto-mac/badge.svg?branch=master&event=push -[build-link]: https://github.com/RustCrypto/traits/actions?query=workflow%3Acrypto-mac - -[//]: # (general links) - -[Message Authentication Code]: https://en.wikipedia.org/wiki/Message_authentication_code -[RustCrypto/MACs]: https://github.com/RustCrypto/MACs diff --git a/crypto-mac/src/core_api.rs b/crypto-mac/src/core_api.rs deleted file mode 100644 index d7d158590..000000000 --- a/crypto-mac/src/core_api.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! Low-level core API traits. -use crypto_common::KeyInit; -pub use crypto_common::{AlgorithmName, CoreWrapper, FixedOutputCore, UpdateCore}; - -/// Marker trait for MAC algorithms. -pub trait MacCore: UpdateCore + FixedOutputCore {} - -impl super::Mac for CoreWrapper {} diff --git a/crypto-mac/src/dev.rs b/crypto-mac/src/dev.rs deleted file mode 100644 index 1c397e631..000000000 --- a/crypto-mac/src/dev.rs +++ /dev/null @@ -1,148 +0,0 @@ -//! Development-related functionality - -pub use blobby; - -/// Define test -#[macro_export] -#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] -macro_rules! new_test { - ($name:ident, $test_name:expr, $mac:ty) => { - #[test] - fn $name() { - use crypto_mac::dev::blobby::Blob3Iterator; - use crypto_mac::{Mac, NewMac}; - - fn run_test(key: &[u8], input: &[u8], tag: &[u8]) -> Option<&'static str> { - let mut mac = <$mac as NewMac>::new_from_slice(key).unwrap(); - mac.update(input); - let result = mac.finalize_reset(); - if &result.into_bytes()[..] != tag { - return Some("whole message"); - } - // test if reset worked correctly - mac.update(input); - if mac.verify(&tag).is_err() { - return Some("after reset"); - } - - let mut mac = <$mac as NewMac>::new_from_slice(key).unwrap(); - // test reading byte by byte - for i in 0..input.len() { - mac.update(&input[i..i + 1]); - } - if let Err(_) = mac.verify(tag) { - return Some("message byte-by-byte"); - } - None - } - - let data = include_bytes!(concat!("data/", $test_name, ".blb")); - - for (i, row) in Blob3Iterator::new(data).unwrap().enumerate() { - let [key, input, tag] = row.unwrap(); - if let Some(desc) = run_test(key, input, tag) { - panic!( - "\n\ - Failed test №{}: {}\n\ - key:\t{:?}\n\ - input:\t{:?}\n\ - tag:\t{:?}\n", - i, desc, key, input, tag, - ); - } - } - } - }; -} - -/// Define test that allows for truncated tag. -#[macro_export] -#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] -macro_rules! new_trunc_test { - ($name:ident, $test_name:expr, $mac:ty) => { - #[test] - fn $name() { - use crypto_mac::dev::blobby::Blob3Iterator; - use crypto_mac::generic_array::typenum::Unsigned; - use crypto_mac::{Mac, NewMac}; - - fn run_test(key: &[u8], input: &[u8], tag: &[u8]) -> Option<&'static str> { - let mut mac = <$mac as NewMac>::new_from_slice(key).unwrap(); - mac.update(input); - let result = mac.finalize_reset(); - let mut len = <$mac as Mac>::OutputSize::to_usize(); - if tag.len() < len { - len = tag.len(); - } - if &result.into_bytes()[..len] != tag { - return Some("whole message"); - } - // test if reset worked correctly - mac.update(input); - let result = mac.finalize(); - if &result.into_bytes()[..len] != tag { - return Some("after reset"); - } - - let mut mac = <$mac as NewMac>::new_from_slice(key).unwrap(); - // test reading byte by byte - for i in 0..input.len() { - mac.update(&input[i..i + 1]); - } - let result = mac.finalize(); - if &result.into_bytes()[..len] != tag { - return Some("message byte-by-byte"); - } - None - } - - let data = include_bytes!(concat!("data/", $test_name, ".blb")); - - for (i, row) in Blob3Iterator::new(data).unwrap().enumerate() { - let [key, input, tag] = row.unwrap(); - if let Some(desc) = run_test(key, input, tag) { - panic!( - "\n\ - Failed test №{}: {}\n\ - key:\t{:?}\n\ - input:\t{:?}\n\ - tag:\t{:?}\n", - i, desc, key, input, tag, - ); - } - } - } - }; -} - -/// Define benchmark -#[macro_export] -#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] -macro_rules! bench { - ($name:ident, $engine:path, $bs:expr) => { - #[bench] - fn $name(b: &mut Bencher) { - let key = Default::default(); - let mut mac = <$engine>::new(&key); - let data = [0; $bs]; - - b.iter(|| { - mac.update(&data); - }); - - b.bytes = $bs; - } - }; - - ($engine:path) => { - extern crate test; - - use crypto_mac::{Mac, NewMac}; - use test::Bencher; - - $crate::bench!(bench1_10, $engine, 10); - $crate::bench!(bench2_100, $engine, 100); - $crate::bench!(bench3_1000, $engine, 1000); - $crate::bench!(bench3_10000, $engine, 10000); - }; -} diff --git a/crypto-mac/src/lib.rs b/crypto-mac/src/lib.rs deleted file mode 100644 index 028874769..000000000 --- a/crypto-mac/src/lib.rs +++ /dev/null @@ -1,119 +0,0 @@ -//! This crate provides trait for Message Authentication Code (MAC) algorithms. - -#![no_std] -#![cfg_attr(docsrs, feature(doc_cfg))] -#![doc( - html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg", - html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg", - html_root_url = "https://docs.rs/crypto-mac/0.12.0-pre" -)] -#![forbid(unsafe_code)] -#![warn(missing_docs, rust_2018_idioms)] - -#[cfg(feature = "std")] -extern crate std; - -#[cfg(feature = "rand_core")] -#[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))] -pub use rand_core; - -pub use crypto_common; -pub use generic_array; - -#[cfg(feature = "dev")] -#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] -pub mod dev; - -pub mod core_api; - -pub use crypto_common::{ - CtOutput, InvalidLength, Key, KeyInit, Reset, Update, -}; -pub use generic_array::typenum::consts; - -use core::fmt; -use generic_array::typenum::Unsigned; -use crypto_common::{ - subtle::ConstantTimeEq, FixedOutput, FixedOutputReset, Output, -}; - -/// Convinience super-trait covering functionality of Message Authentication algorithms. -pub trait Mac: KeyInit + Update + FixedOutput { - /// Obtain the result of a [`Mac`] computation as a [`CtOutput`] and consume - /// [`Mac`] instance. - #[inline] - fn finalize(self) -> CtOutput { - CtOutput::new(self.finalize_fixed()) - } - - /// Obtain the result of a [`Mac`] computation as a [`CtOutput`] and reset - /// [`Mac`] instance. - #[inline] - fn finalize_reset(&mut self) -> CtOutput - where - Self: FixedOutputReset, - { - CtOutput::new(self.finalize_fixed_reset()) - } - - /// Check if tag/code value is correct for the processed input. - #[inline] - fn verify(self, other: &Output) -> Result<(), Error> { - if self.finalize() == other.into() { - Ok(()) - } else { - Err(Error) - } - } - - /// Check if a tag/code truncated from right side (i.e. `tag[..n]`) - /// is correct for the processed input. - /// - /// Returns `Error` if `tag` is empty. - fn verify_truncated_right(self, tag: &[u8]) -> Result<(), Error> { - let n = tag.len(); - if n == 0 || n > Self::OutputSize::USIZE { - return Err(Error); - } - let choice = self.finalize_fixed()[..n].ct_eq(tag); - - if choice.unwrap_u8() == 1 { - Ok(()) - } else { - Err(Error) - } - } - - /// Check if a tag/code truncated from left side (i.e. `tag[n..]`) - /// is correct for the processed input. - /// - /// Returns `Error` if `tag` is not valid or empty. - fn verify_truncated_left(self, tag: &[u8]) -> Result<(), Error> { - let n = tag.len(); - if n == 0 || n > Self::OutputSize::USIZE { - return Err(Error); - } - let m = Self::OutputSize::USIZE - n; - let choice = self.finalize_fixed()[m..].ct_eq(tag); - - if choice.unwrap_u8() == 1 { - Ok(()) - } else { - Err(Error) - } - } -} - -/// Error type for when the [`Output`] of a [`Mac`] -/// is not equal to the expected value. -#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)] -pub struct Error; - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("MAC output mismatch") - } -} - -#[cfg(feature = "std")] -impl std::error::Error for Error {} diff --git a/digest/Cargo.toml b/digest/Cargo.toml index 38aeea0b7..2c0228f62 100644 --- a/digest/Cargo.toml +++ b/digest/Cargo.toml @@ -13,16 +13,19 @@ categories = ["cryptography", "no-std"] [dependencies] generic-array = "0.14" -crypto-common = { version = "0.1", path = "../crypto-common" } +block-buffer = "0.10" +crypto-common = { version = "0.1", path = "../crypto-common", default-features = false } +subtle = { version = "=2.4", default-features = false, optional = true } blobby = { version = "0.3", optional = true } [features] -default = ["block-padding"] +default = ["block-padding", "mac"] +mac = ["subtle"] # Enable MAC and UHF traits alloc = [] std = ["alloc", "crypto-common/std"] dev = ["blobby"] -block-padding = ["crypto-common/block-padding"] +block-padding = ["block-buffer/block-padding"] [package.metadata.docs.rs] all-features = true diff --git a/digest/src/core_api.rs b/digest/src/core_api.rs index 8f83015ea..2f7b5733d 100644 --- a/digest/src/core_api.rs +++ b/digest/src/core_api.rs @@ -1,24 +1,45 @@ -//! Low-level core API traits. +//! Low-level traits operating on blocks and wrappers around them. //! //! Usage of traits in this module in user code is discouraged. Instead use //! core algorithm wrapped by the wrapper types, which implement the //! higher-level traits. -use crate::{ExtendableOutput, InvalidOutputSize}; +use crate::InvalidOutputSize; use generic_array::ArrayLength; -pub use crypto_common::{ - AlgorithmName, Block, BlockSizeUser, BufferUser, CoreWrapper, FixedOutputCore, OutputSizeUser, - Reset, UpdateCore, -}; +pub use crypto_common::{AlgorithmName, Block, BlockSizeUser, OutputSizeUser, Reset}; + +use block_buffer::DigestBuffer; +use crypto_common::Output; mod ct_variable; mod rt_variable; +mod wrapper; mod xof_reader; pub use ct_variable::CtVariableCoreWrapper; pub use rt_variable::RtVariableCoreWrapper; +pub use wrapper::CoreWrapper; pub use xof_reader::XofReaderCoreWrapper; +/// Types which consume data in blocks. +pub trait UpdateCore: BlockSizeUser { + /// Update state using the provided data blocks. + fn update_blocks(&mut self, blocks: &[Block]); +} + +/// Types which use [`DigestBuffer`] functionality. +pub trait BufferUser: BlockSizeUser { + /// Block buffer type over which value operates. + type Buffer: DigestBuffer; +} + +/// Core trait for hash functions with fixed output size. +pub trait FixedOutputCore: UpdateCore + BufferUser + OutputSizeUser { + /// Finalize state using remaining data stored in the provided block buffer, + /// write result into provided array and leave `self` in a dirty state. + fn finalize_fixed_core(&mut self, buffer: &mut Self::Buffer, out: &mut Output); +} + /// Core trait for hash functions with extendable (XOF) output size. pub trait ExtendableOutputCore: UpdateCore + BufferUser { /// XOF reader core state. @@ -56,24 +77,3 @@ pub trait VariableOutputCore: UpdateCore + BufferUser + Sized { f: impl FnOnce(&[u8]), ); } - -impl ExtendableOutput for CoreWrapper { - type Reader = XofReaderCoreWrapper; - - #[inline] - fn finalize_xof(self) -> Self::Reader { - let (mut core, mut buffer) = self.decompose(); - let core = core.finalize_xof_core(&mut buffer); - let buffer = Default::default(); - Self::Reader { core, buffer } - } - - #[inline] - fn finalize_xof_reset(&mut self) -> Self::Reader { - self.apply_reset(|core, buffer| { - let core = core.finalize_xof_core(buffer); - let buffer = Default::default(); - Self::Reader { core, buffer } - }) - } -} diff --git a/digest/src/core_api/ct_variable.rs b/digest/src/core_api/ct_variable.rs index 75f3babbb..a0fd16d46 100644 --- a/digest/src/core_api/ct_variable.rs +++ b/digest/src/core_api/ct_variable.rs @@ -1,6 +1,9 @@ -use super::{AlgorithmName, FixedOutputCore, Reset, UpdateCore, VariableOutputCore}; +use super::{AlgorithmName, BufferUser, FixedOutputCore, Reset, UpdateCore, VariableOutputCore}; +use crate::HashMarker; +#[cfg(feature = "mac")] +use crate::MacMarker; use core::{fmt, marker::PhantomData}; -use crypto_common::{Block, BlockSizeUser, BufferUser, OutputSizeUser}; +use crypto_common::{Block, BlockSizeUser, OutputSizeUser}; use generic_array::{ typenum::{IsLessOrEqual, LeEq, NonZero}, ArrayLength, GenericArray, @@ -19,6 +22,23 @@ where _out: PhantomData, } +impl HashMarker for CtVariableCoreWrapper +where + T: VariableOutputCore + HashMarker, + OutSize: ArrayLength + IsLessOrEqual, + LeEq: NonZero, +{ +} + +#[cfg(feature = "mac")] +impl MacMarker for CtVariableCoreWrapper +where + T: VariableOutputCore + MacMarker, + OutSize: ArrayLength + IsLessOrEqual, + LeEq: NonZero, +{ +} + impl BlockSizeUser for CtVariableCoreWrapper where T: VariableOutputCore, diff --git a/digest/src/core_api/rt_variable.rs b/digest/src/core_api/rt_variable.rs index c9af06ae3..4b6ef29cb 100644 --- a/digest/src/core_api/rt_variable.rs +++ b/digest/src/core_api/rt_variable.rs @@ -1,7 +1,10 @@ use super::{AlgorithmName, UpdateCore, VariableOutputCore}; +use crate::HashMarker; +#[cfg(feature = "mac")] +use crate::MacMarker; use crate::{InvalidOutputSize, Reset, Update, VariableOutput}; +use block_buffer::DigestBuffer; use core::fmt; -use crypto_common::block_buffer::DigestBuffer; use generic_array::typenum::Unsigned; /// Wrapper around [`VariableOutputCore`] which selects output size @@ -16,6 +19,11 @@ where output_size: usize, } +impl HashMarker for RtVariableCoreWrapper where T: VariableOutputCore + HashMarker {} + +#[cfg(feature = "mac")] +impl MacMarker for RtVariableCoreWrapper where T: VariableOutputCore + MacMarker {} + impl Reset for RtVariableCoreWrapper where T: VariableOutputCore + UpdateCore, diff --git a/crypto-common/src/core_wrapper.rs b/digest/src/core_api/wrapper.rs similarity index 64% rename from crypto-common/src/core_wrapper.rs rename to digest/src/core_api/wrapper.rs index 8e4becb05..2a895cde7 100644 --- a/crypto-common/src/core_wrapper.rs +++ b/digest/src/core_api/wrapper.rs @@ -1,11 +1,14 @@ -//! Low-level core API traits. use super::{ - AlgorithmName, BufferUser, FixedOutput, FixedOutputCore, FixedOutputReset, KeyInit, - KeySizeUser, OutputSizeUser, Reset, Update, UpdateCore, + AlgorithmName, BufferUser, ExtendableOutputCore, FixedOutputCore, OutputSizeUser, Reset, + UpdateCore, XofReaderCoreWrapper, }; +use crate::{ExtendableOutput, FixedOutput, FixedOutputReset, HashMarker, Update}; use block_buffer::DigestBuffer; use core::fmt; -use generic_array::GenericArray; +use crypto_common::{Key, KeyInit, KeySizeUser, Output}; + +#[cfg(feature = "mac")] +use crate::MacMarker; /// Wrapper around [`BufferUser`]. /// @@ -16,6 +19,11 @@ pub struct CoreWrapper { buffer: T::Buffer, } +impl HashMarker for CoreWrapper {} + +#[cfg(feature = "mac")] +impl MacMarker for CoreWrapper {} + impl CoreWrapper { /// Create new wrapper from `core`. #[inline] @@ -32,24 +40,12 @@ impl CoreWrapper { } } -impl CoreWrapper { - /// Apply function to core and buffer, return its result, - /// and reset core and buffer. - pub fn apply_reset(&mut self, mut f: impl FnMut(&mut T, &mut T::Buffer) -> V) -> V { - let Self { core, buffer } = self; - let res = f(core, buffer); - core.reset(); - buffer.reset(); - res - } -} - impl KeySizeUser for CoreWrapper { type KeySize = T::KeySize; } impl KeyInit for CoreWrapper { - fn new(key: &GenericArray) -> Self { + fn new(key: &Key) -> Self { Self { core: T::new(key), buffer: Default::default(), @@ -86,7 +82,7 @@ impl OutputSizeUser for CoreWrapper { impl FixedOutput for CoreWrapper { #[inline] - fn finalize_into(mut self, out: &mut GenericArray) { + fn finalize_into(mut self, out: &mut Output) { let Self { core, buffer } = &mut self; core.finalize_fixed_core(buffer, out); } @@ -94,8 +90,31 @@ impl FixedOutput for CoreWrapper { impl FixedOutputReset for CoreWrapper { #[inline] - fn finalize_into_reset(&mut self, out: &mut GenericArray) { - self.apply_reset(|core, buffer| core.finalize_fixed_core(buffer, out)); + fn finalize_into_reset(&mut self, out: &mut Output) { + let Self { core, buffer } = self; + core.finalize_fixed_core(buffer, out); + core.reset(); + buffer.reset(); + } +} + +impl ExtendableOutput for CoreWrapper { + type Reader = XofReaderCoreWrapper; + + #[inline] + fn finalize_xof(self) -> Self::Reader { + let (mut core, mut buffer) = self.decompose(); + let core = core.finalize_xof_core(&mut buffer); + let buffer = Default::default(); + Self::Reader { core, buffer } + } + + #[inline] + fn finalize_xof_reset(&mut self) -> Self::Reader { + let Self { core, buffer } = self; + let core = core.finalize_xof_core(buffer); + let buffer = Default::default(); + Self::Reader { core, buffer } } } diff --git a/digest/src/core_api/xof_reader.rs b/digest/src/core_api/xof_reader.rs index e3468e07f..810cd75dd 100644 --- a/digest/src/core_api/xof_reader.rs +++ b/digest/src/core_api/xof_reader.rs @@ -1,7 +1,7 @@ use super::{AlgorithmName, XofReaderCore}; use crate::XofReader; +use block_buffer::BlockBuffer; use core::fmt; -use crypto_common::block_buffer::BlockBuffer; /// Wrapper around [`XofReaderCore`] implementations. /// diff --git a/digest/src/digest.rs b/digest/src/digest.rs index 9b42fc37c..5e8a7b4dc 100644 --- a/digest/src/digest.rs +++ b/digest/src/digest.rs @@ -1,18 +1,17 @@ -use super::{FixedOutput, FixedOutputReset, Update}; -use crypto_common::OutputSizeUser; +use super::{FixedOutput, FixedOutputReset, Reset, Update}; +use core::fmt; +use crypto_common::{Output, OutputSizeUser}; use generic_array::typenum::Unsigned; -use generic_array::{ArrayLength, GenericArray}; -/// The `Digest` trait specifies an interface common for digest functions. -/// -/// It's a convenience wrapper around [`Update`], [`FixedOutput`], -/// [`Reset`][`crate::Reset`], [`Clone`], and [`Default`] traits. -/// -/// It also provides additional convenience methods. -pub trait Digest { - /// Output size for `Digest` - type OutputSize: ArrayLength; +/// Marker trait for cryptographic hash functions. +pub trait HashMarker {} +/// Convinience wrapper trait covering functionality of cryptographic hash +/// functions with fixed output size. +/// +/// This trait wraps [`Update`], [`FixedOutput`], [`Default`], and +/// [`HashMarker`] traits and provides additional convenience methods. +pub trait Digest: OutputSizeUser { /// Create new hasher instance fn new() -> Self; @@ -45,9 +44,7 @@ pub trait Digest { fn digest(data: impl AsRef<[u8]>) -> Output; } -impl Digest for D { - type OutputSize = ::OutputSize; - +impl Digest for D { #[inline] fn new() -> Self { Self::default() @@ -103,5 +100,123 @@ impl Digest for D { } } -/// Fixed of fixed-sized hash-function used by [`Digest`] methods. -pub type Output = GenericArray::OutputSize>; +/// Modification of the [`Digest`] trait suitable for trait objects. +pub trait DynDigest { + /// Digest input data. + /// + /// This method can be called repeatedly for use with streaming messages. + fn update(&mut self, data: &[u8]); + + /// Retrieve result and reset hasher instance + #[cfg(feature = "alloc")] + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + fn finalize_reset(&mut self) -> Box<[u8]> { + let mut result = vec![0; self.output_size()]; + self.finalize_into_reset(&mut result).unwrap(); + result.into_boxed_slice() + } + + /// Retrieve result and consume boxed hasher instance + #[cfg(feature = "alloc")] + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + #[allow(clippy::boxed_local)] + fn finalize(mut self: Box) -> Box<[u8]> { + let mut result = vec![0; self.output_size()]; + self.finalize_into_reset(&mut result).unwrap(); + result.into_boxed_slice() + } + + /// Write result into provided array and consume the hasher instance. + /// + /// Returns error if buffer length is not equal to `output_size`. + fn finalize_into(self, buf: &mut [u8]) -> Result<(), InvalidBufferLength>; + + /// Write result into provided array and reset the hasher instance. + /// + /// Returns error if buffer length is not equal to `output_size`. + fn finalize_into_reset(&mut self, out: &mut [u8]) -> Result<(), InvalidBufferLength>; + + /// Reset hasher instance to its initial state. + fn reset(&mut self); + + /// Get output size of the hasher + fn output_size(&self) -> usize; + + /// Clone hasher state into a boxed trait object + #[cfg(feature = "alloc")] + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + fn box_clone(&self) -> Box; +} + +impl DynDigest for D { + fn update(&mut self, data: &[u8]) { + Update::update(self, data); + } + + #[cfg(feature = "alloc")] + fn finalize_reset(&mut self) -> Box<[u8]> { + FixedOutputReset::finalize_fixed_reset(self) + .to_vec() + .into_boxed_slice() + } + + #[cfg(feature = "alloc")] + fn finalize(self: Box) -> Box<[u8]> { + FixedOutput::finalize_fixed(self) + .to_vec() + .into_boxed_slice() + } + + fn finalize_into(self, buf: &mut [u8]) -> Result<(), InvalidBufferLength> { + if buf.len() == self.output_size() { + FixedOutput::finalize_into(self, Output::::from_mut_slice(buf)); + Ok(()) + } else { + Err(InvalidBufferLength) + } + } + + fn finalize_into_reset(&mut self, buf: &mut [u8]) -> Result<(), InvalidBufferLength> { + if buf.len() == self.output_size() { + FixedOutputReset::finalize_into_reset(self, Output::::from_mut_slice(buf)); + Ok(()) + } else { + Err(InvalidBufferLength) + } + } + + fn reset(&mut self) { + Reset::reset(self); + } + + fn output_size(&self) -> usize { + ::OutputSize::to_usize() + } + + #[cfg(feature = "alloc")] + fn box_clone(&self) -> Box { + Box::new(self.clone()) + } +} + +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +impl Clone for Box { + fn clone(&self) -> Self { + self.box_clone() + } +} + +/// Buffer length is not equal to the hash output size. +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)] +pub struct InvalidBufferLength; + +impl fmt::Display for InvalidBufferLength { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("invalid buffer length") + } +} + +#[cfg(feature = "std")] +impl std::error::Error for InvalidBufferLength {} diff --git a/digest/src/lib.rs b/digest/src/lib.rs index 3d07d5967..fc9ccd9ae 100644 --- a/digest/src/lib.rs +++ b/digest/src/lib.rs @@ -1,15 +1,15 @@ //! This crate provides traits which describe functionality of cryptographic hash -//! functions. +//! functions and Message Authentication algorithms. //! -//! Traits in this repository are organized into high-level convenience traits, -//! mid-level traits which expose more fine-grained functionality, and -//! low-level traits intended to only be used by algorithm implementations: +//! Traits in this repository are organized into the following levels: //! -//! - **High-level convenience traits**: [`Digest`], [`DynDigest`]. They are wrappers -//! around lower-level traits for most common hash-function use-cases. -//! - **Mid-level traits**: [`Update`], [`FixedOutput`], [`ExtendableOutput`], [`Reset`]. -//! These traits atomically describe available functionality of hash function -//! implementations. +//! - **High-level convenience traits**: [`Digest`], [`DynDigest`], [`Mac`]. +//! Wrappers around lower-level traits for most common use-cases. +//! - **Mid-level traits**: [`Update`], [`FixedOutput`], [`ExtendableOutput`], +//! [`VariableOutput`], [`Reset`], [`XofReader`]. These traits atomically +//! describe available functionality of an algorithm. +//! - **Marker traits**: [`HashMarker`], [`MacMarker`]. Used to distinguish +//! different algorithm classes. //! - **Low-level traits** defined in the [`core_api`] module. These traits //! operate at a block-level and do not contain any built-in buffering. //! They are intended to be implemented by low-level algorithm providers only @@ -17,11 +17,11 @@ //! usually shouldn't be used in application-level code. //! //! Additionally hash functions implement traits from the standard library: -//! [`Default`], [`Clone`], [`Write`][std::io::Write]. The latter is +//! [`Default`], [`Clone`], [`Write`]. The latter is //! feature-gated behind `std` feature, which is usually enabled by default //! by hash implementation crates. //! -//! The [`Digest`] trait is the most commonly used trait. +//! [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html #![no_std] #![cfg_attr(docsrs, feature(doc_cfg))] @@ -48,15 +48,54 @@ pub mod dev; pub mod core_api; mod digest; -mod dyn_digest; +#[cfg(feature = "mac")] +mod mac; use core::fmt; -pub use crate::digest::{Digest, Output}; -pub use crypto_common::block_buffer; -pub use crypto_common::{FixedOutput, FixedOutputReset, Reset, Update}; -pub use dyn_digest::{DynDigest, InvalidBufferLength}; -pub use generic_array::{self, typenum::consts, GenericArray}; +pub use crypto_common; +#[cfg(feature = "mac")] +pub use crypto_common::{InnerInit, InvalidLength, Key, KeyInit}; +pub use crypto_common::{Output, OutputSizeUser, Reset}; +pub use digest::{Digest, DynDigest, HashMarker, InvalidBufferLength}; +pub use generic_array::{self, typenum::consts}; +#[cfg(feature = "mac")] +pub use mac::{CtOutput, Mac, MacError, MacMarker}; + +/// Types which consume data with byte granularity. +pub trait Update { + /// Update state using the provided data. + fn update(&mut self, data: &[u8]); +} + +/// Types which return fixed-sized result after finalization. +pub trait FixedOutput: OutputSizeUser + Sized { + /// Consume value and write result into provided array. + fn finalize_into(self, out: &mut Output); + + /// Retrieve result and consume the hasher instance. + #[inline] + fn finalize_fixed(self) -> Output { + let mut out = Default::default(); + self.finalize_into(&mut out); + out + } +} + +/// Types which return fixed-sized result after finalization and reset +/// values into its initial state. +pub trait FixedOutputReset: FixedOutput + Reset { + /// Write result into provided array and reset value to its initial state. + fn finalize_into_reset(&mut self, out: &mut Output); + + /// Retrieve result and reset the hasher instance. + #[inline] + fn finalize_fixed_reset(&mut self) -> Output { + let mut out = Default::default(); + self.finalize_into_reset(&mut out); + out + } +} /// Trait for describing readers which are used to extract extendable output /// from XOF (extendable-output function) result. @@ -80,7 +119,7 @@ pub trait XofReader { } /// Trait which describes extendable-output functions (XOF). -pub trait ExtendableOutput: Sized + Update + Default + Reset { +pub trait ExtendableOutput: Sized + Update + Reset { /// Reader type Reader: XofReader; @@ -91,7 +130,10 @@ pub trait ExtendableOutput: Sized + Update + Default + Reset { fn finalize_xof_reset(&mut self) -> Self::Reader; /// Compute hash of `data` and write it to `output`. - fn digest_xof(input: impl AsRef<[u8]>, output: &mut [u8]) { + fn digest_xof(input: impl AsRef<[u8]>, output: &mut [u8]) + where + Self: Default, + { let mut hasher = Self::default(); hasher.update(input.as_ref()); hasher.finalize_xof().read(output); diff --git a/digest/src/mac.rs b/digest/src/mac.rs new file mode 100644 index 000000000..5abba08c2 --- /dev/null +++ b/digest/src/mac.rs @@ -0,0 +1,182 @@ +use crate::{FixedOutput, FixedOutputReset, Update}; +use crypto_common::{InvalidLength, Key, KeyInit, KeySizeUser, Output, OutputSizeUser}; + +use core::fmt; +use generic_array::typenum::Unsigned; +use subtle::{Choice, ConstantTimeEq}; + +/// Marker trait for Message Authentication algorithms. +#[cfg_attr(docsrs, doc(cfg(feature = "mac")))] +pub trait MacMarker {} + +/// Convinience wrapper trait covering functionality of Message Authentication algorithms. +/// Convinience wrapper trait covering functionality of cryptographic hash +/// functions with fixed output size. +/// +/// This trait wraps [`KeyInit`], [`Update`], [`FixedOutput`], and [`MacMarker`] +/// traits and provides additional convenience methods. +#[cfg_attr(docsrs, doc(cfg(feature = "mac")))] +pub trait Mac: KeySizeUser + OutputSizeUser + Sized { + /// Create new value from fixed size key. + fn new(key: &Key) -> Self; + + /// Create new value from variable size key. + fn new_from_slice(key: &[u8]) -> Result; + + /// Obtain the result of a [`Mac`] computation as a [`CtOutput`] and consume + /// [`Mac`] instance. + fn finalize(self) -> CtOutput; + + /// Obtain the result of a [`Mac`] computation as a [`CtOutput`] and reset + /// [`Mac`] instance. + fn finalize_reset(&mut self) -> CtOutput + where + Self: FixedOutputReset; + + /// Check if tag/code value is correct for the processed input. + fn verify(self, other: &Output) -> Result<(), MacError>; + + /// Check if a tag/code truncated from right side (i.e. `tag[..n]`) + /// is correct for the processed input. + /// + /// Returns `Error` if `tag` is empty. + fn verify_truncated_right(self, tag: &[u8]) -> Result<(), MacError>; + + /// Check if a tag/code truncated from left side (i.e. `tag[n..]`) + /// is correct for the processed input. + /// + /// Returns `Error` if `tag` is not valid or empty. + fn verify_truncated_left(self, tag: &[u8]) -> Result<(), MacError>; +} + +impl Mac for T { + #[inline(always)] + fn new(key: &Key) -> Self { + KeyInit::new(key) + } + + #[inline(always)] + fn new_from_slice(key: &[u8]) -> Result { + KeyInit::new_from_slice(key) + } + + #[inline] + fn finalize(self) -> CtOutput { + CtOutput::new(self.finalize_fixed()) + } + + #[inline(always)] + fn finalize_reset(&mut self) -> CtOutput + where + Self: FixedOutputReset, + { + CtOutput::new(self.finalize_fixed_reset()) + } + + /// Check if tag/code value is correct for the processed input. + #[inline] + fn verify(self, other: &Output) -> Result<(), MacError> { + if self.finalize() == other.into() { + Ok(()) + } else { + Err(MacError) + } + } + + fn verify_truncated_right(self, tag: &[u8]) -> Result<(), MacError> { + let n = tag.len(); + if n == 0 || n > Self::OutputSize::USIZE { + return Err(MacError); + } + let choice = self.finalize_fixed()[..n].ct_eq(tag); + + if choice.unwrap_u8() == 1 { + Ok(()) + } else { + Err(MacError) + } + } + + fn verify_truncated_left(self, tag: &[u8]) -> Result<(), MacError> { + let n = tag.len(); + if n == 0 || n > Self::OutputSize::USIZE { + return Err(MacError); + } + let m = Self::OutputSize::USIZE - n; + let choice = self.finalize_fixed()[m..].ct_eq(tag); + + if choice.unwrap_u8() == 1 { + Ok(()) + } else { + Err(MacError) + } + } +} + +/// Fixed size output value which provides a safe [`Eq`] implementation that +/// runs in constant time. +/// +/// It is useful for implementing Message Authentication Codes (MACs). +#[derive(Clone)] +#[cfg_attr(docsrs, doc(cfg(feature = "subtle")))] +pub struct CtOutput { + bytes: Output, +} + +impl CtOutput { + /// Create a new [`CtOutput`] value. + #[inline(always)] + pub fn new(bytes: Output) -> Self { + Self { bytes } + } + + /// Get the inner [`Output`] array this type wraps. + #[inline(always)] + pub fn into_bytes(self) -> Output { + self.bytes + } +} + +impl From> for CtOutput { + #[inline(always)] + fn from(bytes: Output) -> Self { + Self { bytes } + } +} + +impl<'a, T: OutputSizeUser> From<&'a Output> for CtOutput { + #[inline(always)] + fn from(bytes: &'a Output) -> Self { + bytes.clone().into() + } +} + +impl ConstantTimeEq for CtOutput { + #[inline(always)] + fn ct_eq(&self, other: &Self) -> Choice { + self.bytes.ct_eq(&other.bytes) + } +} + +impl PartialEq for CtOutput { + #[inline(always)] + fn eq(&self, x: &CtOutput) -> bool { + self.ct_eq(x).unwrap_u8() == 1 + } +} + +impl Eq for CtOutput {} + +/// Error type for when the [`Output`] of a [`Mac`] +/// is not equal to the expected value. +#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)] +pub struct MacError; + +impl fmt::Display for MacError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("MAC tag mismatch") + } +} + +#[cfg(feature = "std")] +impl std::error::Error for MacError {} From 906cfad02752b086ae56fcd7b10c2c00097f0c73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Tue, 9 Nov 2021 19:01:24 +0300 Subject: [PATCH 41/63] cipher: re-export inout --- cipher/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/cipher/src/lib.rs b/cipher/src/lib.rs index 65336f051..5d3aae6ca 100644 --- a/cipher/src/lib.rs +++ b/cipher/src/lib.rs @@ -15,6 +15,7 @@ #![warn(missing_docs, rust_2018_idioms)] pub use crypto_common; +pub use inout; #[cfg(feature = "std")] extern crate std; From ad6963d105e9af87f22dfe16ce325eaa66815045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Tue, 9 Nov 2021 19:31:33 +0300 Subject: [PATCH 42/63] implement StreamCipherCoreWrapper without block-buffer --- cipher/src/lib.rs | 5 +- cipher/src/stream_wrapper.rs | 99 +++++++++++++++++++++++++----------- 2 files changed, 72 insertions(+), 32 deletions(-) diff --git a/cipher/src/lib.rs b/cipher/src/lib.rs index 5d3aae6ca..1809952d0 100644 --- a/cipher/src/lib.rs +++ b/cipher/src/lib.rs @@ -24,7 +24,6 @@ extern crate std; pub use blobby; pub use block_buffer; -// pub use block_buffer::inout; mod block; #[cfg(feature = "dev")] @@ -32,9 +31,9 @@ mod dev; mod errors; mod stream; mod stream_core; -// mod stream_wrapper; +mod stream_wrapper; -pub use crate::{block::*, errors::*, stream::*, stream_core::*};//, stream_wrapper::*}; +pub use crate::{block::*, errors::*, stream::*, stream_core::*, stream_wrapper::*}; pub use crypto_common::{ Block, InnerIvInit, InvalidLength, Iv, IvSizeUser, Key, KeyInit, KeyIvInit, KeySizeUser, }; diff --git a/cipher/src/stream_wrapper.rs b/cipher/src/stream_wrapper.rs index c4aabc9c9..ff83b8d79 100644 --- a/cipher/src/stream_wrapper.rs +++ b/cipher/src/stream_wrapper.rs @@ -1,8 +1,8 @@ use crate::{ - errors::StreamCipherError, OverflowError, SeekNum, + errors::StreamCipherError, OverflowError, SeekNum, Block, StreamCipher, StreamCipherCore, StreamCipherSeek, StreamCipherSeekCore, }; -use block_buffer::{inout::InOutBuf, BlockBuffer}; +use inout::InOutBuf; use crypto_common::{BlockSizeUser, Iv, IvSizeUser, Key, KeyInit, KeyIvInit, KeySizeUser}; use generic_array::typenum::Unsigned; @@ -12,37 +12,49 @@ use generic_array::typenum::Unsigned; #[derive(Clone, Default)] pub struct StreamCipherCoreWrapper { core: T, - buffer: BlockBuffer, + buffer: Block, + pos: usize, } -impl StreamCipherCoreWrapper { - /// Get reference to core. - pub fn get_core(&self) -> &T { - &self.core +impl StreamCipherCoreWrapper { + /// Return current cursor position. + #[inline] + fn get_pos(&self) -> usize { + if self.pos >= T::BlockSize::USIZE { + // SAFETY: `pos` is set only to values smaller than block size + // unsafe { core::hint::unreachable_unchecked() } + } + self.pos as usize } - /// Split wrapper into core and buffer. - pub fn into_inner(self) -> (T, BlockBuffer) { - (self.core, self.buffer) + /// Return size of the internall buffer in bytes. + #[inline] + fn size(&self) -> usize { + T::BlockSize::USIZE } - /// Create wrapper from core and buffer. - pub fn from_inner(core: T, buffer: BlockBuffer) -> Self { - Self { core, buffer } + #[inline] + fn set_pos_unchecked(&mut self, pos: usize) { + debug_assert!(pos < T::BlockSize::USIZE); + self.pos = pos; + } + + /// Return number of remaining bytes in the internall buffer. + #[inline] + fn remaining(&self) -> usize { + self.size() - self.get_pos() } -} -impl StreamCipherCoreWrapper { fn check_remaining(&self, dlen: usize) -> Result<(), StreamCipherError> { let rem_blocks = match self.core.remaining_blocks() { Some(v) => v, None => return Ok(()), }; - let bytes = if self.buffer.get_pos() == 0 { + let bytes = if self.pos == 0 { dlen } else { - let rem = self.buffer.remaining(); + let rem = self.remaining(); if dlen > rem { dlen - rem } else { @@ -65,13 +77,39 @@ impl StreamCipherCoreWrapper { impl StreamCipher for StreamCipherCoreWrapper { #[inline] - fn try_apply_keystream(&mut self, data: InOutBuf<'_, u8>) -> Result<(), StreamCipherError> { + fn try_apply_keystream(&mut self, mut data: InOutBuf<'_, u8>) -> Result<(), StreamCipherError> { self.check_remaining(data.len())?; - let Self { core, buffer } = self; - buffer.xor_data(data, |blocks| { - core.apply_keystream_blocks(blocks, |_| {}, |_| {}) - }); + let pos = self.get_pos(); + let r = self.remaining(); + let n = data.len(); + if pos != 0 { + if n < r { + // double slicing allows to remove panic branches + data.xor(&self.buffer[pos..][..n]); + self.set_pos_unchecked(pos + n); + return Ok(()); + } + let (mut left, right) = data.split_at(r); + data = right; + left.xor(&self.buffer[pos..]); + } + + let (blocks, mut leftover) = data.into_chunks(); + self.core.apply_keystream_blocks(blocks, |_| {}, |_| {}); + + let n = leftover.len(); + if n != 0 { + let mut block = Default::default(); + self.core.apply_keystream_blocks( + InOutBuf::from_mut(&mut block), + |_| {}, + |_| {}, + ); + leftover.xor(&block[..n]); + self.buffer = block; + } + self.set_pos_unchecked(n); Ok(()) } @@ -79,22 +117,23 @@ impl StreamCipher for StreamCipherCoreWrapper { impl StreamCipherSeek for StreamCipherCoreWrapper { fn try_current_pos(&self) -> Result { - let Self { core, buffer } = self; + let Self { core, pos, .. } = self; let bs = T::BlockSize::USIZE; - SN::from_block_byte(core.get_block_pos(), buffer.get_pos(), bs) + SN::from_block_byte(core.get_block_pos(), *pos, bs) } - fn try_seek(&mut self, pos: SN) -> Result<(), StreamCipherError> { - let Self { core, buffer } = self; + fn try_seek(&mut self, new_pos: SN) -> Result<(), StreamCipherError> { + let Self { core, buffer, pos } = self; let bs = T::BlockSize::USIZE; - let (block_pos, byte_pos) = pos.into_block_byte(bs)?; + let (block_pos, byte_pos) = new_pos.into_block_byte(bs)?; core.set_block_pos(block_pos); - let mut block = Default::default(); if byte_pos != 0 { + let mut block = Default::default(); let buf = InOutBuf::from_mut(&mut block); core.apply_keystream_blocks(buf, |_| {}, |_| {}); + *buffer = block; } - buffer.set(block, byte_pos); + *pos = byte_pos; Ok(()) } } @@ -118,6 +157,7 @@ impl KeyIvInit for StreamCipherCoreWrapper { Self { core: T::new(key, iv), buffer: Default::default(), + pos: 0, } } } @@ -128,6 +168,7 @@ impl KeyInit for StreamCipherCoreWrapper { Self { core: T::new(key), buffer: Default::default(), + pos: 0, } } } From d998b3a447b1478f7c506b8d333386015de7902e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Tue, 9 Nov 2021 19:32:26 +0300 Subject: [PATCH 43/63] use unsafe hint --- cipher/src/lib.rs | 2 +- cipher/src/stream_wrapper.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cipher/src/lib.rs b/cipher/src/lib.rs index 1809952d0..151e0a5c9 100644 --- a/cipher/src/lib.rs +++ b/cipher/src/lib.rs @@ -11,7 +11,7 @@ html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg", html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg" )] -#![forbid(unsafe_code)] +// #![forbid(unsafe_code)] #![warn(missing_docs, rust_2018_idioms)] pub use crypto_common; diff --git a/cipher/src/stream_wrapper.rs b/cipher/src/stream_wrapper.rs index ff83b8d79..4167eb7ae 100644 --- a/cipher/src/stream_wrapper.rs +++ b/cipher/src/stream_wrapper.rs @@ -22,7 +22,7 @@ impl StreamCipherCoreWrapper { fn get_pos(&self) -> usize { if self.pos >= T::BlockSize::USIZE { // SAFETY: `pos` is set only to values smaller than block size - // unsafe { core::hint::unreachable_unchecked() } + unsafe { core::hint::unreachable_unchecked() } } self.pos as usize } From 05238cad578031f87137398aae943d10dd7a0df7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Tue, 9 Nov 2021 19:34:55 +0300 Subject: [PATCH 44/63] cipher: add get_core method --- cipher/src/stream_wrapper.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cipher/src/stream_wrapper.rs b/cipher/src/stream_wrapper.rs index 4167eb7ae..8b8cb7238 100644 --- a/cipher/src/stream_wrapper.rs +++ b/cipher/src/stream_wrapper.rs @@ -17,6 +17,11 @@ pub struct StreamCipherCoreWrapper { } impl StreamCipherCoreWrapper { + /// Return reference to the core type. + pub fn get_core(&self) -> &T { + &self.core + } + /// Return current cursor position. #[inline] fn get_pos(&self) -> usize { From dd6aaae056e41391f448a6cb75f3c6c7fde22649 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Tue, 9 Nov 2021 20:40:55 +0300 Subject: [PATCH 45/63] digest: fix Box import --- digest/Cargo.toml | 2 +- digest/src/digest.rs | 5 ++++- digest/src/mac.rs | 2 -- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/digest/Cargo.toml b/digest/Cargo.toml index 2c0228f62..1c9d6020e 100644 --- a/digest/Cargo.toml +++ b/digest/Cargo.toml @@ -21,7 +21,7 @@ blobby = { version = "0.3", optional = true } [features] default = ["block-padding", "mac"] -mac = ["subtle"] # Enable MAC and UHF traits +mac = ["subtle"] # Enable MAC traits alloc = [] std = ["alloc", "crypto-common/std"] dev = ["blobby"] diff --git a/digest/src/digest.rs b/digest/src/digest.rs index 5e8a7b4dc..251d4aa85 100644 --- a/digest/src/digest.rs +++ b/digest/src/digest.rs @@ -3,6 +3,9 @@ use core::fmt; use crypto_common::{Output, OutputSizeUser}; use generic_array::typenum::Unsigned; +#[cfg(feature = "alloc")] +use alloc::boxed::Box; + /// Marker trait for cryptographic hash functions. pub trait HashMarker {} @@ -162,7 +165,7 @@ impl DynDigest for D { #[cfg(feature = "alloc")] fn finalize(self: Box) -> Box<[u8]> { - FixedOutput::finalize_fixed(self) + FixedOutput::finalize_fixed(*self) .to_vec() .into_boxed_slice() } diff --git a/digest/src/mac.rs b/digest/src/mac.rs index 5abba08c2..4ba699bea 100644 --- a/digest/src/mac.rs +++ b/digest/src/mac.rs @@ -10,8 +10,6 @@ use subtle::{Choice, ConstantTimeEq}; pub trait MacMarker {} /// Convinience wrapper trait covering functionality of Message Authentication algorithms. -/// Convinience wrapper trait covering functionality of cryptographic hash -/// functions with fixed output size. /// /// This trait wraps [`KeyInit`], [`Update`], [`FixedOutput`], and [`MacMarker`] /// traits and provides additional convenience methods. From 0ac7c464eb47aa4b86428fb52c62790fa9b19027 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Tue, 9 Nov 2021 20:42:47 +0300 Subject: [PATCH 46/63] digest: re-export block-buffer --- digest/src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/digest/src/lib.rs b/digest/src/lib.rs index fc9ccd9ae..da42d20f0 100644 --- a/digest/src/lib.rs +++ b/digest/src/lib.rs @@ -51,9 +51,9 @@ mod digest; #[cfg(feature = "mac")] mod mac; -use core::fmt; - +pub use block_buffer; pub use crypto_common; + #[cfg(feature = "mac")] pub use crypto_common::{InnerInit, InvalidLength, Key, KeyInit}; pub use crypto_common::{Output, OutputSizeUser, Reset}; @@ -62,6 +62,8 @@ pub use generic_array::{self, typenum::consts}; #[cfg(feature = "mac")] pub use mac::{CtOutput, Mac, MacError, MacMarker}; +use core::fmt; + /// Types which consume data with byte granularity. pub trait Update { /// Update state using the provided data. From 52372efe9a2a574501bdddc5c401523c458dc9e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Tue, 9 Nov 2021 20:50:29 +0300 Subject: [PATCH 47/63] digest: modify truncated methdos --- digest/src/mac.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/digest/src/mac.rs b/digest/src/mac.rs index 4ba699bea..2222aabdb 100644 --- a/digest/src/mac.rs +++ b/digest/src/mac.rs @@ -34,17 +34,17 @@ pub trait Mac: KeySizeUser + OutputSizeUser + Sized { /// Check if tag/code value is correct for the processed input. fn verify(self, other: &Output) -> Result<(), MacError>; - /// Check if a tag/code truncated from right side (i.e. `tag[..n]`) - /// is correct for the processed input. + /// Check truncated tag correctness using left side bytes + /// (i.e. `tag[..n]`) of calculated tag. /// - /// Returns `Error` if `tag` is empty. - fn verify_truncated_right(self, tag: &[u8]) -> Result<(), MacError>; + /// Returns `Error` if `tag` is not valid or empty. + fn verify_truncated_left(self, tag: &[u8]) -> Result<(), MacError>; - /// Check if a tag/code truncated from left side (i.e. `tag[n..]`) - /// is correct for the processed input. + /// Check truncated tag correctness using right side bytes + /// (i.e. `tag[n..]`) of calculated tag. /// /// Returns `Error` if `tag` is not valid or empty. - fn verify_truncated_left(self, tag: &[u8]) -> Result<(), MacError>; + fn verify_truncated_right(self, tag: &[u8]) -> Result<(), MacError>; } impl Mac for T { @@ -81,7 +81,7 @@ impl Mac for T { } } - fn verify_truncated_right(self, tag: &[u8]) -> Result<(), MacError> { + fn verify_truncated_left(self, tag: &[u8]) -> Result<(), MacError> { let n = tag.len(); if n == 0 || n > Self::OutputSize::USIZE { return Err(MacError); @@ -95,7 +95,7 @@ impl Mac for T { } } - fn verify_truncated_left(self, tag: &[u8]) -> Result<(), MacError> { + fn verify_truncated_right(self, tag: &[u8]) -> Result<(), MacError> { let n = tag.len(); if n == 0 || n > Self::OutputSize::USIZE { return Err(MacError); From fa44532c0c7b7ec12ad1afe7bcd1690f009178ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Thu, 11 Nov 2021 20:59:52 +0300 Subject: [PATCH 48/63] fmt, check number of remaining blocks in some stream cipher core methods --- cipher/src/block.rs | 2 +- cipher/src/stream.rs | 34 +++++++++------------------- cipher/src/stream_core.rs | 43 ++++++++++++++++++++++++++++++------ cipher/src/stream_wrapper.rs | 13 +++++------ 4 files changed, 52 insertions(+), 40 deletions(-) diff --git a/cipher/src/block.rs b/cipher/src/block.rs index 56dcca0f9..8a999c7ec 100644 --- a/cipher/src/block.rs +++ b/cipher/src/block.rs @@ -10,8 +10,8 @@ //! [2]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation //! [3]: https://en.wikipedia.org/wiki/Symmetric-key_algorithm -use inout::{InOut, InOutBuf, InSrc, InTmpOutBuf, NotEqualError}; use generic_array::typenum::U1; +use inout::{InOut, InOutBuf, InSrc, InTmpOutBuf, NotEqualError}; pub use crypto_common::{Block, BlockSizeUser}; diff --git a/cipher/src/stream.rs b/cipher/src/stream.rs index abde5e25f..f3b445c01 100644 --- a/cipher/src/stream.rs +++ b/cipher/src/stream.rs @@ -11,19 +11,12 @@ use inout::InOutBuf; /// Marker trait for block-level asynchronous stream ciphers pub trait AsyncStreamCipher: BlockEncryptMut + BlockDecryptMut + Sized { /// Encrypt data using `InOutBuf`. - fn encrypt_inout( - mut self, - data: InOutBuf<'_, u8>, - mut post_fn: impl FnMut(&[Block]), - ) { + fn encrypt_inout(mut self, data: InOutBuf<'_, u8>, mut post_fn: impl FnMut(&[Block])) { let (blocks, tail) = data.into_chunks(); - self.encrypt_blocks_inout_mut( - blocks, - |mut buf| { - buf.copy_tmp2out(); - post_fn(buf.get_out()); - }, - ); + self.encrypt_blocks_inout_mut(blocks, |mut buf| { + buf.copy_tmp2out(); + post_fn(buf.get_out()); + }); let mut block = Block::::default(); let n = tail.len(); if n != 0 { @@ -34,19 +27,12 @@ pub trait AsyncStreamCipher: BlockEncryptMut + BlockDecryptMut + Sized { } /// Decrypt data using `InOutBuf`. - fn decrypt_inout( - mut self, - data: InOutBuf<'_, u8>, - mut post_fn: impl FnMut(&[Block]), - ) { + fn decrypt_inout(mut self, data: InOutBuf<'_, u8>, mut post_fn: impl FnMut(&[Block])) { let (blocks, tail) = data.into_chunks(); - self.decrypt_blocks_inout_mut( - blocks, - |mut buf| { - buf.copy_tmp2out(); - post_fn(buf.get_out()); - }, - ); + self.decrypt_blocks_inout_mut(blocks, |mut buf| { + buf.copy_tmp2out(); + post_fn(buf.get_out()); + }); let mut block = Block::::default(); let n = tail.len(); if n != 0 { diff --git a/cipher/src/stream_core.rs b/cipher/src/stream_core.rs index e43666467..ce8eccfbd 100644 --- a/cipher/src/stream_core.rs +++ b/cipher/src/stream_core.rs @@ -1,7 +1,8 @@ -use block_buffer::{generic_array::typenum::Unsigned}; -use inout::InOutBuf; +use crate::errors::StreamCipherError; +use block_buffer::generic_array::typenum::Unsigned; use core::convert::{TryFrom, TryInto}; use crypto_common::{Block, BlockSizeUser}; +use inout::InOutBuf; /// Block-level synchronous stream ciphers. pub trait StreamCipherCore: BlockSizeUser + Sized { @@ -9,7 +10,7 @@ pub trait StreamCipherCore: BlockSizeUser + Sized { /// /// Returns `None` if number of remaining blocks can not be computed /// (e.g. in ciphers based on the sponge construction) or it's too big - /// to fit to `usize`. + /// to fit into `usize`. fn remaining_blocks(&self) -> Option; /// Apply keystream blocks with pre and post callbacks using @@ -23,13 +24,28 @@ pub trait StreamCipherCore: BlockSizeUser + Sized { post_fn: impl FnMut(&[Block]), ); - /// Apply keystream to data not divided into blocks. + /// Try to apply keystream to data not divided into blocks. /// /// Consumes cipher since it may consume final keystream block only /// partially. /// - /// WARNING: this method does not check number of remaining blocks! - fn apply_keystream_partial(mut self, mut buf: InOutBuf<'_, u8>) { + /// Returns an error if number of remaining blocks is not sufficient + /// for processing the input data. + fn try_apply_keystream_partial( + mut self, + mut buf: InOutBuf<'_, u8>, + ) -> Result<(), StreamCipherError> { + if let Some(rem) = self.remaining_blocks() { + let blocks = if buf.len() % Self::BlockSize::USIZE == 0 { + buf.len() % Self::BlockSize::USIZE + } else { + buf.len() % Self::BlockSize::USIZE + 1 + }; + if blocks > rem { + return Err(StreamCipherError); + } + } + if buf.len() > Self::BlockSize::USIZE { let (blocks, tail) = buf.into_chunks(); self.apply_keystream_blocks(blocks, |_| {}, |_| {}); @@ -37,13 +53,26 @@ pub trait StreamCipherCore: BlockSizeUser + Sized { } let n = buf.len(); if n == 0 { - return; + return Ok(()); } let mut block = Block::::default(); block[..n].copy_from_slice(buf.get_in()); let mut t = InOutBuf::from_mut(&mut block); self.apply_keystream_blocks(t.reborrow(), |_| {}, |_| {}); buf.get_out().copy_from_slice(&block[..n]); + Ok(()) + } + + /// Try to apply keystream to data not divided into blocks. + /// + /// Consumes cipher since it may consume final keystream block only + /// partially. + /// + /// # Panics + /// If number of remaining blocks is not sufficient for processing the + /// input data. + fn apply_keystream_partial(self, buf: InOutBuf<'_, u8>) { + self.try_apply_keystream_partial(buf).unwrap() } } diff --git a/cipher/src/stream_wrapper.rs b/cipher/src/stream_wrapper.rs index 8b8cb7238..1b4971967 100644 --- a/cipher/src/stream_wrapper.rs +++ b/cipher/src/stream_wrapper.rs @@ -1,10 +1,10 @@ use crate::{ - errors::StreamCipherError, OverflowError, SeekNum, Block, - StreamCipher, StreamCipherCore, StreamCipherSeek, StreamCipherSeekCore, + errors::StreamCipherError, Block, OverflowError, SeekNum, StreamCipher, StreamCipherCore, + StreamCipherSeek, StreamCipherSeekCore, }; -use inout::InOutBuf; use crypto_common::{BlockSizeUser, Iv, IvSizeUser, Key, KeyInit, KeyIvInit, KeySizeUser}; use generic_array::typenum::Unsigned; +use inout::InOutBuf; /// Wrapper around [`StreamCipherCore`] implementations. /// @@ -106,11 +106,8 @@ impl StreamCipher for StreamCipherCoreWrapper { let n = leftover.len(); if n != 0 { let mut block = Default::default(); - self.core.apply_keystream_blocks( - InOutBuf::from_mut(&mut block), - |_| {}, - |_| {}, - ); + self.core + .apply_keystream_blocks(InOutBuf::from_mut(&mut block), |_| {}, |_| {}); leftover.xor(&block[..n]); self.buffer = block; } From 11961b13bd79d599a932e7e169dd843f9ffe2a39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Fri, 12 Nov 2021 17:53:10 +0300 Subject: [PATCH 49/63] add update method to the Mac trait --- digest/src/mac.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/digest/src/mac.rs b/digest/src/mac.rs index 2222aabdb..1cdc4267f 100644 --- a/digest/src/mac.rs +++ b/digest/src/mac.rs @@ -21,6 +21,9 @@ pub trait Mac: KeySizeUser + OutputSizeUser + Sized { /// Create new value from variable size key. fn new_from_slice(key: &[u8]) -> Result; + /// Update state using the provided data. + fn update(&mut self, data: &[u8]); + /// Obtain the result of a [`Mac`] computation as a [`CtOutput`] and consume /// [`Mac`] instance. fn finalize(self) -> CtOutput; @@ -58,6 +61,11 @@ impl Mac for T { KeyInit::new_from_slice(key) } + #[inline] + fn update(&mut self, data: &[u8]) { + Update::update(self, data); + } + #[inline] fn finalize(self) -> CtOutput { CtOutput::new(self.finalize_fixed()) From 8e443f4cae9a8d7713ed7a9d68b670e9d1c19475 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Fri, 12 Nov 2021 18:08:22 +0300 Subject: [PATCH 50/63] digest: add new_mac_test macro --- digest/src/dev.rs | 56 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/digest/src/dev.rs b/digest/src/dev.rs index 926ebbd53..f46495ba3 100644 --- a/digest/src/dev.rs +++ b/digest/src/dev.rs @@ -244,3 +244,59 @@ macro_rules! bench { $crate::bench!(bench4_10000, $engine, 10000); }; } + + +/// Define MAC test +#[macro_export] +#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] +macro_rules! new_mac_test { + ($name:ident, $test_name:expr, $mac:ty) => { + #[test] + fn $name() { + use digest::dev::blobby::Blob3Iterator; + use digest::Mac; + + fn run_test(key: &[u8], input: &[u8], tag: &[u8]) -> Option<&'static str> { + let mut mac = <$mac as Mac>::new_from_slice(key).unwrap(); + mac.update(input); + let result = mac.finalize_reset(); + if &result.into_bytes()[..] != tag { + return Some("whole message"); + } + let tag = tag.into(); + + // test if reset worked correctly + mac.update(input); + if mac.verify(tag).is_err() { + return Some("after reset"); + } + + let mut mac = <$mac as Mac>::new_from_slice(key).unwrap(); + // test reading byte by byte + for i in 0..input.len() { + mac.update(&input[i..i + 1]); + } + if let Err(_) = mac.verify(tag) { + return Some("message byte-by-byte"); + } + None + } + + let data = include_bytes!(concat!("data/", $test_name, ".blb")); + + for (i, row) in Blob3Iterator::new(data).unwrap().enumerate() { + let [key, input, tag] = row.unwrap(); + if let Some(desc) = run_test(key, input, tag) { + panic!( + "\n\ + Failed test №{}: {}\n\ + key:\t{:?}\n\ + input:\t{:?}\n\ + tag:\t{:?}\n", + i, desc, key, input, tag, + ); + } + } + } + }; +} From 402b17441ac390801e0121c04f2c615223ed7c2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Fri, 12 Nov 2021 20:54:23 +0300 Subject: [PATCH 51/63] digest: remove default features --- digest/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/digest/Cargo.toml b/digest/Cargo.toml index 1c9d6020e..37a442d36 100644 --- a/digest/Cargo.toml +++ b/digest/Cargo.toml @@ -20,7 +20,6 @@ subtle = { version = "=2.4", default-features = false, optional = true } blobby = { version = "0.3", optional = true } [features] -default = ["block-padding", "mac"] mac = ["subtle"] # Enable MAC traits alloc = [] std = ["alloc", "crypto-common/std"] From f15e7bdfd39a10c9bce5240f6536fe4ab91e673f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Fri, 12 Nov 2021 22:24:54 +0300 Subject: [PATCH 52/63] digest: use new block-buffer --- digest/src/core_api.rs | 26 +++++++++++++---------- digest/src/core_api/ct_variable.rs | 10 +++++---- digest/src/core_api/rt_variable.rs | 4 ++-- digest/src/core_api/wrapper.rs | 34 +++++++++++++++--------------- digest/src/core_api/xof_reader.rs | 4 ++-- digest/src/dev.rs | 1 - 6 files changed, 42 insertions(+), 37 deletions(-) diff --git a/digest/src/core_api.rs b/digest/src/core_api.rs index 2f7b5733d..be557ed40 100644 --- a/digest/src/core_api.rs +++ b/digest/src/core_api.rs @@ -8,7 +8,7 @@ use generic_array::ArrayLength; pub use crypto_common::{AlgorithmName, Block, BlockSizeUser, OutputSizeUser, Reset}; -use block_buffer::DigestBuffer; +use block_buffer::{BlockBuffer, BufferKind}; use crypto_common::Output; mod ct_variable; @@ -21,33 +21,37 @@ pub use rt_variable::RtVariableCoreWrapper; pub use wrapper::CoreWrapper; pub use xof_reader::XofReaderCoreWrapper; +/// Buffer type used by type which implements [`BufferKindUser`]. +pub type Buffer = + BlockBuffer<::BlockSize, ::BufferKind>; + /// Types which consume data in blocks. pub trait UpdateCore: BlockSizeUser { /// Update state using the provided data blocks. fn update_blocks(&mut self, blocks: &[Block]); } -/// Types which use [`DigestBuffer`] functionality. -pub trait BufferUser: BlockSizeUser { - /// Block buffer type over which value operates. - type Buffer: DigestBuffer; +/// Types which use [`BlockBuffer`] functionality. +pub trait BufferKindUser: BlockSizeUser { + /// Block buffer kind over which type operates. + type BufferKind: BufferKind; } /// Core trait for hash functions with fixed output size. -pub trait FixedOutputCore: UpdateCore + BufferUser + OutputSizeUser { +pub trait FixedOutputCore: UpdateCore + BufferKindUser + OutputSizeUser { /// Finalize state using remaining data stored in the provided block buffer, /// write result into provided array and leave `self` in a dirty state. - fn finalize_fixed_core(&mut self, buffer: &mut Self::Buffer, out: &mut Output); + fn finalize_fixed_core(&mut self, buffer: &mut Buffer, out: &mut Output); } /// Core trait for hash functions with extendable (XOF) output size. -pub trait ExtendableOutputCore: UpdateCore + BufferUser { +pub trait ExtendableOutputCore: UpdateCore + BufferKindUser { /// XOF reader core state. type ReaderCore: XofReaderCore; /// Retrieve XOF reader using remaining data stored in the block buffer /// and leave hasher in a dirty state. - fn finalize_xof_core(&mut self, buffer: &mut Self::Buffer) -> Self::ReaderCore; + fn finalize_xof_core(&mut self, buffer: &mut Buffer) -> Self::ReaderCore; } /// Core reader trait for extendable-output function (XOF) result. @@ -57,7 +61,7 @@ pub trait XofReaderCore: BlockSizeUser { } /// Core trait for hash functions with variable output size. -pub trait VariableOutputCore: UpdateCore + BufferUser + Sized { +pub trait VariableOutputCore: UpdateCore + BufferKindUser + Sized { /// Maximum output size. type MaxOutputSize: ArrayLength; @@ -72,7 +76,7 @@ pub trait VariableOutputCore: UpdateCore + BufferUser + Sized { /// `output_size` must be equal to `output_size` used during construction. fn finalize_variable_core( &mut self, - buffer: &mut Self::Buffer, + buffer: &mut Buffer, output_size: usize, f: impl FnOnce(&[u8]), ); diff --git a/digest/src/core_api/ct_variable.rs b/digest/src/core_api/ct_variable.rs index a0fd16d46..a843ccd1f 100644 --- a/digest/src/core_api/ct_variable.rs +++ b/digest/src/core_api/ct_variable.rs @@ -1,4 +1,6 @@ -use super::{AlgorithmName, BufferUser, FixedOutputCore, Reset, UpdateCore, VariableOutputCore}; +use super::{ + AlgorithmName, Buffer, BufferKindUser, FixedOutputCore, Reset, UpdateCore, VariableOutputCore, +}; use crate::HashMarker; #[cfg(feature = "mac")] use crate::MacMarker; @@ -69,13 +71,13 @@ where type OutputSize = OutSize; } -impl BufferUser for CtVariableCoreWrapper +impl BufferKindUser for CtVariableCoreWrapper where T: VariableOutputCore, OutSize: ArrayLength + IsLessOrEqual, LeEq: NonZero, { - type Buffer = T::Buffer; + type BufferKind = T::BufferKind; } impl FixedOutputCore for CtVariableCoreWrapper @@ -87,7 +89,7 @@ where #[inline] fn finalize_fixed_core( &mut self, - buffer: &mut Self::Buffer, + buffer: &mut Buffer, out: &mut GenericArray, ) { self.inner diff --git a/digest/src/core_api/rt_variable.rs b/digest/src/core_api/rt_variable.rs index 4b6ef29cb..c41487fdb 100644 --- a/digest/src/core_api/rt_variable.rs +++ b/digest/src/core_api/rt_variable.rs @@ -3,7 +3,7 @@ use crate::HashMarker; #[cfg(feature = "mac")] use crate::MacMarker; use crate::{InvalidOutputSize, Reset, Update, VariableOutput}; -use block_buffer::DigestBuffer; +use block_buffer::BlockBuffer; use core::fmt; use generic_array::typenum::Unsigned; @@ -15,7 +15,7 @@ where T: VariableOutputCore + UpdateCore, { core: T, - buffer: T::Buffer, + buffer: BlockBuffer, output_size: usize, } diff --git a/digest/src/core_api/wrapper.rs b/digest/src/core_api/wrapper.rs index 2a895cde7..e554f6868 100644 --- a/digest/src/core_api/wrapper.rs +++ b/digest/src/core_api/wrapper.rs @@ -1,30 +1,30 @@ use super::{ - AlgorithmName, BufferUser, ExtendableOutputCore, FixedOutputCore, OutputSizeUser, Reset, - UpdateCore, XofReaderCoreWrapper, + AlgorithmName, Buffer, BufferKindUser, ExtendableOutputCore, FixedOutputCore, OutputSizeUser, + Reset, UpdateCore, XofReaderCoreWrapper, }; use crate::{ExtendableOutput, FixedOutput, FixedOutputReset, HashMarker, Update}; -use block_buffer::DigestBuffer; +use block_buffer::BlockBuffer; use core::fmt; use crypto_common::{Key, KeyInit, KeySizeUser, Output}; #[cfg(feature = "mac")] use crate::MacMarker; -/// Wrapper around [`BufferUser`]. +/// Wrapper around [`BufferKindUser`]. /// /// It handles data buffering and implements the slice-based traits. #[derive(Clone, Default)] -pub struct CoreWrapper { +pub struct CoreWrapper { core: T, - buffer: T::Buffer, + buffer: BlockBuffer, } -impl HashMarker for CoreWrapper {} +impl HashMarker for CoreWrapper {} #[cfg(feature = "mac")] -impl MacMarker for CoreWrapper {} +impl MacMarker for CoreWrapper {} -impl CoreWrapper { +impl CoreWrapper { /// Create new wrapper from `core`. #[inline] pub fn from_core(core: T) -> Self { @@ -34,17 +34,17 @@ impl CoreWrapper { /// Decompose wrapper into inner parts. #[inline] - pub fn decompose(self) -> (T, T::Buffer) { + pub fn decompose(self) -> (T, Buffer) { let Self { core, buffer } = self; (core, buffer) } } -impl KeySizeUser for CoreWrapper { +impl KeySizeUser for CoreWrapper { type KeySize = T::KeySize; } -impl KeyInit for CoreWrapper { +impl KeyInit for CoreWrapper { fn new(key: &Key) -> Self { Self { core: T::new(key), @@ -53,14 +53,14 @@ impl KeyInit for CoreWrapper { } } -impl fmt::Debug for CoreWrapper { +impl fmt::Debug for CoreWrapper { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { T::write_alg_name(f)?; f.write_str(" { .. }") } } -impl Reset for CoreWrapper { +impl Reset for CoreWrapper { #[inline] fn reset(&mut self) { self.core.reset(); @@ -68,7 +68,7 @@ impl Reset for CoreWrapper { } } -impl Update for CoreWrapper { +impl Update for CoreWrapper { #[inline] fn update(&mut self, input: &[u8]) { let Self { core, buffer } = self; @@ -76,7 +76,7 @@ impl Update for CoreWrapper { } } -impl OutputSizeUser for CoreWrapper { +impl OutputSizeUser for CoreWrapper { type OutputSize = D::OutputSize; } @@ -120,7 +120,7 @@ impl ExtendableOutput for CoreWrapper { #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl std::io::Write for CoreWrapper { +impl std::io::Write for CoreWrapper { #[inline] fn write(&mut self, buf: &[u8]) -> std::io::Result { Update::update(self, buf); diff --git a/digest/src/core_api/xof_reader.rs b/digest/src/core_api/xof_reader.rs index 810cd75dd..b9daf9fa5 100644 --- a/digest/src/core_api/xof_reader.rs +++ b/digest/src/core_api/xof_reader.rs @@ -1,6 +1,6 @@ use super::{AlgorithmName, XofReaderCore}; use crate::XofReader; -use block_buffer::BlockBuffer; +use block_buffer::EagerBuffer; use core::fmt; /// Wrapper around [`XofReaderCore`] implementations. @@ -9,7 +9,7 @@ use core::fmt; #[derive(Clone, Default)] pub struct XofReaderCoreWrapper { pub(super) core: T, - pub(super) buffer: BlockBuffer, + pub(super) buffer: EagerBuffer, } impl fmt::Debug for XofReaderCoreWrapper { diff --git a/digest/src/dev.rs b/digest/src/dev.rs index f46495ba3..7b7788720 100644 --- a/digest/src/dev.rs +++ b/digest/src/dev.rs @@ -245,7 +245,6 @@ macro_rules! bench { }; } - /// Define MAC test #[macro_export] #[cfg_attr(docsrs, doc(cfg(feature = "dev")))] From 60ee50e39ec2952e07e77c4b7813423007a73976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Fri, 12 Nov 2021 22:27:25 +0300 Subject: [PATCH 53/63] update Cargo.lock --- Cargo.lock | 239 +++++------------------------------------------------ 1 file changed, 22 insertions(+), 217 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5f2a90ff0..b03759cb8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -33,21 +33,9 @@ dependencies = [ [[package]] name = "base64ct" -version = "1.2.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "392c772b012d685a640cdad68a5a21f4a45e696f85a2c2c907aab2fe49a91e19" - -[[package]] -name = "bitvec" -version = "0.22.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5237f00a8c86130a0cc317830e558b966dd7850d48a953d998c813f01a41b527" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] +checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b" [[package]] name = "blobby" @@ -93,15 +81,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "cipher" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" -dependencies = [ - "generic-array", -] - [[package]] name = "cipher" version = "0.4.0" @@ -113,12 +92,6 @@ dependencies = [ "inout", ] -[[package]] -name = "const-oid" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b" - [[package]] name = "cpufeatures" version = "0.2.1" @@ -128,32 +101,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crypto" -version = "0.3.0" -dependencies = [ - "aead", - "cipher 0.3.0", - "crypto-mac", - "digest 0.9.0", - "elliptic-curve", - "password-hash", - "signature", - "universal-hash", -] - -[[package]] -name = "crypto-bigint" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83bd3bb4314701c568e340cd8cf78c975aa0ca79e03d3f6d1677d5b0c9c0c03" -dependencies = [ - "generic-array", - "rand_core", - "subtle", - "zeroize", -] - [[package]] name = "crypto-common" version = "0.1.0" @@ -162,25 +109,6 @@ dependencies = [ "rand_core", ] -[[package]] -name = "crypto-mac" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" -dependencies = [ - "generic-array", - "subtle", -] - -[[package]] -name = "der" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28e98c534e9c8a0483aa01d6f6913bc063de254311bd267c9cf535e9b70e15b2" -dependencies = [ - "const-oid", -] - [[package]] name = "digest" version = "0.9.0" @@ -201,41 +129,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "elliptic-curve" -version = "0.10.6" -dependencies = [ - "base64ct", - "crypto-bigint", - "ff", - "generic-array", - "group", - "hex-literal", - "pkcs8", - "rand_core", - "serde", - "serde_json", - "subtle", - "zeroize", -] - -[[package]] -name = "ff" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f" -dependencies = [ - "bitvec", - "rand_core", - "subtle", -] - -[[package]] -name = "funty" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1847abb9cb65d566acd5942e94aea9c8f547ad02c98e1649326fc0e8910b8b1e" - [[package]] name = "generic-array" version = "0.14.4" @@ -257,17 +150,6 @@ dependencies = [ "wasi", ] -[[package]] -name = "group" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912" -dependencies = [ - "ff", - "rand_core", - "subtle", -] - [[package]] name = "hash32" version = "0.2.1" @@ -290,9 +172,22 @@ dependencies = [ [[package]] name = "hex-literal" -version = "0.3.4" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" +checksum = "961de220ec9a91af2e1e5bd80d02109155695e516771762381ef8581317066e0" +dependencies = [ + "hex-literal-impl", + "proc-macro-hack", +] + +[[package]] +name = "hex-literal-impl" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "853f769599eb31de176303197b7ba4973299c38c7a7604a6bc88c3eef05b9b46" +dependencies = [ + "proc-macro-hack", +] [[package]] name = "inout" @@ -302,12 +197,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - [[package]] name = "libc" version = "0.2.107" @@ -331,7 +220,7 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "password-hash" -version = "0.3.0" +version = "0.3.2" dependencies = [ "base64ct", "rand_core", @@ -339,25 +228,10 @@ dependencies = [ ] [[package]] -name = "pem-rfc7468" -version = "0.2.3" +name = "proc-macro-hack" +version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f22eb0e3c593294a99e9ff4b24cf6b752d43f193aa4415fe5077c159996d497" -dependencies = [ - "base64ct", -] - -[[package]] -name = "pkcs8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee3ef9b64d26bad0536099c816c6734379e45bbd5f14798def6809e5cc350447" -dependencies = [ - "der", - "pem-rfc7468", - "spki", - "zeroize", -] +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" @@ -377,12 +251,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "radium" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" - [[package]] name = "rand_core" version = "0.6.3" @@ -392,35 +260,12 @@ dependencies = [ "getrandom", ] -[[package]] -name = "ryu" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" - [[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "serde" -version = "1.0.130" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" - -[[package]] -name = "serde_json" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e466864e431129c7e0d3476b92f20458e5879919a0596c6472738d9fa2d342f8" -dependencies = [ - "itoa", - "ryu", - "serde", -] - [[package]] name = "sha2" version = "0.9.8" @@ -436,7 +281,7 @@ dependencies = [ [[package]] name = "signature" -version = "1.3.1" +version = "1.4.0" dependencies = [ "digest 0.9.0", "hex-literal", @@ -464,15 +309,6 @@ dependencies = [ "lock_api", ] -[[package]] -name = "spki" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c01a0c15da1b0b0e1494112e7af814a678fec9bd157881b49beac661e9b6f32" -dependencies = [ - "der", -] - [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -508,12 +344,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - [[package]] name = "typenum" version = "1.14.0" @@ -526,16 +356,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" -[[package]] -name = "universal-hash" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "version_check" version = "0.9.3" @@ -547,18 +367,3 @@ name = "wasi" version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" - -[[package]] -name = "wyz" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "129e027ad65ce1453680623c3fb5163cbf7107bfe1aa32257e7d0e63f9ced188" -dependencies = [ - "tap", -] - -[[package]] -name = "zeroize" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d68d9dcec5f9b43a30d38c49f91dfedfaac384cb8f085faca366c26207dd1619" From 73218ad80af82158b4bb5a01293b22412ec566eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Thu, 18 Nov 2021 17:00:08 +0300 Subject: [PATCH 54/63] digest: update MAC test macros --- digest/src/dev.rs | 75 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 67 insertions(+), 8 deletions(-) diff --git a/digest/src/dev.rs b/digest/src/dev.rs index 7b7788720..4fb2773d3 100644 --- a/digest/src/dev.rs +++ b/digest/src/dev.rs @@ -254,9 +254,66 @@ macro_rules! new_mac_test { fn $name() { use digest::dev::blobby::Blob3Iterator; use digest::Mac; + use core::cmp::min; fn run_test(key: &[u8], input: &[u8], tag: &[u8]) -> Option<&'static str> { - let mut mac = <$mac as Mac>::new_from_slice(key).unwrap(); + let mac0 = <$mac as Mac>::new_from_slice(key).unwrap(); + + let mut mac = mac0.clone(); + mac.update(input); + let result = mac.finalize(); + if &result.into_bytes()[..] != tag { + return Some("whole message"); + } + let tag = tag.into(); + + // test reading different chunk sizes + for chunk_size in 1..min(64, input.len()) { + let mut mac = mac0.clone(); + for chunk in input.chunks(chunk_size) { + mac.update(chunk); + } + if let Err(_) = mac.verify(tag) { + return Some("chunked message"); + } + } + + None + } + + let data = include_bytes!(concat!("data/", $test_name, ".blb")); + + for (i, row) in Blob3Iterator::new(data).unwrap().enumerate() { + let [key, input, tag] = row.unwrap(); + if let Some(desc) = run_test(key, input, tag) { + panic!( + "\n\ + Failed test №{}: {}\n\ + key:\t{:?}\n\ + input:\t{:?}\n\ + tag:\t{:?}\n", + i, desc, key, input, tag, + ); + } + } + } + }; +} + +/// Define new test for a resettable MAC +#[macro_export] +#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] +macro_rules! new_resettable_mac_test { + ($name:ident, $test_name:expr, $mac:ty) => { + #[test] + fn $name() { + use digest::dev::blobby::Blob3Iterator; + use digest::Mac; + + fn run_test(key: &[u8], input: &[u8], tag: &[u8]) -> Option<&'static str> { + let mac0 = <$mac as Mac>::new_from_slice(key).unwrap(); + + let mut mac = mac0.clone(); mac.update(input); let result = mac.finalize_reset(); if &result.into_bytes()[..] != tag { @@ -270,13 +327,15 @@ macro_rules! new_mac_test { return Some("after reset"); } - let mut mac = <$mac as Mac>::new_from_slice(key).unwrap(); - // test reading byte by byte - for i in 0..input.len() { - mac.update(&input[i..i + 1]); - } - if let Err(_) = mac.verify(tag) { - return Some("message byte-by-byte"); + // test reading different chunk sizes + for chunk_size in 1..min(64, input.len()) { + let mut mac = mac0.clone(); + for chunk in input.chunks(chunk_size) { + mac.update(chunk); + } + if let Err(_) = mac.verify(tag) { + return Some("chunked message"); + } } None } From 15507cfbd46efa6511a3a420dcf79ceb0170833a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Thu, 18 Nov 2021 17:02:13 +0300 Subject: [PATCH 55/63] digest: fix KeyInit impl for CoreWrapper --- digest/src/core_api/wrapper.rs | 9 ++++++++- digest/src/dev.rs | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/digest/src/core_api/wrapper.rs b/digest/src/core_api/wrapper.rs index e554f6868..47ec03840 100644 --- a/digest/src/core_api/wrapper.rs +++ b/digest/src/core_api/wrapper.rs @@ -5,7 +5,7 @@ use super::{ use crate::{ExtendableOutput, FixedOutput, FixedOutputReset, HashMarker, Update}; use block_buffer::BlockBuffer; use core::fmt; -use crypto_common::{Key, KeyInit, KeySizeUser, Output}; +use crypto_common::{InvalidLength, Key, KeyInit, KeySizeUser, Output}; #[cfg(feature = "mac")] use crate::MacMarker; @@ -51,6 +51,13 @@ impl KeyInit for CoreWrapper { buffer: Default::default(), } } + + fn new_from_slice(key: &[u8]) -> Result { + Ok(Self { + core: T::new_from_slice(key)?, + buffer: Default::default(), + }) + } } impl fmt::Debug for CoreWrapper { diff --git a/digest/src/dev.rs b/digest/src/dev.rs index 4fb2773d3..c923a4e4d 100644 --- a/digest/src/dev.rs +++ b/digest/src/dev.rs @@ -252,9 +252,9 @@ macro_rules! new_mac_test { ($name:ident, $test_name:expr, $mac:ty) => { #[test] fn $name() { + use core::cmp::min; use digest::dev::blobby::Blob3Iterator; use digest::Mac; - use core::cmp::min; fn run_test(key: &[u8], input: &[u8], tag: &[u8]) -> Option<&'static str> { let mac0 = <$mac as Mac>::new_from_slice(key).unwrap(); From 6eb7bfb7507492739b12ebdc6e760375f109e3a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Thu, 18 Nov 2021 18:19:19 +0300 Subject: [PATCH 56/63] digest: add CoreProxy --- digest/src/core_api.rs | 2 +- digest/src/core_api/wrapper.rs | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/digest/src/core_api.rs b/digest/src/core_api.rs index be557ed40..efeee4919 100644 --- a/digest/src/core_api.rs +++ b/digest/src/core_api.rs @@ -18,7 +18,7 @@ mod xof_reader; pub use ct_variable::CtVariableCoreWrapper; pub use rt_variable::RtVariableCoreWrapper; -pub use wrapper::CoreWrapper; +pub use wrapper::{CoreProxy, CoreWrapper}; pub use xof_reader::XofReaderCoreWrapper; /// Buffer type used by type which implements [`BufferKindUser`]. diff --git a/digest/src/core_api/wrapper.rs b/digest/src/core_api/wrapper.rs index 47ec03840..f655e625d 100644 --- a/digest/src/core_api/wrapper.rs +++ b/digest/src/core_api/wrapper.rs @@ -139,3 +139,20 @@ impl std::io::Write for CoreWrapper { Ok(()) } } + +/// A proxy trait to a core type implemented by [`CoreWrapper`] +// TODO: replace with an inherent associated type on stabilization: +// https://github.com/rust-lang/rust/issues/8995 +pub trait CoreProxy: sealed::Sealed { + type Core; +} + +mod sealed { + pub trait Sealed {} +} + +impl sealed::Sealed for CoreWrapper {} + +impl CoreProxy for CoreWrapper { + type Core = T; +} From 02574a0630766f55a1d1e34f274544bc456178f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Thu, 18 Nov 2021 18:52:49 +0300 Subject: [PATCH 57/63] digest: fix export --- digest/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/digest/src/lib.rs b/digest/src/lib.rs index da42d20f0..aebad936d 100644 --- a/digest/src/lib.rs +++ b/digest/src/lib.rs @@ -54,10 +54,10 @@ mod mac; pub use block_buffer; pub use crypto_common; +pub use crate::digest::{Digest, DynDigest, HashMarker, InvalidBufferLength}; #[cfg(feature = "mac")] pub use crypto_common::{InnerInit, InvalidLength, Key, KeyInit}; pub use crypto_common::{Output, OutputSizeUser, Reset}; -pub use digest::{Digest, DynDigest, HashMarker, InvalidBufferLength}; pub use generic_array::{self, typenum::consts}; #[cfg(feature = "mac")] pub use mac::{CtOutput, Mac, MacError, MacMarker}; From 9109053bf06cfd3a124475800e975e572431d923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Thu, 18 Nov 2021 18:55:31 +0300 Subject: [PATCH 58/63] digest: fix test macro --- digest/src/dev.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/digest/src/dev.rs b/digest/src/dev.rs index c923a4e4d..bb060bedd 100644 --- a/digest/src/dev.rs +++ b/digest/src/dev.rs @@ -307,6 +307,7 @@ macro_rules! new_resettable_mac_test { ($name:ident, $test_name:expr, $mac:ty) => { #[test] fn $name() { + use core::cmp::min; use digest::dev::blobby::Blob3Iterator; use digest::Mac; From 68143c9f6e4a6b14a0cfb011b7f94b0ce700f6ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Thu, 18 Nov 2021 21:36:22 +0300 Subject: [PATCH 59/63] digest: add trunc MAC tests --- digest/src/core_api/wrapper.rs | 1 + digest/src/dev.rs | 65 ++++++++++++++++++++++++++++------ digest/src/mac.rs | 28 ++++++++++++--- 3 files changed, 80 insertions(+), 14 deletions(-) diff --git a/digest/src/core_api/wrapper.rs b/digest/src/core_api/wrapper.rs index f655e625d..ef4862540 100644 --- a/digest/src/core_api/wrapper.rs +++ b/digest/src/core_api/wrapper.rs @@ -144,6 +144,7 @@ impl std::io::Write for CoreWrapper { // TODO: replace with an inherent associated type on stabilization: // https://github.com/rust-lang/rust/issues/8995 pub trait CoreProxy: sealed::Sealed { + /// Type wrapped by [`CoreWrapper`]. type Core; } diff --git a/digest/src/dev.rs b/digest/src/dev.rs index bb060bedd..edb3c6ca9 100644 --- a/digest/src/dev.rs +++ b/digest/src/dev.rs @@ -247,9 +247,19 @@ macro_rules! bench { /// Define MAC test #[macro_export] -#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] +#[cfg(feature = "mac")] +#[cfg_attr(docsrs, doc(cfg(all(feature = "dev", feature = "mac"))))] macro_rules! new_mac_test { ($name:ident, $test_name:expr, $mac:ty) => { + new_mac_test!($name, $test_name, $mac, ""); + }; + ($name:ident, $test_name:expr, $mac:ty, trunc_left) => { + new_mac_test!($name, $test_name, $mac, "left"); + }; + ($name:ident, $test_name:expr, $mac:ty, trunc_right) => { + new_mac_test!($name, $test_name, $mac, "right"); + }; + ($name:ident, $test_name:expr, $mac:ty, $reset:expr) => { #[test] fn $name() { use core::cmp::min; @@ -262,10 +272,15 @@ macro_rules! new_mac_test { let mut mac = mac0.clone(); mac.update(input); let result = mac.finalize(); - if &result.into_bytes()[..] != tag { + let n = tag.len(); + let result_bytes = match $reset { + "left" => &result[..n], + "right" => &result[result.len() - n..], + _ => &result[..], + } + if result_bytes != tag { return Some("whole message"); } - let tag = tag.into(); // test reading different chunk sizes for chunk_size in 1..min(64, input.len()) { @@ -273,7 +288,12 @@ macro_rules! new_mac_test { for chunk in input.chunks(chunk_size) { mac.update(chunk); } - if let Err(_) = mac.verify(tag) { + let res = match $reset { + "left" => mac.verify_truncated_left(tag), + "right" => mac.verify_truncated_right(tag), + _ => mac.verify_slice(tag), + }; + if res.is_err() { return Some("chunked message"); } } @@ -302,9 +322,19 @@ macro_rules! new_mac_test { /// Define new test for a resettable MAC #[macro_export] -#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] +#[cfg(feature = "mac")] +#[cfg_attr(docsrs, doc(cfg(all(feature = "dev", feature = "mac"))))] macro_rules! new_resettable_mac_test { ($name:ident, $test_name:expr, $mac:ty) => { + new_resettable_mac_test!($name, $test_name, $mac, ""); + }; + ($name:ident, $test_name:expr, $mac:ty, trunc_left) => { + new_resettable_mac_test!($name, $test_name, $mac, "left"); + }; + ($name:ident, $test_name:expr, $mac:ty, trunc_right) => { + new_resettable_mac_test!($name, $test_name, $mac, "right"); + }; + ($name:ident, $test_name:expr, $mac:ty, $trunc:expr) => { #[test] fn $name() { use core::cmp::min; @@ -316,15 +346,25 @@ macro_rules! new_resettable_mac_test { let mut mac = mac0.clone(); mac.update(input); - let result = mac.finalize_reset(); - if &result.into_bytes()[..] != tag { + let result = mac.finalize(); + let n = tag.len(); + let result_bytes = match $reset { + "left" => &result[..n], + "right" => &result[result.len() - n..], + _ => &result[..], + } + if result_bytes != tag { return Some("whole message"); } - let tag = tag.into(); // test if reset worked correctly mac.update(input); - if mac.verify(tag).is_err() { + let res = match $reset { + "left" => mac.verify_truncated_left(tag), + "right" => mac.verify_truncated_right(tag), + _ => mac.verify_slice(tag), + }; + if res.is_err() { return Some("after reset"); } @@ -334,7 +374,12 @@ macro_rules! new_resettable_mac_test { for chunk in input.chunks(chunk_size) { mac.update(chunk); } - if let Err(_) = mac.verify(tag) { + let res = match $reset { + "left" => mac.verify_truncated_left(tag), + "right" => mac.verify_truncated_right(tag), + _ => mac.verify_slice(tag), + }; + if res.is_err() { return Some("chunked message"); } } diff --git a/digest/src/mac.rs b/digest/src/mac.rs index 1cdc4267f..df1d0c2b1 100644 --- a/digest/src/mac.rs +++ b/digest/src/mac.rs @@ -35,7 +35,14 @@ pub trait Mac: KeySizeUser + OutputSizeUser + Sized { Self: FixedOutputReset; /// Check if tag/code value is correct for the processed input. - fn verify(self, other: &Output) -> Result<(), MacError>; + fn verify(self, tag: &Output) -> Result<(), MacError>; + + /// Check truncated tag correctness using all bytes + /// of calculated tag. + /// + /// Returns `Error` if `tag` is not valid or not equal in length + /// to MAC's output. + fn verify_slice(self, tag: &[u8]) -> Result<(), MacError>; /// Check truncated tag correctness using left side bytes /// (i.e. `tag[..n]`) of calculated tag. @@ -79,10 +86,23 @@ impl Mac for T { CtOutput::new(self.finalize_fixed_reset()) } - /// Check if tag/code value is correct for the processed input. #[inline] - fn verify(self, other: &Output) -> Result<(), MacError> { - if self.finalize() == other.into() { + fn verify(self, tag: &Output) -> Result<(), MacError> { + if self.finalize() == tag.into() { + Ok(()) + } else { + Err(MacError) + } + } + + #[inline] + fn verify_slice(self, tag: &[u8]) -> Result<(), MacError> { + let n = tag.len(); + if n != Self::OutputSize::USIZE { + return Err(MacError); + } + let choice = self.finalize_fixed().ct_eq(&tag); + if choice.unwrap_u8() == 1 { Ok(()) } else { Err(MacError) From fef8a9740245427f059acc2eaef4336653b753ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Thu, 18 Nov 2021 21:44:48 +0300 Subject: [PATCH 60/63] digest: fix MAC test macros --- digest/src/dev.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/digest/src/dev.rs b/digest/src/dev.rs index edb3c6ca9..13ab1254b 100644 --- a/digest/src/dev.rs +++ b/digest/src/dev.rs @@ -259,7 +259,7 @@ macro_rules! new_mac_test { ($name:ident, $test_name:expr, $mac:ty, trunc_right) => { new_mac_test!($name, $test_name, $mac, "right"); }; - ($name:ident, $test_name:expr, $mac:ty, $reset:expr) => { + ($name:ident, $test_name:expr, $mac:ty, $trunc:expr) => { #[test] fn $name() { use core::cmp::min; @@ -271,13 +271,13 @@ macro_rules! new_mac_test { let mut mac = mac0.clone(); mac.update(input); - let result = mac.finalize(); + let result = mac.finalize().into_bytes(); let n = tag.len(); - let result_bytes = match $reset { + let result_bytes = match $trunc { "left" => &result[..n], "right" => &result[result.len() - n..], _ => &result[..], - } + }; if result_bytes != tag { return Some("whole message"); } @@ -288,7 +288,7 @@ macro_rules! new_mac_test { for chunk in input.chunks(chunk_size) { mac.update(chunk); } - let res = match $reset { + let res = match $trunc { "left" => mac.verify_truncated_left(tag), "right" => mac.verify_truncated_right(tag), _ => mac.verify_slice(tag), @@ -346,20 +346,20 @@ macro_rules! new_resettable_mac_test { let mut mac = mac0.clone(); mac.update(input); - let result = mac.finalize(); + let result = mac.finalize_reset().into_bytes(); let n = tag.len(); - let result_bytes = match $reset { + let result_bytes = match $trunc { "left" => &result[..n], "right" => &result[result.len() - n..], _ => &result[..], - } + }; if result_bytes != tag { return Some("whole message"); } // test if reset worked correctly mac.update(input); - let res = match $reset { + let res = match $trunc { "left" => mac.verify_truncated_left(tag), "right" => mac.verify_truncated_right(tag), _ => mac.verify_slice(tag), @@ -374,7 +374,7 @@ macro_rules! new_resettable_mac_test { for chunk in input.chunks(chunk_size) { mac.update(chunk); } - let res = match $reset { + let res = match $trunc { "left" => mac.verify_truncated_left(tag), "right" => mac.verify_truncated_right(tag), _ => mac.verify_slice(tag), From db6169a4073899a76ee3676b6e62b2fd463872ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Thu, 18 Nov 2021 21:46:15 +0300 Subject: [PATCH 61/63] digest: fix MAC test macros --- digest/src/dev.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/digest/src/dev.rs b/digest/src/dev.rs index 13ab1254b..0ecea312e 100644 --- a/digest/src/dev.rs +++ b/digest/src/dev.rs @@ -251,13 +251,13 @@ macro_rules! bench { #[cfg_attr(docsrs, doc(cfg(all(feature = "dev", feature = "mac"))))] macro_rules! new_mac_test { ($name:ident, $test_name:expr, $mac:ty) => { - new_mac_test!($name, $test_name, $mac, ""); + digest::new_mac_test!($name, $test_name, $mac, ""); }; ($name:ident, $test_name:expr, $mac:ty, trunc_left) => { - new_mac_test!($name, $test_name, $mac, "left"); + digest::new_mac_test!($name, $test_name, $mac, "left"); }; ($name:ident, $test_name:expr, $mac:ty, trunc_right) => { - new_mac_test!($name, $test_name, $mac, "right"); + digest::new_mac_test!($name, $test_name, $mac, "right"); }; ($name:ident, $test_name:expr, $mac:ty, $trunc:expr) => { #[test] @@ -326,13 +326,13 @@ macro_rules! new_mac_test { #[cfg_attr(docsrs, doc(cfg(all(feature = "dev", feature = "mac"))))] macro_rules! new_resettable_mac_test { ($name:ident, $test_name:expr, $mac:ty) => { - new_resettable_mac_test!($name, $test_name, $mac, ""); + digest::new_resettable_mac_test!($name, $test_name, $mac, ""); }; ($name:ident, $test_name:expr, $mac:ty, trunc_left) => { - new_resettable_mac_test!($name, $test_name, $mac, "left"); + digest::new_resettable_mac_test!($name, $test_name, $mac, "left"); }; ($name:ident, $test_name:expr, $mac:ty, trunc_right) => { - new_resettable_mac_test!($name, $test_name, $mac, "right"); + digest::new_resettable_mac_test!($name, $test_name, $mac, "right"); }; ($name:ident, $test_name:expr, $mac:ty, $trunc:expr) => { #[test] From 5bb02a6f8b5dd9d6b686a896e0787f34505920da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Thu, 18 Nov 2021 21:59:31 +0300 Subject: [PATCH 62/63] digest: allow optional comma in macros --- digest/src/dev.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/digest/src/dev.rs b/digest/src/dev.rs index 0ecea312e..c1200d748 100644 --- a/digest/src/dev.rs +++ b/digest/src/dev.rs @@ -9,7 +9,7 @@ use core::fmt::Debug; #[macro_export] #[cfg_attr(docsrs, doc(cfg(feature = "dev")))] macro_rules! new_test { - ($name:ident, $test_name:expr, $hasher:ty, $test_func:ident) => { + ($name:ident, $test_name:expr, $hasher:ty, $test_func:ident $(,)?) => { #[test] fn $name() { use digest::dev::blobby::Blob2Iterator; @@ -250,16 +250,16 @@ macro_rules! bench { #[cfg(feature = "mac")] #[cfg_attr(docsrs, doc(cfg(all(feature = "dev", feature = "mac"))))] macro_rules! new_mac_test { - ($name:ident, $test_name:expr, $mac:ty) => { + ($name:ident, $test_name:expr, $mac:ty $(,)?) => { digest::new_mac_test!($name, $test_name, $mac, ""); }; - ($name:ident, $test_name:expr, $mac:ty, trunc_left) => { + ($name:ident, $test_name:expr, $mac:ty, trunc_left $(,)?) => { digest::new_mac_test!($name, $test_name, $mac, "left"); }; - ($name:ident, $test_name:expr, $mac:ty, trunc_right) => { + ($name:ident, $test_name:expr, $mac:ty, trunc_right $(,)?) => { digest::new_mac_test!($name, $test_name, $mac, "right"); }; - ($name:ident, $test_name:expr, $mac:ty, $trunc:expr) => { + ($name:ident, $test_name:expr, $mac:ty, $trunc:expr $(,)?) => { #[test] fn $name() { use core::cmp::min; @@ -325,16 +325,16 @@ macro_rules! new_mac_test { #[cfg(feature = "mac")] #[cfg_attr(docsrs, doc(cfg(all(feature = "dev", feature = "mac"))))] macro_rules! new_resettable_mac_test { - ($name:ident, $test_name:expr, $mac:ty) => { + ($name:ident, $test_name:expr, $mac:ty $(,)?) => { digest::new_resettable_mac_test!($name, $test_name, $mac, ""); }; - ($name:ident, $test_name:expr, $mac:ty, trunc_left) => { + ($name:ident, $test_name:expr, $mac:ty, trunc_left $(,)?) => { digest::new_resettable_mac_test!($name, $test_name, $mac, "left"); }; - ($name:ident, $test_name:expr, $mac:ty, trunc_right) => { + ($name:ident, $test_name:expr, $mac:ty, trunc_right $(,)?) => { digest::new_resettable_mac_test!($name, $test_name, $mac, "right"); }; - ($name:ident, $test_name:expr, $mac:ty, $trunc:expr) => { + ($name:ident, $test_name:expr, $mac:ty, $trunc:expr $(,)?) => { #[test] fn $name() { use core::cmp::min; From 077c141b57f5284709756500209f432aa2d450a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Fri, 19 Nov 2021 21:28:47 +0300 Subject: [PATCH 63/63] cipher: disable block-buffer dep --- Cargo.lock | 1 - cipher/Cargo.toml | 2 +- cipher/src/lib.rs | 2 +- cipher/src/stream_core.rs | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b03759cb8..9cadc58bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -86,7 +86,6 @@ name = "cipher" version = "0.4.0" dependencies = [ "blobby", - "block-buffer 0.10.0", "crypto-common", "generic-array", "inout", diff --git a/cipher/Cargo.toml b/cipher/Cargo.toml index cebdafc60..272b0acde 100644 --- a/cipher/Cargo.toml +++ b/cipher/Cargo.toml @@ -14,7 +14,7 @@ categories = ["cryptography", "no-std"] [dependencies] generic-array = "0.14" crypto-common = { version = "0.1", path = "../crypto-common" } -block-buffer = { version = "0.10.0", features = ["block-padding"] } +#block-buffer = { version = "0.10.0", features = ["block-padding"] } # TODO: remove and use re-import from block-buffer inout = "0.1" diff --git a/cipher/src/lib.rs b/cipher/src/lib.rs index 151e0a5c9..d9c0e82be 100644 --- a/cipher/src/lib.rs +++ b/cipher/src/lib.rs @@ -23,7 +23,7 @@ extern crate std; #[cfg(feature = "dev")] pub use blobby; -pub use block_buffer; +//pub use block_buffer; mod block; #[cfg(feature = "dev")] diff --git a/cipher/src/stream_core.rs b/cipher/src/stream_core.rs index ce8eccfbd..263b17238 100644 --- a/cipher/src/stream_core.rs +++ b/cipher/src/stream_core.rs @@ -1,7 +1,7 @@ use crate::errors::StreamCipherError; -use block_buffer::generic_array::typenum::Unsigned; use core::convert::{TryFrom, TryInto}; use crypto_common::{Block, BlockSizeUser}; +use generic_array::typenum::Unsigned; use inout::InOutBuf; /// Block-level synchronous stream ciphers.