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, 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    fn remaining_blocks(&self) -> Option<usize> {
45        let used = self.s.wrapping_sub(self.s_init);
46        (u128::MAX - used).try_into().ok()
47    }
48
49    fn process_with_backend(&mut self, f: impl StreamCipherClosure<BlockSize = Self::BlockSize>) {
50        struct Closure<'a, C: StreamCipherClosure<BlockSize = U16>> {
51            s: &'a mut u128,
52            f: C,
53        }
54
55        impl<C: StreamCipherClosure<BlockSize = U16>> BlockSizeUser for Closure<'_, C> {
56            type BlockSize = U16;
57        }
58
59        impl<C: StreamCipherClosure<BlockSize = U16>> BlockCipherEncClosure for Closure<'_, C> {
60            #[inline(always)]
61            fn call<B: BlockCipherEncBackend<BlockSize = U16>>(self, cipher_backend: &B) {
62                let Self { s, f } = self;
63                f.call(&mut Backend { s, cipher_backend });
64            }
65        }
66
67        let Self { cipher, s, .. } = self;
68        cipher.encrypt_with_backend(Closure { s, f });
69    }
70}
71
72impl<C> StreamCipherSeekCore for GenericBeltCtrCore<C>
73where
74    C: BlockCipherEncrypt + BlockSizeUser<BlockSize = U16>,
75{
76    type Counter = u128;
77
78    fn get_block_pos(&self) -> Self::Counter {
79        self.s.wrapping_sub(self.s_init)
80    }
81
82    fn set_block_pos(&mut self, pos: Self::Counter) {
83        self.s = self.s_init.wrapping_add(pos);
84    }
85}
86
87impl<C> BlockSizeUser for GenericBeltCtrCore<C>
88where
89    C: BlockCipherEncrypt + BlockSizeUser<BlockSize = U16>,
90{
91    type BlockSize = C::BlockSize;
92}
93
94impl<C> IvSizeUser for GenericBeltCtrCore<C>
95where
96    C: BlockCipherEncrypt + BlockSizeUser<BlockSize = U16>,
97{
98    type IvSize = C::BlockSize;
99}
100
101impl<C> InnerUser for GenericBeltCtrCore<C>
102where
103    C: BlockCipherEncrypt + BlockSizeUser<BlockSize = U16>,
104{
105    type Inner = C;
106}
107
108impl<C> InnerIvInit for GenericBeltCtrCore<C>
109where
110    C: BlockCipherEncrypt + BlockSizeUser<BlockSize = U16>,
111{
112    #[inline]
113    fn inner_iv_init(cipher: C, iv: &Iv<Self>) -> Self {
114        let mut t = Array::default();
115        cipher.encrypt_block_b2b(iv, &mut t);
116        let s = u128::from_le_bytes(t.into());
117        Self {
118            cipher,
119            s,
120            s_init: s,
121        }
122    }
123}
124
125impl<C> IvState for GenericBeltCtrCore<C>
126where
127    C: BlockCipherEncrypt + BlockCipherDecrypt + BlockSizeUser<BlockSize = U16>,
128{
129    fn iv_state(&self) -> Iv<Self> {
130        let mut t = self.s.to_le_bytes().into();
131        self.cipher.decrypt_block(&mut t);
132        t
133    }
134}
135
136impl<C> AlgorithmName for GenericBeltCtrCore<C>
137where
138    C: BlockCipherEncrypt + BlockSizeUser<BlockSize = U16> + AlgorithmName,
139{
140    fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
141        f.write_str("BeltCtr<")?;
142        <C as AlgorithmName>::write_alg_name(f)?;
143        f.write_str(">")
144    }
145}
146
147impl<C> fmt::Debug for GenericBeltCtrCore<C>
148where
149    C: BlockCipherEncrypt + BlockSizeUser<BlockSize = U16> + AlgorithmName,
150{
151    #[inline]
152    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153        f.write_str("BeltCtr<")?;
154        <C as AlgorithmName>::write_alg_name(f)?;
155        f.write_str("> { ... }")
156    }
157}
158
159impl<C: BlockCipherEncrypt> Drop for GenericBeltCtrCore<C>
160where
161    C: BlockCipherEncrypt + BlockSizeUser<BlockSize = U16>,
162{
163    fn drop(&mut self) {
164        #[cfg(feature = "zeroize")]
165        {
166            self.s.zeroize();
167            self.s_init.zeroize();
168        }
169    }
170}
171
172#[cfg(feature = "zeroize")]
173impl<C> ZeroizeOnDrop for GenericBeltCtrCore<C> where
174    C: BlockCipherEncrypt + BlockSizeUser<BlockSize = U16> + ZeroizeOnDrop
175{
176}
177
178struct Backend<'a, B: BlockCipherEncBackend<BlockSize = U16>> {
179    s: &'a mut u128,
180    cipher_backend: &'a B,
181}
182
183impl<B: BlockCipherEncBackend<BlockSize = U16>> BlockSizeUser for Backend<'_, B> {
184    type BlockSize = B::BlockSize;
185}
186
187impl<B: BlockCipherEncBackend<BlockSize = U16>> ParBlocksSizeUser for Backend<'_, B> {
188    type ParBlocksSize = B::ParBlocksSize;
189}
190
191impl<B: BlockCipherEncBackend<BlockSize = U16>> StreamCipherBackend for Backend<'_, B> {
192    #[inline(always)]
193    fn gen_ks_block(&mut self, block: &mut Block<Self>) {
194        *self.s = self.s.wrapping_add(1);
195        let tmp = self.s.to_le_bytes().into();
196        self.cipher_backend.encrypt_block((&tmp, block).into());
197    }
198
199    #[inline(always)]
200    fn gen_par_ks_blocks(&mut self, blocks: &mut ParBlocks<Self>) {
201        let mut tmp = ParBlocks::<Self>::default();
202        let mut s = *self.s;
203        for block in tmp.iter_mut() {
204            s = s.wrapping_add(1);
205            *block = s.to_le_bytes().into();
206        }
207        *self.s = s;
208        let io_blocks = InOut::from((&tmp, blocks));
209        self.cipher_backend.encrypt_par_blocks(io_blocks);
210    }
211}