From 59097cca9873628cb71a62da5563264545220a5c Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Sun, 1 Nov 2020 08:13:23 -0800 Subject: [PATCH 1/2] cipher: add encrypt/decrypt-only block cipher traits Closes #349 Adds `Encrypt` and `Decrypt` traits which can be used in cases where e.g. only the encryption portion of a block cipher is used, as in CTR mode. This PR does not otherwise attempt to add things like a blanket impl. --- cipher/src/block.rs | 94 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/cipher/src/block.rs b/cipher/src/block.rs index 551e9d14a..a03bb6147 100644 --- a/cipher/src/block.rs +++ b/cipher/src/block.rs @@ -185,3 +185,97 @@ impl BlockCipher for &Alg { Alg::decrypt_blocks(self, blocks); } } + +/// Encrypt-only functionality for block ciphers +pub trait Encrypt { + /// Size of the block in bytes + type BlockSize: ArrayLength; + + /// Number of blocks which can be processed in parallel by + /// cipher implementation + type ParBlocks: ArrayLength>; + + /// Encrypt block in-place + fn encrypt_block(&self, block: &mut GenericArray); + + /// Encrypt several blocks in parallel using instruction level parallelism + /// if possible. + /// + /// If `ParBlocks` equals to 1 it's equivalent to `encrypt_block`. + #[inline] + fn encrypt_par_blocks( + &self, + blocks: &mut GenericArray, Self::ParBlocks>, + ) { + for block in blocks.iter_mut() { + self.encrypt_block(block); + } + } + + /// Encrypt a slice of blocks, leveraging parallelism when available. + #[inline] + fn encrypt_blocks(&self, mut blocks: &mut [GenericArray]) { + let pb = Self::ParBlocks::to_usize(); + + if pb > 1 { + let mut iter = blocks.chunks_exact_mut(pb); + + for chunk in &mut iter { + self.encrypt_par_blocks(chunk.try_into().unwrap()) + } + + blocks = iter.into_remainder(); + } + + for block in blocks { + self.encrypt_block(block); + } + } +} + +/// Decrypt-only functionality for block ciphers +pub trait Decrypt { + /// Size of the block in bytes + type BlockSize: ArrayLength; + + /// Number of blocks which can be processed in parallel by + /// cipher implementation + type ParBlocks: ArrayLength>; + + /// Decrypt block in-place + fn decrypt_block(&self, block: &mut GenericArray); + + /// Decrypt several blocks in parallel using instruction level parallelism + /// if possible. + /// + /// If `ParBlocks` equals to 1 it's equivalent to `decrypt_block`. + #[inline] + fn decrypt_par_blocks( + &self, + blocks: &mut GenericArray, Self::ParBlocks>, + ) { + for block in blocks.iter_mut() { + self.decrypt_block(block); + } + } + + /// Decrypt a slice of blocks, leveraging parallelism when available. + #[inline] + fn decrypt_blocks(&self, mut blocks: &mut [GenericArray]) { + 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()) + } + + blocks = iter.into_remainder(); + } + + for block in blocks { + self.decrypt_block(block); + } + } +} From 9e21c070f73f975bc615fd72dcaa4f0229f474b2 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Sun, 1 Nov 2020 08:54:11 -0800 Subject: [PATCH 2/2] [WIP] exploring a `BlockCipher` marker trait Attempt at refactoring `BlockCipher` into a trait which marks a type as being capable of both `Encrypt` and `Decrypt`. As far as I can tell this requires the unfortunate change of making the block size and parallel block parameters generic. --- cipher/src/block.rs | 168 +++++++++++++------------------------------ cipher/src/stream.rs | 118 +++++++++++++++--------------- 2 files changed, 111 insertions(+), 175 deletions(-) diff --git a/cipher/src/block.rs b/cipher/src/block.rs index a03bb6147..4989f027e 100644 --- a/cipher/src/block.rs +++ b/cipher/src/block.rs @@ -26,11 +26,11 @@ use generic_array::{typenum::Unsigned, ArrayLength, GenericArray}; /// Key for an algorithm that implements [`NewBlockCipher`]. pub type Key = GenericArray::KeySize>; -/// Block on which a [`BlockCipher`] operates. -pub type Block = GenericArray::BlockSize>; - -/// Blocks being acted over in parallel. -pub type ParBlocks = GenericArray, ::ParBlocks>; +// /// Block on which a [`BlockCipher`] operates. +// pub type Block = GenericArray::BlockSize>; +// +// /// Blocks being acted over in parallel. +// pub type ParBlocks = GenericArray, ::ParBlocks>; /// Instantiate a [`BlockCipher`] algorithm. pub trait NewBlockCipher: Sized { @@ -55,81 +55,13 @@ pub trait NewBlockCipher: Sized { /// The trait which defines in-place encryption and decryption /// over single block or several blocks in parallel. -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>; - - /// Encrypt block in-place - fn encrypt_block(&self, block: &mut Block); - - /// Decrypt block in-place - fn decrypt_block(&self, block: &mut Block); - - /// Encrypt several blocks in parallel using instruction level parallelism - /// if possible. - /// - /// If `ParBlocks` equals to 1 it's equivalent to `encrypt_block`. - #[inline] - fn encrypt_blocks(&self, blocks: &mut ParBlocks) { - for block in blocks.iter_mut() { - self.encrypt_block(block); - } - } - - /// Encrypt a slice of blocks, leveraging parallelism when available. - #[inline] - fn encrypt_slice(&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.encrypt_blocks(chunk.try_into().unwrap()) - } - - blocks = iter.into_remainder(); - } - - for block in blocks { - self.encrypt_block(block); - } - } - - /// Decrypt several blocks in parallel using instruction level parallelism - /// if possible. - /// - /// If `ParBlocks` equals to 1 it's equivalent to `decrypt_block`. - #[inline] - fn decrypt_blocks(&self, blocks: &mut ParBlocks) { - for block in blocks.iter_mut() { - self.decrypt_block(block); - } - } - - /// Decrypt a slice of blocks, leveraging parallelism when available. - #[inline] - fn decrypt_slice(&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_blocks(chunk.try_into().unwrap()) - } - - blocks = iter.into_remainder(); - } - - for block in blocks { - self.decrypt_block(block); - } - } +pub trait BlockCipher +where + BlockSize: ArrayLength, + ParBlocks: ArrayLength>, + Self: Encrypt + + Decrypt, +{ } /// Stateful block cipher which permits `&mut self` access. @@ -147,44 +79,44 @@ pub trait BlockCipherMut { fn decrypt_block(&mut self, block: &mut GenericArray); } -impl BlockCipherMut for Alg { - type BlockSize = Alg::BlockSize; - - #[inline] - fn encrypt_block(&mut self, block: &mut GenericArray) { - ::encrypt_block(self, block); - } - - #[inline] - fn decrypt_block(&mut self, block: &mut GenericArray) { - ::decrypt_block(self, block); - } -} - -impl BlockCipher for &Alg { - type BlockSize = Alg::BlockSize; - type ParBlocks = Alg::ParBlocks; - - #[inline] - fn encrypt_block(&self, block: &mut Block) { - Alg::encrypt_block(self, block); - } - - #[inline] - fn decrypt_block(&self, block: &mut Block) { - Alg::decrypt_block(self, block); - } - - #[inline] - fn encrypt_blocks(&self, blocks: &mut ParBlocks) { - Alg::encrypt_blocks(self, blocks); - } - - #[inline] - fn decrypt_blocks(&self, blocks: &mut ParBlocks) { - Alg::decrypt_blocks(self, blocks); - } -} +// impl BlockCipherMut for Alg { +// type BlockSize = Alg::BlockSize; +// +// #[inline] +// fn encrypt_block(&mut self, block: &mut GenericArray) { +// ::encrypt_block(self, block); +// } +// +// #[inline] +// fn decrypt_block(&mut self, block: &mut GenericArray) { +// ::decrypt_block(self, block); +// } +// } + +// impl BlockCipher for &Alg { +// type BlockSize = Alg::BlockSize; +// type ParBlocks = Alg::ParBlocks; +// +// #[inline] +// fn encrypt_block(&self, block: &mut Block) { +// Alg::encrypt_block(self, block); +// } +// +// #[inline] +// fn decrypt_block(&self, block: &mut Block) { +// Alg::decrypt_block(self, block); +// } +// +// #[inline] +// fn encrypt_blocks(&self, blocks: &mut ParBlocks) { +// Alg::encrypt_blocks(self, blocks); +// } +// +// #[inline] +// fn decrypt_blocks(&self, blocks: &mut ParBlocks) { +// Alg::decrypt_blocks(self, blocks); +// } +// } /// Encrypt-only functionality for block ciphers pub trait Encrypt { diff --git a/cipher/src/stream.rs b/cipher/src/stream.rs index ebc022c5c..c78f259c7 100644 --- a/cipher/src/stream.rs +++ b/cipher/src/stream.rs @@ -155,7 +155,11 @@ impl SyncStreamCipher for &mut C { /// Trait for initializing a stream cipher from a block cipher pub trait FromBlockCipher { /// Block cipher - type BlockCipher: BlockCipher; + type BlockCipher: BlockCipher; + /// Block size + type BlockSize: ArrayLength; + /// Parallel blocks + type ParBlocks: ArrayLength>; /// Nonce size in bytes type NonceSize: ArrayLength; @@ -167,62 +171,62 @@ pub trait FromBlockCipher { } /// Trait for initializing a stream cipher from a mutable block cipher -pub trait FromBlockCipherMut { - /// Block cipher - type BlockCipher: BlockCipherMut; - /// Nonce size in bytes - type NonceSize: ArrayLength; - - /// Instantiate a stream cipher from a block cipher - fn from_block_cipher_mut( - cipher: Self::BlockCipher, - nonce: &GenericArray, - ) -> Self; -} - -impl FromBlockCipherMut for C -where - C: FromBlockCipher, -{ - type BlockCipher = ::BlockCipher; - type NonceSize = ::NonceSize; - - fn from_block_cipher_mut( - cipher: Self::BlockCipher, - nonce: &GenericArray, - ) -> C { - C::from_block_cipher(cipher, nonce) - } -} - -impl NewStreamCipher for C -where - C: FromBlockCipherMut, - C::BlockCipher: NewBlockCipher, -{ - type KeySize = <::BlockCipher as NewBlockCipher>::KeySize; - type NonceSize = ::NonceSize; - - fn new(key: &Key, nonce: &Nonce) -> C { - C::from_block_cipher_mut( - <::BlockCipher as NewBlockCipher>::new(key), - nonce, - ) - } - - fn new_var(key: &[u8], nonce: &[u8]) -> Result { - if nonce.len() != Self::NonceSize::USIZE { - Err(InvalidKeyNonceLength) - } else { - C::BlockCipher::new_varkey(key) - .map_err(|_| InvalidKeyNonceLength) - .map(|cipher| { - let nonce = GenericArray::from_slice(nonce); - Self::from_block_cipher_mut(cipher, nonce) - }) - } - } -} +// pub trait FromBlockCipherMut { +// /// Block cipher +// type BlockCipher: BlockCipherMut; +// /// Nonce size in bytes +// type NonceSize: ArrayLength; +// +// /// Instantiate a stream cipher from a block cipher +// fn from_block_cipher_mut( +// cipher: Self::BlockCipher, +// nonce: &GenericArray, +// ) -> Self; +// } + +// impl FromBlockCipherMut for C +// where +// C: FromBlockCipher, +// { +// type BlockCipher = ::BlockCipher; +// type NonceSize = ::NonceSize; +// +// fn from_block_cipher_mut( +// cipher: Self::BlockCipher, +// nonce: &GenericArray, +// ) -> C { +// C::from_block_cipher(cipher, nonce) +// } +// } + +// impl NewStreamCipher for C +// where +// C: FromBlockCipherMut, +// C::BlockCipher: NewBlockCipher, +// { +// type KeySize = <::BlockCipher as NewBlockCipher>::KeySize; +// type NonceSize = ::NonceSize; +// +// fn new(key: &Key, nonce: &Nonce) -> C { +// C::from_block_cipher_mut( +// <::BlockCipher as NewBlockCipher>::new(key), +// nonce, +// ) +// } +// +// fn new_var(key: &[u8], nonce: &[u8]) -> Result { +// if nonce.len() != Self::NonceSize::USIZE { +// Err(InvalidKeyNonceLength) +// } else { +// C::BlockCipher::new_varkey(key) +// .map_err(|_| InvalidKeyNonceLength) +// .map(|cipher| { +// let nonce = GenericArray::from_slice(nonce); +// Self::from_block_cipher_mut(cipher, nonce) +// }) +// } +// } +// } /// Trait implemented for numeric types which can be used with the /// [`SyncStreamCipherSeek`] trait.