Skip to content

Commit

Permalink
cfb-mode: add Buffer{Encryptor|Decryptor} (#17)
Browse files Browse the repository at this point in the history
  • Loading branch information
dignifiedquire committed Sep 13, 2022
1 parent a1e06f2 commit 29ab1c2
Show file tree
Hide file tree
Showing 4 changed files with 323 additions and 6 deletions.
129 changes: 128 additions & 1 deletion cfb-mode/src/decrypt.rs
Expand Up @@ -4,7 +4,7 @@ use cipher::{
inout::InOut,
AlgorithmName, AsyncStreamCipher, Block, BlockBackend, BlockCipher, BlockClosure, BlockDecrypt,
BlockDecryptMut, BlockEncryptMut, BlockSizeUser, InnerIvInit, Iv, IvState, ParBlocks,
ParBlocksSizeUser,
ParBlocksSizeUser, Unsigned,
};
use core::fmt;

Expand All @@ -21,6 +21,64 @@ where
iv: Block<C>,
}

/// CFB mode buffered decryptor.
#[derive(Clone)]
pub struct BufDecryptor<C>
where
C: BlockEncryptMut + BlockCipher,
{
cipher: C,
iv: Block<C>,
pos: usize,
}

impl<C> BufDecryptor<C>
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<C>, usize) {
(&self.iv, self.pos)
}

/// Restore from the given state for resumption.
pub fn from_state(cipher: C, iv: &Block<C>, pos: usize) -> Self {
Self {
cipher,
iv: iv.clone(),
pos,
}
}
}

impl<C> BlockSizeUser for Decryptor<C>
where
C: BlockEncryptMut + BlockCipher,
Expand All @@ -47,13 +105,27 @@ where
type Inner = C;
}

impl<C> InnerUser for BufDecryptor<C>
where
C: BlockEncryptMut + BlockCipher,
{
type Inner = C;
}

impl<C> IvSizeUser for Decryptor<C>
where
C: BlockEncryptMut + BlockCipher,
{
type IvSize = C::BlockSize;
}

impl<C> IvSizeUser for BufDecryptor<C>
where
C: BlockEncryptMut + BlockCipher,
{
type IvSize = C::BlockSize;
}

impl<C> InnerIvInit for Decryptor<C>
where
C: BlockEncryptMut + BlockCipher,
Expand All @@ -66,6 +138,18 @@ where
}
}

impl<C> InnerIvInit for BufDecryptor<C>
where
C: BlockEncryptMut + BlockCipher,
{
#[inline]
fn inner_iv_init(mut cipher: C, iv: &Iv<Self>) -> Self {
let mut iv = iv.clone();
cipher.encrypt_block_mut(&mut iv);
Self { cipher, iv, pos: 0 }
}
}

impl<C> IvState for Decryptor<C>
where
C: BlockEncryptMut + BlockDecrypt + BlockCipher,
Expand All @@ -89,6 +173,17 @@ where
}
}

impl<C> AlgorithmName for BufDecryptor<C>
where
C: BlockEncryptMut + BlockCipher + AlgorithmName,
{
fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("cfb::BufDecryptor<")?;
<C as AlgorithmName>::write_alg_name(f)?;
f.write_str(">")
}
}

impl<C> fmt::Debug for Decryptor<C>
where
C: BlockEncryptMut + BlockCipher + AlgorithmName,
Expand All @@ -100,6 +195,17 @@ where
}
}

impl<C> fmt::Debug for BufDecryptor<C>
where
C: BlockEncryptMut + BlockCipher + AlgorithmName,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("cfb::BufDecryptor<")?;
<C as AlgorithmName>::write_alg_name(f)?;
f.write_str("> { ... }")
}
}

#[cfg(feature = "zeroize")]
#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
impl<C: BlockEncryptMut + BlockCipher> Drop for Decryptor<C> {
Expand All @@ -108,10 +214,22 @@ impl<C: BlockEncryptMut + BlockCipher> Drop for Decryptor<C> {
}
}

#[cfg(feature = "zeroize")]
#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
impl<C: BlockEncryptMut + BlockCipher> Drop for BufDecryptor<C> {
fn drop(&mut self) {
self.iv.zeroize();
}
}

#[cfg(feature = "zeroize")]
#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
impl<C: BlockEncryptMut + BlockCipher + ZeroizeOnDrop> ZeroizeOnDrop for Decryptor<C> {}

#[cfg(feature = "zeroize")]
#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
impl<C: BlockEncryptMut + BlockCipher + ZeroizeOnDrop> ZeroizeOnDrop for BufDecryptor<C> {}

struct Closure<'a, BS, BC>
where
BS: ArrayLength<u8>,
Expand Down Expand Up @@ -193,3 +311,12 @@ where
*self.iv = t[n - 1].clone();
}
}

