//! Common cryptographic traits. #![no_std] #![cfg_attr(docsrs, feature(doc_cfg))] #![doc( html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" )] #![forbid(unsafe_code)] #![warn(missing_docs, rust_2018_idioms)] #[cfg(feature = "std")] extern crate std; #[cfg(feature = "rand_core")] pub use rand_core; pub use generic_array; pub use generic_array::typenum; use core::fmt; use generic_array::{typenum::Unsigned, ArrayLength, GenericArray}; #[cfg(feature = "rand_core")] use rand_core::{CryptoRng, RngCore}; /// Block on which [`BlockSizeUser`] implementors operate. pub type Block = GenericArray::BlockSize>; /// Parallel blocks on which [`ParBlocksSizeUser`] implementors operate. pub type ParBlocks = GenericArray, ::ParBlocksSize>; /// Output array of [`OutputSizeUser`] implementors. pub type Output = GenericArray::OutputSize>; /// Key used by [`KeySizeUser`] implementors. pub type Key = GenericArray::KeySize>; /// Initialization vector (nonce) used by [`IvSizeUser`] implementors. pub type Iv = GenericArray::IvSize>; /// Types which process data in blocks. pub trait BlockSizeUser { /// Size of the block in bytes. type BlockSize: ArrayLength + 'static; /// Return block size in bytes. fn block_size() -> usize { Self::BlockSize::USIZE } } impl BlockSizeUser for &T { type BlockSize = T::BlockSize; } impl BlockSizeUser for &mut T { type BlockSize = T::BlockSize; } /// Types which can process blocks in parallel. pub trait ParBlocksSizeUser: BlockSizeUser { /// Number of blocks which can be processed in parallel. type ParBlocksSize: ArrayLength>; } /// Types which return data with the given size. pub trait OutputSizeUser { /// Size of the output in bytes. type OutputSize: ArrayLength + 'static; /// Return output size in bytes. fn output_size() -> usize { Self::OutputSize::USIZE } } /// Types which use key for initialization. /// /// Generally it's used indirectly via [`KeyInit`] or [`KeyIvInit`]. pub trait KeySizeUser { /// Key size in bytes. type KeySize: ArrayLength + 'static; /// Return key size in bytes. fn key_size() -> usize { Self::KeySize::USIZE } } /// Types which use initialization vector (nonce) for initialization. /// /// Generally it's used indirectly via [`KeyIvInit`] or [`InnerIvInit`]. pub trait IvSizeUser { /// Initialization vector size in bytes. type IvSize: ArrayLength + 'static; /// Return IV size in bytes. fn iv_size() -> usize { Self::IvSize::USIZE } } /// Types which use another type for initialization. /// /// Generally it's used indirectly via [`InnerInit`] or [`InnerIvInit`]. pub trait InnerUser { /// Inner type. type Inner; } /// Resettable types. pub trait Reset { /// Reset state to its initial value. fn reset(&mut self); } /// Trait which stores algorithm name constant, used in `Debug` implementations. pub trait AlgorithmName { /// Write algorithm name into `f`. fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result; } /// Types which can be initialized from key. pub trait KeyInit: KeySizeUser + Sized { /// Create new value from fixed size key. fn new(key: &Key) -> 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(Key::::from_slice(key))) } } /// Generate 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) -> Key { let mut key = Key::::default(); rng.fill_bytes(&mut key); key } } /// Types which can be initialized from key and initialization vector (nonce). pub trait KeyIvInit: KeySizeUser + IvSizeUser + Sized { /// Create new value from fixed length key and nonce. fn new(key: &Key, iv: &Iv) -> Self; /// Create new value from variable length key and nonce. #[inline] fn new_from_slices(key: &[u8], iv: &[u8]) -> Result { let key_len = Self::KeySize::USIZE; let iv_len = Self::IvSize::USIZE; if key.len() != key_len || iv.len() != iv_len { Err(InvalidLength) } else { Ok(Self::new( Key::::from_slice(key), Iv::::from_slice(iv), )) } } /// Generate 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) -> Key { let mut key = Key::::default(); rng.fill_bytes(&mut key); key } /// Generate 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) -> Iv { let mut iv = Iv::::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) -> (Key, Iv) { (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: InnerUser + Sized { /// 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: InnerUser + IvSizeUser + Sized { /// Initialize value using `inner` and `iv` array. fn inner_iv_init(inner: Self::Inner, iv: &Iv) -> 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, Iv::::from_slice(iv))) } } /// Generate 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) -> Iv { let mut iv = Iv::::default(); rng.fill_bytes(&mut iv); iv } } impl KeySizeUser for T where T: InnerUser, T::Inner: KeySizeUser, { type KeySize = ::KeySize; } impl KeyIvInit for T where T: InnerIvInit, T::Inner: KeyInit, { #[inline] fn new(key: &Key, iv: &Iv) -> 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, { #[inline] fn new(key: &Key) -> 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) } } // Unfortunately this blanket impl is impossible without mutually // exclusive traits, see: https://github.com/rust-lang/rfcs/issues/1053 // or at the very least without: https://github.com/rust-lang/rust/issues/20400 /* impl KeyIvInit for T where T: InnerInit, T::Inner: KeyIvInit, { #[inline] fn new(key: &Key, iv: &Iv) -> Self { Self::inner_init(T::Inner::new(key, iv)) } #[inline] fn new_from_slices(key: &[u8], iv: &[u8]) -> Result { T::Inner::new_from_slice(key) .map_err(|_| InvalidLength) .map(Self::inner_init) } } */ /// The error type returned when key and/or IV used in the [`KeyInit`], /// [`KeyIvInit`], and [`InnerIvInit`] 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 {}