Skip to main content

ctr/
ctr_core.rs

1use crate::CtrFlavor;
2use cipher::{
3    AlgorithmName, Block, BlockCipherEncBackend, BlockCipherEncClosure, BlockCipherEncrypt,
4    BlockSizeUser, InnerIvInit, Iv, IvState, ParBlocks, ParBlocksSizeUser, SetIvState,
5    StreamCipherBackend, StreamCipherClosure, StreamCipherCore, StreamCipherSeekCore,
6    array::ArraySize,
7    common::{InnerUser, IvSizeUser},
8};
9use core::fmt;
10
11#[cfg(feature = "zeroize")]
12use cipher::zeroize::ZeroizeOnDrop;
13
14/// Generic CTR block mode instance.
15pub struct CtrCore<C, F>
16where
17    C: BlockCipherEncrypt,
18    F: CtrFlavor<C::BlockSize>,
19{
20    cipher: C,
21    ctr_nonce: F::CtrNonce,
22}
23
24impl<C, F> BlockSizeUser for CtrCore<C, F>
25where
26    C: BlockCipherEncrypt,
27    F: CtrFlavor<C::BlockSize>,
28{
29    type BlockSize = C::BlockSize;
30}
31
32impl<C, F> StreamCipherCore for CtrCore<C, F>
33where
34    C: BlockCipherEncrypt,
35    F: CtrFlavor<C::BlockSize>,
36{
37    #[inline]
38    fn remaining_blocks(&self) -> Option<usize> {
39        F::remaining(&self.ctr_nonce)
40    }
41
42    #[inline]
43    fn process_with_backend(&mut self, f: impl StreamCipherClosure<BlockSize = Self::BlockSize>) {
44        struct Closure<'a, F, BS, SC>
45        where
46            BS: ArraySize,
47            F: CtrFlavor<BS>,
48            SC: StreamCipherClosure<BlockSize = BS>,
49        {
50            ctr_nonce: &'a mut F::CtrNonce,
51            f: SC,
52        }
53
54        impl<F, BS, SC> BlockSizeUser for Closure<'_, F, BS, SC>
55        where
56            BS: ArraySize,
57            F: CtrFlavor<BS>,
58            SC: StreamCipherClosure<BlockSize = BS>,
59        {
60            type BlockSize = BS;
61        }
62
63        impl<F, BS, SC> BlockCipherEncClosure for Closure<'_, F, BS, SC>
64        where
65            BS: ArraySize,
66            F: CtrFlavor<BS>,
67            SC: StreamCipherClosure<BlockSize = BS>,
68        {
69            #[inline(always)]
70            fn call<B: BlockCipherEncBackend<BlockSize = BS>>(self, backend: &B) {
71                let Self { ctr_nonce, f } = self;
72                f.call(&mut Backend::<F, B> { ctr_nonce, backend });
73            }
74        }
75
76        let Self { cipher, ctr_nonce } = self;
77        cipher.encrypt_with_backend(Closure::<F, _, _> { ctr_nonce, f });
78    }
79}
80
81impl<C, F> StreamCipherSeekCore for CtrCore<C, F>
82where
83    C: BlockCipherEncrypt,
84    F: CtrFlavor<C::BlockSize>,
85{
86    type Counter = F::Backend;
87
88    #[inline]
89    fn get_block_pos(&self) -> Self::Counter {
90        F::as_backend(&self.ctr_nonce)
91    }
92
93    #[inline]
94    fn set_block_pos(&mut self, pos: Self::Counter) {
95        F::set_from_backend(&mut self.ctr_nonce, pos);
96    }
97}
98
99impl<C, F> InnerUser for CtrCore<C, F>
100where
101    C: BlockCipherEncrypt,
102    F: CtrFlavor<C::BlockSize>,
103{
104    type Inner = C;
105}
106
107impl<C, F> IvSizeUser for CtrCore<C, F>
108where
109    C: BlockCipherEncrypt,
110    F: CtrFlavor<C::BlockSize>,
111{
112    type IvSize = C::BlockSize;
113}
114
115impl<C, F> InnerIvInit for CtrCore<C, F>
116where
117    C: BlockCipherEncrypt,
118    F: CtrFlavor<C::BlockSize>,
119{
120    #[inline]
121    fn inner_iv_init(cipher: C, iv: &Iv<Self>) -> Self {
122        Self {
123            cipher,
124            ctr_nonce: F::from_nonce(iv),
125        }
126    }
127}
128
129impl<C, F> IvState for CtrCore<C, F>
130where
131    C: BlockCipherEncrypt,
132    F: CtrFlavor<C::BlockSize>,
133{
134    #[inline]
135    fn iv_state(&self) -> Iv<Self> {
136        F::current_block(&self.ctr_nonce)
137    }
138}
139
140impl<C, F> SetIvState for CtrCore<C, F>
141where
142    C: BlockCipherEncrypt,
143    F: CtrFlavor<C::BlockSize>,
144{
145    #[inline]
146    fn set_iv(&mut self, iv: &Iv<Self>) {
147        self.ctr_nonce = F::from_nonce(iv);
148    }
149}
150
151impl<C, F> AlgorithmName for CtrCore<C, F>
152where
153    C: BlockCipherEncrypt + AlgorithmName,
154    F: CtrFlavor<C::BlockSize>,
155{
156    fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
157        f.write_str("Ctr")?;
158        f.write_str(F::NAME)?;
159        f.write_str("<")?;
160        <C as AlgorithmName>::write_alg_name(f)?;
161        f.write_str(">")
162    }
163}
164
165impl<C, F> fmt::Debug for CtrCore<C, F>
166where
167    C: BlockCipherEncrypt + AlgorithmName,
168    F: CtrFlavor<C::BlockSize>,
169{
170    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171        f.write_str("Ctr")?;
172        f.write_str(F::NAME)?;
173        f.write_str("<")?;
174        <C as AlgorithmName>::write_alg_name(f)?;
175        f.write_str("> { ... }")
176    }
177}
178
179#[cfg(feature = "zeroize")]
180impl<C, F> ZeroizeOnDrop for CtrCore<C, F>
181where
182    C: BlockCipherEncrypt + ZeroizeOnDrop,
183    F: CtrFlavor<C::BlockSize>,
184    F::CtrNonce: ZeroizeOnDrop,
185{
186}
187
188struct Backend<'a, F, B>
189where
190    F: CtrFlavor<B::BlockSize>,
191    B: BlockCipherEncBackend,
192{
193    ctr_nonce: &'a mut F::CtrNonce,
194    backend: &'a B,
195}
196
197impl<F, B> BlockSizeUser for Backend<'_, F, B>
198where
199    F: CtrFlavor<B::BlockSize>,
200    B: BlockCipherEncBackend,
201{
202    type BlockSize = B::BlockSize;
203}
204
205impl<F, B> ParBlocksSizeUser for Backend<'_, F, B>
206where
207    F: CtrFlavor<B::BlockSize>,
208    B: BlockCipherEncBackend,
209{
210    type ParBlocksSize = B::ParBlocksSize;
211}
212
213impl<F, B> StreamCipherBackend for Backend<'_, F, B>
214where
215    F: CtrFlavor<B::BlockSize>,
216    B: BlockCipherEncBackend,
217{
218    #[inline(always)]
219    fn gen_ks_block(&mut self, block: &mut Block<Self>) {
220        let tmp = F::next_block(self.ctr_nonce);
221        self.backend.encrypt_block((&tmp, block).into());
222    }
223
224    #[inline(always)]
225    fn gen_par_ks_blocks(&mut self, blocks: &mut ParBlocks<Self>) {
226        let mut tmp = ParBlocks::<Self>::default();
227        for block in tmp.iter_mut() {
228            *block = F::next_block(self.ctr_nonce);
229        }
230        self.backend.encrypt_par_blocks((&tmp, blocks).into());
231    }
232}