From 4a92e68ec796384ec37578c142bea3730546325b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Thu, 4 Mar 2021 14:00:27 +0300 Subject: [PATCH] cipher: add block mode traits and wrappers --- .github/workflows/crypto-common.yml | 1 - Cargo.lock | 9 +- Cargo.toml | 3 +- cipher/Cargo.toml | 3 + cipher/src/block.rs | 111 +++++++--------- cipher/src/errors.rs | 36 +++++- cipher/src/lib.rs | 109 +++++++++++++++- cipher/src/mode.rs | 42 ++++++ cipher/src/mode_wrapper.rs | 194 ++++++++++++++++++++++++++++ crypto-common/Cargo.toml | 1 - crypto-common/src/lib.rs | 109 +--------------- crypto-mac/Cargo.toml | 1 + crypto-mac/src/lib.rs | 3 +- 13 files changed, 438 insertions(+), 184 deletions(-) create mode 100644 cipher/src/mode.rs create mode 100644 cipher/src/mode_wrapper.rs diff --git a/.github/workflows/crypto-common.yml b/.github/workflows/crypto-common.yml index 3a91ff660..84963aaae 100644 --- a/.github/workflows/crypto-common.yml +++ b/.github/workflows/crypto-common.yml @@ -52,6 +52,5 @@ jobs: - run: cargo check --all-features - run: cargo test - run: cargo test --features core-api - - run: cargo test --features rand_core - run: cargo test --features std - run: cargo test --all-features diff --git a/Cargo.lock b/Cargo.lock index 3ca909455..59cccd4cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "aead" version = "0.4.0" @@ -77,7 +79,7 @@ dependencies = [ [[package]] name = "block-buffer" version = "0.10.0-pre.2" -source = "git+https://github.com/RustCrypto/utils?branch=master#47b80c33dd1d83d02426152f681ab2c3acd7e40e" +source = "git+https://github.com/RustCrypto/utils?branch=block_mode#092f0d0ea4ee317d92fbaa5bfecc4433cdcdd196" dependencies = [ "block-padding", "generic-array 0.14.4", @@ -86,7 +88,7 @@ dependencies = [ [[package]] name = "block-padding" version = "0.3.0-pre" -source = "git+https://github.com/RustCrypto/utils?branch=master#47b80c33dd1d83d02426152f681ab2c3acd7e40e" +source = "git+https://github.com/RustCrypto/utils?branch=block_mode#092f0d0ea4ee317d92fbaa5bfecc4433cdcdd196" dependencies = [ "generic-array 0.14.4", ] @@ -108,6 +110,7 @@ name = "cipher" version = "0.3.0-pre.4" dependencies = [ "blobby", + "block-buffer 0.10.0-pre.2", "crypto-common", "generic-array 0.14.4", "rand_core", @@ -145,7 +148,6 @@ version = "0.1.0" dependencies = [ "block-buffer 0.10.0-pre.2", "generic-array 0.14.4", - "rand_core", ] [[package]] @@ -153,6 +155,7 @@ name = "crypto-mac" version = "0.11.0-pre" dependencies = [ "blobby", + "cipher", "crypto-common", "generic-array 0.14.4", "rand_core", diff --git a/Cargo.toml b/Cargo.toml index 95aa71a0a..b9c153fbe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,4 +14,5 @@ members = [ ] [patch.crates-io] -block-buffer = { git = "https://github.com/RustCrypto/utils", branch = "master" } +block-buffer = { git = "https://github.com/RustCrypto/utils", branch = "block_mode" } +block-padding = { git = "https://github.com/RustCrypto/utils", branch = "block_mode" } diff --git a/cipher/Cargo.toml b/cipher/Cargo.toml index 5ca5e8736..d01e925b3 100644 --- a/cipher/Cargo.toml +++ b/cipher/Cargo.toml @@ -15,11 +15,14 @@ categories = ["cryptography", "no-std"] generic-array = "0.14" crypto-common = { version = "0.1", path = "../crypto-common/" } +block-buffer = { version = "0.10.0-pre.2", features = ["block-padding"], optional = true } blobby = { version = "0.3", optional = true } rand_core = { version = "0.6", optional = true } [features] +default = ["mode_wrapper"] std = ["crypto-common/std"] +mode_wrapper = ["block-buffer"] dev = ["blobby"] [package.metadata.docs.rs] diff --git a/cipher/src/block.rs b/cipher/src/block.rs index 30076ba16..1769c782e 100644 --- a/cipher/src/block.rs +++ b/cipher/src/block.rs @@ -1,16 +1,18 @@ -//! Traits used to define functionality of [block ciphers][1]. +//! Traits used to define functionality of [block ciphers][1] and [modes of operation][2]. //! //! # About block ciphers //! //! Block ciphers are keyed, deterministic permutations of a fixed-sized input //! "block" providing a reversible transformation to/from an encrypted output. -//! They are one of the fundamental structural components of [symmetric cryptography][2]. +//! They are one of the fundamental structural components of [symmetric cryptography][3]. //! //! [1]: https://en.wikipedia.org/wiki/Block_cipher -//! [2]: https://en.wikipedia.org/wiki/Symmetric-key_algorithm +//! [2]: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation +//! [3]: https://en.wikipedia.org/wiki/Symmetric-key_algorithm +use crate::errors::InvalidLength; +use crate::{FromKey, FromKeyNonce}; use core::convert::TryInto; -use crypto_common::FromKey; use generic_array::{typenum::Unsigned, ArrayLength, GenericArray}; /// Key for an algorithm that implements [`FromKey`]. @@ -177,80 +179,59 @@ impl BlockDecrypt for &Alg { } } +/// 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 + /// Block cipher used for initialization. type BlockCipher: BlockCipher; - /// Nonce size in bytes + /// Nonce size in bytes. type NonceSize: ArrayLength; - /// Instantiate a stream cipher from a block cipher + /// Initialize instance from block cipher and nonce. fn from_block_cipher_nonce( cipher: Self::BlockCipher, nonce: &GenericArray, ) -> Self; } -/// Implement [`FromKeyNonce`][crate::FromKeyNonce] for a type which implements [`FromBlockCipherNonce`]. -#[macro_export] -macro_rules! impl_from_key_nonce { - ($name:ty) => { - impl crate::FromKeyNonce for $name - where - Self: FromBlockCipherNonce, - ::BlockCipher: FromKey, - { - type KeySize = <::BlockCipher as FromKey>::KeySize; - type NonceSize = ::NonceSize; - - fn new( - key: &GenericArray, - nonce: &GenericArray, - ) -> Self { - let cipher = ::BlockCipher::new(key); - Self::from_block_cipher_nonce(cipher, nonce) - } +impl FromKeyNonce for T +where + T: FromBlockCipherNonce, + T::BlockCipher: FromKey, +{ + type KeySize = ::KeySize; + type NonceSize = T::NonceSize; - fn new_from_slices( - key: &[u8], - nonce: &[u8], - ) -> Result { - use crate::errors::InvalidLength; - if nonce.len() != Self::NonceSize::USIZE { - Err(InvalidLength) - } else { - ::BlockCipher::new_from_slice(key) - .map_err(|_| InvalidLength) - .map(|cipher| { - let nonce = GenericArray::from_slice(nonce); - Self::from_block_cipher_nonce(cipher, nonce) - }) - } - } - } - }; + fn new( + key: &GenericArray, + nonce: &GenericArray, + ) -> Self { + Self::from_block_cipher_nonce(T::BlockCipher::new(key), nonce) + } } -/// Implement [`FromKey`] for a type which implements [`From`][From], -/// where `C` implements [`FromKey`]. -#[macro_export] -macro_rules! impl_from_key { - ($name:ty) => { - impl cipher::FromKey for $name - where - Self: From, - { - type KeySize = C::KeySize; - - fn new(key: &GenericArray) -> Self { - C::new(key).into() - } +impl FromKey for T +where + T: FromBlockCipher, + T::BlockCipher: FromKey, +{ + type KeySize = ::KeySize; - fn new_from_slice(key: &[u8]) -> Result { - C::new_from_slice(key) - .map_err(|_| cipher::errors::InvalidLength) - .map(|cipher| cipher.into()) - } - } - }; + fn new(key: &GenericArray) -> Self { + Self::from_block_cipher(T::BlockCipher::new(key)) + } + + fn new_from_slice(key: &[u8]) -> Result { + T::BlockCipher::new_from_slice(key) + .map_err(|_| InvalidLength) + .map(Self::from_block_cipher) + } } diff --git a/cipher/src/errors.rs b/cipher/src/errors.rs index 6dbb5eb25..644495e80 100644 --- a/cipher/src/errors.rs +++ b/cipher/src/errors.rs @@ -2,8 +2,6 @@ use core::fmt; -pub use crypto_common::InvalidLength; - /// The error type returned when stream cipher has reached the end of a keystream. #[derive(Copy, Clone, Debug)] pub struct LoopError; @@ -36,3 +34,37 @@ 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. +/// +/// [`FromKey`]: crate::FromKey +/// [`FromKeyNonce`]: crate::FromKeyNonce +#[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 {} + +/// The error type returned by the [`BlockModeEncryptWrapper`] and +/// [`BlockModeDecryptWrapper`] types. +/// +/// [`BlockModeEncryptWrapper`]: crate::BlockModeEncryptWrapper +/// [`BlockModeDecryptWrapper`]: crate::BlockModeDecryptWrapper +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub struct BlockModeError; + +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 BlockModeError {} diff --git a/cipher/src/lib.rs b/cipher/src/lib.rs index d565f64ea..da2951d87 100644 --- a/cipher/src/lib.rs +++ b/cipher/src/lib.rs @@ -23,8 +23,113 @@ mod block; #[cfg(feature = "dev")] mod dev; pub mod errors; +mod mode; mod stream; -pub use crate::{block::*, stream::*}; -pub use crypto_common::{FromKey, FromKeyNonce}; +#[cfg(feature = "mode_wrapper")] +mod mode_wrapper; + +pub use crate::{block::*, mode::*, stream::*}; 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 new file mode 100644 index 000000000..336f50cfa --- /dev/null +++ b/cipher/src/mode.rs @@ -0,0 +1,42 @@ +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/mode_wrapper.rs b/cipher/src/mode_wrapper.rs new file mode 100644 index 000000000..36f379c3e --- /dev/null +++ b/cipher/src/mode_wrapper.rs @@ -0,0 +1,194 @@ +//! Convinience wrapper around types which implement `BlockMode`. + +use crate::errors::BlockModeError; +use crate::{BlockModeDecrypt, BlockModeEncrypt, FromBlockCipherNonce}; +use block_buffer::{block_padding::Padding, BlockBuffer, LazyBlockBuffer}; +use core::{marker::PhantomData, slice::from_mut}; +use generic_array::{typenum::Unsigned, GenericArray}; + +/// Convinience wrapper around the [`BlockModeEncrypt`] trait, which handles +/// data buffering and provides slice-based methods. +pub struct BlockModeEncryptWrapper> { + inner: M, + buffer: BlockBuffer, + _p: PhantomData

, +} + +impl FromBlockCipherNonce for BlockModeEncryptWrapper +where + M: BlockModeEncrypt + FromBlockCipherNonce, + P: Padding, +{ + type BlockCipher = M::BlockCipher; + type NonceSize = M::NonceSize; + + fn from_block_cipher_nonce( + cipher: Self::BlockCipher, + nonce: &GenericArray, + ) -> Self { + Self { + inner: M::from_block_cipher_nonce(cipher, nonce), + buffer: Default::default(), + _p: Default::default(), + } + } +} + +impl BlockModeEncryptWrapper +where + M: BlockModeEncrypt, + P: Padding, +{ + /// Encrypt part of a plaintext. + /// + /// This mehthod MUST be used in conjuction with the [`encrypt_final`][Self::encrypt_final] method, + /// otherwise plaintext will not be properly padded and may be truncated. + /// + /// The method encrypts plaintext in `data`, writes the resulting plaintext + /// into `out_buf`, and returns it in the `Ok` variant. If a whole message + /// can not be processed, it caches plaintext leftovers into inner buffer + /// for future use. + /// + /// It's recommended for `out_buf` to be at least one block longer than + /// `data`, otherwise the method can return `Err(BlockModeError)` if there is + /// not enough space for encrypted blocks. + #[inline] + pub fn encrypt_part<'a>( + &mut self, + plaintext: &[u8], + out_buf: &'a mut [u8], + ) -> Result<&'a [u8], BlockModeError> { + let Self { inner, buffer, .. } = self; + buffer + .block_mode_processing(plaintext, out_buf, |blocks| inner.encrypt_blocks(blocks)) + .map_err(|_| BlockModeError) + } + + /// Pad and encrypt plaintext. + /// + /// The method pads `plaintext` and encrypts it writing the resulting + /// ciphertext into `out_buf`. + /// + /// It's recommended for `out_buf` to be at least one block longer than + /// `data`, otherwise the method can return `Err(BlockModeError)` if there is + /// not enough space for encrypted blocks. + #[inline] + pub fn encrypt_final<'a>( + mut self, + plaintext: &[u8], + out_buf: &'a mut [u8], + ) -> Result<&'a [u8], BlockModeError> { + let Self { inner, buffer, .. } = &mut self; + let res_len = buffer + .block_mode_processing(plaintext, out_buf, |blocks| inner.encrypt_blocks(blocks)) + .map_err(|_| BlockModeError)? + .len(); + let final_block = buffer.pad_with::

(); + inner.encrypt_blocks(from_mut(final_block)); + + let bs = M::BlockSize::USIZE; + let final_len = res_len.checked_add(bs).ok_or(BlockModeError)?; + let buf = out_buf.get_mut(..final_len).ok_or(BlockModeError)?; + // note: even though `buf[t..]` and `buf[res_len..]` are guaranteed to be + // equivalent, compiler generates a panic branch for the latter. + let t = final_len - bs; + debug_assert_eq!(t, res_len); + buf[t..].copy_from_slice(final_block); + Ok(buf) + } +} + +/// Convinience wrapper around the [`BlockModeDecrypt`] trait, which handles +/// data buffering and provides slice-based methods. +pub struct BlockModeDecryptWrapper> { + inner: M, + buffer: LazyBlockBuffer, + _p: PhantomData

, +} + +impl FromBlockCipherNonce for BlockModeDecryptWrapper +where + M: BlockModeDecrypt + FromBlockCipherNonce, + P: Padding, +{ + type BlockCipher = M::BlockCipher; + type NonceSize = M::NonceSize; + + fn from_block_cipher_nonce( + cipher: Self::BlockCipher, + nonce: &GenericArray, + ) -> Self { + Self { + inner: M::from_block_cipher_nonce(cipher, nonce), + buffer: Default::default(), + _p: Default::default(), + } + } +} + +impl BlockModeDecryptWrapper +where + M: BlockModeDecrypt, + P: Padding, +{ + /// Decrypt part of a ciphertext. + /// + /// This mehthod MUST be used in conjuction with the [`decrypt_final`] method, + /// otherwise plaintext will not be properly padded and may be truncated. + /// + /// The method decrypts `ciphertext`, writes the resulting plaintext + /// into `out_buf`, and returns it in the `Ok` variant. If a whole message + /// can not be processed, it caches ciphertext leftovers into inner buffer + /// for future use. + /// + /// It's recommended for `out_buf` to be at least one block longer than + /// `data`, otherwise the method can return `Err(BlockModeError)` if there is + /// not enough space for encrypted blocks. + /// + /// [`decrypt_final`]: Self::decrypt_final + #[inline] + pub fn decrypt_part<'a>( + &mut self, + ciphertext: &[u8], + out_buf: &'a mut [u8], + ) -> Result<&'a [u8], BlockModeError> { + let Self { inner, buffer, .. } = self; + buffer + .block_mode_processing(ciphertext, out_buf, |blocks| inner.decrypt_blocks(blocks)) + .map_err(|_| BlockModeError) + } + + /// Pad and decrypt plaintext. + /// + /// The method decrypts ciphertext, writes the resulting plaintext into + /// into `out_buf`, and unpads it. + /// + /// It's recommended for `out_buf` to be at least one block longer than + /// `data`, otherwise the method can return `Err(BlockModeError)` if there is + /// not enough space for encrypted blocks. + #[inline] + pub fn decrypt_final<'a>( + mut self, + ciphertext: &[u8], + out_buf: &'a mut [u8], + ) -> Result<&'a [u8], BlockModeError> { + let Self { inner, buffer, .. } = &mut self; + let res_len = buffer + .block_mode_processing(ciphertext, out_buf, |blocks| inner.decrypt_blocks(blocks)) + .map_err(|_| BlockModeError)? + .len(); + let final_block = buffer.get_full_block().ok_or(BlockModeError)?; + inner.decrypt_blocks(from_mut(final_block)); + let tail = P::unpad(final_block).map_err(|_| BlockModeError)?; + + let tail_len = tail.len(); + let final_len = res_len.checked_add(tail_len).ok_or(BlockModeError)?; + let buf = out_buf.get_mut(..final_len).ok_or(BlockModeError)?; + // note: even though `buf[t..]` and `buf[res_len..]` are guaranteed to be + // equivalent, compiler generates a panic branch for the latter. + let t = final_len - tail_len; + debug_assert_eq!(t, res_len); + buf[t..].copy_from_slice(tail); + Ok(buf) + } +} diff --git a/crypto-common/Cargo.toml b/crypto-common/Cargo.toml index 460aa92b6..fd1fdb780 100644 --- a/crypto-common/Cargo.toml +++ b/crypto-common/Cargo.toml @@ -13,7 +13,6 @@ categories = ["cryptography", "no-std"] [dependencies] generic-array = "0.14" -rand_core = { version = "0.6", optional = true } block-buffer = { version = "0.10.0-pre.2", optional = true } [features] diff --git a/crypto-common/src/lib.rs b/crypto-common/src/lib.rs index 0189872cc..5869bc677 100644 --- a/crypto-common/src/lib.rs +++ b/crypto-common/src/lib.rs @@ -12,10 +12,7 @@ #[cfg(feature = "std")] extern crate std; -use core::fmt; -use generic_array::{typenum::Unsigned, ArrayLength, GenericArray}; -#[cfg(feature = "rand_core")] -use rand_core::{CryptoRng, RngCore}; +use generic_array::{ArrayLength, GenericArray}; #[cfg(feature = "core-api")] #[cfg_attr(docsrs, doc(cfg(feature = "core-api")))] @@ -25,96 +22,6 @@ pub use block_buffer; #[cfg_attr(docsrs, doc(cfg(feature = "core-api")))] pub mod core_api; -/// 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 - } -} - /// Trait for types which consume data. pub trait Update { /// Update state using the provided data. @@ -158,17 +65,3 @@ pub trait Reset { /// Reset value to its initial state. fn reset(&mut self); } - -/// The error type returned when key and/or nonce used in [`FromKey`] -/// or [`FromKeyNonce`] 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-mac/Cargo.toml b/crypto-mac/Cargo.toml index 8168c2bdc..4c367b963 100644 --- a/crypto-mac/Cargo.toml +++ b/crypto-mac/Cargo.toml @@ -14,6 +14,7 @@ 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 e9db92242..5020bc7a9 100644 --- a/crypto-mac/src/lib.rs +++ b/crypto-mac/src/lib.rs @@ -25,7 +25,8 @@ pub mod dev; #[cfg_attr(docsrs, doc(cfg(feature = "core-api")))] pub mod core_api; -pub use crypto_common::{FixedOutput, FixedOutputReset, FromKey, InvalidLength, Reset, Update}; +pub use cipher::{errors::InvalidLength, FromKey}; +pub use crypto_common::{FixedOutput, FixedOutputReset, Reset, Update}; pub use generic_array::{self, typenum::consts}; use core::fmt;