diff --git a/Cargo.lock b/Cargo.lock index ac9536a6a..33d01836f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,7 +19,7 @@ dependencies = [ "arrayvec", "blobby", "bytes", - "crypto-common 0.2.0-rc.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crypto-common 0.2.0-rc.0", "heapless", ] @@ -130,7 +130,7 @@ version = "0.11.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17092d478f4fadfb35a7e082f62e49f0907fdf048801d9d706277e34f9df8a78" dependencies = [ - "crypto-common 0.2.0-rc.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crypto-common 0.2.0-rc.0", "zeroize", ] @@ -160,15 +160,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fca2be1d5c43812bae364ee3f30b3afcb7877cf59f4aeb94c66f313a41d2fac9" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cc" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" +checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" dependencies = [ "jobserver", "libc", @@ -217,10 +217,10 @@ dependencies = [ [[package]] name = "cipher" -version = "0.5.0-pre.6" +version = "0.5.0-pre.7" dependencies = [ "blobby", - "crypto-common 0.2.0-rc.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crypto-common 0.2.0-rc.1", "inout 0.2.0-rc.0", "zeroize", ] @@ -317,6 +317,8 @@ dependencies = [ [[package]] name = "crypto-common" version = "0.2.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c070b79a496dccd931229780ad5bbedd535ceff6c3565605a8e440e18e1aa2b" dependencies = [ "getrandom", "hybrid-array", @@ -325,9 +327,7 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.2.0-rc.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c070b79a496dccd931229780ad5bbedd535ceff6c3565605a8e440e18e1aa2b" +version = "0.2.0-rc.1" dependencies = [ "getrandom", "hybrid-array", @@ -435,7 +435,7 @@ dependencies = [ "blobby", "block-buffer 0.11.0-rc.0", "const-oid 0.10.0-rc.0", - "crypto-common 0.2.0-rc.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crypto-common 0.2.0-rc.0", "subtle", "zeroize", ] @@ -926,9 +926,12 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "dee4364d9f3b902ef14fab8a1ddffb783a1cb6b4bba3bfc1fa3922732c7de97f" +dependencies = [ + "zerocopy", +] [[package]] name = "pqcrypto" @@ -1115,9 +1118,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.121" +version = "1.0.124" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ab380d7d9f22ef3f21ad3e6c1ebe8e4fc7a2000ccba2e4d71fc96f15b2cb609" +checksum = "66ad62847a56b3dba58cc891acd13884b9c61138d330c0d7b6181713d4fce38d" dependencies = [ "itoa", "memchr", @@ -1303,7 +1306,7 @@ dependencies = [ name = "universal-hash" version = "0.6.0-rc.0" dependencies = [ - "crypto-common 0.2.0-rc.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crypto-common 0.2.0-rc.0", "subtle", ] @@ -1356,6 +1359,27 @@ dependencies = [ "sha2 0.9.9", ] +[[package]] +name = "zerocopy" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854e949ac82d619ee9a14c66a1b674ac730422372ccb759ce0c39cabcf2bf8e6" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "125139de3f6b9d625c39e2efdd73d41bdac468ccd556556440e322be0e1bbd91" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "zeroize" version = "1.8.1" diff --git a/cipher/Cargo.toml b/cipher/Cargo.toml index 044e84b4c..1125a68b4 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.5.0-pre.6" +version = "0.5.0-pre.7" authors = ["RustCrypto Developers"] license = "MIT OR Apache-2.0" readme = "README.md" @@ -13,18 +13,19 @@ keywords = ["crypto", "block-cipher", "stream-cipher", "trait"] categories = ["cryptography", "no-std"] [dependencies] -crypto-common = "0.2.0-rc.0" +crypto-common = { version = "0.2.0-rc.1", path = "../crypto-common/" } inout = "0.2.0-rc.0" # optional dependencies blobby = { version = "0.3", optional = true } -zeroize = { version = "1.7", optional = true, default-features = false } +zeroize = { version = "1.8", optional = true, default-features = false } [features] alloc = [] std = ["alloc", "crypto-common/std", "inout/std"] block-padding = ["inout/block-padding"] -rand_core = ["crypto-common/rand_core"] # Enable random key and IV generation methods +# Enable random key and IV generation methods +rand_core = ["crypto-common/rand_core"] dev = ["blobby"] [package.metadata.docs.rs] diff --git a/cipher/src/block.rs b/cipher/src/block.rs index fd69bf570..3699ebfdb 100644 --- a/cipher/src/block.rs +++ b/cipher/src/block.rs @@ -10,10 +10,9 @@ //! [2]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation //! [3]: https://en.wikipedia.org/wiki/Symmetric-key_algorithm -use crate::{ParBlocks, ParBlocksSizeUser}; #[cfg(all(feature = "block-padding", feature = "alloc"))] use alloc::{vec, vec::Vec}; -use crypto_common::BlockSizes; +use crypto_common::{Block, BlockSizeUser}; #[cfg(feature = "block-padding")] use inout::{ block_padding::{Padding, UnpadError}, @@ -21,66 +20,20 @@ use inout::{ }; use inout::{InOut, InOutBuf, NotEqualError}; -pub use crypto_common::{array::ArraySize, typenum::Unsigned, Block, BlockSizeUser}; +mod backends; +mod ctx; -/// Marker trait for block ciphers. -pub trait BlockCipher: BlockSizeUser {} +use ctx::{BlockCtx, BlocksCtx}; -/// Trait implemented by block cipher encryption and decryption backends. -pub trait BlockBackend: ParBlocksSizeUser { - /// Process single inout block. - fn proc_block(&mut self, block: InOut<'_, '_, Block>); - - /// Process inout blocks in parallel. - #[inline(always)] - fn proc_par_blocks(&mut self, mut blocks: InOut<'_, '_, ParBlocks>) { - for i in 0..Self::ParBlocksSize::USIZE { - self.proc_block(blocks.get(i)); - } - } - - /// Process buffer of inout blocks. Length of the buffer MUST be smaller - /// than `Self::ParBlocksSize`. - #[inline(always)] - fn proc_tail_blocks(&mut self, blocks: InOutBuf<'_, '_, Block>) { - assert!(blocks.len() < Self::ParBlocksSize::USIZE); - for block in blocks { - self.proc_block(block); - } - } - - /// Process single block in-place. - #[inline(always)] - fn proc_block_inplace(&mut self, block: &mut Block) { - self.proc_block(block.into()); - } - - /// Process blocks in parallel in-place. - #[inline(always)] - fn proc_par_blocks_inplace(&mut self, blocks: &mut ParBlocks) { - self.proc_par_blocks(blocks.into()); - } - - /// Process buffer of blocks in-place. Length of the buffer MUST be smaller - /// than `Self::ParBlocksSize`. - #[inline(always)] - fn proc_tail_blocks_inplace(&mut self, blocks: &mut [Block]) { - self.proc_tail_blocks(blocks.into()); - } -} - -/// Trait for [`BlockBackend`] users. -/// -/// This trait is used to define rank-2 closures. -pub trait BlockClosure: BlockSizeUser { - /// Execute closure with the provided block cipher backend. - fn call>(self, backend: &mut B); -} +pub use backends::{ + BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherEncBackend, BlockCipherEncClosure, + BlockModeDecBackend, BlockModeDecClosure, BlockModeEncBackend, BlockModeEncClosure, +}; /// Encrypt-only functionality for block ciphers. pub trait BlockCipherEncrypt: BlockSizeUser + Sized { /// Encrypt data using backend provided to the rank-2 closure. - fn encrypt_with_backend(&self, f: impl BlockClosure); + fn encrypt_with_backend(&self, f: impl BlockCipherEncClosure); /// Encrypt single `inout` block. #[inline] @@ -178,7 +131,9 @@ pub trait BlockCipherEncrypt: BlockSizeUser + Sized { #[cfg(all(feature = "block-padding", feature = "alloc"))] #[inline] fn encrypt_padded_vec>(&self, msg: &[u8]) -> Vec { - let mut out = allocate_out_vec::(msg.len()); + use crypto_common::typenum::Unsigned; + let bs = Self::BlockSize::USIZE; + let mut out = vec![0; bs * (msg.len() / bs + 1)]; let len = self .encrypt_padded_b2b::

(msg, &mut out) .expect("enough space for encrypting is allocated") @@ -191,7 +146,7 @@ pub trait BlockCipherEncrypt: BlockSizeUser + Sized { /// Decrypt-only functionality for block ciphers. pub trait BlockCipherDecrypt: BlockSizeUser { /// Decrypt data using backend provided to the rank-2 closure. - fn decrypt_with_backend(&self, f: impl BlockClosure); + fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure); /// Decrypt single `inout` block. #[inline] @@ -310,6 +265,18 @@ pub trait BlockCipherDecrypt: BlockSizeUser { } } +impl BlockCipherEncrypt for &Alg { + fn encrypt_with_backend(&self, f: impl BlockCipherEncClosure) { + Alg::encrypt_with_backend(self, f); + } +} + +impl BlockCipherDecrypt for &Alg { + fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure) { + Alg::decrypt_with_backend(self, f); + } +} + /// Encrypt-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 @@ -317,7 +284,7 @@ pub trait BlockCipherDecrypt: BlockSizeUser { /// underlying hardware peripheral. pub trait BlockModeEncrypt: BlockSizeUser + Sized { /// Encrypt data using backend provided to the rank-2 closure. - fn encrypt_with_backend(&mut self, f: impl BlockClosure); + fn encrypt_with_backend(&mut self, f: impl BlockModeEncClosure); /// Encrypt single `inout` block. #[inline] @@ -415,7 +382,9 @@ pub trait BlockModeEncrypt: BlockSizeUser + Sized { #[cfg(all(feature = "block-padding", feature = "alloc"))] #[inline] fn encrypt_padded_vec>(self, msg: &[u8]) -> Vec { - let mut out = allocate_out_vec::(msg.len()); + use crypto_common::typenum::Unsigned; + let bs = Self::BlockSize::USIZE; + let mut out = vec![0; bs * (msg.len() / bs + 1)]; let len = self .encrypt_padded_b2b::

(msg, &mut out) .expect("enough space for encrypting is allocated") @@ -432,7 +401,7 @@ pub trait BlockModeEncrypt: BlockSizeUser + Sized { /// underlying hardware peripheral. pub trait BlockModeDecrypt: BlockSizeUser + Sized { /// Decrypt data using backend provided to the rank-2 closure. - fn decrypt_with_backend(&mut self, f: impl BlockClosure); + fn decrypt_with_backend(&mut self, f: impl BlockModeDecClosure); /// Decrypt single `inout` block. #[inline] @@ -550,145 +519,3 @@ pub trait BlockModeDecrypt: BlockSizeUser + Sized { Ok(out) } } - -impl BlockCipher for &Alg {} - -impl BlockCipherEncrypt for &Alg { - fn encrypt_with_backend(&self, f: impl BlockClosure) { - Alg::encrypt_with_backend(self, f); - } -} - -impl BlockCipherDecrypt for &Alg { - fn decrypt_with_backend(&self, f: impl BlockClosure) { - Alg::decrypt_with_backend(self, f); - } -} - -/// Closure used in methods which operate over separate blocks. -struct BlockCtx<'inp, 'out, BS: BlockSizes> { - block: InOut<'inp, 'out, Block>, -} - -impl<'inp, 'out, BS: BlockSizes> BlockSizeUser for BlockCtx<'inp, 'out, BS> { - type BlockSize = BS; -} - -impl<'inp, 'out, BS: BlockSizes> BlockClosure for BlockCtx<'inp, 'out, BS> { - #[inline(always)] - fn call>(self, backend: &mut B) { - backend.proc_block(self.block); - } -} - -/// Closure used in methods which operate over slice of blocks. -struct BlocksCtx<'inp, 'out, BS: BlockSizes> { - blocks: InOutBuf<'inp, 'out, Block>, -} - -impl<'inp, 'out, BS: BlockSizes> BlockSizeUser for BlocksCtx<'inp, 'out, BS> { - type BlockSize = BS; -} - -impl<'inp, 'out, BS: BlockSizes> BlockClosure for BlocksCtx<'inp, 'out, BS> { - #[inline(always)] - fn call>(self, backend: &mut B) { - if B::ParBlocksSize::USIZE > 1 { - let (chunks, tail) = self.blocks.into_chunks(); - for chunk in chunks { - backend.proc_par_blocks(chunk); - } - backend.proc_tail_blocks(tail); - } else { - for block in self.blocks { - backend.proc_block(block); - } - } - } -} - -#[cfg(all(feature = "block-padding", feature = "alloc"))] -fn allocate_out_vec(len: usize) -> Vec { - let bs = BS::BlockSize::USIZE; - vec![0; bs * (len / bs + 1)] -} - -/// Implement simple block backend -#[macro_export] -macro_rules! impl_simple_block_encdec { - ( - <$($N:ident$(:$b0:ident$(+$b:ident)*)?),*> - $cipher:ident, $block_size:ty, $state:ident, $block:ident, - encrypt: $enc_block:block - decrypt: $dec_block:block - ) => { - impl<$($N$(:$b0$(+$b)*)?),*> $crate::BlockSizeUser for $cipher<$($N),*> { - type BlockSize = $block_size; - } - - impl<$($N$(:$b0$(+$b)*)?),*> $crate::BlockCipherEncrypt for $cipher<$($N),*> { - fn encrypt_with_backend(&self, f: impl $crate::BlockClosure) { - struct EncBack<'a, $($N$(:$b0$(+$b)*)?),* >(&'a $cipher<$($N),*>); - - impl<'a, $($N$(:$b0$(+$b)*)?),* > $crate::BlockSizeUser for EncBack<'a, $($N),*> { - type BlockSize = $block_size; - } - - impl<'a, $($N$(:$b0$(+$b)*)?),* > $crate::ParBlocksSizeUser for EncBack<'a, $($N),*> { - type ParBlocksSize = $crate::consts::U1; - } - - impl<'a, $($N$(:$b0$(+$b)*)?),* > $crate::BlockBackend for EncBack<'a, $($N),*> { - #[inline(always)] - fn proc_block( - &mut self, - mut $block: $crate::inout::InOut<'_, '_, $crate::Block> - ) { - let $state: &$cipher<$($N),*> = self.0; - $enc_block - } - } - - f.call(&mut EncBack(self)) - } - } - - impl<$($N$(:$b0$(+$b)*)?),*> $crate::BlockCipherDecrypt for $cipher<$($N),*> { - fn decrypt_with_backend(&self, f: impl $crate::BlockClosure) { - struct DecBack<'a, $($N$(:$b0$(+$b)*)?),* >(&'a $cipher<$($N),*>); - - impl<'a, $($N$(:$b0$(+$b)*)?),* > $crate::BlockSizeUser for DecBack<'a, $($N),*> { - type BlockSize = $block_size; - } - - impl<'a, $($N$(:$b0$(+$b)*)?),* > $crate::ParBlocksSizeUser for DecBack<'a, $($N),*> { - type ParBlocksSize = $crate::consts::U1; - } - - impl<'a, $($N$(:$b0$(+$b)*)?),* > $crate::BlockBackend for DecBack<'a, $($N),*> { - #[inline(always)] - fn proc_block( - &mut self, - mut $block: $crate::inout::InOut<'_, '_, $crate::Block> - ) { - let $state: &$cipher<$($N),*> = self.0; - $dec_block - } - } - - f.call(&mut DecBack(self)) - } - } - }; - ( - $cipher:ident, $block_size:ty, $state:ident, $block:ident, - encrypt: $enc_block:block - decrypt: $dec_block:block - ) => { - $crate::impl_simple_block_encdec!( - <> $cipher, $block_size, $state, $block, - encrypt: $enc_block - decrypt: $dec_block - ); - }; -} diff --git a/cipher/src/block/backends.rs b/cipher/src/block/backends.rs new file mode 100644 index 000000000..e035b3993 --- /dev/null +++ b/cipher/src/block/backends.rs @@ -0,0 +1,206 @@ +use crypto_common::{typenum::Unsigned, Block, BlockSizeUser, ParBlocks, ParBlocksSizeUser}; +use inout::{InOut, InOutBuf}; + +/// Trait implemented by block cipher mode encryption backends. +pub trait BlockCipherEncBackend: ParBlocksSizeUser { + /// Encrypt single inout block. + fn encrypt_block(&self, block: InOut<'_, '_, Block>); + + /// Encrypt inout blocks in parallel. + #[inline(always)] + fn encrypt_par_blocks(&self, mut blocks: InOut<'_, '_, ParBlocks>) { + for i in 0..Self::ParBlocksSize::USIZE { + self.encrypt_block(blocks.get(i)); + } + } + + /// Encrypt buffer of inout blocks. Length of the buffer MUST be smaller + /// than `Self::ParBlocksSize`. + #[inline(always)] + fn encrypt_tail_blocks(&self, blocks: InOutBuf<'_, '_, Block>) { + assert!(blocks.len() < Self::ParBlocksSize::USIZE); + for block in blocks { + self.encrypt_block(block); + } + } + + /// Encrypt single block in-place. + #[inline(always)] + fn encrypt_block_inplace(&self, block: &mut Block) { + self.encrypt_block(block.into()); + } + + /// Encrypt blocks in parallel in-place. + #[inline(always)] + fn encrypt_par_blocks_inplace(&self, blocks: &mut ParBlocks) { + self.encrypt_par_blocks(blocks.into()); + } + + /// Encrypt buffer of blocks in-place. Length of the buffer MUST be smaller + /// than `Self::ParBlocksSize`. + #[inline(always)] + fn encrypt_tail_blocks_inplace(&self, blocks: &mut [Block]) { + self.encrypt_tail_blocks(blocks.into()); + } +} + +/// Trait for [`BlockCipherEncBackend`] users. +/// +/// This trait is used to define rank-2 closures. +pub trait BlockCipherEncClosure: BlockSizeUser { + /// Execute closure with the provided block cipher backend. + fn call>(self, backend: &B); +} + +/// Trait implemented by block cipher decryption backends. +pub trait BlockCipherDecBackend: ParBlocksSizeUser { + /// Decrypt single inout block. + fn decrypt_block(&self, block: InOut<'_, '_, Block>); + + /// Decrypt inout blocks in parallel. + #[inline(always)] + fn decrypt_par_blocks(&self, mut blocks: InOut<'_, '_, ParBlocks>) { + for i in 0..Self::ParBlocksSize::USIZE { + self.decrypt_block(blocks.get(i)); + } + } + + /// Decrypt buffer of inout blocks. Length of the buffer MUST be smaller + /// than `Self::ParBlocksSize`. + #[inline(always)] + fn decrypt_tail_blocks(&self, blocks: InOutBuf<'_, '_, Block>) { + assert!(blocks.len() < Self::ParBlocksSize::USIZE); + for block in blocks { + self.decrypt_block(block); + } + } + + /// Decrypt single block in-place. + #[inline(always)] + fn decrypt_block_inplace(&self, block: &mut Block) { + self.decrypt_block(block.into()); + } + + /// Decrypt blocks in parallel in-place. + #[inline(always)] + fn decrypt_par_blocks_inplace(&self, blocks: &mut ParBlocks) { + self.decrypt_par_blocks(blocks.into()); + } + + /// Decrypt buffer of blocks in-place. Length of the buffer MUST be smaller + /// than `Self::ParBlocksSize`. + #[inline(always)] + fn decrypt_tail_blocks_inplace(&self, blocks: &mut [Block]) { + self.decrypt_tail_blocks(blocks.into()); + } +} + +/// Trait for [`BlockCipherDecBackend`] users. +/// +/// This trait is used to define rank-2 closures. +pub trait BlockCipherDecClosure: BlockSizeUser { + /// Execute closure with the provided block cipher backend. + fn call>(self, backend: &B); +} + +/// Trait implemented by block cipher mode encryption backends. +pub trait BlockModeEncBackend: ParBlocksSizeUser { + /// Encrypt single inout block. + fn encrypt_block(&mut self, block: InOut<'_, '_, Block>); + + /// Encrypt inout blocks in parallel. + #[inline(always)] + fn encrypt_par_blocks(&mut self, mut blocks: InOut<'_, '_, ParBlocks>) { + for i in 0..Self::ParBlocksSize::USIZE { + self.encrypt_block(blocks.get(i)); + } + } + + /// Encrypt buffer of inout blocks. Length of the buffer MUST be smaller + /// than `Self::ParBlocksSize`. + #[inline(always)] + fn encrypt_tail_blocks(&mut self, blocks: InOutBuf<'_, '_, Block>) { + assert!(blocks.len() < Self::ParBlocksSize::USIZE); + for block in blocks { + self.encrypt_block(block); + } + } + + /// Encrypt single block in-place. + #[inline(always)] + fn encrypt_block_inplace(&mut self, block: &mut Block) { + self.encrypt_block(block.into()); + } + + /// Encrypt blocks in parallel in-place. + #[inline(always)] + fn encrypt_par_blocks_inplace(&mut self, blocks: &mut ParBlocks) { + self.encrypt_par_blocks(blocks.into()); + } + + /// Encrypt buffer of blocks in-place. Length of the buffer MUST be smaller + /// than `Self::ParBlocksSize`. + #[inline(always)] + fn encrypt_tail_blocks_inplace(&mut self, blocks: &mut [Block]) { + self.encrypt_tail_blocks(blocks.into()); + } +} + +/// Trait for [`BlockModeEncBackend`] users. +/// +/// This trait is used to define rank-2 closures. +pub trait BlockModeEncClosure: BlockSizeUser { + /// Execute closure with the provided block cipher backend. + fn call>(self, backend: &mut B); +} + +/// Trait implemented by block cipher mode decryption backends. +pub trait BlockModeDecBackend: ParBlocksSizeUser { + /// Decrypt single inout block. + fn decrypt_block(&mut self, block: InOut<'_, '_, Block>); + + /// Decrypt inout blocks in parallel. + #[inline(always)] + fn decrypt_par_blocks(&mut self, mut blocks: InOut<'_, '_, ParBlocks>) { + for i in 0..Self::ParBlocksSize::USIZE { + self.decrypt_block(blocks.get(i)); + } + } + + /// Decrypt buffer of inout blocks. Length of the buffer MUST be smaller + /// than `Self::ParBlocksSize`. + #[inline(always)] + fn decrypt_tail_blocks(&mut self, blocks: InOutBuf<'_, '_, Block>) { + assert!(blocks.len() < Self::ParBlocksSize::USIZE); + for block in blocks { + self.decrypt_block(block); + } + } + + /// Decrypt single block in-place. + #[inline(always)] + fn decrypt_block_inplace(&mut self, block: &mut Block) { + self.decrypt_block(block.into()); + } + + /// Decrypt blocks in parallel in-place. + #[inline(always)] + fn decrypt_par_blocks_inplace(&mut self, blocks: &mut ParBlocks) { + self.decrypt_par_blocks(blocks.into()); + } + + /// Decrypt buffer of blocks in-place. Length of the buffer MUST be smaller + /// than `Self::ParBlocksSize`. + #[inline(always)] + fn decrypt_tail_blocks_inplace(&mut self, blocks: &mut [Block]) { + self.decrypt_tail_blocks(blocks.into()); + } +} + +/// Trait for [`BlockModeDecBackend`] users. +/// +/// This trait is used to define rank-2 closures. +pub trait BlockModeDecClosure: BlockSizeUser { + /// Execute closure with the provided block cipher backend. + fn call>(self, backend: &mut B); +} diff --git a/cipher/src/block/ctx.rs b/cipher/src/block/ctx.rs new file mode 100644 index 000000000..7b0f04632 --- /dev/null +++ b/cipher/src/block/ctx.rs @@ -0,0 +1,120 @@ +use crypto_common::{typenum::Unsigned, Block, BlockSizeUser, BlockSizes}; +use inout::{InOut, InOutBuf}; + +use super::{ + BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherEncBackend, BlockCipherEncClosure, + BlockModeDecBackend, BlockModeDecClosure, BlockModeEncBackend, BlockModeEncClosure, +}; + +/// Closure used in methods which operate over separate blocks. +pub(super) struct BlockCtx<'inp, 'out, BS: BlockSizes> { + pub block: InOut<'inp, 'out, Block>, +} + +impl<'inp, 'out, BS: BlockSizes> BlockSizeUser for BlockCtx<'inp, 'out, BS> { + type BlockSize = BS; +} + +impl<'inp, 'out, BS: BlockSizes> BlockCipherEncClosure for BlockCtx<'inp, 'out, BS> { + #[inline(always)] + fn call>(self, backend: &B) { + backend.encrypt_block(self.block); + } +} + +impl<'inp, 'out, BS: BlockSizes> BlockCipherDecClosure for BlockCtx<'inp, 'out, BS> { + #[inline(always)] + fn call>(self, backend: &B) { + backend.decrypt_block(self.block); + } +} + +impl<'inp, 'out, BS: BlockSizes> BlockModeEncClosure for BlockCtx<'inp, 'out, BS> { + #[inline(always)] + fn call>(self, backend: &mut B) { + backend.encrypt_block(self.block); + } +} + +impl<'inp, 'out, BS: BlockSizes> BlockModeDecClosure for BlockCtx<'inp, 'out, BS> { + #[inline(always)] + fn call>(self, backend: &mut B) { + backend.decrypt_block(self.block); + } +} +/// Closure used in methods which operate over slice of blocks. +pub(super) struct BlocksCtx<'inp, 'out, BS: BlockSizes> { + pub blocks: InOutBuf<'inp, 'out, Block>, +} + +impl<'inp, 'out, BS: BlockSizes> BlockSizeUser for BlocksCtx<'inp, 'out, BS> { + type BlockSize = BS; +} + +impl<'inp, 'out, BS: BlockSizes> BlockCipherEncClosure for BlocksCtx<'inp, 'out, BS> { + #[inline(always)] + fn call>(self, backend: &B) { + if B::ParBlocksSize::USIZE > 1 { + let (chunks, tail) = self.blocks.into_chunks(); + for chunk in chunks { + backend.encrypt_par_blocks(chunk); + } + backend.encrypt_tail_blocks(tail); + } else { + for block in self.blocks { + backend.encrypt_block(block); + } + } + } +} + +impl<'inp, 'out, BS: BlockSizes> BlockCipherDecClosure for BlocksCtx<'inp, 'out, BS> { + #[inline(always)] + fn call>(self, backend: &B) { + if B::ParBlocksSize::USIZE > 1 { + let (chunks, tail) = self.blocks.into_chunks(); + for chunk in chunks { + backend.decrypt_par_blocks(chunk); + } + backend.decrypt_tail_blocks(tail); + } else { + for block in self.blocks { + backend.decrypt_block(block); + } + } + } +} + +impl<'inp, 'out, BS: BlockSizes> BlockModeEncClosure for BlocksCtx<'inp, 'out, BS> { + #[inline(always)] + fn call>(self, backend: &mut B) { + if B::ParBlocksSize::USIZE > 1 { + let (chunks, tail) = self.blocks.into_chunks(); + for chunk in chunks { + backend.encrypt_par_blocks(chunk); + } + backend.encrypt_tail_blocks(tail); + } else { + for block in self.blocks { + backend.encrypt_block(block); + } + } + } +} + +impl<'inp, 'out, BS: BlockSizes> BlockModeDecClosure for BlocksCtx<'inp, 'out, BS> { + #[inline(always)] + fn call>(self, backend: &mut B) { + if B::ParBlocksSize::USIZE > 1 { + let (chunks, tail) = self.blocks.into_chunks(); + for chunk in chunks { + backend.decrypt_par_blocks(chunk); + } + backend.decrypt_tail_blocks(tail); + } else { + for block in self.blocks { + backend.decrypt_block(block); + } + } + } +} diff --git a/cipher/src/dev/block.rs b/cipher/src/dev/block.rs index 80ea55273..42558c561 100644 --- a/cipher/src/dev/block.rs +++ b/cipher/src/dev/block.rs @@ -7,8 +7,11 @@ macro_rules! block_cipher_test { #[test] fn $name() { use cipher::{ - array::Array, blobby::Blob3Iterator, typenum::Unsigned, BlockCipherDecrypt, - BlockCipherEncrypt, BlockSizeUser, KeyInit, + array::Array, + blobby::Blob3Iterator, + block::{BlockCipherDecrypt, BlockCipherEncrypt}, + typenum::Unsigned, + BlockSizeUser, KeyInit, }; fn run_test(key: &[u8], pt: &[u8], ct: &[u8]) -> bool { @@ -290,7 +293,7 @@ macro_rules! block_encryptor_bench { #[bench] pub fn $block_name(bh: &mut test::Bencher) { #[allow(unused)] - use cipher::{BlockCipherEncrypt, BlockModeEncrypt}; + use $crate::{BlockCipherEncrypt, BlockModeEncrypt}; let mut cipher = $init; let mut blocks = vec![Default::default(); 1024]; @@ -307,7 +310,7 @@ macro_rules! block_encryptor_bench { #[bench] pub fn $blocks_name(bh: &mut test::Bencher) { #[allow(unused)] - use cipher::{BlockCipherEncrypt, BlockModeEncrypt}; + use $crate::{BlockCipherEncrypt, BlockModeEncrypt}; let mut cipher = $init; let mut blocks = vec![Default::default(); 1024]; @@ -353,7 +356,7 @@ macro_rules! block_decryptor_bench { #[bench] pub fn $block_name(bh: &mut test::Bencher) { #[allow(unused)] - use cipher::{BlockCipherDecrypt, BlockModeDecrypt}; + use $crate::{BlockCipherDecrypt, BlockModeDecrypt}; let mut cipher = $init; let mut blocks = vec![Default::default(); 1024]; @@ -370,7 +373,7 @@ macro_rules! block_decryptor_bench { #[bench] pub fn $blocks_name(bh: &mut test::Bencher) { #[allow(unused)] - use cipher::{BlockCipherDecrypt, BlockModeDecrypt}; + use $crate::{BlockCipherDecrypt, BlockModeDecrypt}; let mut cipher = $init; let mut blocks = vec![Default::default(); 1024]; diff --git a/cipher/src/lib.rs b/cipher/src/lib.rs index ba485aa5a..1c7ae89ee 100644 --- a/cipher/src/lib.rs +++ b/cipher/src/lib.rs @@ -18,45 +18,34 @@ missing_debug_implementations )] -pub use crypto_common; -pub use inout; - #[cfg(all(feature = "block-padding", feature = "alloc"))] extern crate alloc; - #[cfg(feature = "std")] extern crate std; +#[cfg(feature = "dev")] +pub use blobby; +pub use crypto_common; #[cfg(feature = "rand_core")] pub use crypto_common::rand_core; - +pub use inout; #[cfg(feature = "block-padding")] pub use inout::block_padding; - #[cfg(feature = "zeroize")] pub use zeroize; -#[cfg(feature = "dev")] -pub use blobby; - -mod block; +pub mod block; #[cfg(feature = "dev")] mod dev; -mod errors; -mod stream; -mod stream_core; -mod stream_wrapper; +pub mod stream; + +pub use block::*; +pub use stream::*; -pub use crate::{block::*, errors::*, stream::*, stream_core::*, stream_wrapper::*}; pub use crypto_common::{ - array, + array::{self, Array}, typenum::{self, consts}, - AlgorithmName, Block, InnerIvInit, InvalidLength, Iv, IvSizeUser, Key, KeyInit, KeyIvInit, - KeySizeUser, ParBlocks, ParBlocksSizeUser, + AlgorithmName, Block, BlockSizeUser, InnerIvInit, InvalidLength, Iv, IvSizeUser, IvState, Key, + KeyInit, KeyIvInit, KeySizeUser, ParBlocks, ParBlocksSizeUser, }; - -/// Trait for loading current IV state. -pub trait IvState: IvSizeUser { - /// Returns current IV state. - fn iv_state(&self) -> Iv; -} +pub use inout::{InOut, InOutBuf}; diff --git a/cipher/src/stream.rs b/cipher/src/stream.rs index ac7a2fe5d..520837db5 100644 --- a/cipher/src/stream.rs +++ b/cipher/src/stream.rs @@ -3,11 +3,21 @@ //! See [RustCrypto/stream-ciphers](https://github.com/RustCrypto/stream-ciphers) //! for ciphers implementation. -use crate::errors::{OverflowError, StreamCipherError}; -use crate::stream_core::Counter; -use crate::{Block, BlockModeDecrypt, BlockModeEncrypt}; +use crate::block::{BlockModeDecrypt, BlockModeEncrypt}; +use crypto_common::Block; use inout::{InOutBuf, NotEqualError}; +mod core_api; +mod errors; +mod wrapper; + +pub use core_api::{ + StreamCipherBackend, StreamCipherClosure, StreamCipherCore, StreamCipherCounter, + StreamCipherSeekCore, +}; +pub use errors::{OverflowError, StreamCipherError}; +pub use wrapper::StreamCipherCoreWrapper; + /// Marker trait for block-level asynchronous stream ciphers pub trait AsyncStreamCipher: Sized { /// Encrypt data using `InOutBuf`. @@ -192,17 +202,21 @@ impl StreamCipher for &mut C { 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: u8, + bs: u8, + ) -> Result; /// Try to get block number and bytes position for given block size `bs`. - fn into_block_byte(self, bs: u8) -> Result<(T, u8), OverflowError>; + fn into_block_byte(self, bs: u8) -> Result<(T, u8), OverflowError>; } macro_rules! impl_seek_num { {$($t:ty )*} => { $( impl SeekNum for $t { - fn from_block_byte(block: T, byte: u8, block_size: u8) -> Result { + fn from_block_byte(block: T, byte: u8, block_size: u8) -> Result { debug_assert!(byte != 0); let rem = block_size.checked_sub(byte).ok_or(OverflowError)?; let block: Self = block.try_into().map_err(|_| OverflowError)?; @@ -212,7 +226,7 @@ macro_rules! impl_seek_num { .ok_or(OverflowError) } - fn into_block_byte(self, block_size: u8) -> Result<(T, u8), OverflowError> { + fn into_block_byte(self, block_size: u8) -> Result<(T, u8), OverflowError> { let bs: Self = block_size.into(); let byte = (self % bs) as u8; let block = T::try_from(self / bs).map_err(|_| OverflowError)?; diff --git a/cipher/src/stream_core.rs b/cipher/src/stream/core_api.rs similarity index 86% rename from cipher/src/stream_core.rs rename to cipher/src/stream/core_api.rs index c121ca46a..aab1c32b5 100644 --- a/cipher/src/stream_core.rs +++ b/cipher/src/stream/core_api.rs @@ -1,9 +1,10 @@ -use crate::{ParBlocks, ParBlocksSizeUser, StreamCipherError}; -use crypto_common::{array::Array, typenum::Unsigned, Block, BlockSizeUser, BlockSizes}; +use super::StreamCipherError; +use crate::{array::Array, typenum::Unsigned}; +use crypto_common::{Block, BlockSizeUser, BlockSizes, ParBlocks, ParBlocksSizeUser}; use inout::{InOut, InOutBuf}; /// Trait implemented by stream cipher backends. -pub trait StreamBackend: ParBlocksSizeUser { +pub trait StreamCipherBackend: ParBlocksSizeUser { /// Generate keystream block. fn gen_ks_block(&mut self, block: &mut Block); @@ -26,12 +27,12 @@ pub trait StreamBackend: ParBlocksSizeUser { } } -/// Trait for [`StreamBackend`] users. +/// Trait for [`StreamCipherBackend`] users. /// /// This trait is used to define rank-2 closures. -pub trait StreamClosure: BlockSizeUser { +pub trait StreamCipherClosure: BlockSizeUser { /// Execute closure with the provided stream cipher backend. - fn call>(self, backend: &mut B); + fn call>(self, backend: &mut B); } /// Block-level synchronous stream ciphers. @@ -44,7 +45,7 @@ pub trait StreamCipherCore: BlockSizeUser + Sized { fn remaining_blocks(&self) -> Option; /// Process data using backend provided to the rank-2 closure. - fn process_with_backend(&mut self, f: impl StreamClosure); + fn process_with_backend(&mut self, f: impl StreamCipherClosure); /// Write keystream block. /// @@ -152,7 +153,7 @@ pub trait StreamCipherCore: BlockSizeUser + Sized { /// 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: +pub trait StreamCipherCounter: TryFrom + TryFrom + TryFrom @@ -169,7 +170,7 @@ pub trait Counter: /// Block-level seeking trait for stream ciphers. pub trait StreamCipherSeekCore: StreamCipherCore { /// Counter type used inside stream cipher. - type Counter: Counter; + type Counter: StreamCipherCounter; /// Get current block position. fn get_block_pos(&self) -> Self::Counter; @@ -180,7 +181,7 @@ pub trait StreamCipherSeekCore: StreamCipherCore { macro_rules! impl_counter { {$($t:ty )*} => { - $( impl Counter for $t { } )* + $( impl StreamCipherCounter for $t { } )* }; } @@ -192,9 +193,9 @@ struct WriteBlockCtx<'a, BS: BlockSizes> { impl<'a, BS: BlockSizes> BlockSizeUser for WriteBlockCtx<'a, BS> { type BlockSize = BS; } -impl<'a, BS: BlockSizes> StreamClosure for WriteBlockCtx<'a, BS> { +impl<'a, BS: BlockSizes> StreamCipherClosure for WriteBlockCtx<'a, BS> { #[inline(always)] - fn call>(self, backend: &mut B) { + fn call>(self, backend: &mut B) { backend.gen_ks_block(self.block); } } @@ -205,9 +206,9 @@ struct WriteBlocksCtx<'a, BS: BlockSizes> { impl<'a, BS: BlockSizes> BlockSizeUser for WriteBlocksCtx<'a, BS> { type BlockSize = BS; } -impl<'a, BS: BlockSizes> StreamClosure for WriteBlocksCtx<'a, BS> { +impl<'a, BS: BlockSizes> StreamCipherClosure for WriteBlocksCtx<'a, BS> { #[inline(always)] - fn call>(self, backend: &mut B) { + fn call>(self, backend: &mut B) { if B::ParBlocksSize::USIZE > 1 { let (chunks, tail) = Array::slice_as_chunks_mut(self.blocks); for chunk in chunks { @@ -230,9 +231,9 @@ impl<'inp, 'out, BS: BlockSizes> BlockSizeUser for ApplyBlockCtx<'inp, 'out, BS> type BlockSize = BS; } -impl<'inp, 'out, BS: BlockSizes> StreamClosure for ApplyBlockCtx<'inp, 'out, BS> { +impl<'inp, 'out, BS: BlockSizes> StreamCipherClosure for ApplyBlockCtx<'inp, 'out, BS> { #[inline(always)] - fn call>(mut self, backend: &mut B) { + fn call>(mut self, backend: &mut B) { let mut t = Default::default(); backend.gen_ks_block(&mut t); self.block.xor_in2out(&t); @@ -247,10 +248,10 @@ impl<'inp, 'out, BS: BlockSizes> BlockSizeUser for ApplyBlocksCtx<'inp, 'out, BS type BlockSize = BS; } -impl<'inp, 'out, BS: BlockSizes> StreamClosure for ApplyBlocksCtx<'inp, 'out, BS> { +impl<'inp, 'out, BS: BlockSizes> StreamCipherClosure for ApplyBlocksCtx<'inp, 'out, BS> { #[inline(always)] #[allow(clippy::needless_range_loop)] - fn call>(self, backend: &mut B) { + fn call>(self, backend: &mut B) { if B::ParBlocksSize::USIZE > 1 { let (chunks, mut tail) = self.blocks.into_chunks::(); for mut chunk in chunks { diff --git a/cipher/src/errors.rs b/cipher/src/stream/errors.rs similarity index 100% rename from cipher/src/errors.rs rename to cipher/src/stream/errors.rs diff --git a/cipher/src/stream_wrapper.rs b/cipher/src/stream/wrapper.rs similarity index 99% rename from cipher/src/stream_wrapper.rs rename to cipher/src/stream/wrapper.rs index 626b4e3d0..abf4a9b04 100644 --- a/cipher/src/stream_wrapper.rs +++ b/cipher/src/stream/wrapper.rs @@ -1,4 +1,4 @@ -use crate::{ +use super::{ errors::StreamCipherError, Block, OverflowError, SeekNum, StreamCipher, StreamCipherCore, StreamCipherSeek, StreamCipherSeekCore, }; diff --git a/crypto-common/Cargo.toml b/crypto-common/Cargo.toml index 8ccd7ea05..52be3f26b 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.2.0-rc.0" +version = "0.2.0-rc.1" authors = ["RustCrypto Developers"] license = "MIT OR Apache-2.0" readme = "README.md" diff --git a/crypto-common/src/lib.rs b/crypto-common/src/lib.rs index 712fcf49b..bd62fade1 100644 --- a/crypto-common/src/lib.rs +++ b/crypto-common/src/lib.rs @@ -305,6 +305,12 @@ pub trait InnerIvInit: InnerUser + IvSizeUser + Sized { } } +/// Trait for loading current IV state. +pub trait IvState: IvSizeUser { + /// Returns current IV state. + fn iv_state(&self) -> Iv; +} + impl KeySizeUser for T where T: InnerUser,