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: v0.3 changes (without block-modes integration) #435

Merged
merged 11 commits into from Dec 30, 2020
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> {
Copy link
Member Author

Choose a reason for hiding this comment

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

As long as we're bikeshedding this method name, I've thought it would be clearer if it had slice in the name, e.g. new_from_slice or from_slice.

Copy link
Member

Choose a reason for hiding this comment

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

new_from_slice sounds good! from_slice is shorter, but I think will be more confusing, since it could be mistaken for a specialized version of the From trait. Also usually from* methods imply simple conversion, which is not the case here.

i wonder if for stream cipher and block modes we should use plural new_from_slices, since they accept two slices.

Copy link
Member Author

Choose a reason for hiding this comment

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

@newpavlov sounds good

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 crate::{errors::InvalidLength, BlockCipher, NewBlockCipher};
use generic_array::{typenum::Unsigned, ArrayLength, GenericArray};

/// 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 block;
mod stream;
16 changes: 8 additions & 8 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::generic_array::{typenum::Unsigned, GenericArray};
use cipher::{
blobby::Blob3Iterator, BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher,
};

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, AsyncStreamCipher, NewCipher};

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::{generic_array::GenericArray, NewCipher, StreamCipher};
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::{generic_array::GenericArray, AsyncStreamCipher, NewCipher};
use test::Bencher;

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

use core::fmt;

Expand Down
17 changes: 9 additions & 8 deletions cipher/src/lib.rs
Expand Up @@ -16,14 +16,15 @@
#[cfg(feature = "std")]
extern crate std;

pub mod block;
#[cfg(feature = "dev")]
pub use blobby;

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

pub use crate::{
block::{
BlockCipher, BlockDecrypt, BlockDecryptMut, BlockEncrypt, BlockEncryptMut, NewBlockCipher,
},
stream::{NewStreamCipher, StreamCipher, SyncStreamCipher, SyncStreamCipherSeek},
};
pub use crate::{block::*, common::*, stream::*};
pub use generic_array::{self, typenum::consts};