#![no_std]
#![doc(html_logo_url =
"https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")]
extern crate block_cipher_trait;
#[cfg(feature = "std")]
extern crate std;
use block_cipher_trait::BlockCipher;
use block_cipher_trait::generic_array::GenericArray;
use block_cipher_trait::generic_array::typenum::Unsigned;
use core::slice;
mod errors;
pub use errors::InvalidKeyIvLength;
pub struct Cfb<C: BlockCipher> {
cipher: C,
iv: GenericArray<u8, C::BlockSize>,
pos: usize,
}
type Block<C> = GenericArray<u8, <C as BlockCipher>::BlockSize>;
type ParBlocks<C> = GenericArray<Block<C>, <C as BlockCipher>::ParBlocks>;
type Key<C> = GenericArray<u8, <C as BlockCipher>::KeySize>;
impl<C: BlockCipher> Cfb<C> {
pub fn new(key: &Key<C>, iv: &Block<C>) -> Self {
let cipher = C::new(key);
let mut iv = iv.clone();
cipher.encrypt_block(&mut iv);
Self { cipher, iv, pos: 0 }
}
pub fn new_var(key: &[u8], iv: &[u8]) -> Result<Self, InvalidKeyIvLength> {
if iv.len() != C::BlockSize::to_usize() {
return Err(InvalidKeyIvLength);
}
let cipher = C::new_varkey(key).map_err(|_| InvalidKeyIvLength)?;
let mut iv = GenericArray::clone_from_slice(iv);
cipher.encrypt_block(&mut iv);
Ok(Self { cipher, iv, pos: 0 })
}
pub fn encrypt(&mut self, mut buffer: &mut [u8]) {
let bs = C::BlockSize::to_usize();
let mut iv;
if buffer.len() < bs - self.pos {
xor_set1(buffer, &mut self.iv[self.pos..]);
self.pos += buffer.len();
return;
} else {
let (left, right) = { buffer }.split_at_mut(bs - self.pos);
buffer = right;
iv = self.iv.clone();
xor_set1(left, &mut iv[self.pos..]);
self.cipher.encrypt_block(&mut iv);
}
while buffer.len() >= bs {
let (block, r) = { buffer }.split_at_mut(bs);
buffer = r;
xor_set1(block, iv.as_mut_slice());
self.cipher.encrypt_block(&mut iv);
}
xor_set1(buffer, iv.as_mut_slice());
self.pos = buffer.len();
self.iv = iv;
}
pub fn decrypt(&mut self, mut buffer: &mut [u8]) {
let bs = C::BlockSize::to_usize();
let pb = C::ParBlocks::to_usize();
let mut iv;
if buffer.len() < bs - self.pos {
xor_set2(buffer, &mut self.iv[self.pos..]);
self.pos += buffer.len();
return;
} else {
let (left, right) = { buffer }.split_at_mut(bs - self.pos);
buffer = right;
iv = self.iv.clone();
xor_set2(left, &mut iv[self.pos..]);
self.cipher.encrypt_block(&mut iv);
}
let bss = bs * pb;
if pb != 1 && buffer.len() >= bss {
let mut iv_blocks: ParBlocks<C> = unsafe {
(&*(buffer.as_ptr() as *const ParBlocks<C>)).clone()
};
self.cipher.encrypt_blocks(&mut iv_blocks);
let (block, r) = { buffer }.split_at_mut(bs);
buffer = r;
xor(block, iv.as_slice());
while buffer.len() >= 2*bss - bs {
let (blocks, r) = { buffer }.split_at_mut(bss);
buffer = r;
let mut next_iv_blocks: ParBlocks<C> = unsafe {
let ptr = buffer.as_ptr().offset(- (bs as isize));
(&*(ptr as *const ParBlocks<C>)).clone()
};
self.cipher.encrypt_blocks(&mut next_iv_blocks);
xor(blocks, unsafe {
let ptr = iv_blocks.as_mut_ptr() as *mut u8;
slice::from_raw_parts(ptr, bss)
});
iv_blocks = next_iv_blocks;
}
let n = pb - 1;
let (blocks, r) = { buffer }.split_at_mut(n*bs);
buffer = r;
let chunks = blocks.chunks_mut(bs);
for (iv, block) in iv_blocks[..n].iter().zip(chunks) {
xor(block, iv.as_slice())
}
iv = iv_blocks[n].clone();
}
while buffer.len() >= bs {
let (block, r) = { buffer }.split_at_mut(bs);
buffer = r;
xor_set2(block, iv.as_mut_slice());
self.cipher.encrypt_block(&mut iv);
}
xor_set2(buffer, iv.as_mut_slice());
self.pos = buffer.len();
self.iv = iv;
}
}
#[inline(always)]
fn xor(buf1: &mut [u8], buf2: &[u8]) {
for (a, b) in buf1.iter_mut().zip(buf2) {
*a ^= *b;
}
}
#[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;
}
}
#[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;
}
}