diff --git a/Cargo.lock b/Cargo.lock
index a60ffc880..df81926ab 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -155,7 +155,6 @@ name = "crypto-mac"
version = "0.11.0-pre"
dependencies = [
"blobby",
- "cipher",
"crypto-common",
"generic-array 0.14.4",
"rand_core",
diff --git a/aead/src/stream.rs b/aead/src/stream.rs
index c61b76fb1..170904559 100644
--- a/aead/src/stream.rs
+++ b/aead/src/stream.rs
@@ -226,7 +226,7 @@ macro_rules! impl_stream_object {
pub fn new(key: &Key, nonce: &Nonce) -> Self
where
A: NewAead,
- S: NewStream
+ S: NewStream,
{
Self::from_stream_primitive(S::new(key, nonce))
}
@@ -237,7 +237,7 @@ macro_rules! impl_stream_object {
pub fn from_aead(aead: A, nonce: &Nonce) -> Self
where
A: NewAead,
- S: NewStream
+ S: NewStream,
{
Self::from_stream_primitive(S::from_aead(aead, nonce))
}
@@ -291,7 +291,8 @@ macro_rules! impl_stream_object {
return Err(Error);
}
- self.stream.$in_place_op(self.position, false, associated_data, buffer)?;
+ self.stream
+ .$in_place_op(self.position, false, associated_data, buffer)?;
// Note: overflow checked above
self.position += S::COUNTER_INCR;
@@ -322,12 +323,13 @@ macro_rules! impl_stream_object {
pub fn $last_in_place_method(
self,
associated_data: &[u8],
- buffer: &mut dyn Buffer
+ buffer: &mut dyn Buffer,
) -> Result<(), Error> {
- self.stream.$in_place_op(self.position, true, associated_data, buffer)
+ self.stream
+ .$in_place_op(self.position, true, associated_data, buffer)
}
}
- }
+ };
}
impl_stream_object!(
diff --git a/cipher/Cargo.toml b/cipher/Cargo.toml
index d01e925b3..2feabf3bc 100644
--- a/cipher/Cargo.toml
+++ b/cipher/Cargo.toml
@@ -20,9 +20,9 @@ blobby = { version = "0.3", optional = true }
rand_core = { version = "0.6", optional = true }
[features]
-default = ["mode_wrapper"]
+#default = ["mode_wrapper"]
std = ["crypto-common/std"]
-mode_wrapper = ["block-buffer"]
+wrappers = ["block-buffer"]
dev = ["blobby"]
[package.metadata.docs.rs]
diff --git a/cipher/src/block.rs b/cipher/src/block.rs
index 1769c782e..5bf086b02 100644
--- a/cipher/src/block.rs
+++ b/cipher/src/block.rs
@@ -9,229 +9,196 @@
//! [1]: https://en.wikipedia.org/wiki/Block_cipher
//! [2]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
//! [3]: https://en.wikipedia.org/wiki/Symmetric-key_algorithm
+use crate::inout::{InOutBuf, InOutVal, InResOutBuf};
+pub use crypto_common::{Block, BlockProcessing, InnerIvInit};
+use generic_array::{typenum::U1, GenericArray};
-use crate::errors::InvalidLength;
-use crate::{FromKey, FromKeyNonce};
-use core::convert::TryInto;
-use generic_array::{typenum::Unsigned, ArrayLength, GenericArray};
-
-/// Key for an algorithm that implements [`FromKey`].
-pub type BlockCipherKey = GenericArray::KeySize>;
-
-/// Block on which a [`BlockCipher`] operates.
-pub type Block = GenericArray::BlockSize>;
-
-/// Block on which a [`BlockCipher`] operates in parallel.
-pub type ParBlocks = GenericArray, ::ParBlocks>;
-
-/// Trait which marks a type as being a block cipher.
-pub trait BlockCipher {
- /// Size of the block in bytes
- type BlockSize: ArrayLength;
-
- /// Number of blocks which can be processed in parallel by
- /// cipher implementation
- type ParBlocks: ArrayLength>;
-}
-
-/// Encrypt-only functionality for block ciphers.
-pub trait BlockEncrypt: BlockCipher {
- /// Encrypt block in-place
- fn encrypt_block(&self, block: &mut Block);
-
- /// Encrypt several blocks in parallel using instruction level parallelism
- /// if possible.
+/// Marker trait for types which represent block ciphers.
+///
+/// Even if a type is marked by this trait implements only `BlockEncryptMut` and/or
+/// `BlockDecryptMut`, it is assumed that its inner state is not changed by calling
+/// its methods, i.e. mutable-only implementations are used only for hardware
+/// encryption engines which require `&mut self` access to an underlying hardware
+/// peripheral.
+pub trait BlockCipher {}
+
+/// Marker trait for types which represent asynchronous stream ciphers.
+pub trait AsyncStreamCipher {}
+
+/// Encrypt-only functionality of block ciphers.
+pub trait BlockEncrypt: BlockProcessing {
+ /// Encrypt the provided block.
///
- /// If `ParBlocks` equals to 1 it's equivalent to `encrypt_block`.
- #[inline]
- fn encrypt_par_blocks(&self, blocks: &mut ParBlocks) {
- for block in blocks.iter_mut() {
- self.encrypt_block(block);
- }
+ /// Usually `block` is either `&mut Block`, or `(&Block, &mut Block)`.
+ fn encrypt_block(&self, block: impl InOutVal>);
+
+ /// Encrypt provided blocks in parallel.
+ fn encrypt_blocks(
+ &self,
+ mut blocks: InOutBuf<'_, '_, Block>,
+ proc: impl FnMut(InResOutBuf<'_, '_, '_, Block>),
+ ) {
+ blocks.chunks::(
+ &self,
+ |state, inc, res| state.encrypt_block((&inc[0], &mut res[0])),
+ |state, inc, res| state.encrypt_block((&inc[0], &mut res[0])),
+ proc,
+ );
}
+}
- /// Encrypt a slice of blocks, leveraging parallelism when available.
- #[inline]
- fn encrypt_blocks(&self, mut blocks: &mut [Block]) {
- let pb = Self::ParBlocks::to_usize();
-
- if pb > 1 {
- let mut iter = blocks.chunks_exact_mut(pb);
-
- for chunk in &mut iter {
- self.encrypt_par_blocks(chunk.try_into().unwrap())
- }
-
- blocks = iter.into_remainder();
- }
-
- for block in blocks {
- self.encrypt_block(block);
- }
+/// Decrypt-only functionality of block ciphers.
+pub trait BlockDecrypt: BlockProcessing {
+ /// Decrypt the provided block.
+ ///
+ /// Usually `block` is either `&mut Block`, or `(&Block, &mut Block)`.
+ fn decrypt_block(&self, block: impl InOutVal>);
+
+ /// Decrypt provided blocks in parallel.
+ fn decrypt_blocks(
+ &self,
+ mut blocks: InOutBuf<'_, '_, Block>,
+ proc: impl FnMut(InResOutBuf<'_, '_, '_, Block>),
+ ) {
+ blocks.chunks::(
+ &self,
+ |state, inc, res| state.decrypt_block((&inc[0], &mut res[0])),
+ |state, inc, res| state.decrypt_block((&inc[0], &mut res[0])),
+ proc,
+ );
}
}
-/// Decrypt-only functionality for block ciphers.
-pub trait BlockDecrypt: BlockCipher {
- /// Decrypt block in-place
- fn decrypt_block(&self, block: &mut Block);
-
- /// Decrypt several blocks in parallel using instruction level parallelism
- /// if possible.
+/// Encrypt-only functionality of block ciphers and block cipher modes of operation.
+pub trait BlockEncryptMut: BlockProcessing {
+ /// Encrypt the provided block.
///
- /// If `ParBlocks` equals to 1 it's equivalent to `decrypt_block`.
- #[inline]
- fn decrypt_par_blocks(&self, blocks: &mut ParBlocks) {
- for block in blocks.iter_mut() {
- self.decrypt_block(block);
- }
+ /// Usually `block` is either `&mut Block`, or `(&Block, &mut Block)`.
+ fn encrypt_block(&mut self, block: impl InOutVal>);
+
+ /// Encrypt provided blocks in parallel.
+ fn encrypt_blocks(
+ &mut self,
+ mut blocks: InOutBuf<'_, '_, Block>,
+ proc: impl FnMut(InResOutBuf<'_, '_, '_, Block>),
+ ) {
+ blocks.chunks::(
+ self,
+ |state, inc, res| state.encrypt_block((&inc[0], &mut res[0])),
+ |state, inc, res| state.encrypt_block((&inc[0], &mut res[0])),
+ proc,
+ );
}
+}
- /// Decrypt a slice of blocks, leveraging parallelism when available.
- #[inline]
- fn decrypt_blocks(&self, mut blocks: &mut [Block]) {
- let pb = Self::ParBlocks::to_usize();
-
- if pb > 1 {
- let mut iter = blocks.chunks_exact_mut(pb);
-
- for chunk in &mut iter {
- self.decrypt_par_blocks(chunk.try_into().unwrap())
- }
-
- blocks = iter.into_remainder();
- }
-
- for block in blocks {
- self.decrypt_block(block);
- }
+/// Decrypt-only functionality of block ciphers and block cipher modes of operation.
+pub trait BlockDecryptMut: BlockProcessing {
+ /// Decrypt the provided block.
+ ///
+ /// Usually `block` is either `&mut Block`, or `(&Block, &mut Block)`.
+ fn decrypt_block(&mut self, block: impl InOutVal>);
+
+ /// Decrypt provided blocks in parallel.
+ fn decrypt_blocks(
+ &mut self,
+ mut blocks: InOutBuf<'_, '_, Block>,
+ proc: impl FnMut(InResOutBuf<'_, '_, '_, Block>),
+ ) {
+ blocks.chunks::(
+ self,
+ |state, inc, res| state.decrypt_block((&inc[0], &mut res[0])),
+ |state, inc, res| state.decrypt_block((&inc[0], &mut res[0])),
+ proc,
+ );
}
}
-/// Encrypt-only functionality for block ciphers with mutable access to `self`.
+/// Trait for block cipher modes of operation, used to obtain the current state
+/// in the form of an IV that can re-initialize mode later and resume the original
+/// operation.
///
-/// The main use case for this trait is hardware encryption engines which
-/// require `&mut self` access to an underlying hardware peripheral.
-pub trait BlockEncryptMut: BlockCipher {
- /// Encrypt block in-place
- fn encrypt_block_mut(&mut self, block: &mut Block);
-}
-
-/// Decrypt-only functionality for block ciphers with mutable access to `self`.
+/// The IV value SHOULD be used for resuming operations only and MUST NOT be
+/// exposed to attackers. Failing to comply with this requirement breaks
+/// unpredictability and opens attack venues (see e.g. [1], sec. 3.6.2).
///
-/// The main use case for this trait is hardware encryption engines which
-/// require `&mut self` access to an underlying hardware peripheral.
-pub trait BlockDecryptMut: BlockCipher {
- /// Decrypt block in-place
- fn decrypt_block_mut(&mut self, block: &mut Block);
+/// [1]: https://www.cs.umd.edu/~jkatz/imc.html
+pub trait IvState: InnerIvInit {
+ /// Returns the IV needed to process the following block. This value MUST
+ /// NOT be exposed to attackers.
+ fn iv_state(&self) -> GenericArray;
}
-impl BlockEncryptMut for Alg {
- fn encrypt_block_mut(&mut self, block: &mut Block) {
- self.encrypt_block(block);
- }
-}
-
-impl BlockDecryptMut for Alg {
- fn decrypt_block_mut(&mut self, block: &mut Block) {
- self.decrypt_block(block);
- }
-}
+// =========================== BLANKET IMPLS ===========================
-// Impls of block cipher traits for reference types
+impl BlockCipher for &T {}
-impl BlockCipher for &Alg {
- type BlockSize = Alg::BlockSize;
- type ParBlocks = Alg::ParBlocks;
-}
+impl BlockCipher for &mut T {}
impl BlockEncrypt for &Alg {
#[inline]
- fn encrypt_block(&self, block: &mut Block) {
+ fn encrypt_block(&self, block: impl InOutVal>) {
Alg::encrypt_block(self, block);
}
#[inline]
- fn encrypt_par_blocks(&self, blocks: &mut ParBlocks) {
- Alg::encrypt_par_blocks(self, blocks);
- }
-
- #[inline]
- fn encrypt_blocks(&self, blocks: &mut [Block]) {
- Alg::encrypt_blocks(self, blocks);
+ fn encrypt_blocks(
+ &self,
+ blocks: InOutBuf<'_, '_, Block>,
+ proc: impl FnMut(InResOutBuf<'_, '_, '_, Block>),
+ ) {
+ Alg::encrypt_blocks(self, blocks, proc);
}
}
impl BlockDecrypt for &Alg {
#[inline]
- fn decrypt_block(&self, block: &mut Block) {
- Alg::decrypt_block(self, block);
+ fn decrypt_block(&self, block: impl InOutVal>) {
+ Alg::decrypt_block(self, block)
}
#[inline]
- fn decrypt_par_blocks(&self, blocks: &mut ParBlocks) {
- Alg::decrypt_par_blocks(self, blocks);
+ fn decrypt_blocks(
+ &self,
+ blocks: InOutBuf<'_, '_, Block>,
+ proc: impl FnMut(InResOutBuf<'_, '_, '_, Block>),
+ ) {
+ Alg::decrypt_blocks(self, blocks, proc);
}
+}
+impl BlockEncryptMut for Alg {
#[inline]
- fn decrypt_blocks(&self, blocks: &mut [Block]) {
- Alg::decrypt_blocks(self, blocks);
+ fn encrypt_block(&mut self, block: impl InOutVal>) {
+ Alg::encrypt_block(self, block)
}
-}
-
-/// Trait for types which can be initialized from a block cipher.
-pub trait FromBlockCipher {
- /// Block cipher used for initialization.
- type BlockCipher: BlockCipher;
-
- /// Initialize instance from block cipher.
- fn from_block_cipher(cipher: Self::BlockCipher) -> Self;
-}
-/// Trait for types which can be initialized from a block cipher and nonce.
-pub trait FromBlockCipherNonce {
- /// Block cipher used for initialization.
- type BlockCipher: BlockCipher;
- /// Nonce size in bytes.
- type NonceSize: ArrayLength;
-
- /// Initialize instance from block cipher and nonce.
- fn from_block_cipher_nonce(
- cipher: Self::BlockCipher,
- nonce: &GenericArray,
- ) -> Self;
-}
-
-impl FromKeyNonce for T
-where
- T: FromBlockCipherNonce,
- T::BlockCipher: FromKey,
-{
- type KeySize = ::KeySize;
- type NonceSize = T::NonceSize;
-
- fn new(
- key: &GenericArray,
- nonce: &GenericArray,
- ) -> Self {
- Self::from_block_cipher_nonce(T::BlockCipher::new(key), nonce)
+ #[inline]
+ fn encrypt_blocks(
+ &mut self,
+ blocks: InOutBuf<'_, '_, Block>,
+ proc: impl FnMut(InResOutBuf<'_, '_, '_, Block>),
+ ) {
+ Alg::encrypt_blocks(self, blocks, proc);
}
}
-impl FromKey for T
-where
- T: FromBlockCipher,
- T::BlockCipher: FromKey,
-{
- type KeySize = ::KeySize;
-
- fn new(key: &GenericArray) -> Self {
- Self::from_block_cipher(T::BlockCipher::new(key))
+impl BlockDecryptMut for Alg {
+ #[inline]
+ fn decrypt_block(&mut self, block: impl InOutVal>) {
+ Alg::decrypt_block(self, block);
}
- fn new_from_slice(key: &[u8]) -> Result {
- T::BlockCipher::new_from_slice(key)
- .map_err(|_| InvalidLength)
- .map(Self::from_block_cipher)
+ #[inline]
+ fn decrypt_blocks(
+ &mut self,
+ blocks: InOutBuf<'_, '_, Block>,
+ proc: impl FnMut(InResOutBuf<'_, '_, '_, Block>),
+ ) {
+ Alg::decrypt_blocks(self, blocks, proc);
}
}
+
+// note: unfortunately we can't write a blanket implementation of
+// `BlockEncryptMut`/`BlockDecryptMut` for implementors of `StreamCipherCore`
+// since such impl will conflict with blanket impls for
+// `BlockEncrypt`/`BlockDecrypt`
diff --git a/cipher/src/dev/block.rs b/cipher/src/dev/block.rs
index fc53b9435..16f39e2a5 100644
--- a/cipher/src/dev/block.rs
+++ b/cipher/src/dev/block.rs
@@ -10,12 +10,10 @@ macro_rules! block_cipher_test {
#[test]
fn $name() {
use cipher::generic_array::{typenum::Unsigned, GenericArray};
- use cipher::{
- blobby::Blob3Iterator, BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher,
- };
+ use cipher::{blobby::Blob3Iterator, BlockDecrypt, BlockEncrypt, KeyInit};
- fn run_test(key: &[u8], pt: &[u8], ct: &[u8]) -> bool {
- let state = <$cipher as NewBlockCipher>::new_from_slice(key).unwrap();
+ fn run_single_test(key: &[u8], pt: &[u8], ct: &[u8]) -> bool {
+ let state = <$cipher as KeyInit>::new_from_slice(key).unwrap();
let mut block = GenericArray::clone_from_slice(pt);
state.encrypt_block(&mut block);
@@ -31,6 +29,7 @@ macro_rules! block_cipher_test {
true
}
+ /*
fn run_par_test(key: &[u8], pt: &[u8]) -> bool {
type ParBlocks = <$cipher as BlockCipher>::ParBlocks;
type BlockSize = <$cipher as BlockCipher>::BlockSize;
@@ -69,15 +68,15 @@ macro_rules! block_cipher_test {
true
}
+ */
- let pb = <$cipher as BlockCipher>::ParBlocks::to_usize();
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) {
+ if !run_single_test(key, pt, ct) {
panic!(
"\n\
- Failed test №{}\n\
+ Failed single block test №{}\n\
key:\t{:?}\n\
plaintext:\t{:?}\n\
ciphertext:\t{:?}\n",
@@ -85,6 +84,7 @@ macro_rules! block_cipher_test {
);
}
+ /*
// test parallel blocks encryption/decryption
if pb != 1 {
if !run_par_test(key, pt) {
@@ -98,10 +98,11 @@ macro_rules! block_cipher_test {
);
}
}
+ */
}
// test if cipher can be cloned
let key = Default::default();
- let _ = <$cipher as NewBlockCipher>::new(&key).clone();
+ let _ = <$cipher as KeyInit>::new(&key).clone();
}
};
}
diff --git a/cipher/src/errors.rs b/cipher/src/errors.rs
index 644495e80..b21ce5f82 100644
--- a/cipher/src/errors.rs
+++ b/cipher/src/errors.rs
@@ -35,36 +35,32 @@ impl From for LoopError {
#[cfg(feature = "std")]
impl std::error::Error for OverflowError {}
-/// The error type returned when key and/or nonce used in the [`FromKey`]
-/// and [`FromKeyNonce`] slice-based methods had an invalid length.
+/// The error type returned by the [`BlockModeEncryptWrapper`] and
+/// [`BlockModeDecryptWrapper`] types.
///
-/// [`FromKey`]: crate::FromKey
-/// [`FromKeyNonce`]: crate::FromKeyNonce
+/// [`BlockModeEncryptWrapper`]: crate::BlockModeEncryptWrapper
+/// [`BlockModeDecryptWrapper`]: crate::BlockModeDecryptWrapper
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
-pub struct InvalidLength;
+pub struct BlockModeError;
-impl fmt::Display for InvalidLength {
+impl fmt::Display for BlockModeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.write_str("Invalid Length")
}
}
#[cfg(feature = "std")]
-impl std::error::Error for InvalidLength {}
+impl std::error::Error for BlockModeError {}
-/// The error type returned by the [`BlockModeEncryptWrapper`] and
-/// [`BlockModeDecryptWrapper`] types.
-///
-/// [`BlockModeEncryptWrapper`]: crate::BlockModeEncryptWrapper
-/// [`BlockModeDecryptWrapper`]: crate::BlockModeDecryptWrapper
+/// The error type for methods which require slices of equal length.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
-pub struct BlockModeError;
+pub struct NotEqualError;
-impl fmt::Display for BlockModeError {
+impl fmt::Display for NotEqualError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
- f.write_str("Invalid Length")
+ f.write_str("Length of slices is not equal")
}
}
#[cfg(feature = "std")]
-impl std::error::Error for BlockModeError {}
+impl std::error::Error for NotEqualError {}
diff --git a/cipher/src/inout.rs b/cipher/src/inout.rs
new file mode 100644
index 000000000..f10a18c88
--- /dev/null
+++ b/cipher/src/inout.rs
@@ -0,0 +1,382 @@
+use crate::errors::NotEqualError;
+use core::marker::PhantomData;
+use core::slice;
+use generic_array::{ArrayLength, GenericArray};
+
+// TODO: rename to InOutRef
+pub trait InOutVal {
+ fn get_in(&self) -> &T;
+
+ fn get_out(&mut self) -> &mut T;
+}
+
+impl InOutVal for &mut T {
+ fn get_in(&self) -> &T {
+ self
+ }
+ fn get_out(&mut self) -> &mut T {
+ self
+ }
+}
+
+impl InOutVal for (&T, &mut T) {
+ fn get_in(&self) -> &T {
+ self.0
+ }
+ fn get_out(&mut self) -> &mut T {
+ self.1
+ }
+}
+
+// note: it would be nice to have:
+// impl> InOutVal for &mut C { .. }
+// but unfortunately it conflicts with the `&mut T` impl
+
+/// Fat pointer type which references one immutable (input) slice and one mutable
+/// (output) slice of equal length.
+pub struct InOutBuf<'in_buf, 'out_buf, T> {
+ in_ptr: *const T,
+ out_ptr: *mut T,
+ len: usize,
+ _pd: PhantomData<(&'in_buf T, &'out_buf mut T)>,
+}
+
+impl<'a, T> From<&'a mut [T]> for InOutBuf<'a, 'a, T> {
+ fn from(buf: &'a mut [T]) -> Self {
+ Self {
+ in_ptr: buf.as_ptr(),
+ out_ptr: buf.as_mut_ptr(),
+ len: buf.len(),
+ _pd: PhantomData,
+ }
+ }
+}
+
+impl<'in_buf, 'out_buf, T> InOutBuf<'in_buf, 'out_buf, T> {
+ /// Divides one buffer into two at an index.
+ ///
+ /// The first will contain all indices from `[0, mid)` (excluding
+ /// the index `mid` itself) and the second will contain all
+ /// indices from `[mid, len)` (excluding the index `len` itself).
+ ///
+ /// # Panics
+ ///
+ /// Panics if `mid > len`.
+ #[inline]
+ pub fn split_at(
+ self,
+ mid: usize,
+ ) -> (
+ InOutBuf<'in_buf, 'out_buf, T>,
+ InOutBuf<'in_buf, 'out_buf, T>,
+ ) {
+ assert!(mid <= self.len);
+ let (tail_in_ptr, tail_out_ptr) = unsafe { (self.in_ptr.add(mid), self.out_ptr.add(mid)) };
+ (
+ InOutBuf {
+ in_ptr: self.in_ptr,
+ out_ptr: self.out_ptr,
+ len: mid,
+ _pd: PhantomData,
+ },
+ InOutBuf {
+ in_ptr: tail_in_ptr,
+ out_ptr: tail_out_ptr,
+ len: self.len() - mid,
+ _pd: PhantomData,
+ },
+ )
+ }
+
+ /// Partitions buffer into 2 parts: body of arrays and tail.
+ #[inline]
+ pub fn into_blocks>(
+ self,
+ ) -> (
+ InOutBuf<'in_buf, 'out_buf, GenericArray>,
+ InOutBuf<'in_buf, 'out_buf, T>,
+ ) {
+ let nb = self.len() / N::USIZE;
+ let body_len = nb * N::USIZE;
+ let (tail_in_ptr, tail_out_ptr) =
+ unsafe { (self.in_ptr.add(body_len), self.out_ptr.add(body_len)) };
+ (
+ InOutBuf {
+ in_ptr: self.in_ptr as *const GenericArray,
+ out_ptr: self.out_ptr as *mut GenericArray,
+ len: nb,
+ _pd: PhantomData,
+ },
+ InOutBuf {
+ in_ptr: tail_in_ptr,
+ out_ptr: tail_out_ptr,
+ len: self.len() - body_len,
+ _pd: PhantomData,
+ },
+ )
+ }
+
+ /// Copy data from input buffer to output. Does nothing if input and
+ /// output buffers point to the same memory.
+ #[inline]
+ pub fn copy_in2out(&mut self) {
+ if self.in_ptr != self.out_ptr {
+ // SAFETY: if pointers are not equal, then memory regions do not overlap
+ unsafe {
+ core::ptr::copy_nonoverlapping(self.in_ptr, self.out_ptr, self.len);
+ }
+ }
+ }
+}
+
+impl<'in_buf, 'out_buf, T> InOutBuf<'in_buf, 'out_buf, T> {
+ /// Create a new value from simple references.
+ #[inline]
+ pub fn from_refs(in_val: &'in_buf T, out_val: &'out_buf mut T) -> Self {
+ Self {
+ in_ptr: in_val as *const T,
+ out_ptr: out_val as *mut T,
+ len: 1,
+ _pd: PhantomData,
+ }
+ }
+
+ /// Create a new value from slices.
+ ///
+ /// Returns an error if length of slices is not equal to each other.
+ // TODO: add error type
+ #[inline]
+ pub fn new(in_buf: &'in_buf [T], out_buf: &'out_buf mut [T]) -> Result {
+ if in_buf.len() != out_buf.len() {
+ Err(NotEqualError)
+ } else {
+ Ok(Self {
+ in_ptr: in_buf.as_ptr(),
+ out_ptr: out_buf.as_mut_ptr(),
+ len: in_buf.len(),
+ _pd: Default::default(),
+ })
+ }
+ }
+
+ pub fn chunks(
+ &mut self,
+ state: S,
+ mut proc_chunk: PC,
+ mut proc_tail: PT,
+ proc_res: PR,
+ ) where
+ T: Clone + Default,
+ N: ArrayLength + 'static,
+ PC: FnMut(&mut S, &GenericArray, &mut GenericArray),
+ PT: FnMut(&mut S, &[T], &mut GenericArray),
+ PR: FnMut(InResOutBuf<'_, '_, 'out_buf, T>),
+ {
+ self.try_chunks::(
+ state,
+ |state, inb, out| {
+ proc_chunk(state, inb, out);
+ Ok(())
+ },
+ |state, inb, out| {
+ proc_tail(state, inb, out);
+ Ok(())
+ },
+ proc_res,
+ )
+ .expect("closures always return Ok");
+ }
+
+ pub fn try_chunks(
+ &mut self,
+ mut state: S,
+ mut proc_chunk: PC,
+ mut proc_tail: PT,
+ mut proc_res: PR,
+ ) -> Result<(), E>
+ where
+ T: Clone + Default,
+ N: ArrayLength + 'static,
+ PC: FnMut(&mut S, &GenericArray, &mut GenericArray) -> Result<(), E>,
+ PT: FnMut(&mut S, &[T], &mut GenericArray) -> Result<(), E>,
+ PR: FnMut(InResOutBuf<'_, '_, 'out_buf, T>),
+ {
+ let mut pos = 0;
+ let len = self.len;
+ while len - pos >= N::USIZE {
+ let mut res_chunk = GenericArray::::default();
+ unsafe {
+ let in_chunk = &*(self.in_ptr.add(pos) as *const GenericArray);
+ proc_chunk(&mut state, in_chunk, &mut res_chunk)?;
+ proc_res(InResOutBuf::from_raw(
+ in_chunk.as_ptr(),
+ res_chunk.as_mut_ptr(),
+ self.out_ptr.add(pos),
+ N::USIZE,
+ ));
+ }
+ pos += N::USIZE
+ }
+ let rem = len - pos;
+ if rem != 0 {
+ let mut res_chunk = GenericArray::::default();
+ unsafe {
+ let in_tail = slice::from_raw_parts(self.in_ptr.add(pos), rem);
+ proc_tail(&mut state, in_tail, &mut res_chunk)?;
+ proc_res(InResOutBuf::from_raw(
+ in_tail.as_ptr(),
+ res_chunk.as_mut_ptr(),
+ self.out_ptr.add(pos),
+ rem,
+ ));
+ }
+ }
+ Ok(())
+ }
+
+ /// Process elements in the inner buffers using the `f` callback.
+ ///
+ /// The first immutable reference passed to the callback is from the input
+ /// buffer, while the second mutable one is from output buffer.
+ pub fn process_pairs(&self, mut f: impl FnMut(&'in_buf T, &'out_buf mut T)) {
+ for i in 0..self.len {
+ // SAFETY: constructors guarantee that `in_ptr` and `out_ptr`
+ // point to slices of length `len`
+ unsafe {
+ f(&*(self.in_ptr.add(i)), &mut *(self.out_ptr.add(i)));
+ }
+ }
+ }
+
+ /// Get lenght of the inner buffers.
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.len
+ }
+
+ /// Returns `true` if `self` has a length of zero elements.
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.len == 0
+ }
+
+ pub fn get_in(&self) -> &'in_buf [T] {
+ unsafe { slice::from_raw_parts(self.in_ptr, self.len) }
+ }
+
+ pub fn get_out(&mut self) -> &mut [T] {
+ unsafe { slice::from_raw_parts_mut(self.out_ptr, self.len) }
+ }
+}
+
+pub struct InResOutBuf<'in_buf, 'res_buf, 'out_buf, T> {
+ in_ptr: *const T,
+ res_ptr: *mut T,
+ out_ptr: *mut T,
+ len: usize,
+ _pd: PhantomData<(&'in_buf T, &'res_buf T, &'out_buf mut T)>,
+}
+
+impl<'in_buf, 'res_buf, 'out_buf, T: Clone> InResOutBuf<'in_buf, 'res_buf, 'out_buf, T> {
+ #[inline]
+ unsafe fn from_raw(in_ptr: *const T, res_ptr: *mut T, out_ptr: *mut T, len: usize) -> Self {
+ Self {
+ in_ptr,
+ res_ptr,
+ out_ptr,
+ len,
+ _pd: PhantomData,
+ }
+ }
+
+ #[inline]
+ pub fn from_slices(
+ in_buf: &'in_buf [T],
+ res_buf: &'res_buf mut [T],
+ out_buf: &'out_buf mut [T],
+ ) -> Result {
+ let len = in_buf.len();
+ if len != res_buf.len() || len != out_buf.len() {
+ Err(NotEqualError)
+ } else {
+ Ok(Self {
+ in_ptr: in_buf.as_ptr(),
+ res_ptr: res_buf.as_mut_ptr(),
+ out_ptr: out_buf.as_mut_ptr(),
+ len,
+ _pd: PhantomData,
+ })
+ }
+ }
+
+ #[inline]
+ pub fn from_arrays>(
+ in_buf: &'in_buf GenericArray,
+ res_buf: &'res_buf mut GenericArray,
+ out_buf: &'out_buf mut GenericArray,
+ ) -> Self {
+ Self {
+ in_ptr: in_buf.as_ptr(),
+ res_ptr: res_buf.as_mut_ptr(),
+ out_ptr: out_buf.as_mut_ptr(),
+ len: N::USIZE,
+ _pd: PhantomData,
+ }
+ }
+
+ #[inline]
+ pub fn get_in_res(&mut self) -> (&'in_buf [T], &'res_buf mut [T]) {
+ let n = self.len;
+ unsafe {
+ (
+ slice::from_raw_parts(self.in_ptr, n),
+ slice::from_raw_parts_mut(self.res_ptr, n),
+ )
+ }
+ }
+
+ #[inline]
+ pub fn get_res_out(&mut self) -> (&'res_buf mut [T], &'out_buf mut [T]) {
+ let n = self.len;
+ unsafe {
+ (
+ slice::from_raw_parts_mut(self.res_ptr, n),
+ slice::from_raw_parts_mut(self.out_ptr, n),
+ )
+ }
+ }
+
+ /// Get lenght of the inner buffers.
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.len
+ }
+
+ /// Returns `true` if `self` has a length of zero elements.
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.len == 0
+ }
+}
+
+#[inline(always)]
+pub fn copy_res2out(mut buf: InResOutBuf<'_, '_, '_, T>) {
+ let (res, out) = buf.get_res_out();
+ out.copy_from_slice(res);
+}
+
+#[inline(always)]
+pub fn xor_inres2out>(
+ buf: InResOutBuf<'_, '_, '_, GenericArray>,
+) {
+ // length of bufers in bytes
+ let n = N::USIZE * buf.len();
+ let in_ptr = buf.in_ptr as *const u8;
+ let res_ptr = buf.res_ptr as *const u8;
+ let out_ptr = buf.out_ptr as *mut u8;
+ for i in 0..n {
+ unsafe {
+ *(out_ptr.add(i)) = *(in_ptr.add(i)) ^ *(res_ptr.add(i));
+ }
+ }
+}
diff --git a/cipher/src/lib.rs b/cipher/src/lib.rs
index da2951d87..ca35ef1fe 100644
--- a/cipher/src/lib.rs
+++ b/cipher/src/lib.rs
@@ -10,8 +10,8 @@
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
)]
-#![forbid(unsafe_code)]
-#![warn(missing_docs, rust_2018_idioms)]
+// #![forbid(unsafe_code)]
+// #![warn(missing_docs, rust_2018_idioms)]
#[cfg(feature = "std")]
extern crate std;
@@ -23,113 +23,20 @@ mod block;
#[cfg(feature = "dev")]
mod dev;
pub mod errors;
-mod mode;
+mod inout;
mod stream;
#[cfg(feature = "mode_wrapper")]
mod mode_wrapper;
-pub use crate::{block::*, mode::*, stream::*};
+pub use block::{
+ AsyncStreamCipher, BlockCipher, BlockDecrypt, BlockDecryptMut, BlockEncrypt, BlockEncryptMut,
+ IvState,
+};
+pub use inout::{InOutBuf, InOutVal, InResOutBuf};
+//StreamCipherCore,
+pub use crate::{inout::*, stream::*};
+pub use crypto_common::{Block, BlockProcessing, InnerInit, InnerIvInit, KeyInit, KeyIvInit};
pub use generic_array::{self, typenum::consts};
#[cfg(feature = "mode_wrapper")]
pub use mode_wrapper::{BlockModeDecryptWrapper, BlockModeEncryptWrapper};
-
-use crate::errors::InvalidLength;
-use generic_array::{typenum::Unsigned, ArrayLength, GenericArray};
-#[cfg(feature = "rand_core")]
-use rand_core::{CryptoRng, RngCore};
-
-// note: ideally the following traits would be defined in the `crypto-common` crate,
-// but it would make impossible the generic impls over `T: FromBlockCipher(Nonce)`
-// in the `block` module, see the following link for proposal to change it:
-// https://internals.rust-lang.org/t/14125
-
-/// Trait for types which can be created from key and nonce.
-pub trait FromKeyNonce: Sized {
- /// Key size in bytes.
- type KeySize: ArrayLength;
-
- /// Nonce size in bytes.
- type NonceSize: ArrayLength;
-
- /// Create new value from fixed length key and nonce.
- fn new(
- key: &GenericArray,
- nonce: &GenericArray,
- ) -> Self;
-
- /// Create new value from variable length key and nonce.
- #[inline]
- fn new_from_slices(key: &[u8], nonce: &[u8]) -> Result {
- 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))
- }
- }
-
- /// Generate a random key using the provided [`CryptoRng`].
- #[cfg(feature = "rand_core")]
- #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))]
- #[inline]
- fn generate_key(mut rng: impl CryptoRng + RngCore) -> GenericArray {
- let mut key = GenericArray::::default();
- rng.fill_bytes(&mut key);
- key
- }
-
- /// Generate a random nonce using the provided [`CryptoRng`].
- #[cfg(feature = "rand_core")]
- #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))]
- #[inline]
- fn generate_nonce(mut rng: impl CryptoRng + RngCore) -> GenericArray {
- let mut nonce = GenericArray::::default();
- rng.fill_bytes(&mut nonce);
- nonce
- }
-
- /// Generate random key and nonce using the provided [`CryptoRng`].
- #[cfg(feature = "rand_core")]
- #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))]
- #[inline]
- fn generate_key_nonce(
- mut rng: impl CryptoRng + RngCore,
- ) -> (
- GenericArray,
- GenericArray,
- ) {
- (Self::generate_key(&mut rng), Self::generate_nonce(&mut rng))
- }
-}
-
-/// Trait for types which can be created from key.
-pub trait FromKey: Sized {
- /// Key size in bytes.
- type KeySize: ArrayLength;
-
- /// Create new value from fixed size key.
- fn new(key: &GenericArray) -> Self;
-
- /// Create new value from variable size key.
- fn new_from_slice(key: &[u8]) -> Result {
- if key.len() != Self::KeySize::to_usize() {
- Err(InvalidLength)
- } else {
- Ok(Self::new(GenericArray::from_slice(key)))
- }
- }
-
- /// Generate a random key using the provided [`CryptoRng`].
- #[cfg(feature = "rand_core")]
- #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))]
- #[inline]
- fn generate_key(mut rng: impl CryptoRng + RngCore) -> GenericArray {
- let mut key = GenericArray::::default();
- rng.fill_bytes(&mut key);
- key
- }
-}
diff --git a/cipher/src/mode.rs b/cipher/src/mode.rs
deleted file mode 100644
index 336f50cfa..000000000
--- a/cipher/src/mode.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-use crate::{BlockCipher, FromKeyNonce};
-use generic_array::{ArrayLength, GenericArray};
-
-/// Trait for types which implement a block cipher [mode of operation][1].
-///
-/// [1]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
-pub trait BlockMode {
- /// Size of the block in bytes
- type BlockSize: ArrayLength;
-}
-
-/// Trait for a block cipher mode of operation block-level encryptor.
-///
-/// This trait operates only on blocks, for convinient slice-based methods with padding
-/// see the [`BlockModeEncryptWrapper`][crate::BlockModeEncryptWrapper] type.
-pub trait BlockModeEncrypt: BlockMode {
- /// Encrypt blocks of data.
- fn encrypt_blocks(&mut self, blocks: &mut [GenericArray]);
-}
-
-/// Trait for a block cipher mode of operation block-level decryptor.
-///
-/// This trait operates only on blocks, for convinient slice-based methods with padding
-/// see the [`BlockModeDecryptWrapper`][crate::BlockModeDecryptWrapper] type.
-pub trait BlockModeDecrypt: BlockMode {
- /// Decrypt blocks of data.
- fn decrypt_blocks(&mut self, blocks: &mut [GenericArray]);
-}
-
-/// Trait for a block mode, used to obtain the current state in the form of an IV
-/// that can initialize a BlockMode later and resume the original operation.
-///
-/// The IV value SHOULD be used for resuming operations only and MUST NOT be
-/// exposed to attackers. Failing to comply with this requirement breaks
-/// unpredictability and opens attack venues (see e.g. [1], sec. 3.6.2).
-///
-/// [1]: https://www.cs.umd.edu/~jkatz/imc.html
-pub trait BlockModeIvState: FromKeyNonce {
- /// Returns the IV needed to process the following block. This value MUST
- /// NOT be exposed to attackers.
- fn iv_state(&self) -> GenericArray;
-}
diff --git a/cipher/src/stream.rs b/cipher/src/stream.rs
index 3bea72828..7ad5cf489 100644
--- a/cipher/src/stream.rs
+++ b/cipher/src/stream.rs
@@ -4,7 +4,44 @@
//! for ciphers implementation.
use crate::errors::{LoopError, OverflowError};
+use crate::inout::{InOutBuf, InResOutBuf};
use core::convert::{TryFrom, TryInto};
+use crypto_common::{Block, BlockProcessing};
+use generic_array::typenum::U1;
+
+/// Synchronous stream ciphers.
+pub trait StreamCipherCore: BlockProcessing {
+ /// Generate next keystream block.
+ fn gen_keystream_block(&mut self) -> Result, LoopError>;
+
+ /// Generate keystream blocks in parallel for provided data blocks.
+ fn gen_keystream_blocks(
+ &mut self,
+ mut blocks: InOutBuf<'_, '_, Block>,
+ proc: impl FnMut(InResOutBuf<'_, '_, '_, Block>),
+ ) -> Result<(), LoopError> {
+ blocks.try_chunks::(
+ self,
+ |state, _, res| state.gen_keystream_block().map(|b| res[0] = b),
+ |state, _, res| state.gen_keystream_block().map(|b| res[0] = b),
+ proc,
+ )
+ }
+}
+
+/// Counter-based synchronous stream ciphers.
+///
+/// Such ciphers allow random access to an underlying keystream and can return
+/// current position in it.
+pub trait CtrBasedStreamCipherCore: StreamCipherCore {
+ type Counter;
+
+ /// Get current block position.
+ fn get_block_pos(&self) -> Self::Counter;
+
+ /// Set current block position.
+ fn set_block_pos(&mut self, pos: Self::Counter);
+}
/// Synchronous stream cipher core trait.
pub trait StreamCipher {
@@ -105,7 +142,7 @@ pub trait SeekNum:
fn from_block_byte(block: T, byte: u8, bs: u8) -> Result;
/// Try to get block number and bytes position for given block size `bs`.
- fn to_block_byte(self, bs: u8) -> Result<(T, u8), OverflowError>;
+ fn to_block_byte(&self, bs: u8) -> Result<(T, u8), OverflowError>;
}
macro_rules! impl_seek_num {
@@ -119,7 +156,7 @@ macro_rules! impl_seek_num {
Ok(pos)
}
- fn to_block_byte>(self, bs: u8) -> Result<(T, u8), OverflowError> {
+ fn to_block_byte>(&self, bs: u8) -> Result<(T, u8), OverflowError> {
let bs = bs as Self;
let byte = self % bs;
let block = T::try_from(self/bs).map_err(|_| OverflowError)?;
diff --git a/crypto-common/src/core_api.rs b/crypto-common/src/core_api.rs
index 7def7a076..167c59cf0 100644
--- a/crypto-common/src/core_api.rs
+++ b/crypto-common/src/core_api.rs
@@ -1,20 +1,18 @@
//! Low-level core API traits.
-use super::{FixedOutput, FixedOutputReset, Reset, Update};
+use super::{Block, BlockProcessing, FixedOutput, FixedOutputReset, Reset, Update};
use block_buffer::DigestBuffer;
use core::fmt;
use generic_array::{ArrayLength, GenericArray};
-/// Trait for types which consume data in blocks.
+/// Types which consume data in blocks.
#[cfg(feature = "core-api")]
#[cfg_attr(docsrs, doc(cfg(feature = "core-api")))]
-pub trait UpdateCore {
- /// Block size in bytes.
- type BlockSize: ArrayLength;
+pub trait UpdateCore: BlockProcessing {
/// Block buffer type over which value operates.
type Buffer: DigestBuffer;
/// Update state using the provided data blocks.
- fn update_blocks(&mut self, blocks: &[GenericArray]);
+ fn update_blocks(&mut self, blocks: &[Block]);
}
/// Core trait for hash functions with fixed output size.
diff --git a/crypto-common/src/errors.rs b/crypto-common/src/errors.rs
new file mode 100644
index 000000000..379acdef7
--- /dev/null
+++ b/crypto-common/src/errors.rs
@@ -0,0 +1,15 @@
+use core::fmt;
+
+/// The error type returned when key and/or IV used in the [`FromKey`]
+/// and [`FromKeyIv`] slice-based methods had an invalid length.
+#[derive(Copy, Clone, Eq, PartialEq, Debug)]
+pub struct InvalidLength;
+
+impl fmt::Display for InvalidLength {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ f.write_str("Invalid Length")
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for InvalidLength {}
diff --git a/crypto-common/src/init.rs b/crypto-common/src/init.rs
new file mode 100644
index 000000000..b65683c50
--- /dev/null
+++ b/crypto-common/src/init.rs
@@ -0,0 +1,164 @@
+//! Traits related to types initialization.
+
+use crate::InvalidLength;
+use generic_array::{typenum::Unsigned, ArrayLength, GenericArray};
+
+/// Types which can be initialized from a key.
+pub trait KeyInit: Sized {
+ /// Key size in bytes.
+ type KeySize: ArrayLength;
+
+ /// Create new value from fixed size key.
+ fn new(key: &GenericArray) -> Self;
+
+ /// Create new value from variable size key.
+ fn new_from_slice(key: &[u8]) -> Result {
+ if key.len() != Self::KeySize::to_usize() {
+ Err(InvalidLength)
+ } else {
+ Ok(Self::new(GenericArray::from_slice(key)))
+ }
+ }
+
+ /// Generate a random key using the provided [`CryptoRng`].
+ #[cfg(feature = "rand_core")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))]
+ #[inline]
+ fn generate_key(mut rng: impl CryptoRng + RngCore) -> GenericArray {
+ let mut key = GenericArray::::default();
+ rng.fill_bytes(&mut key);
+ key
+ }
+}
+
+/// Types which can be initialized from key and initialization vector/nonce.
+pub trait KeyIvInit: Sized {
+ /// Key size in bytes.
+ type KeySize: ArrayLength;
+
+ /// Initialization vector size in bytes.
+ type IvSize: ArrayLength;
+
+ /// Create new value from fixed length key and nonce.
+ fn new(key: &GenericArray, iv: &GenericArray) -> Self;
+
+ /// Create new value from variable length key and nonce.
+ #[inline]
+ fn new_from_slices(key: &[u8], iv: &[u8]) -> Result {
+ let kl = Self::KeySize::to_usize();
+ let nl = Self::IvSize::to_usize();
+ if key.len() != kl || iv.len() != nl {
+ Err(InvalidLength)
+ } else {
+ let key = GenericArray::from_slice(key);
+ let iv = GenericArray::from_slice(iv);
+ Ok(Self::new(key, iv))
+ }
+ }
+
+ /// Generate a random key using the provided [`CryptoRng`].
+ #[cfg(feature = "rand_core")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))]
+ #[inline]
+ fn generate_key(mut rng: impl CryptoRng + RngCore) -> GenericArray {
+ let mut key = GenericArray::::default();
+ rng.fill_bytes(&mut key);
+ key
+ }
+
+ /// Generate a random IV using the provided [`CryptoRng`].
+ #[cfg(feature = "rand_core")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))]
+ #[inline]
+ fn generate_iv(mut rng: impl CryptoRng + RngCore) -> GenericArray {
+ let mut iv = GenericArray::::default();
+ rng.fill_bytes(&mut iv);
+ iv
+ }
+
+ /// Generate random key and nonce using the provided [`CryptoRng`].
+ #[cfg(feature = "rand_core")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))]
+ #[inline]
+ fn generate_key_iv(
+ mut rng: impl CryptoRng + RngCore,
+ ) -> (
+ GenericArray,
+ GenericArray,
+ ) {
+ (Self::generate_key(&mut rng), Self::generate_iv(&mut rng))
+ }
+}
+
+/// Types which can be initialized from another type (usually block ciphers).
+///
+/// Usually used for initializing types from block ciphers.
+pub trait InnerInit: Sized {
+ /// Type used for initialization.
+ type Inner;
+
+ /// Initialize value from the `inner`.
+ fn inner_init(inner: Self::Inner) -> Self;
+}
+
+/// Types which can be initialized from another type and additional initialization
+/// vector/nonce.
+///
+/// Usually used for initializing types from block ciphers.
+pub trait InnerIvInit: Sized {
+ /// Block cipher used for initialization.
+ type Inner;
+ /// Initialization vector size in bytes.
+ type IvSize: ArrayLength;
+
+ /// Initialize value using `inner` and `iv` array.
+ fn inner_iv_init(inner: Self::Inner, iv: &GenericArray) -> Self;
+
+ /// Initialize value using `inner` and `iv` slice.
+ fn inner_iv_slice_init(inner: Self::Inner, iv: &[u8]) -> Result {
+ if iv.len() != Self::IvSize::to_usize() {
+ Err(InvalidLength)
+ } else {
+ Ok(Self::inner_iv_init(inner, GenericArray::from_slice(iv)))
+ }
+ }
+}
+
+impl KeyIvInit for T
+where
+ T: InnerIvInit,
+ T::Inner: KeyInit,
+{
+ type KeySize = ::KeySize;
+ type IvSize = T::IvSize;
+
+ #[inline]
+ fn new(key: &GenericArray, iv: &GenericArray) -> Self {
+ Self::inner_iv_init(T::Inner::new(key), iv)
+ }
+
+ #[inline]
+ fn new_from_slices(key: &[u8], iv: &[u8]) -> Result {
+ T::Inner::new_from_slice(key).and_then(|i| T::inner_iv_slice_init(i, iv))
+ }
+}
+
+impl KeyInit for T
+where
+ T: InnerInit,
+ T::Inner: KeyInit,
+{
+ type KeySize = ::KeySize;
+
+ #[inline]
+ fn new(key: &GenericArray) -> Self {
+ Self::inner_init(T::Inner::new(key))
+ }
+
+ #[inline]
+ fn new_from_slice(key: &[u8]) -> Result {
+ T::Inner::new_from_slice(key)
+ .map_err(|_| InvalidLength)
+ .map(Self::inner_init)
+ }
+}
diff --git a/crypto-common/src/lib.rs b/crypto-common/src/lib.rs
index 5869bc677..5c74945cf 100644
--- a/crypto-common/src/lib.rs
+++ b/crypto-common/src/lib.rs
@@ -18,11 +18,29 @@ use generic_array::{ArrayLength, GenericArray};
#[cfg_attr(docsrs, doc(cfg(feature = "core-api")))]
pub use block_buffer;
+mod init;
+pub use init::{InnerInit, InnerIvInit, KeyInit, KeyIvInit};
+mod errors;
+pub use errors::InvalidLength;
+
#[cfg(feature = "core-api")]
#[cfg_attr(docsrs, doc(cfg(feature = "core-api")))]
pub mod core_api;
-/// Trait for types which consume data.
+/// Types which process data in blocks.
+pub trait BlockProcessing {
+ /// Size of the block in bytes.
+ type BlockSize: ArrayLength + 'static;
+}
+
+/// Block on which a [`BlockProcessing`] operates.
+pub type Block = GenericArray::BlockSize>;
+
+impl BlockProcessing for &Alg {
+ type BlockSize = Alg::BlockSize;
+}
+
+/// Types which consume data.
pub trait Update {
/// Update state using the provided data.
fn update(&mut self, data: &[u8]);
diff --git a/crypto-mac/Cargo.toml b/crypto-mac/Cargo.toml
index 4c367b963..8168c2bdc 100644
--- a/crypto-mac/Cargo.toml
+++ b/crypto-mac/Cargo.toml
@@ -14,7 +14,6 @@ categories = ["cryptography", "no-std"]
[dependencies]
generic-array = "0.14"
crypto-common = { version = "0.1", path = "../crypto-common/" }
-cipher = { version = "0.3.0-pre.4", path = "../cipher/" }
subtle = { version = "2", default-features = false }
blobby = { version = "0.3", optional = true }
diff --git a/crypto-mac/src/lib.rs b/crypto-mac/src/lib.rs
index 5020bc7a9..c2b7f8974 100644
--- a/crypto-mac/src/lib.rs
+++ b/crypto-mac/src/lib.rs
@@ -25,8 +25,7 @@ pub mod dev;
#[cfg_attr(docsrs, doc(cfg(feature = "core-api")))]
pub mod core_api;
-pub use cipher::{errors::InvalidLength, FromKey};
-pub use crypto_common::{FixedOutput, FixedOutputReset, Reset, Update};
+pub use crypto_common::{FixedOutput, FixedOutputReset, InvalidLength, KeyInit, Reset, Update};
pub use generic_array::{self, typenum::consts};
use core::fmt;
@@ -34,10 +33,10 @@ use generic_array::GenericArray;
use subtle::{Choice, ConstantTimeEq};
/// Key for an algorithm that implements [`FromKey`].
-pub type Key = GenericArray::KeySize>;
+pub type Key = GenericArray::KeySize>;
/// Convinience super-trait covering functionality of Message Authentication algorithms.
-pub trait Mac: FromKey + Update + FixedOutput {
+pub trait Mac: KeyInit + Update + FixedOutput {
/// Obtain the result of a [`Mac`] computation as a [`Output`] and consume
/// [`Mac`] instance.
fn finalize(self) -> Output {
@@ -65,7 +64,7 @@ pub trait Mac: FromKey + Update + FixedOutput {
}
}
-impl Mac for T {}
+impl Mac for T {}
/// [`Output`] is a thin wrapper around bytes array which provides a safe `Eq`
/// implementation that runs in a fixed time.
diff --git a/digest/src/core_api.rs b/digest/src/core_api.rs
index 63e573d33..84b429c4d 100644
--- a/digest/src/core_api.rs
+++ b/digest/src/core_api.rs
@@ -5,9 +5,10 @@
//! higher-level traits.
use crate::InvalidOutputSize;
use crate::{ExtendableOutput, Reset};
-use generic_array::{ArrayLength, GenericArray};
+use generic_array::ArrayLength;
pub use crypto_common::core_api::{AlgorithmName, CoreWrapper, FixedOutputCore, UpdateCore};
+pub use crypto_common::{Block, BlockProcessing};
mod ct_variable;
mod rt_variable;
@@ -28,12 +29,9 @@ pub trait ExtendableOutputCore: UpdateCore {
}
/// Core reader trait for extendable-output function (XOF) result.
-pub trait XofReaderCore {
- /// Block size in bytes.
- type BlockSize: ArrayLength;
-
+pub trait XofReaderCore: BlockProcessing {
/// Read next XOF block.
- fn read_block(&mut self) -> GenericArray;
+ fn read_block(&mut self) -> Block;
}
/// Core trait for hash functions with variable output size.
diff --git a/digest/src/core_api/ct_variable.rs b/digest/src/core_api/ct_variable.rs
index 11474326f..22c2b5059 100644
--- a/digest/src/core_api/ct_variable.rs
+++ b/digest/src/core_api/ct_variable.rs
@@ -1,4 +1,6 @@
-use super::{AlgorithmName, FixedOutputCore, Reset, UpdateCore, VariableOutputCore};
+use super::{
+ AlgorithmName, Block, BlockProcessing, FixedOutputCore, Reset, UpdateCore, VariableOutputCore,
+};
use core::{fmt, marker::PhantomData};
use generic_array::{
typenum::{IsLessOrEqual, LeEq, NonZero},
@@ -18,17 +20,25 @@ where
_out: PhantomData,
}
-impl UpdateCore for CtVariableCoreWrapper
+impl BlockProcessing for CtVariableCoreWrapper
where
T: VariableOutputCore,
OutSize: ArrayLength + IsLessOrEqual,
LeEq: NonZero,
{
type BlockSize = T::BlockSize;
+}
+
+impl UpdateCore for CtVariableCoreWrapper
+where
+ T: VariableOutputCore,
+ OutSize: ArrayLength + IsLessOrEqual,
+ LeEq: NonZero,
+{
type Buffer = T::Buffer;
#[inline]
- fn update_blocks(&mut self, blocks: &[GenericArray]) {
+ fn update_blocks(&mut self, blocks: &[Block]) {
self.inner.update_blocks(blocks);
}
}