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#[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}