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
14pub 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}