Skip to main content

belt_ctr/
lib.rs

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