,
_p: PhantomData,
}
impl Cbc
where
C: BlockCipher + NewBlockCipher,
P: Padding,
{
#[inline(always)]
fn single_blocks_decrypt(&mut self, blocks: &mut [Block]) {
let mut iv = self.iv.clone();
for block in blocks {
let block_copy = block.clone();
self.cipher.decrypt_block(block);
xor(block, iv.as_slice());
iv = block_copy;
}
self.iv = iv;
}
}
impl BlockMode for Cbc
where
C: BlockCipher + NewBlockCipher,
P: Padding,
{
type IvSize = C::BlockSize;
fn new(cipher: C, iv: &Block) -> Self {
Self {
cipher,
iv: iv.clone(),
_p: Default::default(),
}
}
fn encrypt_blocks(&mut self, blocks: &mut [Block]) {
self.iv = {
let mut iv = &self.iv;
for block in blocks {
xor(block, &iv);
self.cipher.encrypt_block(block);
iv = block;
}
iv.clone()
};
}
fn decrypt_blocks(&mut self, blocks: &mut [Block]) {
let pbn = C::ParBlocks::to_usize();
if pbn != 1 {
let (par_blocks, leftover) = get_par_blocks::(blocks);
let mut iv_buf = ParBlocks::::default();
iv_buf[0] = self.iv.clone();
for pb in par_blocks {
iv_buf[1..].clone_from_slice(&pb[..pbn - 1]);
let next_iv = pb[pbn - 1].clone();
self.cipher.decrypt_blocks(pb);
pb.iter_mut()
.zip(iv_buf.iter())
.for_each(|(a, b)| xor(a, b));
iv_buf[0] = next_iv;
}
self.iv = iv_buf[0].clone();
self.single_blocks_decrypt(leftover);
} else {
self.single_blocks_decrypt(blocks);
}
}
}
block-modes-0.7.0/src/cfb.rs 0100644 0000765 0000024 00000006173 13742324650 0014000 0 ustar 0000000 0000000 use crate::traits::BlockMode;
use crate::utils::{xor, Block, ParBlocks};
use block_padding::Padding;
use cipher::block::{BlockCipher, NewBlockCipher};
use cipher::generic_array::typenum::Unsigned;
use cipher::generic_array::GenericArray;
use core::marker::PhantomData;
use core::ptr;
/// [Cipher feedback][1] (CFB) block mode instance with a full block feedback.
///
/// [1]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_feedback_(CFB)
#[derive(Clone)]
pub struct Cfb {
cipher: C,
iv: GenericArray,
_p: PhantomData,
}
impl BlockMode for Cfb
where
C: BlockCipher + NewBlockCipher,
P: Padding,
{
type IvSize = C::BlockSize;
fn new(cipher: C, iv: &Block) -> Self {
let mut iv = iv.clone();
cipher.encrypt_block(&mut iv);
Self {
cipher,
iv,
_p: Default::default(),
}
}
fn encrypt_blocks(&mut self, blocks: &mut [Block]) {
for block in blocks {
xor_set1(block, self.iv.as_mut_slice());
self.cipher.encrypt_block(&mut self.iv);
}
}
fn decrypt_blocks(&mut self, mut blocks: &mut [Block]) {
let pb = C::ParBlocks::to_usize();
if blocks.len() >= pb {
// SAFETY: we have checked that `blocks` has enough elements
#[allow(unsafe_code)]
let mut par_iv = read_par_block::(blocks);
self.cipher.encrypt_blocks(&mut par_iv);
let (b, r) = { blocks }.split_at_mut(1);
blocks = r;
xor(&mut b[0], &self.iv);
while blocks.len() >= 2 * pb - 1 {
let next_par_iv = read_par_block::(&blocks[pb - 1..]);
let (par_block, r) = { blocks }.split_at_mut(pb);
blocks = r;
for (a, b) in par_block.iter_mut().zip(par_iv.iter()) {
xor(a, b)
}
par_iv = next_par_iv;
self.cipher.encrypt_blocks(&mut par_iv);
}
let (par_block, r) = { blocks }.split_at_mut(pb - 1);
blocks = r;
for (a, b) in par_block.iter_mut().zip(par_iv[..pb - 1].iter()) {
xor(a, b)
}
self.iv = par_iv[pb - 1].clone();
}
for block in blocks {
xor_set2(block, self.iv.as_mut_slice());
self.cipher.encrypt_block(&mut self.iv);
}
}
}
#[inline(always)]
fn read_par_block(blocks: &[Block]) -> ParBlocks {
assert!(blocks.len() >= C::ParBlocks::to_usize());
// SAFETY: assert checks that `blocks` is long enough
#[allow(unsafe_code)]
unsafe {
ptr::read(blocks.as_ptr() as *const ParBlocks)
}
}
#[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;
}
}
block-modes-0.7.0/src/cfb8.rs 0100644 0000765 0000024 00000003432 13742324650 0014063 0 ustar 0000000 0000000 use crate::traits::BlockMode;
use crate::utils::Block;
use block_padding::Padding;
use cipher::block::{BlockCipher, NewBlockCipher};
use cipher::generic_array::GenericArray;
use core::marker::PhantomData;
/// [Cipher feedback][1] (CFB) block mode instance with a full block feedback.
///
/// [1]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_feedback_(CFB)
#[derive(Clone)]
pub struct Cfb8 {
cipher: C,
iv: GenericArray,
_p: PhantomData,
}
impl BlockMode for Cfb8
where
C: BlockCipher + NewBlockCipher,
P: Padding,
{
type IvSize = C::BlockSize;
fn new(cipher: C, iv: &Block) -> Self {
Self {
cipher,
iv: iv.clone(),
_p: Default::default(),
}
}
fn encrypt_blocks(&mut self, blocks: &mut [Block]) {
let mut iv = self.iv.clone();
let n = iv.len();
for block in blocks.iter_mut() {
for b in block.iter_mut() {
let iv_copy = iv.clone();
self.cipher.encrypt_block(&mut iv);
*b ^= iv[0];
iv[..n - 1].clone_from_slice(&iv_copy[1..]);
iv[n - 1] = *b;
}
}
self.iv = iv;
}
fn decrypt_blocks(&mut self, blocks: &mut [Block]) {
let mut iv = self.iv.clone();
let n = iv.len();
for block in blocks.iter_mut() {
for b in block.iter_mut() {
let iv_copy = iv.clone();
self.cipher.encrypt_block(&mut iv);
let t = *b;
*b ^= iv[0];
iv[..n - 1].clone_from_slice(&iv_copy[1..]);
iv[n - 1] = t;
}
}
self.iv = iv;
}
}
block-modes-0.7.0/src/ecb.rs 0100644 0000765 0000024 00000004363 13742324650 0013776 0 ustar 0000000 0000000 use crate::errors::InvalidKeyIvLength;
use crate::traits::BlockMode;
use crate::utils::{get_par_blocks, Block};
use block_padding::Padding;
use cipher::block::{BlockCipher, NewBlockCipher};
use cipher::generic_array::typenum::{Unsigned, U0};
use cipher::generic_array::GenericArray;
use core::marker::PhantomData;
/// [Electronic Codebook][1] (ECB) block cipher mode instance.
///
/// Note that `new` method ignores IV, so during initialization you can
/// just pass `Default::default()` instead.
///
/// [1]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#ECB
#[derive(Clone)]
pub struct Ecb {
cipher: C,
_p: PhantomData,
}
impl BlockMode for Ecb
where
C: BlockCipher + NewBlockCipher,
P: Padding,
{
type IvSize = U0;
fn new(cipher: C, _iv: &GenericArray) -> Self {
Self {
cipher,
_p: Default::default(),
}
}
fn new_var(key: &[u8], _iv: &[u8]) -> Result {
let cipher = C::new_varkey(key).map_err(|_| InvalidKeyIvLength)?;
Ok(Self {
cipher,
_p: Default::default(),
})
}
fn encrypt_blocks(&mut self, blocks: &mut [Block]) {
if C::ParBlocks::to_usize() != 1 {
let (par_blocks, blocks) = get_par_blocks::(blocks);
par_blocks
.iter_mut()
.for_each(|pb| self.cipher.encrypt_blocks(pb));
blocks
.iter_mut()
.for_each(|pb| self.cipher.encrypt_block(pb));
} else {
blocks
.iter_mut()
.for_each(|pb| self.cipher.encrypt_block(pb));
}
}
fn decrypt_blocks(&mut self, blocks: &mut [Block]) {
if C::ParBlocks::to_usize() != 1 {
let (par_blocks, blocks) = get_par_blocks::(blocks);
par_blocks
.iter_mut()
.for_each(|pb| self.cipher.decrypt_blocks(pb));
blocks
.iter_mut()
.for_each(|pb| self.cipher.decrypt_block(pb));
} else {
blocks
.iter_mut()
.for_each(|pb| self.cipher.decrypt_block(pb));
}
}
}
block-modes-0.7.0/src/errors.rs 0100644 0000765 0000024 00000001375 13742317602 0014560 0 ustar 0000000 0000000 use core::fmt;
#[cfg(feature = "std")]
use std::error;
/// Block mode error.
#[derive(Clone, Copy, Debug)]
pub struct BlockModeError;
/// Invalid key or IV length error.
#[derive(Clone, Copy, Debug)]
pub struct InvalidKeyIvLength;
impl fmt::Display for BlockModeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.write_str("BlockModeError")
}
}
#[cfg(feature = "std")]
impl error::Error for BlockModeError {
fn description(&self) -> &str {
"block mode error"
}
}
impl fmt::Display for InvalidKeyIvLength {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.write_str("InvalidKeyIvLength")
}
}
#[cfg(feature = "std")]
impl error::Error for InvalidKeyIvLength {}
block-modes-0.7.0/src/lib.rs 0100644 0000765 0000024 00000006220 13742324650 0014005 0 ustar 0000000 0000000 //! This crate contains generic implementation of [block cipher modes of
//! operation][1].
//!
//! Note that some block modes (such as CTR, CFB, and OFB) transform block ciphers
//! into stream ciphers. Implementations in this crate require padding, so if you
//! want use those modes as stream ciphers (i.e. without padding), then check out
//! crates in the [RustCrypto/stream-ciphers][2] repository.
//!
//! # Usage example
//! ```
//! use aes::Aes128;
//! use block_modes::{BlockMode, Cbc};
//! use block_modes::block_padding::Pkcs7;
//! use hex_literal::hex;
//!
//! // create an alias for convenience
//! type Aes128Cbc = Cbc;
//!
//! # fn main() {
//! let key = hex!("000102030405060708090a0b0c0d0e0f");
//! let iv = hex!("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");
//! let plaintext = b"Hello world!";
//! let cipher = Aes128Cbc::new_var(&key, &iv).unwrap();
//!
//! // buffer must have enough space for message+padding
//! let mut buffer = [0u8; 32];
//! // copy message to the buffer
//! let pos = plaintext.len();
//! buffer[..pos].copy_from_slice(plaintext);
//! let ciphertext = cipher.encrypt(&mut buffer, pos).unwrap();
//!
//! assert_eq!(ciphertext, hex!("1b7a4c403124ae2fb52bedc534d82fa8"));
//!
//! // re-create cipher mode instance
//! let cipher = Aes128Cbc::new_var(&key, &iv).unwrap();
//! let mut buf = ciphertext.to_vec();
//! let decrypted_ciphertext = cipher.decrypt(&mut buf).unwrap();
//!
//! assert_eq!(decrypted_ciphertext, plaintext);
//! # }
//! ```
//!
//! With an enabled `alloc` feature (which is enabled by default) you can use
//! `encrypt_vec` and `descrypt_vec` methods:
//! ```
//! # use aes::Aes128;
//! # use block_modes::{BlockMode, Cbc};
//! # use block_modes::block_padding::Pkcs7;
//! # use hex_literal::hex;
//! #
//! # // create an alias for convenience
//! # type Aes128Cbc = Cbc;
//! #
//! # fn main() {
//! # let key = hex!("000102030405060708090a0b0c0d0e0f");
//! # let iv = hex!("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");
//! # let plaintext = b"Hello world!";
//! let cipher = Aes128Cbc::new_var(&key, &iv).unwrap();
//! let ciphertext = cipher.encrypt_vec(plaintext);
//!
//! assert_eq!(ciphertext, hex!("1b7a4c403124ae2fb52bedc534d82fa8"));
//!
//! let cipher = Aes128Cbc::new_var(&key, &iv).unwrap();
//! let decrypted_ciphertext = cipher.decrypt_vec(&ciphertext).unwrap();
//!
//! assert_eq!(decrypted_ciphertext, plaintext);
//! # }
//! ```
//!
//! [1]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
//! [2]: https://github.com/RustCrypto/stream-ciphers
#![no_std]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
)]
#![deny(unsafe_code)]
#![warn(missing_docs, rust_2018_idioms)]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
mod errors;
mod traits;
mod utils;
mod cbc;
mod cfb;
mod cfb8;
mod ecb;
mod ofb;
mod pcbc;
pub use block_padding;
pub use cipher;
pub use crate::{
cbc::Cbc,
cfb::Cfb,
cfb8::Cfb8,
ecb::Ecb,
errors::{BlockModeError, InvalidKeyIvLength},
ofb::Ofb,
pcbc::Pcbc,
traits::BlockMode,
};
block-modes-0.7.0/src/ofb.rs 0100644 0000765 0000024 00000002204 13742324650 0014003 0 ustar 0000000 0000000 use crate::traits::BlockMode;
use crate::utils::{xor, Block};
use block_padding::Padding;
use cipher::block::{BlockCipher, NewBlockCipher};
use cipher::generic_array::GenericArray;
use core::marker::PhantomData;
/// [Output feedback][1] (OFB) block mode instance with a full block feedback.
///
/// [1]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_feedback_(CFB)
#[derive(Clone)]
pub struct Ofb {
cipher: C,
iv: GenericArray,
_p: PhantomData,
}
impl BlockMode for Ofb
where
C: BlockCipher + NewBlockCipher,
P: Padding,
{
type IvSize = C::BlockSize;
fn new(cipher: C, iv: &Block) -> Self {
Self {
cipher,
iv: iv.clone(),
_p: Default::default(),
}
}
fn encrypt_blocks(&mut self, blocks: &mut [Block]) {
for block in blocks.iter_mut() {
self.cipher.encrypt_block(&mut self.iv);
xor(block, &self.iv);
}
}
fn decrypt_blocks(&mut self, blocks: &mut [Block]) {
self.encrypt_blocks(blocks)
}
}
block-modes-0.7.0/src/pcbc.rs 0100644 0000765 0000024 00000003271 13742324650 0014151 0 ustar 0000000 0000000 use crate::traits::BlockMode;
use crate::utils::{xor, Block};
use block_padding::Padding;
use cipher::block::{BlockCipher, NewBlockCipher};
use cipher::generic_array::GenericArray;
use core::marker::PhantomData;
/// [Propagating Cipher Block Chaining][1] (PCBC) mode instance.
///
/// [1]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#PCBC
#[derive(Clone)]
pub struct Pcbc {
cipher: C,
iv: GenericArray,
_p: PhantomData,
}
impl Pcbc
where
C: BlockCipher + NewBlockCipher,
P: Padding,
{
/// Initialize PCBC
pub fn new(cipher: C, iv: &Block) -> Self {
Self {
cipher,
iv: iv.clone(),
_p: Default::default(),
}
}
}
impl BlockMode for Pcbc
where
C: BlockCipher + NewBlockCipher,
P: Padding,
{
type IvSize = C::BlockSize;
fn new(cipher: C, iv: &GenericArray) -> Self {
Self {
cipher,
iv: iv.clone(),
_p: Default::default(),
}
}
fn encrypt_blocks(&mut self, blocks: &mut [Block]) {
for block in blocks {
let plaintext = block.clone();
xor(block, &self.iv);
self.cipher.encrypt_block(block);
self.iv = plaintext;
xor(&mut self.iv, block);
}
}
fn decrypt_blocks(&mut self, blocks: &mut [Block]) {
for block in blocks {
let ciphertext = block.clone();
self.cipher.decrypt_block(block);
xor(block, &self.iv);
self.iv = ciphertext;
xor(&mut self.iv, block);
}
}
}
block-modes-0.7.0/src/traits.rs 0100644 0000765 0000024 00000007461 13742324650 0014555 0 ustar 0000000 0000000 #[cfg(feature = "alloc")]
pub use alloc::vec::Vec;
use crate::errors::{BlockModeError, InvalidKeyIvLength};
use crate::utils::{to_blocks, Block, Key};
use block_padding::Padding;
use cipher::block::{BlockCipher, NewBlockCipher};
use cipher::generic_array::typenum::Unsigned;
use cipher::generic_array::{ArrayLength, GenericArray};
/// Trait for a block cipher mode of operation that is used to apply a block cipher
/// operation to input data to transform it into a variable-length output message.
pub trait BlockMode: Sized
where
C: BlockCipher + NewBlockCipher,
P: Padding,
{
/// Initialization Vector size.
type IvSize: ArrayLength;
/// Create a new block mode instance from initialized block cipher and IV.
fn new(cipher: C, iv: &GenericArray) -> Self;
/// Create a new block mode instance from fixed sized key and IV.
fn new_fix(key: &Key, iv: &GenericArray) -> Self {
Self::new(C::new(key), iv)
}
/// Create a new block mode instance from variable size key and IV.
///
/// Returns an error if key or IV have unsupported length.
fn new_var(key: &[u8], iv: &[u8]) -> Result {
if iv.len() != Self::IvSize::USIZE {
return Err(InvalidKeyIvLength);
}
let iv = GenericArray::from_slice(iv);
let cipher = C::new_varkey(key).map_err(|_| InvalidKeyIvLength)?;
Ok(Self::new(cipher, iv))
}
/// Encrypt blocks of data
fn encrypt_blocks(&mut self, blocks: &mut [Block]);
/// Decrypt blocks of data
fn decrypt_blocks(&mut self, blocks: &mut [Block]);
/// Encrypt message in-place.
///
/// `&buffer[..pos]` is used as a message and `&buffer[pos..]` as a reserved
/// space for padding. The padding space should be big enough for padding,
/// otherwise method will return `Err(BlockModeError)`.
fn encrypt(mut self, buffer: &mut [u8], pos: usize) -> Result<&[u8], BlockModeError> {
let bs = C::BlockSize::to_usize();
let buf = P::pad(buffer, pos, bs).map_err(|_| BlockModeError)?;
self.encrypt_blocks(to_blocks(buf));
Ok(buf)
}
/// Decrypt message in-place.
///
/// Returns an error if `buffer` length is not multiple of block size and
/// if after decoding message has malformed padding.
fn decrypt(mut self, buffer: &mut [u8]) -> Result<&[u8], BlockModeError> {
let bs = C::BlockSize::to_usize();
if buffer.len() % bs != 0 {
return Err(BlockModeError);
}
self.decrypt_blocks(to_blocks(buffer));
P::unpad(buffer).map_err(|_| BlockModeError)
}
/// Encrypt message and store result in vector.
#[cfg(feature = "alloc")]
fn encrypt_vec(mut self, plaintext: &[u8]) -> Vec {
let bs = C::BlockSize::to_usize();
let pos = plaintext.len();
let n = pos + bs;
let mut buf = Vec::with_capacity(n);
buf.extend_from_slice(plaintext);
// prepare space for padding
let block: Block = Default::default();
buf.extend_from_slice(&block[..n - pos]);
let n = P::pad(&mut buf, pos, bs)
.expect("enough space for padding is allocated")
.len();
buf.truncate(n);
self.encrypt_blocks(to_blocks(&mut buf));
buf
}
/// Encrypt message and store result in vector.
#[cfg(feature = "alloc")]
fn decrypt_vec(mut self, ciphertext: &[u8]) -> Result, BlockModeError> {
let bs = C::BlockSize::to_usize();
if ciphertext.len() % bs != 0 {
return Err(BlockModeError);
}
let mut buf = ciphertext.to_vec();
self.decrypt_blocks(to_blocks(&mut buf));
let n = P::unpad(&buf).map_err(|_| BlockModeError)?.len();
buf.truncate(n);
Ok(buf)
}
}
block-modes-0.7.0/src/utils.rs 0100644 0000765 0000024 00000002413 13742324650 0014377 0 ustar 0000000 0000000 use cipher::block::{BlockCipher, NewBlockCipher};
use cipher::generic_array::typenum::Unsigned;
use cipher::generic_array::{ArrayLength, GenericArray};
use core::slice;
#[inline(always)]
pub fn xor(buf: &mut [u8], key: &[u8]) {
debug_assert_eq!(buf.len(), key.len());
for (a, b) in buf.iter_mut().zip(key) {
*a ^= *b;
}
}
pub(crate) type Key = GenericArray::KeySize>;
pub(crate) type Block = GenericArray::BlockSize>;
pub(crate) type ParBlocks = GenericArray, ::ParBlocks>;
pub(crate) fn to_blocks(data: &mut [u8]) -> &mut [GenericArray]
where
N: ArrayLength,
{
let n = N::to_usize();
debug_assert!(data.len() % n == 0);
#[allow(unsafe_code)]
unsafe {
slice::from_raw_parts_mut(data.as_ptr() as *mut GenericArray, data.len() / n)
}
}
pub(crate) fn get_par_blocks(
blocks: &mut [Block],
) -> (&mut [ParBlocks], &mut [Block]) {
let pb = C::ParBlocks::to_usize();
let n_par = blocks.len() / pb;
let (par, single) = blocks.split_at_mut(n_par * pb);
#[allow(unsafe_code)]
let par = unsafe { slice::from_raw_parts_mut(par.as_ptr() as *mut ParBlocks, n_par) };
(par, single)
}
block-modes-0.7.0/tests/data/aes128.iv.bin 0100644 0000765 0000024 00000000020 13254010102 0016235 0 ustar 0000000 0000000 block-modes-0.7.0/tests/data/aes128.key.bin 0100644 0000765 0000024 00000000020 13204102202 0016405 0 ustar 0000000 0000000 +~(Ҧ O<