1use crate::utils::xor;
2use cipher::{
3 errors::{LoopError, OverflowError},
4 Block, BlockCipher, BlockEncrypt, FromBlockCipher, NewBlockCipher, SeekNum, StreamCipher,
5 StreamCipherSeek,
6};
7use generic_array::typenum::{
8 type_operators::{IsGreater, IsLessOrEqual},
9 Unsigned, U0, U16, U8,
10};
11use generic_array::{ArrayLength, GenericArray};
12
13#[derive(Clone)]
20pub struct GostCtr128<C, S = <C as BlockCipher>::BlockSize>
21where
22 C: BlockCipher<BlockSize = U16> + BlockEncrypt + NewBlockCipher,
23 C::ParBlocks: ArrayLength<GenericArray<u8, U16>>,
24 S: ArrayLength<u8> + Unsigned + IsGreater<U0> + IsLessOrEqual<U16>,
25{
26 cipher: C,
27 nonce: u64,
28 ctr: u64,
29 block: GenericArray<u8, S>,
30 pos: u8,
31}
32
33impl<C, S> GostCtr128<C, S>
34where
35 C: BlockCipher<BlockSize = U16> + BlockEncrypt + NewBlockCipher,
36 C::ParBlocks: ArrayLength<GenericArray<u8, U16>>,
37 S: ArrayLength<u8> + Unsigned + IsGreater<U0> + IsLessOrEqual<U16>,
38{
39 fn gen_block(&self, ctr: u64) -> GenericArray<u8, S> {
40 let mut block: Block<C> = Default::default();
41 block[..8].copy_from_slice(&self.nonce.to_be_bytes());
42 block[8..].copy_from_slice(&ctr.to_be_bytes());
43 self.cipher.encrypt_block(&mut block);
44 let mut res: GenericArray<u8, S> = Default::default();
45 res.copy_from_slice(&block[..S::USIZE]);
46 res
47 }
48}
49
50impl<C, S> FromBlockCipher for GostCtr128<C, S>
51where
52 C: BlockCipher<BlockSize = U16> + BlockEncrypt + NewBlockCipher,
53 C::ParBlocks: ArrayLength<GenericArray<u8, U16>>,
54 S: ArrayLength<u8> + Unsigned + IsGreater<U0> + IsLessOrEqual<U16>,
55{
56 type BlockCipher = C;
57 type NonceSize = U8;
58
59 fn from_block_cipher(cipher: C, nonce: &GenericArray<u8, U8>) -> Self {
60 Self {
61 cipher,
62 nonce: u64::from_be_bytes(*nonce.as_ref()),
63 ctr: 0,
64 block: Default::default(),
65 pos: 0,
66 }
67 }
68}
69
70impl<C, S> StreamCipher for GostCtr128<C, S>
71where
72 C: BlockCipher<BlockSize = U16> + BlockEncrypt + NewBlockCipher,
73 C::ParBlocks: ArrayLength<GenericArray<u8, U16>>,
74 S: ArrayLength<u8> + Unsigned + IsGreater<U0> + IsLessOrEqual<U16>,
75{
76 fn try_apply_keystream(&mut self, mut data: &mut [u8]) -> Result<(), LoopError> {
77 let s = self.block.len();
78 let pos = self.pos as usize;
79 let mut ctr = self.ctr;
80
81 if pos != 0 {
82 if data.len() < s - pos {
83 let n = data.len();
84 xor(data, &self.block[pos..pos + n]);
85 self.pos += n as u8;
86 return Ok(());
87 } else if pos != 0 {
88 let (l, r) = { data }.split_at_mut(s - pos);
89 data = r;
90 xor(l, &self.block[pos..]);
91 ctr += 1;
92 }
93 }
94
95 let mut iter = data.chunks_exact_mut(s);
96 for chunk in &mut iter {
97 xor(chunk, &self.gen_block(ctr));
98 ctr += 1;
99 }
100 let rem = iter.into_remainder();
101 self.pos = rem.len() as u8;
102 self.ctr = ctr;
103 if !rem.is_empty() {
104 self.block = self.gen_block(ctr);
105 xor(rem, &self.block[..rem.len()]);
106 }
107
108 Ok(())
109 }
110}
111
112impl<C, S> StreamCipherSeek for GostCtr128<C, S>
113where
114 C: BlockCipher<BlockSize = U16> + BlockEncrypt + NewBlockCipher,
115 C::ParBlocks: ArrayLength<GenericArray<u8, U16>>,
116 S: ArrayLength<u8> + Unsigned + IsGreater<U0> + IsLessOrEqual<U16>,
117{
118 fn try_current_pos<T: SeekNum>(&self) -> Result<T, OverflowError> {
119 T::from_block_byte(self.ctr, self.pos, S::U8)
120 }
121
122 fn try_seek<T: SeekNum>(&mut self, pos: T) -> Result<(), LoopError> {
123 let res = pos.to_block_byte(S::U8)?;
124 self.ctr = res.0;
125 self.pos = res.1;
126 if self.pos != 0 {
127 self.block = self.gen_block(res.0);
128 }
129 Ok(())
130 }
131}