gost_modes/
ctr64.rs

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, U4, U8,
10};
11use generic_array::{ArrayLength, GenericArray};
12
13/// Counter (CTR) mode of operation for 64-bit block ciphers as defined in
14/// GOST R 34.13-2015
15///
16/// Type parameters:
17/// - `C`: block cipher.
18/// - `S`: number of block bytes used for message encryption. Default: block size.
19#[derive(Clone)]
20pub struct GostCtr64<C, S = <C as BlockCipher>::BlockSize>
21where
22    C: BlockCipher<BlockSize = U8> + BlockEncrypt + NewBlockCipher,
23    C::ParBlocks: ArrayLength<GenericArray<u8, U8>>,
24    S: ArrayLength<u8> + Unsigned + IsGreater<U0> + IsLessOrEqual<U8>,
25{
26    cipher: C,
27    nonce: u32,
28    ctr: u32,
29    block: GenericArray<u8, S>,
30    pos: u8,
31}
32
33impl<C, S> GostCtr64<C, S>
34where
35    C: BlockCipher<BlockSize = U8> + BlockEncrypt + NewBlockCipher,
36    C::ParBlocks: ArrayLength<GenericArray<u8, U8>>,
37    S: ArrayLength<u8> + Unsigned + IsGreater<U0> + IsLessOrEqual<U8>,
38{
39    fn gen_block(&self, ctr: u32) -> GenericArray<u8, S> {
40        let mut block: Block<C> = Default::default();
41        block[..4].copy_from_slice(&self.nonce.to_be_bytes());
42        block[4..].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 GostCtr64<C, S>
51where
52    C: BlockCipher<BlockSize = U8> + BlockEncrypt + NewBlockCipher,
53    C::ParBlocks: ArrayLength<GenericArray<u8, U8>>,
54    S: ArrayLength<u8> + Unsigned + IsGreater<U0> + IsLessOrEqual<U8>,
55{
56    type BlockCipher = C;
57    type NonceSize = U4;
58
59    fn from_block_cipher(cipher: C, nonce: &GenericArray<u8, U4>) -> Self {
60        Self {
61            cipher,
62            nonce: u32::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 GostCtr64<C, S>
71where
72    C: BlockCipher<BlockSize = U8> + BlockEncrypt + NewBlockCipher,
73    C::ParBlocks: ArrayLength<GenericArray<u8, U8>>,
74    S: ArrayLength<u8> + Unsigned + IsGreater<U0> + IsLessOrEqual<U8>,
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 GostCtr64<C, S>
113where
114    C: BlockCipher<BlockSize = U8> + BlockEncrypt + NewBlockCipher,
115    C::ParBlocks: ArrayLength<GenericArray<u8, U8>>,
116    S: ArrayLength<u8> + Unsigned + IsGreater<U0> + IsLessOrEqual<U8>,
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}