Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cipher: integrate block-modes #394

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions cipher/Cargo.toml
Expand Up @@ -14,9 +14,12 @@ categories = ["cryptography", "no-std"]
[dependencies]
generic-array = "0.14"
blobby = { version = "0.3", optional = true }
block-padding = { verstion = "0.2", optional = true }
Copy link
Member

@tarcieri tarcieri Dec 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: verstion

Suggested change
block-padding = { verstion = "0.2", optional = true }
block-padding = { version = "0.2", optional = true }


[features]
default = ["block-mode"]
std = []
block-mode = ["block-padding"]
dev = ["blobby"]

[package.metadata.docs.rs]
Expand Down
16 changes: 6 additions & 10 deletions cipher/src/block.rs
Expand Up @@ -9,21 +9,17 @@
//! [1]: https://en.wikipedia.org/wiki/Block_cipher
//! [2]: https://en.wikipedia.org/wiki/Symmetric-key_algorithm

#[cfg(feature = "dev")]
#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
pub mod dev;

use crate::errors::InvalidLength;
use core::convert::TryInto;
use generic_array::{typenum::Unsigned, ArrayLength, GenericArray};

/// Key for an algorithm that implements [`NewBlockCipher`].
pub type Key<B> = GenericArray<u8, <B as NewBlockCipher>::KeySize>;
pub type BlockCipherKey<B> = GenericArray<u8, <B as NewBlockCipher>::KeySize>;

/// Block on which a [`BlockCipher`] operates.
pub type Block<B> = GenericArray<u8, <B as BlockCipher>::BlockSize>;

/// Blocks being acted over in parallel.
/// Block on which a [`BlockCipher`] operates in parallel.
pub type ParBlocks<B> = GenericArray<Block<B>, <B as BlockCipher>::ParBlocks>;

