[go: up one dir, main page]

ctr/
ctr_core.rs

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
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: 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}