1use cipher::{
2 Block, BlockCipherEncrypt, BlockSizeUser, InnerIvInit, Iv,
3 IvSizeUser, typenum::{U16, U32, U64}, common::InnerUser,
4};
5use core::fmt;
6
7#[cfg(feature = "zeroize")]
8use zeroize::ZeroizeOnDrop;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum Error {
13 ZeroIv,
15}
16
17impl fmt::Display for Error {
18 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19 match self {
20 Self::ZeroIv => write!(f, "IV cannot be all zeroes in ELK mode"),
21 }
22 }
23}
24
25impl core::error::Error for Error {}
26
27pub trait ElkPolynomial {
29 fn apply_mask(block: &mut [u8]);
30}
31
32impl ElkPolynomial for U16 {
33 #[inline(always)]
34 fn apply_mask(block: &mut [u8]) {
35 block[1] ^= 1 << 1; block[3] ^= 1 << 1; block[4] ^= 1 << 1; block[7] ^= 1 << 7; block[8] ^= 1 << 3; block[11] ^= 1 << 5; block[13] ^= 1 << 7; block[15] ^= 1 << 0; }
48}
49
50impl ElkPolynomial for U32 {
51 #[inline(always)]
52 fn apply_mask(block: &mut [u8]) {
53 block[3] ^= 1 << 5; block[7] ^= 1 << 1; block[11] ^= 1 << 7; block[14] ^= 1 << 3; block[18] ^= 1 << 5; block[23] ^= 1 << 7; block[27] ^= 1 << 5; block[31] ^= 1 << 0; }
66}
67
68impl ElkPolynomial for U64 {
69 #[inline(always)]
70 fn apply_mask(block: &mut [u8]) {
71 block[6] ^= 1 << 5; block[14] ^= 1 << 5; block[22] ^= 1 << 3; block[28] ^= 1 << 1; block[37] ^= 1 << 3; block[46] ^= 1 << 3; block[55] ^= 1 << 7; block[63] ^= 1 << 0; }
84}
85
86#[inline]
88fn step_lfsr<C>(state: &mut Block<C>)
89where
90 C: BlockSizeUser,
91 C::BlockSize: ElkPolynomial,
92{
93 let overflow = state[0] >> 7;
94 let len = state.len();
95
96 for i in 0..(len - 1) {
98 state[i] = (state[i] << 1) | (state[i + 1] >> 7);
99 }
100 state[len - 1] <<= 1;
101
102 if overflow != 0 {
104 C::BlockSize::apply_mask(state.as_mut_slice());
105 }
106}
107
108#[derive(Clone)]
111#[cfg_attr(feature = "zeroize", derive(ZeroizeOnDrop))]
112pub struct Elk<C>
113where
114 C: BlockCipherEncrypt + BlockSizeUser,
115 C::BlockSize: ElkPolynomial,
116{
117 #[cfg_attr(feature = "zeroize", zeroize(skip))]
118 cipher: C,
119 state: Block<C>,
120}
121
122impl<C> BlockSizeUser for Elk<C>
123where
124 C: BlockCipherEncrypt + BlockSizeUser,
125 C::BlockSize: ElkPolynomial,
126{
127 type BlockSize = C::BlockSize;
128}
129
130impl<C> InnerUser for Elk<C>
131where
132 C: BlockCipherEncrypt + BlockSizeUser,
133 C::BlockSize: ElkPolynomial,
134{
135 type Inner = C;
136}
137
138impl<C> IvSizeUser for Elk<C>
139where
140 C: BlockCipherEncrypt + BlockSizeUser,
141 C::BlockSize: ElkPolynomial,
142{
143 type IvSize = C::BlockSize;
144}
145
146impl<C> InnerIvInit for Elk<C>
147where
148 C: BlockCipherEncrypt + BlockSizeUser,
149 C::BlockSize: ElkPolynomial,
150{
151 #[inline]
152 fn inner_iv_init(cipher: C, iv: &Iv<Self>) -> Self {
153 Self {
154 cipher,
155 state: iv.clone(),
156 }
157 }
158}
159
160impl<C> cipher::AlgorithmName for Elk<C>
161where
162 C: BlockCipherEncrypt + BlockSizeUser + cipher::AlgorithmName,
163 C::BlockSize: ElkPolynomial,
164{
165 fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
166 f.write_str("Elk<")?;
167 <C as cipher::AlgorithmName>::write_alg_name(f)?;
168 f.write_str(">")
169 }
170}
171
172impl<C> fmt::Debug for Elk<C>
173where
174 C: BlockCipherEncrypt + BlockSizeUser + cipher::AlgorithmName,
175 C::BlockSize: ElkPolynomial,
176{
177 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178 f.write_str("Elk<")?;
179 <C as cipher::AlgorithmName>::write_alg_name(f)?;
180 f.write_str("> { ... }")
181 }
182}
183
184impl<C> Elk<C>
185where
186 C: BlockCipherEncrypt + BlockSizeUser,
187 C::BlockSize: ElkPolynomial,
188{
189 pub fn apply_keystream(&mut self, data: &mut [u8]) -> Result<(), Error> {
196 if self.state.iter().all(|&b| b == 0) {
198 return Err(Error::ZeroIv);
199 }
200
201 if data.is_empty() {
202 return Ok(());
203 }
204
205 let block_size = self.state.len();
206 let m = data.len();
207
208 if m < block_size {
209 step_lfsr::<C>(&mut self.state);
212 let mut keystream = self.state.clone();
213 self.cipher.encrypt_block(&mut keystream);
214
215 for (byte, key_byte) in data.iter_mut().zip(keystream.iter()) {
216 *byte ^= key_byte;
217 }
218
219 #[cfg(feature = "zeroize")]
220 {
221 use zeroize::Zeroize;
222 keystream.zeroize();
223 }
224 } else {
225 let mut keystream = self.state.clone();
227 let mut chunks = data.chunks_mut(block_size);
228
229 if let Some(chunk) = chunks.next() {
231 keystream.clone_from(&self.state);
232 self.cipher.encrypt_block(&mut keystream);
233 for (byte, key_byte) in chunk.iter_mut().zip(keystream.iter()) {
234 *byte ^= key_byte;
235 }
236 }
237
238 let mut next_chunk = chunks.next();
240 while let Some(chunk) = next_chunk {
241 next_chunk = chunks.next();
243
244 step_lfsr::<C>(&mut self.state);
246 keystream.clone_from(&self.state);
247 self.cipher.encrypt_block(&mut keystream);
248
249 for (byte, key_byte) in chunk.iter_mut().zip(keystream.iter()) {
250 *byte ^= key_byte;
251 }
252 }
253
254 #[cfg(feature = "zeroize")]
255 {
256 use zeroize::Zeroize;
257 keystream.zeroize();
258 }
259 }
260
261 Ok(())
262 }
263}
264
265#[cfg(kani)]
266mod verification {
267 use super::*;
268 use cipher::{Block, BlockCipherEncrypt, BlockSizeUser};
269 use cipher::typenum::U16;
270
271 #[derive(Clone)]
272 struct MockCipher<Size> {
273 _marker: core::marker::PhantomData<Size>,
274 }
275
276 impl<Size> BlockSizeUser for MockCipher<Size>
277 where
278 Size: hybrid_array::ArraySize,
279 {
280 type BlockSize = Size;
281 }
282
283 impl<Size> BlockCipherEncrypt for MockCipher<Size>
284 where
285 Size: hybrid_array::ArraySize,
286 {
287 fn encrypt_block(&self, _block: &mut Block<Self>) {
288 }
290
291 fn encrypt_with_backend(&self, _backend: impl cipher::BlockCipherEncClosure<BlockSize = Self::BlockSize>) {
292 }
294 }
295
296 #[kani::proof]
297 #[kani::unwind(22)]
298 fn verify_elk_16_multi_block() {
299 let state_bytes: [u8; 16] = kani::any();
300 let state: Block<MockCipher<U16>> = hybrid_array::Array::from(state_bytes);
301 let cipher = MockCipher { _marker: core::marker::PhantomData };
302 let mut elk = Elk { cipher, state };
303
304 let mut buffer = [0u8; 48];
306 let data_len: usize = kani::any();
307 kani::assume(data_len <= 48);
308 let data = &mut buffer[..data_len];
309
310 let _ = elk.apply_keystream(data);
311 }
312}