blob: d3115c5d8056a1dd988713ef7079008325e42e62 [file] [log] [blame]
//! Development-related functionality
pub use blobby;
/// Define block cipher test
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
macro_rules! block_cipher_test {
($name:ident, $test_name:expr, $cipher:ty $(,)?) => {
#[test]
fn $name() {
use cipher::{
blobby::Blob3Iterator, generic_array::GenericArray, typenum::Unsigned,
BlockDecryptMut, BlockEncryptMut, BlockSizeUser, KeyInit,
};
fn run_test(key: &[u8], pt: &[u8], ct: &[u8]) -> bool {
let mut state = <$cipher as KeyInit>::new_from_slice(key).unwrap();
let mut block = GenericArray::clone_from_slice(pt);
state.encrypt_block_mut(&mut block);
if ct != block.as_slice() {
return false;
}
state.decrypt_block_mut(&mut block);
if pt != block.as_slice() {
return false;
}
true
}
fn run_par_test(key: &[u8], pt: &[u8]) -> bool {
type Block = cipher::Block<$cipher>;
let mut state = <$cipher as KeyInit>::new_from_slice(key).unwrap();
let block = Block::clone_from_slice(pt);
let mut blocks1 = vec![block; 101];
for (i, b) in blocks1.iter_mut().enumerate() {
*b = block;
b[0] = b[0].wrapping_add(i as u8);
}
let mut blocks2 = blocks1.clone();
// check that `encrypt_blocks` and `encrypt_block`
// result in the same ciphertext
state.encrypt_blocks_mut(&mut blocks1);
for b in blocks2.iter_mut() {
state.encrypt_block_mut(b);
}
if blocks1 != blocks2 {
return false;
}
// check that `encrypt_blocks` and `encrypt_block`
// result in the same plaintext
state.decrypt_blocks_mut(&mut blocks1);
for b in blocks2.iter_mut() {
state.decrypt_block_mut(b);
}
if blocks1 != blocks2 {
return false;
}
true
}
let data = include_bytes!(concat!("data/", $test_name, ".blb"));
for (i, row) in Blob3Iterator::new(data).unwrap().enumerate() {
let [key, pt, ct] = row.unwrap();
if !run_test(key, pt, ct) {
panic!(
"\n\
Failed test №{}\n\
key:\t{:?}\n\
plaintext:\t{:?}\n\
ciphertext:\t{:?}\n",
i, key, pt, ct,
);
}
// test parallel blocks encryption/decryption
if !run_par_test(key, pt) {
panic!(
"\n\
Failed parallel test №{}\n\
key:\t{:?}\n\
plaintext:\t{:?}\n\
ciphertext:\t{:?}\n",
i, key, pt, ct,
);
}
}
}
};
}
/// Define block mode encryption test
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
macro_rules! block_mode_enc_test {
($name:ident, $test_name:expr, $cipher:ty $(,)?) => {
#[test]
fn $name() {
use cipher::{
blobby::Blob4Iterator, generic_array::GenericArray, inout::InOutBuf,
typenum::Unsigned, BlockEncryptMut, BlockSizeUser, KeyIvInit,
};
fn run_test(key: &[u8], iv: &[u8], pt: &[u8], ct: &[u8]) -> bool {
assert_eq!(pt.len(), ct.len());
// test block-by-block processing
let mut state = <$cipher as KeyIvInit>::new_from_slices(key, iv).unwrap();
let mut out = vec![0u8; ct.len()];
let mut buf = InOutBuf::new(pt, &mut out).unwrap();
let (blocks, tail) = buf.reborrow().into_chunks();
assert_eq!(tail.len(), 0);
for block in blocks {
state.encrypt_block_inout_mut(block);
}
if buf.get_out() != ct {
return false;
}
// test multi-block processing
let mut state = <$cipher as KeyIvInit>::new_from_slices(key, iv).unwrap();
buf.get_out().iter_mut().for_each(|b| *b = 0);
let (blocks, _) = buf.reborrow().into_chunks();
state.encrypt_blocks_inout_mut(blocks);
if buf.get_out() != ct {
return false;
}
true
}
let data = include_bytes!(concat!("data/", $test_name, ".blb"));
for (i, row) in Blob4Iterator::new(data).unwrap().enumerate() {
let [key, iv, pt, ct] = row.unwrap();
if !run_test(key, iv, pt, ct) {
panic!(
"\n\
Failed test №{}\n\
key:\t{:?}\n\
iv:\t{:?}\n\
plaintext:\t{:?}\n\
ciphertext:\t{:?}\n",
i, key, iv, pt, ct,
);
}
}
}
};
}
/// Define block mode decryption test
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
macro_rules! block_mode_dec_test {
($name:ident, $test_name:expr, $cipher:ty $(,)?) => {
#[test]
fn $name() {
use cipher::{
blobby::Blob4Iterator, generic_array::GenericArray, inout::InOutBuf,
typenum::Unsigned, BlockDecryptMut, BlockSizeUser, KeyIvInit,
};
fn run_test(key: &[u8], iv: &[u8], pt: &[u8], ct: &[u8]) -> bool {
assert_eq!(pt.len(), ct.len());
// test block-by-block processing
let mut state = <$cipher as KeyIvInit>::new_from_slices(key, iv).unwrap();
let mut out = vec![0u8; pt.len()];
let mut buf = InOutBuf::new(ct, &mut out).unwrap();
let (blocks, tail) = buf.reborrow().into_chunks();
assert_eq!(tail.len(), 0);
for block in blocks {
state.decrypt_block_inout_mut(block);
}
if buf.get_out() != pt {
return false;
}
// test multi-block processing
let mut state = <$cipher as KeyIvInit>::new_from_slices(key, iv).unwrap();
buf.get_out().iter_mut().for_each(|b| *b = 0);
let (blocks, _) = buf.reborrow().into_chunks();
state.decrypt_blocks_inout_mut(blocks);
if buf.get_out() != pt {
return false;
}
true
}
let data = include_bytes!(concat!("data/", $test_name, ".blb"));
for (i, row) in Blob4Iterator::new(data).unwrap().enumerate() {
let [key, iv, pt, ct] = row.unwrap();
if !run_test(key, iv, pt, ct) {
panic!(
"\n\
Failed test №{}\n\
key:\t{:?}\n\
iv:\t{:?}\n\
plaintext:\t{:?}\n\
ciphertext:\t{:?}\n",
i, key, iv, pt, ct,
);
}
}
}
};
}
/// Define `IvState` test
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
macro_rules! iv_state_test {
($name:ident, $cipher:ty, encrypt $(,)?) => {
$crate::iv_state_test!($name, $cipher, encrypt_blocks_mut);
};
($name:ident, $cipher:ty, decrypt $(,)?) => {
$crate::iv_state_test!($name, $cipher, decrypt_blocks_mut);
};
($name:ident, $cipher:ty, apply_ks $(,)?) => {
$crate::iv_state_test!($name, $cipher, apply_keystream_blocks);
};
($name:ident, $cipher:ty, $method:ident $(,)?) => {
#[test]
fn $name() {
use cipher::*;
let mut blocks = [Block::<$cipher>::default(); 32];
for (i, block) in blocks.iter_mut().enumerate() {
for (j, b) in block.iter_mut().enumerate() {
*b = (i + j) as u8;
}
}
let mut key = Key::<$cipher>::default();
let mut iv = Iv::<$cipher>::default();
key.iter_mut().for_each(|b| *b = 0x42);
iv.iter_mut().for_each(|b| *b = 0x24);
let mut cipher = <$cipher>::new(&key, &iv);
let mut target = blocks.clone();
cipher.$method(&mut target);
for i in 0..32 {
let mut blocks = blocks.clone();
let (b1, b2) = blocks.split_at_mut(i);
let mut cipher1 = <$cipher>::new(&key, &iv);
cipher1.$method(b1);
let temp_iv = cipher1.iv_state();
let mut cipher2 = <$cipher>::new(&key, &temp_iv);
cipher2.$method(b2);
assert_eq!(blocks, target);
}
}
};
}
/// Define block encryptor benchmark
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
macro_rules! block_encryptor_bench {
(Key: $cipher:ty, $block_name:ident, $blocks_name:ident $(,)? ) => {
$crate::block_encryptor_bench!(
{
use $crate::KeyInit;
let key = test::black_box(Default::default());
<$cipher>::new(&key)
},
$cipher,
$block_name,
$blocks_name,
);
};
(KeyIv: $cipher:ty, $block_name:ident, $blocks_name:ident $(,)? ) => {
$crate::block_encryptor_bench!(
{
use $crate::KeyIvInit;
let key = test::black_box(Default::default());
let iv = test::black_box(Default::default());
<$cipher>::new(&key, &iv)
},
$cipher,
$block_name,
$blocks_name,
);
};
($init:block, $cipher:ty, $block_name:ident, $blocks_name:ident $(,)? ) => {
#[bench]
pub fn $block_name(bh: &mut test::Bencher) {
use cipher::BlockEncryptMut;
let mut cipher = $init;
let mut blocks = vec![Default::default(); 1024];
bh.iter(|| {
for block in blocks.iter_mut() {
cipher.encrypt_block_mut(block);
}
test::black_box(&blocks);
});
bh.bytes = (blocks.len() * blocks[0].len()) as u64;
}
#[bench]
pub fn $blocks_name(bh: &mut test::Bencher) {
use cipher::BlockEncryptMut;
let mut cipher = $init;
let mut blocks = vec![Default::default(); 1024];
bh.iter(|| {
cipher.encrypt_blocks_mut(&mut blocks);
test::black_box(&blocks);
});
bh.bytes = (blocks.len() * blocks[0].len()) as u64;
}
};
}
/// Define block decryptor benchmark
#[macro_export]
#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
macro_rules! block_decryptor_bench {
(Key: $cipher:ty, $block_name:ident, $blocks_name:ident $(,)? ) => {
$crate::block_decryptor_bench!(
{
use $crate::KeyInit;
let key = test::black_box(Default::default());
<$cipher>::new(&key)
},
$cipher,
$block_name,
$blocks_name,
);
};
(KeyIv: $cipher:ty, $block_name:ident, $blocks_name:ident $(,)? ) => {
$crate::block_decryptor_bench!(
{
use $crate::KeyIvInit;
let key = test::black_box(Default::default());
let iv = test::black_box(Default::default());
<$cipher>::new(&key, &iv)
},
$cipher,
$block_name,
$blocks_name,
);
};
($init:block, $cipher:ty, $block_name:ident, $blocks_name:ident $(,)? ) => {
#[bench]
pub fn $block_name(bh: &mut test::Bencher) {
use cipher::BlockDecryptMut;
let mut cipher = $init;
let mut blocks = vec![Default::default(); 1024];
bh.iter(|| {
for block in blocks.iter_mut() {
cipher.decrypt_block_mut(block);
}
test::black_box(&blocks);
});
bh.bytes = (blocks.len() * blocks[0].len()) as u64;
}
#[bench]
pub fn $blocks_name(bh: &mut test::Bencher) {
use cipher::BlockDecryptMut;
let mut cipher = $init;
let mut blocks = vec![Default::default(); 1024];
bh.iter(|| {
cipher.decrypt_blocks_mut(&mut blocks);
test::black_box(&blocks);
});
bh.bytes = (blocks.len() * blocks[0].len()) as u64;
}
};
}