diff --git a/cfb-mode/benches/aes128.rs b/cfb-mode/benches/aes128.rs index 1d5c9df..f53923a 100644 --- a/cfb-mode/benches/aes128.rs +++ b/cfb-mode/benches/aes128.rs @@ -1,7 +1,7 @@ #![feature(test)] extern crate test; -use aes::Aes128; +use aes::{cipher::consts::U1, Aes128}; cipher::block_encryptor_bench!( KeyIv: cfb_mode::Encryptor, @@ -14,3 +14,15 @@ cipher::block_decryptor_bench!( cfb_aes128_decrypt_block, cfb_aes128_decrypt_blocks, ); + +cipher::block_encryptor_bench!( + KeyIv: cfb_mode::Encryptor, + cfb8_aes128_encrypt_block, + cfb8_aes128_encrypt_blocks, +); + +cipher::block_decryptor_bench!( + KeyIv: cfb_mode::Decryptor, + cfb8_aes128_decrypt_block, + cfb8_aes128_decrypt_blocks, +); diff --git a/cfb-mode/src/buf_decrypt.rs b/cfb-mode/src/buf_decrypt.rs new file mode 100644 index 0000000..9164b60 --- /dev/null +++ b/cfb-mode/src/buf_decrypt.rs @@ -0,0 +1,135 @@ +use cipher::{ + crypto_common::{InnerUser, IvSizeUser}, + AlgorithmName, Block, BlockCipher, BlockEncryptMut, InnerIvInit, Iv, Unsigned, +}; +use core::fmt; + +#[cfg(feature = "zeroize")] +use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; + +/// CFB mode buffered decryptor. +#[derive(Clone)] +pub struct BufDecryptor +where + C: BlockEncryptMut + BlockCipher, +{ + cipher: C, + iv: Block, + pos: usize, +} + +impl BufDecryptor +where + C: BlockEncryptMut + BlockCipher, +{ + /// Decrypt a buffer in multiple parts. + pub fn decrypt(&mut self, mut data: &mut [u8]) { + let bs = C::BlockSize::to_usize(); + let n = data.len(); + + if n < bs - self.pos { + xor_set2(data, &mut self.iv[self.pos..self.pos + n]); + self.pos += n; + return; + } + let (left, right) = { data }.split_at_mut(bs - self.pos); + data = right; + let mut iv = self.iv.clone(); + xor_set2(left, &mut iv[self.pos..]); + self.cipher.encrypt_block_mut(&mut iv); + + let mut chunks = data.chunks_exact_mut(bs); + for chunk in &mut chunks { + xor_set2(chunk, iv.as_mut_slice()); + self.cipher.encrypt_block_mut(&mut iv); + } + + let rem = chunks.into_remainder(); + xor_set2(rem, iv.as_mut_slice()); + self.pos = rem.len(); + self.iv = iv; + } + + /// Returns the current state (block and position) of the decryptor. + pub fn get_state(&self) -> (&Block, usize) { + (&self.iv, self.pos) + } + + /// Restore from the given state for resumption. + pub fn from_state(cipher: C, iv: &Block, pos: usize) -> Self { + Self { + cipher, + iv: iv.clone(), + pos, + } + } +} + +impl InnerUser for BufDecryptor +where + C: BlockEncryptMut + BlockCipher, +{ + type Inner = C; +} + +impl IvSizeUser for BufDecryptor +where + C: BlockEncryptMut + BlockCipher, +{ + type IvSize = C::BlockSize; +} + +impl InnerIvInit for BufDecryptor +where + C: BlockEncryptMut + BlockCipher, +{ + #[inline] + fn inner_iv_init(mut cipher: C, iv: &Iv) -> Self { + let mut iv = iv.clone(); + cipher.encrypt_block_mut(&mut iv); + Self { cipher, iv, pos: 0 } + } +} + +impl AlgorithmName for BufDecryptor +where + C: BlockEncryptMut + BlockCipher + AlgorithmName, +{ + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("cfb::BufDecryptor<")?; + ::write_alg_name(f)?; + f.write_str(">") + } +} + +impl fmt::Debug for BufDecryptor +where + C: BlockEncryptMut + BlockCipher + AlgorithmName, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("cfb::BufDecryptor<")?; + ::write_alg_name(f)?; + f.write_str("> { ... }") + } +} + +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl Drop for BufDecryptor { + fn drop(&mut self) { + self.iv.zeroize(); + } +} + +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl ZeroizeOnDrop for BufDecryptor {} + +#[inline(always)] +fn xor_set2(buf1: &mut [u8], buf2: &mut [u8]) { + for (a, b) in buf1.iter_mut().zip(buf2) { + let t = *a; + *a ^= *b; + *b = t; + } +} diff --git a/cfb-mode/src/buf_encrypt.rs b/cfb-mode/src/buf_encrypt.rs new file mode 100644 index 0000000..0992376 --- /dev/null +++ b/cfb-mode/src/buf_encrypt.rs @@ -0,0 +1,136 @@ +use cipher::{ + crypto_common::{InnerUser, IvSizeUser}, + AlgorithmName, Block, BlockCipher, BlockEncryptMut, InnerIvInit, Iv, Unsigned, +}; +use core::fmt; + +#[cfg(feature = "zeroize")] +use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; + +/// CFB mode buffered encryptor. +#[derive(Clone)] +pub struct BufEncryptor +where + C: BlockEncryptMut + BlockCipher, +{ + cipher: C, + iv: Block, + pos: usize, +} + +impl BufEncryptor +where + C: BlockEncryptMut + BlockCipher, +{ + /// Encrypt a buffer in multiple parts. + pub fn encrypt(&mut self, mut data: &mut [u8]) { + let bs = C::BlockSize::USIZE; + let n = data.len(); + + if n < bs - self.pos { + xor_set1(data, &mut self.iv[self.pos..self.pos + n]); + self.pos += n; + return; + } + + let (left, right) = { data }.split_at_mut(bs - self.pos); + data = right; + let mut iv = self.iv.clone(); + xor_set1(left, &mut iv[self.pos..]); + self.cipher.encrypt_block_mut(&mut iv); + + let mut chunks = data.chunks_exact_mut(bs); + for chunk in &mut chunks { + xor_set1(chunk, iv.as_mut_slice()); + self.cipher.encrypt_block_mut(&mut iv); + } + + let rem = chunks.into_remainder(); + xor_set1(rem, iv.as_mut_slice()); + self.pos = rem.len(); + self.iv = iv; + } + + /// Returns the current state (block and position) of the decryptor. + pub fn get_state(&self) -> (&Block, usize) { + (&self.iv, self.pos) + } + + /// Restore from the given state for resumption. + pub fn from_state(cipher: C, iv: &Block, pos: usize) -> Self { + Self { + cipher, + iv: iv.clone(), + pos, + } + } +} + +impl InnerUser for BufEncryptor +where + C: BlockEncryptMut + BlockCipher, +{ + type Inner = C; +} + +impl IvSizeUser for BufEncryptor +where + C: BlockEncryptMut + BlockCipher, +{ + type IvSize = C::BlockSize; +} + +impl InnerIvInit for BufEncryptor +where + C: BlockEncryptMut + BlockCipher, +{ + #[inline] + fn inner_iv_init(mut cipher: C, iv: &Iv) -> Self { + let mut iv = iv.clone(); + cipher.encrypt_block_mut(&mut iv); + Self { cipher, iv, pos: 0 } + } +} + +impl AlgorithmName for BufEncryptor +where + C: BlockEncryptMut + BlockCipher + AlgorithmName, +{ + fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("cfb::BufEncryptor<")?; + ::write_alg_name(f)?; + f.write_str(">") + } +} + +impl fmt::Debug for BufEncryptor +where + C: BlockEncryptMut + BlockCipher + AlgorithmName, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("cfb::BufEncryptor<")?; + ::write_alg_name(f)?; + f.write_str("> { ... }") + } +} + +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl Drop for BufEncryptor { + fn drop(&mut self) { + self.iv.zeroize(); + } +} + +#[cfg(feature = "zeroize")] +#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] +impl ZeroizeOnDrop for BufEncryptor {} + +#[inline(always)] +fn xor_set1(buf1: &mut [u8], buf2: &mut [u8]) { + for (a, b) in buf1.iter_mut().zip(buf2) { + let t = *a ^ *b; + *a = t; + *b = t; + } +} diff --git a/cfb-mode/src/decrypt.rs b/cfb-mode/src/decrypt.rs index 7e7c1d6..1076c94 100644 --- a/cfb-mode/src/decrypt.rs +++ b/cfb-mode/src/decrypt.rs @@ -1,170 +1,100 @@ use cipher::{ + consts::U1, crypto_common::{InnerUser, IvSizeUser}, generic_array::{ArrayLength, GenericArray}, inout::InOut, - AlgorithmName, AsyncStreamCipher, Block, BlockBackend, BlockCipher, BlockClosure, BlockDecrypt, - BlockDecryptMut, BlockEncryptMut, BlockSizeUser, InnerIvInit, Iv, IvState, ParBlocks, - ParBlocksSizeUser, Unsigned, + AlgorithmName, AsyncStreamCipher, Block, BlockBackend, BlockCipher, BlockClosure, + BlockDecryptMut, BlockEncryptMut, BlockSizeUser, InnerIvInit, Iv, IvState, ParBlocksSizeUser, }; -use core::fmt; +use core::{fmt, marker::PhantomData}; #[cfg(feature = "zeroize")] use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; /// CFB mode decryptor. #[derive(Clone)] -pub struct Decryptor +pub struct Decryptor::BlockSize> where C: BlockEncryptMut + BlockCipher, + MBS: ArrayLength, { cipher: C, iv: Block, + _pd: PhantomData, } -/// CFB mode buffered decryptor. -#[derive(Clone)] -pub struct BufDecryptor +impl BlockSizeUser for Decryptor where C: BlockEncryptMut + BlockCipher, + MBS: ArrayLength, { - cipher: C, - iv: Block, - pos: usize, -} - -impl BufDecryptor -where - C: BlockEncryptMut + BlockCipher, -{ - /// Decrypt a buffer in multiple parts. - pub fn decrypt(&mut self, mut data: &mut [u8]) { - let bs = C::BlockSize::to_usize(); - let n = data.len(); - - if n < bs - self.pos { - xor_set2(data, &mut self.iv[self.pos..self.pos + n]); - self.pos += n; - return; - } - let (left, right) = { data }.split_at_mut(bs - self.pos); - data = right; - let mut iv = self.iv.clone(); - xor_set2(left, &mut iv[self.pos..]); - self.cipher.encrypt_block_mut(&mut iv); - - let mut chunks = data.chunks_exact_mut(bs); - for chunk in &mut chunks { - xor_set2(chunk, iv.as_mut_slice()); - self.cipher.encrypt_block_mut(&mut iv); - } - - let rem = chunks.into_remainder(); - xor_set2(rem, iv.as_mut_slice()); - self.pos = rem.len(); - self.iv = iv; - } - - /// Returns the current state (block and position) of the decryptor. - pub fn get_state(&self) -> (&Block, usize) { - (&self.iv, self.pos) - } - - /// Restore from the given state for resumption. - pub fn from_state(cipher: C, iv: &Block, pos: usize) -> Self { - Self { - cipher, - iv: iv.clone(), - pos, - } - } + type BlockSize = MBS; } -impl BlockSizeUser for Decryptor -where - C: BlockEncryptMut + BlockCipher, -{ - type BlockSize = C::BlockSize; -} - -impl BlockDecryptMut for Decryptor +impl BlockDecryptMut for Decryptor where C: BlockEncryptMut + BlockCipher, + MBS: ArrayLength, { fn decrypt_with_backend_mut(&mut self, f: impl BlockClosure) { - let Self { cipher, iv } = self; - cipher.encrypt_with_backend_mut(Closure { iv, f }) + let Self { cipher, iv, _pd } = self; + cipher.encrypt_with_backend_mut(Closure { iv, f, _pd: *_pd }) } } -impl AsyncStreamCipher for Decryptor where C: BlockEncryptMut + BlockCipher {} - -impl InnerUser for Decryptor +impl AsyncStreamCipher for Decryptor where C: BlockEncryptMut + BlockCipher, + MBS: ArrayLength, { - type Inner = C; } -impl InnerUser for BufDecryptor +impl InnerUser for Decryptor where C: BlockEncryptMut + BlockCipher, + MBS: ArrayLength, { type Inner = C; } -impl IvSizeUser for Decryptor +impl IvSizeUser for Decryptor where C: BlockEncryptMut + BlockCipher, + MBS: ArrayLength, { type IvSize = C::BlockSize; } -impl IvSizeUser for BufDecryptor -where - C: BlockEncryptMut + BlockCipher, -{ - type IvSize = C::BlockSize; -} - -impl InnerIvInit for Decryptor +impl InnerIvInit for Decryptor where C: BlockEncryptMut + BlockCipher, + MBS: ArrayLength, { #[inline] - fn inner_iv_init(mut cipher: C, iv: &Iv) -> Self { - let mut iv = iv.clone(); - cipher.encrypt_block_mut(&mut iv); - Self { cipher, iv } + fn inner_iv_init(cipher: C, iv: &Iv) -> Self { + Self { + cipher, + iv: iv.clone(), + _pd: PhantomData, + } } } -impl InnerIvInit for BufDecryptor +impl IvState for Decryptor where C: BlockEncryptMut + BlockCipher, -{ - #[inline] - fn inner_iv_init(mut cipher: C, iv: &Iv) -> Self { - let mut iv = iv.clone(); - cipher.encrypt_block_mut(&mut iv); - Self { cipher, iv, pos: 0 } - } -} - -impl IvState for Decryptor -where - C: BlockEncryptMut + BlockDecrypt + BlockCipher, + MBS: ArrayLength, { #[inline] fn iv_state(&self) -> Iv { - let mut res = self.iv.clone(); - self.cipher.decrypt_block(&mut res); - res + self.iv.clone() } } -impl AlgorithmName for Decryptor +impl AlgorithmName for Decryptor where C: BlockEncryptMut + BlockCipher + AlgorithmName, + MBS: ArrayLength, { fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("cfb::Decryptor<")?; @@ -173,20 +103,10 @@ where } } -impl AlgorithmName for BufDecryptor -where - C: BlockEncryptMut + BlockCipher + AlgorithmName, -{ - fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("cfb::BufDecryptor<")?; - ::write_alg_name(f)?; - f.write_str(">") - } -} - -impl fmt::Debug for Decryptor +impl fmt::Debug for Decryptor where C: BlockEncryptMut + BlockCipher + AlgorithmName, + MBS: ArrayLength, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("cfb::Decryptor<")?; @@ -195,20 +115,13 @@ where } } -impl fmt::Debug for BufDecryptor -where - C: BlockEncryptMut + BlockCipher + AlgorithmName, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("cfb::BufDecryptor<")?; - ::write_alg_name(f)?; - f.write_str("> { ... }") - } -} - #[cfg(feature = "zeroize")] #[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] -impl Drop for Decryptor { +impl Drop for Decryptor +where + C: BlockEncryptMut + BlockCipher, + MBS: ArrayLength, +{ fn drop(&mut self) { self.iv.zeroize(); } @@ -216,107 +129,114 @@ impl Drop for Decryptor { #[cfg(feature = "zeroize")] #[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] -impl Drop for BufDecryptor { - fn drop(&mut self) { - self.iv.zeroize(); - } +impl ZeroizeOnDrop for Decryptor +where + C: BlockEncryptMut + BlockCipher + ZeroizeOnDrop, + MBS: ArrayLength, +{ } -#[cfg(feature = "zeroize")] -#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] -impl ZeroizeOnDrop for Decryptor {} - -#[cfg(feature = "zeroize")] -#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] -impl ZeroizeOnDrop for BufDecryptor {} - -struct Closure<'a, BS, BC> +struct Closure<'a, CBS, MBS, BC> where - BS: ArrayLength, - BC: BlockClosure, + CBS: ArrayLength, + MBS: ArrayLength, + BC: BlockClosure, { - iv: &'a mut GenericArray, + iv: &'a mut GenericArray, f: BC, + _pd: PhantomData, } -impl<'a, BS, BC> BlockSizeUser for Closure<'a, BS, BC> +impl<'a, CBS, MBS, BC> BlockSizeUser for Closure<'a, CBS, MBS, BC> where - BS: ArrayLength, - BC: BlockClosure, + CBS: ArrayLength, + MBS: ArrayLength, + BC: BlockClosure, { - type BlockSize = BS; + type BlockSize = CBS; } -impl<'a, BS, BC> BlockClosure for Closure<'a, BS, BC> +impl<'a, CBS, MBS, BC> BlockClosure for Closure<'a, CBS, MBS, BC> where - BS: ArrayLength, - BC: BlockClosure, + CBS: ArrayLength, + MBS: ArrayLength, + BC: BlockClosure, { #[inline(always)] fn call>(self, backend: &mut B) { - let Self { iv, f } = self; - f.call(&mut Backend { iv, backend }); + let Self { iv, f, _pd } = self; + f.call(&mut Backend { iv, backend, _pd }); } } -struct Backend<'a, BS, BK> +struct Backend<'a, CBS, MBS, BK> where - BS: ArrayLength, - BK: BlockBackend, + CBS: ArrayLength, + MBS: ArrayLength, + BK: BlockBackend, { - iv: &'a mut GenericArray, + iv: &'a mut GenericArray, backend: &'a mut BK, + _pd: PhantomData, } -impl<'a, BS, BK> BlockSizeUser for Backend<'a, BS, BK> +impl<'a, CBS, MBS, BK> BlockSizeUser for Backend<'a, CBS, MBS, BK> where - BS: ArrayLength, - BK: BlockBackend, + CBS: ArrayLength, + MBS: ArrayLength, + BK: BlockBackend, { - type BlockSize = BS; + type BlockSize = MBS; } -impl<'a, BS, BK> ParBlocksSizeUser for Backend<'a, BS, BK> +impl<'a, CBS, MBS, BK> ParBlocksSizeUser for Backend<'a, CBS, MBS, BK> where - BS: ArrayLength, - BK: BlockBackend, + CBS: ArrayLength, + MBS: ArrayLength, + BK: BlockBackend, { - type ParBlocksSize = BK::ParBlocksSize; + // It's possible to implement parallel decryption, but currently + // `ParBlocksSize` is tied to block size. Since cipher block size + // and method block size in general can be different, we can not + // write `type ParBlocksSize = BK::ParBlocksSize`. + type ParBlocksSize = U1; } -impl<'a, BS, BK> BlockBackend for Backend<'a, BS, BK> +impl<'a, CBS, MBS, BK> BlockBackend for Backend<'a, CBS, MBS, BK> where - BS: ArrayLength, - BK: BlockBackend, + CBS: ArrayLength, + MBS: ArrayLength, + BK: BlockBackend, { #[inline(always)] fn proc_block(&mut self, mut block: InOut<'_, '_, Block>) { - let mut t = block.clone_in(); - block.xor_in2out(self.iv); - self.backend.proc_block((&mut t).into()); - *self.iv = t; - } + let cbs = CBS::USIZE; + let mbs = MBS::USIZE; - #[inline(always)] - fn proc_par_blocks(&mut self, mut blocks: InOut<'_, '_, ParBlocks>) { - let mut t = ParBlocks::::default(); - let b = (blocks.get_in(), &mut t).into(); - self.backend.proc_par_blocks(b); + let mut iv_cpy = self.iv.clone(); - let n = t.len(); - blocks.get(0).xor_in2out(self.iv); - for i in 1..n { - blocks.get(i).xor_in2out(&t[i - 1]) - } - *self.iv = t[n - 1].clone(); - } -} + let mid = cbs - mbs; + self.iv[..mid].copy_from_slice(&iv_cpy[mbs..]); + self.iv[mid..].copy_from_slice(block.get_in()); -#[inline(always)] -fn xor_set2(buf1: &mut [u8], buf2: &mut [u8]) { - for (a, b) in buf1.iter_mut().zip(buf2) { - let t = *a; - *a ^= *b; - *b = t; + self.backend.proc_block((&mut iv_cpy).into()); + block.xor_in2out(GenericArray::from_slice(&iv_cpy[..mbs])); } + + // See comment in `ParBlocksSizeUser` impl + /* + #[inline(always)] + fn proc_par_blocks(&mut self, mut blocks: InOut<'_, '_, ParBlocks>) { + // let mut t = ParBlocks::::default(); + // let b = (blocks.get_in(), &mut t).into(); + // self.backend.proc_par_blocks(b); + + // let n = t.len(); + // blocks.get(0).xor_in2out(self.iv); + // for i in 1..n { + // blocks.get(i).xor_in2out(&t[i - 1]) + // } + // *self.iv = t[n - 1].clone(); + } + */ } diff --git a/cfb-mode/src/encrypt.rs b/cfb-mode/src/encrypt.rs index cde30b8..8c04e5b 100644 --- a/cfb-mode/src/encrypt.rs +++ b/cfb-mode/src/encrypt.rs @@ -3,180 +3,98 @@ use cipher::{ crypto_common::{InnerUser, IvSizeUser}, generic_array::{ArrayLength, GenericArray}, inout::InOut, - AlgorithmName, AsyncStreamCipher, Block, BlockBackend, BlockCipher, BlockClosure, BlockDecrypt, - BlockEncryptMut, BlockSizeUser, InnerIvInit, Iv, IvState, ParBlocksSizeUser, Unsigned, + AlgorithmName, AsyncStreamCipher, Block, BlockBackend, BlockCipher, BlockClosure, + BlockEncryptMut, BlockSizeUser, InnerIvInit, Iv, IvState, ParBlocksSizeUser, }; -use core::fmt; +use core::{fmt, marker::PhantomData}; #[cfg(feature = "zeroize")] use cipher::zeroize::{Zeroize, ZeroizeOnDrop}; /// CFB mode encryptor. #[derive(Clone)] -pub struct Encryptor +pub struct Encryptor::BlockSize> where C: BlockEncryptMut + BlockCipher, + MBS: ArrayLength, { cipher: C, iv: Block, + _pd: PhantomData, } -/// CFB mode buffered encryptor. -#[derive(Clone)] -pub struct BufEncryptor +impl BlockSizeUser for Encryptor where C: BlockEncryptMut + BlockCipher, + MBS: ArrayLength, { - cipher: C, - iv: Block, - pos: usize, + type BlockSize = MBS; } -impl BufEncryptor -where - C: BlockEncryptMut + BlockCipher, -{ - /// Encrypt a buffer in multiple parts. - pub fn encrypt(&mut self, mut data: &mut [u8]) { - let bs = C::BlockSize::USIZE; - let n = data.len(); - - if n < bs - self.pos { - xor_set1(data, &mut self.iv[self.pos..self.pos + n]); - self.pos += n; - return; - } - - let (left, right) = { data }.split_at_mut(bs - self.pos); - data = right; - let mut iv = self.iv.clone(); - xor_set1(left, &mut iv[self.pos..]); - self.cipher.encrypt_block_mut(&mut iv); - - let mut chunks = data.chunks_exact_mut(bs); - for chunk in &mut chunks { - xor_set1(chunk, iv.as_mut_slice()); - self.cipher.encrypt_block_mut(&mut iv); - } - - let rem = chunks.into_remainder(); - xor_set1(rem, iv.as_mut_slice()); - self.pos = rem.len(); - self.iv = iv; - } - - /// Returns the current state (block and position) of the decryptor. - pub fn get_state(&self) -> (&Block, usize) { - (&self.iv, self.pos) - } - - /// Restore from the given state for resumption. - pub fn from_state(cipher: C, iv: &Block, pos: usize) -> Self { - Self { - cipher, - iv: iv.clone(), - pos, - } - } -} - -impl BlockSizeUser for Encryptor -where - C: BlockEncryptMut + BlockCipher, -{ - type BlockSize = C::BlockSize; -} - -impl BlockEncryptMut for Encryptor +impl BlockEncryptMut for Encryptor where C: BlockEncryptMut + BlockCipher, + MBS: ArrayLength, { fn encrypt_with_backend_mut(&mut self, f: impl BlockClosure) { - let Self { cipher, iv } = self; - cipher.encrypt_with_backend_mut(Closure { iv, f }) + let Self { cipher, iv, _pd } = self; + cipher.encrypt_with_backend_mut(Closure { iv, f, _pd: *_pd }) } } -impl AsyncStreamCipher for Encryptor where C: BlockEncryptMut + BlockCipher {} - -impl InnerUser for Encryptor +impl AsyncStreamCipher for Encryptor where C: BlockEncryptMut + BlockCipher, + MBS: ArrayLength, { - type Inner = C; } -impl InnerUser for BufEncryptor +impl InnerUser for Encryptor where C: BlockEncryptMut + BlockCipher, + MBS: ArrayLength, { type Inner = C; } -impl IvSizeUser for Encryptor -where - C: BlockEncryptMut + BlockCipher, -{ - type IvSize = C::BlockSize; -} - -impl IvSizeUser for BufEncryptor +impl IvSizeUser for Encryptor where C: BlockEncryptMut + BlockCipher, + MBS: ArrayLength, { type IvSize = C::BlockSize; } -impl InnerIvInit for Encryptor +impl InnerIvInit for Encryptor where C: BlockEncryptMut + BlockCipher, + MBS: ArrayLength, { #[inline] - fn inner_iv_init(mut cipher: C, iv: &Iv) -> Self { - let mut iv = iv.clone(); - cipher.encrypt_block_mut(&mut iv); - Self { cipher, iv } + fn inner_iv_init(cipher: C, iv: &Iv) -> Self { + Self { + cipher, + iv: iv.clone(), + _pd: PhantomData, + } } } -impl InnerIvInit for BufEncryptor +impl IvState for Encryptor where C: BlockEncryptMut + BlockCipher, -{ - #[inline] - fn inner_iv_init(mut cipher: C, iv: &Iv) -> Self { - let mut iv = iv.clone(); - cipher.encrypt_block_mut(&mut iv); - Self { cipher, iv, pos: 0 } - } -} - -impl IvState for Encryptor -where - C: BlockEncryptMut + BlockDecrypt + BlockCipher, + MBS: ArrayLength, { #[inline] fn iv_state(&self) -> Iv { - let mut res = self.iv.clone(); - self.cipher.decrypt_block(&mut res); - res - } -} - -impl AlgorithmName for BufEncryptor -where - C: BlockEncryptMut + BlockCipher + AlgorithmName, -{ - fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("cfb::BufEncryptor<")?; - ::write_alg_name(f)?; - f.write_str(">") + self.iv.clone() } } -impl AlgorithmName for Encryptor +impl AlgorithmName for Encryptor where C: BlockEncryptMut + BlockCipher + AlgorithmName, + MBS: ArrayLength, { fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("cfb::Encryptor<")?; @@ -185,9 +103,10 @@ where } } -impl fmt::Debug for Encryptor +impl fmt::Debug for Encryptor where C: BlockEncryptMut + BlockCipher + AlgorithmName, + MBS: ArrayLength, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("cfb::Encryptor<")?; @@ -196,20 +115,13 @@ where } } -impl fmt::Debug for BufEncryptor -where - C: BlockEncryptMut + BlockCipher + AlgorithmName, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("cfb::BufEncryptor<")?; - ::write_alg_name(f)?; - f.write_str("> { ... }") - } -} - #[cfg(feature = "zeroize")] #[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] -impl Drop for Encryptor { +impl Drop for Encryptor +where + C: BlockEncryptMut + BlockCipher, + MBS: ArrayLength, +{ fn drop(&mut self) { self.iv.zeroize(); } @@ -217,93 +129,92 @@ impl Drop for Encryptor { #[cfg(feature = "zeroize")] #[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] -impl Drop for BufEncryptor { - fn drop(&mut self) { - self.iv.zeroize(); - } +impl ZeroizeOnDrop for Encryptor +where + C: BlockEncryptMut + BlockCipher + ZeroizeOnDrop, + MBS: ArrayLength, +{ } -#[cfg(feature = "zeroize")] -#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] -impl ZeroizeOnDrop for Encryptor {} - -#[cfg(feature = "zeroize")] -#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] -impl ZeroizeOnDrop for BufEncryptor {} - -struct Closure<'a, BS, BC> +struct Closure<'a, CBS, MBS, BC> where - BS: ArrayLength, - BC: BlockClosure, + CBS: ArrayLength, + MBS: ArrayLength, + BC: BlockClosure, { - iv: &'a mut GenericArray, + iv: &'a mut GenericArray, f: BC, + _pd: PhantomData, } -impl<'a, BS, BC> BlockSizeUser for Closure<'a, BS, BC> +impl<'a, CBS, MBS, BC> BlockSizeUser for Closure<'a, CBS, MBS, BC> where - BS: ArrayLength, - BC: BlockClosure, + CBS: ArrayLength, + MBS: ArrayLength, + BC: BlockClosure, { - type BlockSize = BS; + type BlockSize = CBS; } -impl<'a, BS, BC> BlockClosure for Closure<'a, BS, BC> +impl<'a, CBS, MBS, BC> BlockClosure for Closure<'a, CBS, MBS, BC> where - BS: ArrayLength, - BC: BlockClosure, + CBS: ArrayLength, + MBS: ArrayLength, + BC: BlockClosure, { #[inline(always)] fn call>(self, backend: &mut B) { - let Self { iv, f } = self; - f.call(&mut Backend { iv, backend }); + let Self { iv, f, _pd } = self; + f.call(&mut Backend { iv, backend, _pd }); } } -struct Backend<'a, BS, BK> +struct Backend<'a, CBS, MBS, BK> where - BS: ArrayLength, - BK: BlockBackend, + CBS: ArrayLength, + MBS: ArrayLength, + BK: BlockBackend, { - iv: &'a mut GenericArray, + iv: &'a mut GenericArray, backend: &'a mut BK, + _pd: PhantomData, } -impl<'a, BS, BK> BlockSizeUser for Backend<'a, BS, BK> +impl<'a, CBS, MBS, BK> BlockSizeUser for Backend<'a, CBS, MBS, BK> where - BS: ArrayLength, - BK: BlockBackend, + CBS: ArrayLength, + MBS: ArrayLength, + BK: BlockBackend, { - type BlockSize = BS; + type BlockSize = MBS; } -impl<'a, BS, BK> ParBlocksSizeUser for Backend<'a, BS, BK> +impl<'a, CBS, MBS, BK> ParBlocksSizeUser for Backend<'a, CBS, MBS, BK> where - BS: ArrayLength, - BK: BlockBackend, + CBS: ArrayLength, + MBS: ArrayLength, + BK: BlockBackend, { type ParBlocksSize = U1; } -impl<'a, BS, BK> BlockBackend for Backend<'a, BS, BK> +impl<'a, CBS, MBS, BK> BlockBackend for Backend<'a, CBS, MBS, BK> where - BS: ArrayLength, - BK: BlockBackend, + CBS: ArrayLength, + MBS: ArrayLength, + BK: BlockBackend, { #[inline(always)] fn proc_block(&mut self, mut block: InOut<'_, '_, Block>) { - block.xor_in2out(self.iv); - let mut t = block.get_out().clone(); - self.backend.proc_block((&mut t).into()); - *self.iv = t; - } -} + let cbs = CBS::USIZE; + let mbs = MBS::USIZE; + + let iv_cpy = self.iv.clone(); + self.backend.proc_block((&mut *self.iv).into()); + block.xor_in2out(GenericArray::from_slice(&self.iv[..mbs])); -#[inline(always)] -fn xor_set1(buf1: &mut [u8], buf2: &mut [u8]) { - for (a, b) in buf1.iter_mut().zip(buf2) { - let t = *a ^ *b; - *a = t; - *b = t; + let mid = cbs - mbs; + self.iv[..mid].copy_from_slice(&iv_cpy[mbs..]); + self.iv[mid..].copy_from_slice(block.get_out()); } } diff --git a/cfb-mode/src/lib.rs b/cfb-mode/src/lib.rs index 5291081..b5f938c 100644 --- a/cfb-mode/src/lib.rs +++ b/cfb-mode/src/lib.rs @@ -59,9 +59,14 @@ #![cfg_attr(docsrs, feature(doc_cfg))] #![warn(missing_docs, rust_2018_idioms)] +pub use cipher; + +mod buf_decrypt; +mod buf_encrypt; mod decrypt; mod encrypt; -pub use cipher; -pub use decrypt::{BufDecryptor, Decryptor}; -pub use encrypt::{BufEncryptor, Encryptor}; +pub use buf_decrypt::BufDecryptor; +pub use buf_encrypt::BufEncryptor; +pub use decrypt::Decryptor; +pub use encrypt::Encryptor; diff --git a/cfb-mode/tests/aes.rs b/cfb-mode/tests/aes.rs index 188ea47..7a1d675 100644 --- a/cfb-mode/tests/aes.rs +++ b/cfb-mode/tests/aes.rs @@ -1,6 +1,6 @@ use aes::*; use cfb_mode::{BufDecryptor, BufEncryptor, Decryptor, Encryptor}; -use cipher::{block_mode_dec_test, block_mode_enc_test, iv_state_test, KeyInit}; +use cipher::{block_mode_dec_test, block_mode_enc_test, consts::U1, iv_state_test, KeyInit}; iv_state_test!(aes128_cfb_enc_iv_state, Encryptor, encrypt); iv_state_test!(aes128_cfb_dec_iv_state, Decryptor, decrypt); @@ -9,20 +9,40 @@ iv_state_test!(aes192_cfb_dec_iv_state, Decryptor, decrypt); iv_state_test!(aes256_cfb_enc_iv_state, Encryptor, encrypt); iv_state_test!(aes256_cfb_dec_iv_state, Decryptor, decrypt); +iv_state_test!(aes128_cfb8_enc_iv_state, Encryptor, encrypt); +iv_state_test!(aes128_cfb8_dec_iv_state, Decryptor, decrypt); +iv_state_test!(aes192_cfb8_enc_iv_state, Encryptor, encrypt); +iv_state_test!(aes192_cfb8_dec_iv_state, Decryptor, decrypt); +iv_state_test!(aes256_cfb8_enc_iv_state, Encryptor, encrypt); +iv_state_test!(aes256_cfb8_dec_iv_state, Decryptor, decrypt); + // Test vectors from CVAP "AES Multiblock Message Test (MMT) Sample Vectors": // -block_mode_enc_test!(aes128_cfb_enc_test, "aes128", Encryptor); -block_mode_dec_test!(aes128_cfb_dec_test, "aes128", Decryptor); -block_mode_enc_test!(aes128enc_cfb_enc_test, "aes128", Encryptor); -block_mode_dec_test!(aes128enc_cfb_dec_test, "aes128", Decryptor); -block_mode_enc_test!(aes192_cfb_enc_test, "aes192", Encryptor); -block_mode_dec_test!(aes192_cfb_dec_test, "aes192", Decryptor); -block_mode_enc_test!(aes192enc_cfb_enc_test, "aes192", Encryptor); -block_mode_dec_test!(aes192dec_cfb_dec_test, "aes192", Decryptor); -block_mode_enc_test!(aes256_cfb_enc_test, "aes256", Encryptor); -block_mode_dec_test!(aes256_cfb_dec_test, "aes256", Decryptor); -block_mode_enc_test!(aes256enc_cfb_enc_test, "aes256", Encryptor); -block_mode_dec_test!(aes256dec_cfb_dec_test, "aes256", Decryptor); +block_mode_enc_test!(aes128_cfb_enc_test, "cfb_aes128", Encryptor); +block_mode_dec_test!(aes128_cfb_dec_test, "cfb_aes128", Decryptor); +block_mode_enc_test!(aes128enc_cfb_enc_test, "cfb_aes128", Encryptor); +block_mode_dec_test!(aes128enc_cfb_dec_test, "cfb_aes128", Decryptor); +block_mode_enc_test!(aes192_cfb_enc_test, "cfb_aes192", Encryptor); +block_mode_dec_test!(aes192_cfb_dec_test, "cfb_aes192", Decryptor); +block_mode_enc_test!(aes192enc_cfb_enc_test, "cfb_aes192", Encryptor); +block_mode_dec_test!(aes192dec_cfb_dec_test, "cfb_aes192", Decryptor); +block_mode_enc_test!(aes256_cfb_enc_test, "cfb_aes256", Encryptor); +block_mode_dec_test!(aes256_cfb_dec_test, "cfb_aes256", Decryptor); +block_mode_enc_test!(aes256enc_cfb_enc_test, "cfb_aes256", Encryptor); +block_mode_dec_test!(aes256dec_cfb_dec_test, "cfb_aes256", Decryptor); + +block_mode_enc_test!(aes128_cfb8_enc_test, "cfb8_aes128", Encryptor); +block_mode_dec_test!(aes128_cfb8_dec_test, "cfb8_aes128", Decryptor); +block_mode_enc_test!(aes128enc_cfb8_enc_test, "cfb8_aes128", Encryptor); +block_mode_dec_test!(aes128enc_cfb8_dec_test, "cfb8_aes128", Decryptor); +block_mode_enc_test!(aes192_cfb8_enc_test, "cfb8_aes192", Encryptor); +block_mode_dec_test!(aes192_cfb8_dec_test, "cfb8_aes192", Decryptor); +block_mode_enc_test!(aes192enc_cfb8_enc_test, "cfb8_aes192", Encryptor); +block_mode_dec_test!(aes192dec_cfb8_dec_test, "cfb8_aes192", Decryptor); +block_mode_enc_test!(aes256_cfb8_enc_test, "cfb8_aes256", Encryptor); +block_mode_dec_test!(aes256_cfb8_dec_test, "cfb8_aes256", Decryptor); +block_mode_enc_test!(aes256enc_cfb8_enc_test, "cfb8_aes256", Encryptor); +block_mode_dec_test!(aes256dec_cfb8_dec_test, "cfb8_aes256", Decryptor); /// Test methods from the `AsyncStreamCipher` trait. #[test] @@ -54,6 +74,38 @@ fn aes128_cfb_async_test() { } } +/* +/// Test methods from the `AsyncStreamCipher` trait. +#[test] +fn aes128_cfb8_async_test() { + use cipher::{AsyncStreamCipher, KeyIvInit}; + + type Enc = Encryptor; + type Dec = Decryptor; + + let key = [42; 16]; + let iv = [24; 16]; + let mut pt = [0u8; 101]; + for (i, b) in pt.iter_mut().enumerate() { + *b = (i % 11) as u8; + } + let enc = Enc::new_from_slices(&key, &iv).unwrap(); + let mut ct = pt.clone(); + enc.encrypt(&mut ct); + for i in 1..100 { + let enc = Enc::new_from_slices(&key, &iv).unwrap(); + let mut t = pt.clone(); + let t = &mut t[..i]; + enc.encrypt(t); + assert_eq!(t, &ct[..i]); + + let dec = Dec::new_from_slices(&key, &iv).unwrap(); + dec.decrypt(t); + assert_eq!(t, &pt[..i]); + } +} +*/ + #[test] fn aes128_cfb_buffered_test() { use cipher::{AsyncStreamCipher, KeyIvInit}; diff --git a/cfb-mode/tests/data/cfb8_aes128.blb b/cfb-mode/tests/data/cfb8_aes128.blb new file mode 100644 index 0000000..81b6caf Binary files /dev/null and b/cfb-mode/tests/data/cfb8_aes128.blb differ diff --git a/cfb-mode/tests/data/cfb8_aes192.blb b/cfb-mode/tests/data/cfb8_aes192.blb new file mode 100644 index 0000000..f7eb86d Binary files /dev/null and b/cfb-mode/tests/data/cfb8_aes192.blb differ diff --git a/cfb-mode/tests/data/cfb8_aes256.blb b/cfb-mode/tests/data/cfb8_aes256.blb new file mode 100644 index 0000000..9a03c66 Binary files /dev/null and b/cfb-mode/tests/data/cfb8_aes256.blb differ diff --git a/cfb-mode/tests/data/aes128.blb b/cfb-mode/tests/data/cfb_aes128.blb similarity index 100% rename from cfb-mode/tests/data/aes128.blb rename to cfb-mode/tests/data/cfb_aes128.blb diff --git a/cfb-mode/tests/data/aes192.blb b/cfb-mode/tests/data/cfb_aes192.blb similarity index 100% rename from cfb-mode/tests/data/aes192.blb rename to cfb-mode/tests/data/cfb_aes192.blb diff --git a/cfb-mode/tests/data/aes256.blb b/cfb-mode/tests/data/cfb_aes256.blb similarity index 100% rename from cfb-mode/tests/data/aes256.blb rename to cfb-mode/tests/data/cfb_aes256.blb