1 | //! AES block cipher constant-time implementation. |
2 | //! |
3 | //! The implementation uses a technique called [fixslicing][1], an improved |
4 | //! form of bitslicing which represents ciphers in a way which enables |
5 | //! very efficient constant-time implementations in software. |
6 | //! |
7 | //! [1]: https://eprint.iacr.org/2020/1123.pdf |
8 | |
9 | #![deny (unsafe_code)] |
10 | |
11 | #[cfg_attr (not(target_pointer_width = "64" ), path = "soft/fixslice32.rs" )] |
12 | #[cfg_attr (target_pointer_width = "64" , path = "soft/fixslice64.rs" )] |
13 | pub(crate) mod fixslice; |
14 | |
15 | use crate::Block; |
16 | use cipher::{ |
17 | consts::{U16, U24, U32}, |
18 | inout::InOut, |
19 | AlgorithmName, BlockBackend, BlockCipher, BlockClosure, BlockDecrypt, BlockEncrypt, |
20 | BlockSizeUser, Key, KeyInit, KeySizeUser, ParBlocksSizeUser, |
21 | }; |
22 | use core::fmt; |
23 | use fixslice::{BatchBlocks, FixsliceBlocks, FixsliceKeys128, FixsliceKeys192, FixsliceKeys256}; |
24 | |
25 | macro_rules! define_aes_impl { |
26 | ( |
27 | $name:tt, |
28 | $name_enc:ident, |
29 | $name_dec:ident, |
30 | $name_back_enc:ident, |
31 | $name_back_dec:ident, |
32 | $key_size:ty, |
33 | $fixslice_keys:ty, |
34 | $fixslice_key_schedule:path, |
35 | $fixslice_decrypt:path, |
36 | $fixslice_encrypt:path, |
37 | $doc:expr $(,)? |
38 | ) => { |
39 | #[doc=$doc] |
40 | #[doc = "block cipher" ] |
41 | #[derive(Clone)] |
42 | pub struct $name { |
43 | keys: $fixslice_keys, |
44 | } |
45 | |
46 | impl $name { |
47 | #[inline(always)] |
48 | pub(crate) fn get_enc_backend(&self) -> $name_back_enc<'_> { |
49 | $name_back_enc(self) |
50 | } |
51 | |
52 | #[inline(always)] |
53 | pub(crate) fn get_dec_backend(&self) -> $name_back_dec<'_> { |
54 | $name_back_dec(self) |
55 | } |
56 | } |
57 | |
58 | impl KeySizeUser for $name { |
59 | type KeySize = $key_size; |
60 | } |
61 | |
62 | impl KeyInit for $name { |
63 | #[inline] |
64 | fn new(key: &Key<Self>) -> Self { |
65 | Self { |
66 | keys: $fixslice_key_schedule(key.as_ref()), |
67 | } |
68 | } |
69 | } |
70 | |
71 | impl BlockSizeUser for $name { |
72 | type BlockSize = U16; |
73 | } |
74 | |
75 | impl BlockCipher for $name {} |
76 | |
77 | impl BlockEncrypt for $name { |
78 | fn encrypt_with_backend(&self, f: impl BlockClosure<BlockSize = U16>) { |
79 | f.call(&mut self.get_enc_backend()) |
80 | } |
81 | } |
82 | |
83 | impl BlockDecrypt for $name { |
84 | fn decrypt_with_backend(&self, f: impl BlockClosure<BlockSize = U16>) { |
85 | f.call(&mut self.get_dec_backend()) |
86 | } |
87 | } |
88 | |
89 | impl From<$name_enc> for $name { |
90 | #[inline] |
91 | fn from(enc: $name_enc) -> $name { |
92 | enc.inner |
93 | } |
94 | } |
95 | |
96 | impl From<&$name_enc> for $name { |
97 | #[inline] |
98 | fn from(enc: &$name_enc) -> $name { |
99 | enc.inner.clone() |
100 | } |
101 | } |
102 | |
103 | impl fmt::Debug for $name { |
104 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { |
105 | f.write_str(concat!(stringify!($name), " { .. }" )) |
106 | } |
107 | } |
108 | |
109 | impl AlgorithmName for $name { |
110 | fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { |
111 | f.write_str(stringify!($name)) |
112 | } |
113 | } |
114 | |
115 | impl Drop for $name { |
116 | #[inline] |
117 | fn drop(&mut self) { |
118 | #[cfg(feature = "zeroize" )] |
119 | zeroize::Zeroize::zeroize(&mut self.keys); |
120 | } |
121 | } |
122 | |
123 | #[cfg(feature = "zeroize" )] |
124 | impl zeroize::ZeroizeOnDrop for $name {} |
125 | |
126 | #[doc=$doc] |
127 | #[doc = "block cipher (encrypt-only)" ] |
128 | #[derive(Clone)] |
129 | pub struct $name_enc { |
130 | inner: $name, |
131 | } |
132 | |
133 | impl $name_enc { |
134 | #[inline(always)] |
135 | pub(crate) fn get_enc_backend(&self) -> $name_back_enc<'_> { |
136 | self.inner.get_enc_backend() |
137 | } |
138 | } |
139 | |
140 | impl BlockCipher for $name_enc {} |
141 | |
142 | impl KeySizeUser for $name_enc { |
143 | type KeySize = $key_size; |
144 | } |
145 | |
146 | impl KeyInit for $name_enc { |
147 | #[inline(always)] |
148 | fn new(key: &Key<Self>) -> Self { |
149 | let inner = $name::new(key); |
150 | Self { inner } |
151 | } |
152 | } |
153 | |
154 | impl BlockSizeUser for $name_enc { |
155 | type BlockSize = U16; |
156 | } |
157 | |
158 | impl BlockEncrypt for $name_enc { |
159 | fn encrypt_with_backend(&self, f: impl BlockClosure<BlockSize = U16>) { |
160 | f.call(&mut self.get_enc_backend()) |
161 | } |
162 | } |
163 | |
164 | impl fmt::Debug for $name_enc { |
165 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { |
166 | f.write_str(concat!(stringify!($name_enc), " { .. }" )) |
167 | } |
168 | } |
169 | |
170 | impl AlgorithmName for $name_enc { |
171 | fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { |
172 | f.write_str(stringify!($name_enc)) |
173 | } |
174 | } |
175 | |
176 | #[cfg(feature = "zeroize" )] |
177 | impl zeroize::ZeroizeOnDrop for $name_enc {} |
178 | |
179 | #[doc=$doc] |
180 | #[doc = "block cipher (decrypt-only)" ] |
181 | #[derive(Clone)] |
182 | pub struct $name_dec { |
183 | inner: $name, |
184 | } |
185 | |
186 | impl $name_dec { |
187 | #[inline(always)] |
188 | pub(crate) fn get_dec_backend(&self) -> $name_back_dec<'_> { |
189 | self.inner.get_dec_backend() |
190 | } |
191 | } |
192 | |
193 | impl BlockCipher for $name_dec {} |
194 | |
195 | impl KeySizeUser for $name_dec { |
196 | type KeySize = $key_size; |
197 | } |
198 | |
199 | impl KeyInit for $name_dec { |
200 | #[inline(always)] |
201 | fn new(key: &Key<Self>) -> Self { |
202 | let inner = $name::new(key); |
203 | Self { inner } |
204 | } |
205 | } |
206 | |
207 | impl From<$name_enc> for $name_dec { |
208 | #[inline] |
209 | fn from(enc: $name_enc) -> $name_dec { |
210 | Self { inner: enc.inner } |
211 | } |
212 | } |
213 | |
214 | impl From<&$name_enc> for $name_dec { |
215 | #[inline] |
216 | fn from(enc: &$name_enc) -> $name_dec { |
217 | Self { |
218 | inner: enc.inner.clone(), |
219 | } |
220 | } |
221 | } |
222 | |
223 | impl BlockSizeUser for $name_dec { |
224 | type BlockSize = U16; |
225 | } |
226 | |
227 | impl BlockDecrypt for $name_dec { |
228 | fn decrypt_with_backend(&self, f: impl BlockClosure<BlockSize = U16>) { |
229 | f.call(&mut self.get_dec_backend()); |
230 | } |
231 | } |
232 | |
233 | impl fmt::Debug for $name_dec { |
234 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { |
235 | f.write_str(concat!(stringify!($name_dec), " { .. }" )) |
236 | } |
237 | } |
238 | |
239 | impl AlgorithmName for $name_dec { |
240 | fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { |
241 | f.write_str(stringify!($name_dec)) |
242 | } |
243 | } |
244 | |
245 | #[cfg(feature = "zeroize" )] |
246 | impl zeroize::ZeroizeOnDrop for $name_dec {} |
247 | |
248 | pub(crate) struct $name_back_enc<'a>(&'a $name); |
249 | |
250 | impl<'a> BlockSizeUser for $name_back_enc<'a> { |
251 | type BlockSize = U16; |
252 | } |
253 | |
254 | impl<'a> ParBlocksSizeUser for $name_back_enc<'a> { |
255 | type ParBlocksSize = FixsliceBlocks; |
256 | } |
257 | |
258 | impl<'a> BlockBackend for $name_back_enc<'a> { |
259 | #[inline(always)] |
260 | fn proc_block(&mut self, mut block: InOut<'_, '_, Block>) { |
261 | let mut blocks = BatchBlocks::default(); |
262 | blocks[0] = block.clone_in().into(); |
263 | let res = $fixslice_encrypt(&self.0.keys, &blocks); |
264 | *block.get_out() = res[0].into(); |
265 | } |
266 | |
267 | #[inline(always)] |
268 | fn proc_par_blocks(&mut self, mut blocks: InOut<'_, '_, BatchBlocks>) { |
269 | let res = $fixslice_encrypt(&self.0.keys, blocks.get_in()); |
270 | *blocks.get_out() = res; |
271 | } |
272 | } |
273 | |
274 | pub(crate) struct $name_back_dec<'a>(&'a $name); |
275 | |
276 | impl<'a> BlockSizeUser for $name_back_dec<'a> { |
277 | type BlockSize = U16; |
278 | } |
279 | |
280 | impl<'a> ParBlocksSizeUser for $name_back_dec<'a> { |
281 | type ParBlocksSize = FixsliceBlocks; |
282 | } |
283 | |
284 | impl<'a> BlockBackend for $name_back_dec<'a> { |
285 | #[inline(always)] |
286 | fn proc_block(&mut self, mut block: InOut<'_, '_, Block>) { |
287 | let mut blocks = BatchBlocks::default(); |
288 | blocks[0] = block.clone_in(); |
289 | let res = $fixslice_decrypt(&self.0.keys, &blocks); |
290 | *block.get_out() = res[0]; |
291 | } |
292 | |
293 | #[inline(always)] |
294 | fn proc_par_blocks(&mut self, mut blocks: InOut<'_, '_, BatchBlocks>) { |
295 | let res = $fixslice_decrypt(&self.0.keys, blocks.get_in()); |
296 | *blocks.get_out() = res; |
297 | } |
298 | } |
299 | }; |
300 | } |
301 | |
302 | define_aes_impl!( |
303 | Aes128, |
304 | Aes128Enc, |
305 | Aes128Dec, |
306 | Aes128BackEnc, |
307 | Aes128BackDec, |
308 | U16, |
309 | FixsliceKeys128, |
310 | fixslice::aes128_key_schedule, |
311 | fixslice::aes128_decrypt, |
312 | fixslice::aes128_encrypt, |
313 | "AES-128" , |
314 | ); |
315 | |
316 | define_aes_impl!( |
317 | Aes192, |
318 | Aes192Enc, |
319 | Aes192Dec, |
320 | Aes192BackEnc, |
321 | Aes192BackDec, |
322 | U24, |
323 | FixsliceKeys192, |
324 | fixslice::aes192_key_schedule, |
325 | fixslice::aes192_decrypt, |
326 | fixslice::aes192_encrypt, |
327 | "AES-192" , |
328 | ); |
329 | |
330 | define_aes_impl!( |
331 | Aes256, |
332 | Aes256Enc, |
333 | Aes256Dec, |
334 | Aes256BackEnc, |
335 | Aes256BackDec, |
336 | U32, |
337 | FixsliceKeys256, |
338 | fixslice::aes256_key_schedule, |
339 | fixslice::aes256_decrypt, |
340 | fixslice::aes256_encrypt, |
341 | "AES-256" , |
342 | ); |
343 | |