1#![no_std]
6#![doc(
7 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg",
8 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg"
9)]
10#![deny(unsafe_code)]
11#![cfg_attr(docsrs, feature(doc_cfg))]
12#![warn(missing_docs, rust_2018_idioms)]
13
14pub use cipher;
15
16use cipher::{
17 AlgorithmName, Block, BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherDecrypt,
18 BlockCipherEncBackend, BlockCipherEncClosure, BlockCipherEncrypt, BlockSizeUser, InOut, Key,
19 KeyInit, KeySizeUser, ParBlocksSizeUser, consts::*,
20};
21use core::{fmt, mem::size_of};
22
23#[cfg(feature = "zeroize")]
24use cipher::zeroize::{Zeroize, ZeroizeOnDrop};
25
26macro_rules! define_speck_impl {
27 (
28 $name:ident,
29 $block_size:ty,
30 $key_size:ty,
31 $word_type:ty,
32 $n:literal,
33 $m:literal,
34 $alpha:literal,
35 $beta:literal,
36 $mask:literal,
37 $rounds:literal,
38 $doc:expr $(,)?
39 ) => {
40 #[doc=$doc]
41 #[doc = "block cipher"]
42 #[derive(Clone)]
43 pub struct $name {
44 k: [$word_type; $rounds],
45 }
46
47 impl $name {
48 #[inline]
49 fn from_be_bytes(bytes: &[u8]) -> $word_type {
50 let mut tmp = [0u8; size_of::<$word_type>()];
51 let offset = size_of::<$word_type>() - $n / 8;
52 tmp[offset..].copy_from_slice(bytes);
53 <$word_type>::from_be_bytes(tmp)
54 }
55
56 #[inline]
57 #[allow(clippy::wrong_self_convention)]
58 fn to_be_bytes(word: $word_type) -> [u8; $n / 8] {
59 let tmp = word.to_be_bytes();
60 let offset = size_of::<$word_type>() - $n / 8;
61 tmp[offset..].try_into().unwrap()
62 }
63
64 #[inline]
65 fn rotate_right(x: $word_type, pos: $word_type) -> $word_type {
66 (x >> pos) | (x << ($n - pos))
68 }
69
70 #[inline]
71 fn rotate_left(x: $word_type, pos: $word_type) -> $word_type {
72 (x << pos) | (x >> ($n - pos))
74 }
75
76 #[inline]
77 fn round_function(
78 k: $word_type,
79 mut x: $word_type,
80 mut y: $word_type,
81 ) -> ($word_type, $word_type) {
82 x = $name::rotate_right(x, $alpha);
83 x = <$word_type>::wrapping_add(x, y) & $mask;
84 x = (x ^ k) & $mask;
85 y = $name::rotate_left(y, $beta);
86 y = (y ^ x) & $mask;
87 (x, y)
88 }
89
90 #[inline]
91 fn inverse_round_function(
92 k: $word_type,
93 mut x: $word_type,
94 mut y: $word_type,
95 ) -> ($word_type, $word_type) {
96 y = (y ^ x) & $mask;
97 y = $name::rotate_right(y, $beta);
98 x = (x ^ k) & $mask;
99 x = <$word_type>::wrapping_sub(x, y) & $mask;
100 x = $name::rotate_left(x, $alpha);
101 (x, y)
102 }
103 }
104
105 impl KeySizeUser for $name {
106 type KeySize = $key_size;
107 }
108
109 impl KeyInit for $name {
110 fn new(key: &Key<Self>) -> Self {
111 let mut k = [0; $rounds];
112 let mut l = [0; $m - 1 + $rounds - 1];
113 k[0] = $name::from_be_bytes(&key[($m - 1) * ($n / 8)..($m) * ($n / 8)]);
114
115 for i in 0..$m - 1 {
116 l[i] = $name::from_be_bytes(
117 &key[($m - 2 - i) * ($n / 8)..($m - 1 - i) * ($n / 8)],
118 );
119 }
120
121 for i in 0..($rounds - 1) {
122 let res = $name::round_function(i.try_into().unwrap(), l[i], k[i]);
123 l[i + $m - 1] = res.0;
124 k[i + 1] = res.1;
125 }
126
127 Self { k }
128 }
129 }
130
131 impl BlockSizeUser for $name {
132 type BlockSize = $block_size;
133 }
134
135 impl ParBlocksSizeUser for $name {
136 type ParBlocksSize = U1;
137 }
138
139 impl BlockCipherEncrypt for $name {
140 #[inline]
141 fn encrypt_with_backend(
142 &self,
143 f: impl BlockCipherEncClosure<BlockSize = Self::BlockSize>,
144 ) {
145 f.call(self)
146 }
147 }
148
149 impl BlockCipherEncBackend for $name {
150 #[inline]
151 fn encrypt_block(&self, mut block: InOut<'_, '_, Block<Self>>) {
152 let b = block.get_in();
153 let mut x = $name::from_be_bytes(&b[0..($n / 8)]);
154 let mut y = $name::from_be_bytes(&b[($n / 8)..2 * ($n / 8)]);
155 for i in 0..$rounds {
156 let res = $name::round_function(self.k[i], x, y);
157 x = res.0;
158 y = res.1;
159 }
160
161 let b = block.get_out();
162 b[0..($n / 8)].copy_from_slice(&$name::to_be_bytes(x));
163 b[($n / 8)..2 * ($n / 8)].copy_from_slice(&$name::to_be_bytes(y));
164 }
165 }
166
167 impl BlockCipherDecrypt for $name {
168 #[inline]
169 fn decrypt_with_backend(
170 &self,
171 f: impl BlockCipherDecClosure<BlockSize = Self::BlockSize>,
172 ) {
173 f.call(self)
174 }
175 }
176
177 impl BlockCipherDecBackend for $name {
178 #[inline]
179 fn decrypt_block(&self, mut block: InOut<'_, '_, Block<Self>>) {
180 let b = block.get_in();
181 let mut x = $name::from_be_bytes(&b[0..($n / 8)]);
182 let mut y = $name::from_be_bytes(&b[($n / 8)..2 * ($n / 8)]);
183 for i in (0..$rounds).rev() {
184 let res = $name::inverse_round_function(self.k[i], x, y);
185 x = res.0;
186 y = res.1;
187 }
188
189 let b = block.get_out();
190 b[0..($n / 8)].copy_from_slice(&$name::to_be_bytes(x));
191 b[($n / 8)..2 * ($n / 8)].copy_from_slice(&$name::to_be_bytes(y));
192 }
193 }
194
195 impl fmt::Debug for $name {
196 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197 f.write_str(concat!(stringify!($name), " { .. }"))
198 }
199 }
200
201 impl AlgorithmName for $name {
202 fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
203 f.write_str(stringify!($name))
204 }
205 }
206
207 impl Drop for $name {
208 fn drop(&mut self) {
209 #[cfg(feature = "zeroize")]
210 self.k.zeroize();
211 }
212 }
213
214 #[cfg(feature = "zeroize")]
215 impl ZeroizeOnDrop for $name {}
216 };
217}
218
219define_speck_impl!(
220 Speck32_64,
221 U4,
222 U8,
223 u16,
224 16,
225 4,
226 7,
227 2,
228 0xFFFF,
229 22,
230 "Speck32/64"
231);
232define_speck_impl!(
233 Speck48_72,
234 U6,
235 U9,
236 u32,
237 24,
238 3,
239 8,
240 3,
241 0xFFFFFF,
242 22,
243 "Speck48/72"
244);
245define_speck_impl!(
246 Speck48_96,
247 U6,
248 U12,
249 u32,
250 24,
251 4,
252 8,
253 3,
254 0xFFFFFF,
255 23,
256 "Speck48/96"
257);
258define_speck_impl!(
259 Speck64_96,
260 U8,
261 U12,
262 u32,
263 32,
264 3,
265 8,
266 3,
267 0xFFFFFFFF,
268 26,
269 "Speck64/96"
270);
271define_speck_impl!(
272 Speck64_128,
273 U8,
274 U16,
275 u32,
276 32,
277 4,
278 8,
279 3,
280 0xFFFFFFFF,
281 27,
282 "Speck64/128"
283);
284define_speck_impl!(
285 Speck96_96,
286 U12,
287 U12,
288 u64,
289 48,
290 2,
291 8,
292 3,
293 0xFFFFFFFFFFFF,
294 28,
295 "Speck96/96"
296);
297define_speck_impl!(
298 Speck96_144,
299 U12,
300 U18,
301 u64,
302 48,
303 3,
304 8,
305 3,
306 0xFFFFFFFFFFFF,
307 29,
308 "Speck96/144"
309);
310define_speck_impl!(
311 Speck128_128,
312 U16,
313 U16,
314 u64,
315 64,
316 2,
317 8,
318 3,
319 0xFFFFFFFFFFFFFFFF,
320 32,
321 "Speck128/128"
322);
323define_speck_impl!(
324 Speck128_192,
325 U16,
326 U24,
327 u64,
328 64,
329 3,
330 8,
331 3,
332 0xFFFFFFFFFFFFFFFF,
333 33,
334 "Speck128/192"
335);
336define_speck_impl!(
337 Speck128_256,
338 U16,
339 U32,
340 u64,
341 64,
342 4,
343 8,
344 3,
345 0xFFFFFFFFFFFFFFFF,
346 34,
347 "Speck128/256"
348);