1use crate::utils::xor;
2use cipher::{
3 errors::LoopError, Block, BlockCipher, BlockEncrypt, FromBlockCipher, NewBlockCipher,
4 StreamCipher,
5};
6use core::{marker::PhantomData, ops::Mul};
7use generic_array::typenum::{
8 type_operators::{IsGreater, IsLessOrEqual},
9 Prod, Unsigned, U0, U1, U255,
10};
11use generic_array::{ArrayLength, GenericArray};
12
13#[derive(Clone)]
23pub struct GostOfb<C, Z = U1, S = <C as BlockCipher>::BlockSize>
24where
25 C: BlockCipher + BlockEncrypt + NewBlockCipher,
26 C::BlockSize: IsLessOrEqual<U255>,
27 S: Unsigned + IsGreater<U0> + IsLessOrEqual<C::BlockSize>,
28 Z: ArrayLength<Block<C>> + Unsigned + Mul<C::BlockSize> + IsGreater<U0> + IsLessOrEqual<U255>,
29 Prod<Z, C::BlockSize>: ArrayLength<u8>,
30{
31 cipher: C,
32 state: GenericArray<Block<C>, Z>,
33 block_pos: u8,
34 pos: u8,
35 _p: PhantomData<S>,
36}
37
38impl<C, Z, S> FromBlockCipher for GostOfb<C, Z, S>
39where
40 C: BlockCipher + BlockEncrypt + NewBlockCipher,
41 C::BlockSize: IsLessOrEqual<U255>,
42 S: Unsigned + IsGreater<U0> + IsLessOrEqual<C::BlockSize>,
43 Z: ArrayLength<Block<C>> + Unsigned + Mul<C::BlockSize> + IsGreater<U0> + IsLessOrEqual<U255>,
44 Prod<Z, C::BlockSize>: ArrayLength<u8>,
45{
46 type BlockCipher = C;
47 type NonceSize = Prod<Z, C::BlockSize>;
48
49 fn from_block_cipher(cipher: C, nonce: &GenericArray<u8, Self::NonceSize>) -> Self {
50 let bs = C::BlockSize::to_usize();
51 let mut state: GenericArray<Block<C>, Z> = Default::default();
52 for (chunk, block) in nonce.chunks_exact(bs).zip(state.iter_mut()) {
53 let mut t = GenericArray::clone_from_slice(chunk);
54 cipher.encrypt_block(&mut t);
55 *block = t;
56 }
57
58 Self {
59 cipher,
60 state,
61 block_pos: 0,
62 pos: 0,
63 _p: Default::default(),
64 }
65 }
66}
67
68impl<C, Z, S> StreamCipher for GostOfb<C, Z, S>
69where
70 C: BlockCipher + BlockEncrypt + NewBlockCipher,
71 C::BlockSize: IsLessOrEqual<U255>,
72 S: Unsigned + IsGreater<U0> + IsLessOrEqual<C::BlockSize>,
73 Z: ArrayLength<Block<C>> + Unsigned + Mul<C::BlockSize> + IsGreater<U0> + IsLessOrEqual<U255>,
74 Prod<Z, C::BlockSize>: ArrayLength<u8>,
75{
76 fn try_apply_keystream(&mut self, mut data: &mut [u8]) -> Result<(), LoopError> {
77 let s = S::USIZE;
78 let pos = self.pos as usize;
79 let block_pos = self.block_pos as usize;
80
81 if data.len() < s - pos {
82 let n = data.len();
83 xor(data, &self.state[block_pos][pos..pos + n]);
84 self.pos += n as u8;
85 return Ok(());
86 } else if pos != 0 {
87 let (l, r) = { data }.split_at_mut(s - pos);
88 data = r;
89 xor(l, &self.state[block_pos][pos..s]);
90 self.pos = 0;
91 self.cipher
92 .encrypt_block(&mut self.state[self.block_pos as usize]);
93 self.block_pos = (self.block_pos + 1) % Z::U8;
94 }
95
96 let mut iter = data.chunks_exact_mut(s);
97 for chunk in &mut iter {
98 xor(chunk, &self.state[self.block_pos as usize][..s]);
99 self.cipher
100 .encrypt_block(&mut self.state[self.block_pos as usize]);
101 self.block_pos = (self.block_pos + 1) % Z::U8;
102 }
103 let rem = iter.into_remainder();
104 xor(rem, &self.state[self.block_pos as usize][..rem.len()]);
105 self.pos += rem.len() as u8;
106
107 Ok(())
108 }
109}