block_modes/
traits.rs

1#[cfg(feature = "alloc")]
2pub use alloc::vec::Vec;
3
4use crate::{
5    errors::{BlockModeError, InvalidKeyIvLength},
6    utils::{to_blocks, Block, Key},
7};
8use block_padding::Padding;
9use cipher::{
10    generic_array::{typenum::Unsigned, ArrayLength, GenericArray},
11    BlockCipher, NewBlockCipher,
12};
13
14/// Trait for a block cipher mode of operation that is used to apply a block cipher
15/// operation to input data to transform it into a variable-length output message.
16pub trait BlockMode<C: BlockCipher, P: Padding>: Sized {
17    /// Initialization Vector size.
18    type IvSize: ArrayLength<u8>;
19
20    /// Create a new block mode instance from initialized block cipher and IV.
21    fn new(cipher: C, iv: &GenericArray<u8, Self::IvSize>) -> Self;
22
23    /// Create a new block mode instance from fixed sized key and IV.
24    fn new_fix(key: &Key<C>, iv: &GenericArray<u8, Self::IvSize>) -> Self
25    where
26        C: NewBlockCipher,
27    {
28        Self::new(C::new(key), iv)
29    }
30
31    /// Create a new block mode instance from variable size key and IV.
32    ///
33    /// Returns an error if key or IV have unsupported length.
34    fn new_from_slices(key: &[u8], iv: &[u8]) -> Result<Self, InvalidKeyIvLength>
35    where
36        C: NewBlockCipher,
37    {
38        if iv.len() != Self::IvSize::USIZE {
39            return Err(InvalidKeyIvLength);
40        }
41        let iv = GenericArray::from_slice(iv);
42        let cipher = C::new_from_slice(key).map_err(|_| InvalidKeyIvLength)?;
43        Ok(Self::new(cipher, iv))
44    }
45
46    /// Encrypt blocks of data
47    fn encrypt_blocks(&mut self, blocks: &mut [Block<C>]);
48
49    /// Decrypt blocks of data
50    fn decrypt_blocks(&mut self, blocks: &mut [Block<C>]);
51
52    /// Encrypt message in-place.
53    ///
54    /// `&buffer[..pos]` is used as a message and `&buffer[pos..]` as a reserved
55    /// space for padding. The padding space should be big enough for padding,
56    /// otherwise method will return `Err(BlockModeError)`.
57    fn encrypt(mut self, buffer: &mut [u8], pos: usize) -> Result<&[u8], BlockModeError> {
58        let bs = C::BlockSize::to_usize();
59        let buf = P::pad(buffer, pos, bs).map_err(|_| BlockModeError)?;
60        self.encrypt_blocks(to_blocks(buf));
61        Ok(buf)
62    }
63
64    /// Decrypt message in-place.
65    ///
66    /// Returns an error if `buffer` length is not multiple of block size and
67    /// if after decoding message has malformed padding.
68    fn decrypt(mut self, buffer: &mut [u8]) -> Result<&[u8], BlockModeError> {
69        let bs = C::BlockSize::to_usize();
70        if buffer.len() % bs != 0 {
71            return Err(BlockModeError);
72        }
73        self.decrypt_blocks(to_blocks(buffer));
74        P::unpad(buffer).map_err(|_| BlockModeError)
75    }
76
77    /// Encrypt message and store result in vector.
78    #[cfg(feature = "alloc")]
79    fn encrypt_vec(mut self, plaintext: &[u8]) -> Vec<u8> {
80        let bs = C::BlockSize::to_usize();
81        let pos = plaintext.len();
82        let n = pos + bs;
83        let mut buf = Vec::with_capacity(n);
84        buf.extend_from_slice(plaintext);
85        // prepare space for padding
86        let block: Block<C> = Default::default();
87        buf.extend_from_slice(&block[..n - pos]);
88
89        let n = P::pad(&mut buf, pos, bs)
90            .expect("enough space for padding is allocated")
91            .len();
92        buf.truncate(n);
93        self.encrypt_blocks(to_blocks(&mut buf));
94        buf
95    }
96
97    /// Encrypt message and store result in vector.
98    #[cfg(feature = "alloc")]
99    fn decrypt_vec(mut self, ciphertext: &[u8]) -> Result<Vec<u8>, BlockModeError> {
100        let bs = C::BlockSize::to_usize();
101        if ciphertext.len() % bs != 0 {
102            return Err(BlockModeError);
103        }
104        let mut buf = ciphertext.to_vec();
105        self.decrypt_blocks(to_blocks(&mut buf));
106        let n = P::unpad(&buf).map_err(|_| BlockModeError)?.len();
107        buf.truncate(n);
108        Ok(buf)
109    }
110}
111
112/// Trait for a BlockMode, used to obtain the current state in the form of an IV
113/// that can initialize a BlockMode later and resume the original operation.
114///
115/// The IV value SHOULD be used for resuming operations only and MUST NOT be
116/// exposed to attackers. Failing to comply with this requirement breaks
117/// unpredictability and opens attack venues (see e.g. [1], sec. 3.6.2).
118///
119/// [1]: https://www.cs.umd.edu/~jkatz/imc.html
120pub trait IvState<C, P>: BlockMode<C, P>
121where
122    C: BlockCipher,
123    P: Padding,
124{
125    /// Returns the IV needed to process the following block. This value MUST
126    /// NOT be exposed to attackers.
127    fn iv_state(&self) -> GenericArray<u8, Self::IvSize>;
128}