#[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;
}
}
130 changes: 129 additions & 1 deletion cfb-mode/src/encrypt.rs
Expand Up @@ -4,7 +4,7 @@ use cipher::{
generic_array::{ArrayLength, GenericArray},
inout::InOut,
AlgorithmName, AsyncStreamCipher, Block, BlockBackend, BlockCipher, BlockClosure, BlockDecrypt,
BlockEncryptMut, BlockSizeUser, InnerIvInit, Iv, IvState, ParBlocksSizeUser,
BlockEncryptMut, BlockSizeUser, InnerIvInit, Iv, IvState, ParBlocksSizeUser, Unsigned,
};
use core::fmt;

Expand All @@ -21,6 +21,65 @@ where
iv: Block<C>,
}

/// CFB mode buffered encryptor.
#[derive(Clone)]
pub struct BufEncryptor<C>
where
C: BlockEncryptMut + BlockCipher,
{
cipher: C,
iv: Block<C>,
pos: usize,
}

impl<C> BufEncryptor<C>
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<C>, usize) {
(&self.iv, self.pos)
}

/// Restore from the given state for resumption.
pub fn from_state(cipher: C, iv: &Block<C>, pos: usize) -> Self {
Self {
cipher,
iv: iv.clone(),
pos,
}
}
}

impl<C> BlockSizeUser for Encryptor<C>
where
C: BlockEncryptMut + BlockCipher,
Expand All @@ -47,13 +106,27 @@ where
type Inner = C;
}

impl<C> InnerUser for BufEncryptor<C>
where
C: BlockEncryptMut + BlockCipher,
{
type Inner = C;
}

impl<C> IvSizeUser for Encryptor<C>
where
C: BlockEncryptMut + BlockCipher,
{
type IvSize = C::BlockSize;
}

impl<C> IvSizeUser for BufEncryptor<C>
where
C: BlockEncryptMut + BlockCipher,
{
type IvSize = C::BlockSize;
}

impl<C> InnerIvInit for Encryptor<C>
where
C: BlockEncryptMut + BlockCipher,
Expand All @@ -66,6 +139,18 @@ where
}
}

impl<C> InnerIvInit for BufEncryptor<C>
where
C: BlockEncryptMut + BlockCipher,
{
#[inline]
fn inner_iv_init(mut cipher: C, iv: &Iv<Self>) -> Self {
let mut iv = iv.clone();
cipher.encrypt_block_mut(&mut iv);
Self { cipher, iv, pos: 0 }
}
}

impl<C> IvState for Encryptor<C>
where
C: BlockEncryptMut + BlockDecrypt + BlockCipher,
Expand All @@ -78,6 +163,17 @@ where
}
}

impl<C> AlgorithmName for BufEncryptor<C>
where
C: BlockEncryptMut + BlockCipher + AlgorithmName,
{
fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("cfb::BufEncryptor<")?;
<C as AlgorithmName>::write_alg_name(f)?;
f.write_str(">")
}
}

impl<C> AlgorithmName for Encryptor<C>
where
C: BlockEncryptMut + BlockCipher + AlgorithmName,
Expand All @@ -100,6 +196,17 @@ where
}
}

impl<C> fmt::Debug for BufEncryptor<C>
where
C: BlockEncryptMut + BlockCipher + AlgorithmName,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("cfb::BufEncryptor<")?;
<C as AlgorithmName>::write_alg_name(f)?;
f.write_str("> { ... }")
}
}

#[cfg(feature = "zeroize")]
#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
impl<C: BlockEncryptMut + BlockCipher> Drop for Encryptor<C> {
Expand All @@ -108,10 +215,22 @@ impl<C: BlockEncryptMut + BlockCipher> Drop for Encryptor<C> {
}
}

#[cfg(feature = "zeroize")]
#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
impl<C: BlockEncryptMut + BlockCipher> Drop for BufEncryptor<C> {
fn drop(&mut self) {
self.iv.zeroize();
}
}

#[cfg(feature = "zeroize")]
#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
impl<C: BlockEncryptMut + BlockCipher + ZeroizeOnDrop> ZeroizeOnDrop for Encryptor<C> {}

#[cfg(feature = "zeroize")]
#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
impl<C: BlockEncryptMut + BlockCipher + ZeroizeOnDrop> ZeroizeOnDrop for BufEncryptor<C> {}

struct Closure<'a, BS, BC>
where
BS: ArrayLength<u8>,
Expand Down Expand Up @@ -179,3 +298,12 @@ where
*self.iv = t;
}
}

#[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;
}
}
4 changes: 2 additions & 2 deletions cfb-mode/src/lib.rs
Expand Up @@ -64,5 +64,5 @@ mod decrypt;
mod encrypt;

pub use cipher;
pub use decrypt::Decryptor;
pub use encrypt::Encryptor;
pub use decrypt::{BufDecryptor, Decryptor};
pub use encrypt::{BufEncryptor, Encryptor};

0 comments on commit 29ab1c2

Please sign in to comment.