gost_modes/
cbc.rs

1use crate::{utils::xor, GostPadding};
2use block_modes::{block_padding::Padding, BlockMode};
3use cipher::{Block, BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher};
4use core::{marker::PhantomData, ops::Mul};
5use generic_array::typenum::{
6    type_operators::{IsGreater, IsLessOrEqual},
7    Prod, Unsigned, U0, U1, U255,
8};
9use generic_array::{ArrayLength, GenericArray};
10
11/// Cipher Block Chaining (CBC) mode of operation as defined in GOST R 34.13-2015
12///
13/// Type parameters:
14/// - `C`: block cipher.
15/// - `P`: padding algorithm. Default: `GostPadding`.
16/// - `Z`: nonce length in block sizes. Default: 1.
17///
18/// With default parameters this mode is fully equivalent to the `Cbc` mode defined
19/// in the `block-modes` crate.
20#[derive(Clone)]
21pub struct GostCbc<C, P = GostPadding, Z = U1>
22where
23    C: BlockCipher + NewBlockCipher,
24    C::BlockSize: IsLessOrEqual<U255>,
25    Z: ArrayLength<Block<C>> + Unsigned + Mul<C::BlockSize> + IsGreater<U0> + IsLessOrEqual<U255>,
26    Prod<Z, C::BlockSize>: ArrayLength<u8>,
27    P: Padding,
28{
29    cipher: C,
30    state: GenericArray<Block<C>, Z>,
31    pos: u8,
32    _p: PhantomData<P>,
33}
34
35impl<C, P, Z> BlockMode<C, P> for GostCbc<C, P, Z>
36where
37    C: BlockCipher + BlockEncrypt + BlockDecrypt + NewBlockCipher,
38    C::BlockSize: IsLessOrEqual<U255>,
39    Z: ArrayLength<Block<C>> + Unsigned + Mul<C::BlockSize> + IsGreater<U0> + IsLessOrEqual<U255>,
40    Prod<Z, C::BlockSize>: ArrayLength<u8>,
41    P: Padding,
42{
43    type IvSize = Prod<Z, C::BlockSize>;
44
45    fn new(cipher: C, iv: &GenericArray<u8, Self::IvSize>) -> Self {
46        let bs = C::BlockSize::USIZE;
47        let mut state = GenericArray::<Block<C>, Z>::default();
48        for (block, chunk) in state.iter_mut().zip(iv.chunks_exact(bs)) {
49            *block = GenericArray::clone_from_slice(chunk);
50        }
51        Self {
52            cipher,
53            state,
54            pos: 0,
55            _p: Default::default(),
56        }
57    }
58
59    fn encrypt_blocks(&mut self, blocks: &mut [Block<C>]) {
60        for block in blocks {
61            let sb = &mut self.state[self.pos as usize];
62            xor(block, sb);
63            self.cipher.encrypt_block(block);
64            *sb = block.clone();
65            self.pos += 1;
66            self.pos %= Z::U8;
67        }
68    }
69
70    fn decrypt_blocks(&mut self, blocks: &mut [Block<C>]) {
71        for block in blocks {
72            let pos = self.pos as usize;
73            let b = self.state[pos].clone();
74            self.state[pos] = block.clone();
75            self.cipher.decrypt_block(block);
76            xor(block, &b);
77            self.pos += 1;
78            self.pos %= Z::U8;
79        }
80    }
81}