1use crate::CtrFlavor;
2use cipher::{
3 AlgorithmName, Block, BlockCipherEncBackend, BlockCipherEncClosure, BlockCipherEncrypt,
4 BlockSizeUser, InnerIvInit, Iv, IvState, ParBlocks, ParBlocksSizeUser, StreamCipherBackend,
5 StreamCipherClosure, StreamCipherCore, StreamCipherSeekCore,
6 array::ArraySize,
7 crypto_common::{BlockSizes, 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: BlockSizes,
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: BlockSizes,
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> AlgorithmName for CtrCore<C, F>
141where
142 C: BlockCipherEncrypt + AlgorithmName,
143 F: CtrFlavor<C::BlockSize>,
144{
145 fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
146 f.write_str("Ctr")?;
147 f.write_str(F::NAME)?;
148 f.write_str("<")?;
149 <C as AlgorithmName>::write_alg_name(f)?;
150 f.write_str(">")
151 }
152}
153
154impl<C, F> Clone for CtrCore<C, F>
155where
156 C: BlockCipherEncrypt + Clone,
157 F: CtrFlavor<C::BlockSize>,
158{
159 #[inline]
160 fn clone(&self) -> Self {
161 Self {
162 cipher: self.cipher.clone(),
163 ctr_nonce: self.ctr_nonce.clone(),
164 }
165 }
166}
167
168impl<C, F> fmt::Debug for CtrCore<C, F>
169where
170 C: BlockCipherEncrypt + AlgorithmName,
171 F: CtrFlavor<C::BlockSize>,
172{
173 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174 f.write_str("Ctr")?;
175 f.write_str(F::NAME)?;
176 f.write_str("<")?;
177 <C as AlgorithmName>::write_alg_name(f)?;
178 f.write_str("> { ... }")
179 }
180}
181
182#[cfg(feature = "zeroize")]
183impl<C, F> ZeroizeOnDrop for CtrCore<C, F>
184where
185 C: BlockCipherEncrypt + ZeroizeOnDrop,
186 F: CtrFlavor<C::BlockSize>,
187 F::CtrNonce: ZeroizeOnDrop,
188{
189}
190
191struct Backend<'a, F, B>
192where
193 F: CtrFlavor<B::BlockSize>,
194 B: BlockCipherEncBackend,
195{
196 ctr_nonce: &'a mut F::CtrNonce,
197 backend: &'a B,
198}
199
200impl<F, B> BlockSizeUser for Backend<'_, F, B>
201where
202 F: CtrFlavor<B::BlockSize>,
203 B: BlockCipherEncBackend,
204{
205 type BlockSize = B::BlockSize;
206}
207
208impl<F, B> ParBlocksSizeUser for Backend<'_, F, B>
209where
210 F: CtrFlavor<B::BlockSize>,
211 B: BlockCipherEncBackend,
212{
213 type ParBlocksSize = B::ParBlocksSize;
214}
215
216impl<F, B> StreamCipherBackend for Backend<'_, F, B>
217where
218 F: CtrFlavor<B::BlockSize>,
219 B: BlockCipherEncBackend,
220{
221 #[inline(always)]
222 fn gen_ks_block(&mut self, block: &mut Block<Self>) {
223 let tmp = F::next_block(self.ctr_nonce);
224 self.backend.encrypt_block((&tmp, block).into());
225 }
226
227 #[inline(always)]
228 fn gen_par_ks_blocks(&mut self, blocks: &mut ParBlocks<Self>) {
229 let mut tmp = ParBlocks::<Self>::default();
230 for block in tmp.iter_mut() {
231 *block = F::next_block(self.ctr_nonce);
232 }
233 self.backend.encrypt_par_blocks((&tmp, blocks).into());
234 }
235}