//! Traits used to define functionality of [block ciphers][1]. //! //! # 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]. //! //! [1]: https://en.wikipedia.org/wiki/Block_cipher //! [2]: https://en.wikipedia.org/wiki/Symmetric-key_algorithm use crate::errors::InvalidLength; use core::convert::TryInto; use generic_array::{typenum::Unsigned, ArrayLength, GenericArray}; /// Key for an algorithm that implements [`NewBlockCipher`]. 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>; /// Instantiate a [`BlockCipher`] algorithm. pub trait NewBlockCipher: Sized { /// Key size in bytes with which cipher guaranteed to be initialized. type KeySize: ArrayLength; /// Create new block cipher instance from key with fixed size. fn new(key: &BlockCipherKey) -> 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_from_slice(key: &[u8]) -> Result { if key.len() != Self::KeySize::to_usize() { Err(InvalidLength) } else { Ok(Self::new(GenericArray::from_slice(key))) } } } /// 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. /// /// 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); } } /// 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 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. /// /// 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); } } /// 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); } } } /// Encrypt-only functionality for block ciphers with mutable access to `self`. /// /// 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 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); } 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); } } // Impls of block cipher traits for reference types impl BlockCipher for &Alg { type BlockSize = Alg::BlockSize; type ParBlocks = Alg::ParBlocks; } impl BlockEncrypt for &Alg { #[inline] fn encrypt_block(&self, block: &mut Block) { 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); } } impl BlockDecrypt for &Alg { #[inline] fn decrypt_block(&self, block: &mut Block) { Alg::decrypt_block(self, block); } #[inline] fn decrypt_par_blocks(&self, blocks: &mut ParBlocks) { Alg::decrypt_par_blocks(self, blocks); } #[inline] fn decrypt_blocks(&self, blocks: &mut [Block]) { Alg::decrypt_blocks(self, blocks); } }