1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#[cfg(feature = "alloc")]
pub use alloc::vec::Vec;

use crate::{
    errors::{BlockModeError, InvalidKeyIvLength},
    utils::{to_blocks, Block, Key},
};
use block_padding::Padding;
use cipher::{
    generic_array::{typenum::Unsigned, ArrayLength, GenericArray},
    BlockCipher, NewBlockCipher,
};

/// Trait for a block cipher mode of operation that is used to apply a block cipher
/// operation to input data to transform it into a variable-length output message.
pub trait BlockMode<C: BlockCipher, P: Padding>: Sized {
    /// Initialization Vector size.
    type IvSize: ArrayLength<u8>;

    /// Create a new block mode instance from initialized block cipher and IV.
    fn new(cipher: C, iv: &GenericArray<u8, Self::IvSize>) -> Self;

    /// Create a new block mode instance from fixed sized key and IV.
    fn new_fix(key: &Key<C>, iv: &GenericArray<u8, Self::IvSize>) -> Self
    where
        C: NewBlockCipher,
    {
        Self::new(C::new(key), iv)
    }

    /// Create a new block mode instance from variable size key and IV.
    ///
    /// Returns an error if key or IV have unsupported length.
    fn new_from_slices(key: &[u8], iv: &[u8]) -> Result<Self, InvalidKeyIvLength>
    where
        C: NewBlockCipher,
    {
        if iv.len() != Self::IvSize::USIZE {
            return Err(InvalidKeyIvLength);
        }
        let iv = GenericArray::from_slice(iv);
        let cipher = C::new_from_slice(key).map_err(|_| InvalidKeyIvLength)?;
        Ok(Self::new(cipher, iv))
    }

    /// Encrypt blocks of data
    fn encrypt_blocks(&mut self, blocks: &mut [Block<C>]);

    /// Decrypt blocks of data
    fn decrypt_blocks(&mut self, blocks: &mut [Block<C>]);

    /// Encrypt message in-place.
    ///
    /// `&buffer[..pos]` is used as a message and `&buffer[pos..]` as a reserved
    /// space for padding. The padding space should be big enough for padding,
    /// otherwise method will return `Err(BlockModeError)`.
    fn encrypt(mut self, buffer: &mut [u8], pos: usize) -> Result<&[u8], BlockModeError> {
        let bs = C::BlockSize::to_usize();
        let buf = P::pad(buffer, pos, bs).map_err(|_| BlockModeError)?;
        self.encrypt_blocks(to_blocks(buf));
        Ok(buf)
    }

    /// Decrypt message in-place.
    ///
    /// Returns an error if `buffer` length is not multiple of block size and
    /// if after decoding message has malformed padding.
    fn decrypt(mut self, buffer: &mut [u8]) -> Result<&[u8], BlockModeError> {
        let bs = C::BlockSize::to_usize();
        if buffer.len() % bs != 0 {
            return Err(BlockModeError);
        }
        self.decrypt_blocks(to_blocks(buffer));
        P::unpad(buffer).map_err(|_| BlockModeError)
    }

    /// Encrypt message and store result in vector.
    #[cfg(feature = "alloc")]
    fn encrypt_vec(mut self, plaintext: &[u8]) -> Vec<u8> {
        let bs = C::BlockSize::to_usize();
        let pos = plaintext.len();
        let n = pos + bs;
        let mut buf = Vec::with_capacity(n);
        buf.extend_from_slice(plaintext);
        // prepare space for padding
        let block: Block<C> = Default::default();
        buf.extend_from_slice(&block[..n - pos]);

        let n = P::pad(&mut buf, pos, bs)
            .expect("enough space for padding is allocated")
            .len();
        buf.truncate(n);
        self.encrypt_blocks(to_blocks(&mut buf));
        buf
    }

    /// Encrypt message and store result in vector.
    #[cfg(feature = "alloc")]
    fn decrypt_vec(mut self, ciphertext: &[u8]) -> Result<Vec<u8>, BlockModeError> {
        let bs = C::BlockSize::to_usize();
        if ciphertext.len() % bs != 0 {
            return Err(BlockModeError);
        }
        let mut buf = ciphertext.to_vec();
        self.decrypt_blocks(to_blocks(&mut buf));
        let n = P::unpad(&buf).map_err(|_| BlockModeError)?.len();
        buf.truncate(n);
        Ok(buf)
    }
}

/// Trait for a BlockMode, 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 IvState<C, P>: BlockMode<C, P>
where
    C: BlockCipher,
    P: Padding,
{
    /// Returns the IV needed to process the following block. This value MUST
    /// NOT be exposed to attackers.
    fn iv_state(&self) -> GenericArray<u8, Self::IvSize>;
}