/// Instantiate a [`BlockCipher`] algorithm.
Expand All @@ -32,13 +28,13 @@ pub trait NewBlockCipher: Sized {
type KeySize: ArrayLength<u8>;

/// Create new block cipher instance from key with fixed size.
fn new(key: &Key<Self>) -> Self;
fn new(key: &BlockCipherKey<Self>) -> Self;

/// Create new block cipher instance from key with variable size.
///
/// Default implementation will accept only keys with length equal to
/// `KeySize`, but some ciphers can accept range of key lengths.
fn new_varkey(key: &[u8]) -> Result<Self, InvalidLength> {
fn new_var(key: &[u8]) -> Result<Self, InvalidLength> {
if key.len() != Self::KeySize::to_usize() {
Err(InvalidLength)
} else {
Expand All @@ -57,7 +53,7 @@ pub trait BlockCipher {
type ParBlocks: ArrayLength<Block<Self>>;
}

/// Encrypt-only functionality for block ciphers
/// Encrypt-only functionality for block ciphers.
pub trait BlockEncrypt: BlockCipher {
/// Encrypt block in-place
fn encrypt_block(&self, block: &mut Block<Self>);
Expand Down Expand Up @@ -94,7 +90,7 @@ pub trait BlockEncrypt: BlockCipher {
}
}

/// Decrypt-only functionality for block ciphers
/// Decrypt-only functionality for block ciphers.
pub trait BlockDecrypt: BlockCipher {
/// Decrypt block in-place
fn decrypt_block(&self, block: &mut Block<Self>);
Expand Down
79 changes: 79 additions & 0 deletions cipher/src/common.rs
@@ -0,0 +1,79 @@
use generic_array::{ArrayLength, GenericArray, typenum::Unsigned};
use crate::{BlockCipher, NewBlockCipher, errors::InvalidLength};

/// Key for an algorithm that implements [`NewCipher`].
pub type CipherKey<C> = GenericArray<u8, <C as NewCipher>::KeySize>;

/// Nonce for an algorithm that implements [`NewCipher`].
pub type Nonce<C> = GenericArray<u8, <C as NewCipher>::NonceSize>;

/// Cipher creation trait.
///
/// It can be used for creation of block modes, synchronous and asynchronous stream ciphers.
pub trait NewCipher: Sized {
/// Key size in bytes
type KeySize: ArrayLength<u8>;

/// Nonce size in bytes
type NonceSize: ArrayLength<u8>;

/// Create new stream cipher instance from variable length key and nonce.
fn new(key: &CipherKey<Self>, nonce: &Nonce<Self>) -> Self;

/// Create new stream cipher instance from variable length key and nonce.
#[inline]
fn new_var(key: &[u8], nonce: &[u8]) -> Result<Self, InvalidLength> {
let kl = Self::KeySize::to_usize();
let nl = Self::NonceSize::to_usize();
if key.len() != kl || nonce.len() != nl {
Err(InvalidLength)
} else {
let key = GenericArray::from_slice(key);
let nonce = GenericArray::from_slice(nonce);
Ok(Self::new(key, nonce))
}
}
}

/// Trait for types which can be initialized from a block cipher and nonce.
pub trait FromBlockCipher {
/// Block cipher
type BlockCipher: BlockCipher;
/// Nonce size in bytes
type NonceSize: ArrayLength<u8>;

/// Instantiate a stream cipher from a block cipher
fn from_block_cipher(
cipher: Self::BlockCipher,
nonce: &GenericArray<u8, Self::NonceSize>,
) -> Self;
}

impl<C> NewCipher for C
where
C: FromBlockCipher,
C::BlockCipher: NewBlockCipher,
{
type KeySize = <<Self as FromBlockCipher>::BlockCipher as NewBlockCipher>::KeySize;
type NonceSize = <Self as FromBlockCipher>::NonceSize;

fn new(key: &CipherKey<Self>, nonce: &Nonce<Self>) -> C {
C::from_block_cipher(
<<Self as FromBlockCipher>::BlockCipher as NewBlockCipher>::new(key),
nonce,
)
}

fn new_var(key: &[u8], nonce: &[u8]) -> Result<Self, InvalidLength> {
if nonce.len() != Self::NonceSize::USIZE {
Err(InvalidLength)
} else {
C::BlockCipher::new_var(key)
.map_err(|_| InvalidLength)
.map(|cipher| {
let nonce = GenericArray::from_slice(nonce);
Self::from_block_cipher(cipher, nonce)
})
}
}
}
2 changes: 2 additions & 0 deletions cipher/src/dev.rs
@@ -0,0 +1,2 @@
mod stream;
mod block;
14 changes: 7 additions & 7 deletions cipher/src/block/dev.rs → cipher/src/dev/block.rs
Expand Up @@ -9,13 +9,13 @@ macro_rules! block_cipher_test {
($name:ident, $test_name:expr, $cipher:ty) => {
#[test]
fn $name() {
use cipher::block::{
dev::blobby::Blob3Iterator, BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher,
use cipher::{
blobby::Blob3Iterator, BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher,
};
use cipher::generic_array::{typenum::Unsigned, GenericArray};

fn run_test(key: &[u8], pt: &[u8], ct: &[u8]) -> bool {
let state = <$cipher as NewBlockCipher>::new_varkey(key).unwrap();
let state = <$cipher as NewBlockCipher>::new_var(key).unwrap();

let mut block = GenericArray::clone_from_slice(pt);
state.encrypt_block(&mut block);
Expand All @@ -37,7 +37,7 @@ macro_rules! block_cipher_test {
type Block = GenericArray<u8, BlockSize>;
type ParBlock = GenericArray<Block, ParBlocks>;

let state = <$cipher as NewBlockCipher>::new_varkey(key).unwrap();
let state = <$cipher as NewBlockCipher>::new_var(key).unwrap();

let block = Block::clone_from_slice(pt);
let mut blocks1 = ParBlock::default();
Expand Down Expand Up @@ -113,12 +113,12 @@ macro_rules! block_cipher_bench {
($cipher:path, $key_len:expr) => {
extern crate test;

use cipher::block::{BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher};
use cipher::{BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher};
use test::Bencher;

#[bench]
pub fn encrypt(bh: &mut Bencher) {
let state = <$cipher>::new_varkey(&[1u8; $key_len]).unwrap();
let state = <$cipher>::new_var(&[1u8; $key_len]).unwrap();
let mut block = Default::default();

bh.iter(|| {
Expand All @@ -130,7 +130,7 @@ macro_rules! block_cipher_bench {

#[bench]
pub fn decrypt(bh: &mut Bencher) {
let state = <$cipher>::new_varkey(&[1u8; $key_len]).unwrap();
let state = <$cipher>::new_var(&[1u8; $key_len]).unwrap();
let mut block = Default::default();

bh.iter(|| {
Expand Down
14 changes: 6 additions & 8 deletions cipher/src/stream/dev.rs → cipher/src/dev/stream.rs
Expand Up @@ -3,12 +3,12 @@
/// Test core functionality of synchronous stream cipher
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
macro_rules! stream_cipher_sync_test {
macro_rules! stream_cipher_test {
($name:ident, $cipher:ty, $test_name:expr) => {
#[test]
fn $name() {
use cipher::generic_array::GenericArray;
use cipher::stream::{blobby::Blob4Iterator, NewStreamCipher, SyncStreamCipher};
use cipher::{blobby::Blob4Iterator, NewCipher, StreamCipher};

let data = include_bytes!(concat!("data/", $test_name, ".blb"));
for (i, row) in Blob4Iterator::new(data).unwrap().enumerate() {
Expand Down Expand Up @@ -44,7 +44,7 @@ macro_rules! stream_cipher_seek_test {
#[test]
fn $name() {
use cipher::generic_array::GenericArray;
use cipher::stream::{NewStreamCipher, SyncStreamCipher, SyncStreamCipherSeek};
use cipher::{NewCipher, StreamCipher, StreamCipherSeek};

fn get_cipher() -> $cipher {
<$cipher>::new(&Default::default(), &Default::default())
Expand Down Expand Up @@ -97,7 +97,7 @@ macro_rules! stream_cipher_async_test {
#[test]
fn $name() {
use cipher::generic_array::GenericArray;
use cipher::stream::{blobby::Blob4Iterator, NewStreamCipher, StreamCipher};
use cipher::{blobby::Blob4Iterator, NewCipher, AsyncStreamCipher};

fn run_test(
key: &[u8],
Expand Down Expand Up @@ -172,8 +172,7 @@ macro_rules! stream_cipher_sync_bench {
($cipher:path) => {
extern crate test;

use cipher::generic_array::GenericArray;
use cipher::stream::{NewStreamCipher, SyncStreamCipher};
use cipher::{NewCipher, StreamCipher, generic_array::GenericArray};
use test::Bencher;

#[inline(never)]
Expand Down Expand Up @@ -225,8 +224,7 @@ macro_rules! stream_cipher_async_bench {
($cipher:path) => {
extern crate test;

use cipher::generic_array::GenericArray;
use cipher::stream::{NewStreamCipher, StreamCipher};
use cipher::{NewCipher, AsyncStreamCipher, generic_array::GenericArray};
use test::Bencher;

#[inline(never)]
Expand Down
15 changes: 14 additions & 1 deletion cipher/src/errors.rs
@@ -1,4 +1,4 @@
//! Error types
//! Error types.

use core::fmt;

Expand Down Expand Up @@ -48,3 +48,16 @@ impl From<OverflowError> for LoopError {

#[cfg(feature = "std")]
impl std::error::Error for OverflowError {}

/// Block mode error.
#[derive(Clone, Copy, Debug)]
pub struct BlockModeError;

impl fmt::Display for BlockModeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.write_str("BlockModeError")
}
}

#[cfg(feature = "std")]
impl std::error::Error for BlockModeError {}
22 changes: 16 additions & 6 deletions cipher/src/lib.rs
Expand Up @@ -15,15 +15,25 @@

#[cfg(feature = "std")]
extern crate std;
#[cfg(feature = "block-mode")]
pub extern crate block_padding;
#[cfg(feature = "dev")]
pub extern crate blobby;

pub mod block;
pub mod errors;
pub mod stream;
#[cfg(feature = "dev")]
mod dev;
mod block;
mod common;
#[cfg(feature = "block-padding")]
mod mode;
mod stream;

pub use crate::{
block::{
BlockCipher, BlockDecrypt, BlockDecryptMut, BlockEncrypt, BlockEncryptMut, NewBlockCipher,
},
stream::{NewStreamCipher, StreamCipher, SyncStreamCipher, SyncStreamCipherSeek},
block::*,
common::*,
stream::*,
};
#[cfg(feature = "block-mode")]
pub use crate::mode::BlockModeCore;
pub use generic_array::{self, typenum::consts};