1 | //! AES block ciphers implementation using AES-NI instruction set. |
2 | //! |
3 | //! Ciphers functionality is accessed using `BlockCipher` trait from the |
4 | //! [`cipher`](https://docs.rs/cipher) crate. |
5 | //! |
6 | //! # Vulnerability |
7 | //! Lazy FP state restory vulnerability can allow local process to leak content |
8 | //! of the FPU register, in which round keys are stored. This vulnerability |
9 | //! can be mitigated at the operating system level by installing relevant |
10 | //! patches. (i.e. keep your OS updated!) More info: |
11 | //! - [Intel advisory](https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00145.html) |
12 | //! - [Wikipedia](https://en.wikipedia.org/wiki/Lazy_FP_state_restore) |
13 | //! |
14 | //! # Related documents |
15 | //! - [Intel AES-NI whitepaper](https://software.intel.com/sites/default/files/article/165683/aes-wp-2012-09-22-v01.pdf) |
16 | //! - [Use of the AES Instruction Set](https://www.cosic.esat.kuleuven.be/ecrypt/AESday/slides/Use_of_the_AES_Instruction_Set.pdf) |
17 | |
18 | #[macro_use ] |
19 | mod utils; |
20 | |
21 | mod aes128; |
22 | mod aes192; |
23 | mod aes256; |
24 | |
25 | #[cfg (test)] |
26 | mod test_expand; |
27 | |
28 | #[cfg (feature = "hazmat" )] |
29 | pub(crate) mod hazmat; |
30 | |
31 | #[cfg (target_arch = "x86" )] |
32 | use core::arch::x86 as arch; |
33 | #[cfg (target_arch = "x86_64" )] |
34 | use core::arch::x86_64 as arch; |
35 | |
36 | use crate::{Block, Block8}; |
37 | use cipher::{ |
38 | consts::{U16, U24, U32, U8}, |
39 | inout::InOut, |
40 | AlgorithmName, BlockBackend, BlockCipher, BlockClosure, BlockDecrypt, BlockEncrypt, |
41 | BlockSizeUser, Key, KeyInit, KeySizeUser, ParBlocksSizeUser, |
42 | }; |
43 | use core::fmt; |
44 | |
45 | macro_rules! define_aes_impl { |
46 | ( |
47 | $name:tt, |
48 | $name_enc:ident, |
49 | $name_dec:ident, |
50 | $name_back_enc:ident, |
51 | $name_back_dec:ident, |
52 | $module:tt, |
53 | $key_size:ty, |
54 | $doc:expr $(,)? |
55 | ) => { |
56 | #[doc=$doc] |
57 | #[doc = "block cipher" ] |
58 | #[derive(Clone)] |
59 | pub struct $name { |
60 | encrypt: $name_enc, |
61 | decrypt: $name_dec, |
62 | } |
63 | |
64 | impl $name { |
65 | #[inline(always)] |
66 | pub(crate) fn get_enc_backend(&self) -> $name_back_enc<'_> { |
67 | self.encrypt.get_enc_backend() |
68 | } |
69 | |
70 | #[inline(always)] |
71 | pub(crate) fn get_dec_backend(&self) -> $name_back_dec<'_> { |
72 | self.decrypt.get_dec_backend() |
73 | } |
74 | } |
75 | |
76 | impl BlockCipher for $name {} |
77 | |
78 | impl KeySizeUser for $name { |
79 | type KeySize = $key_size; |
80 | } |
81 | |
82 | impl KeyInit for $name { |
83 | #[inline] |
84 | fn new(key: &Key<Self>) -> Self { |
85 | let encrypt = $name_enc::new(key); |
86 | let decrypt = $name_dec::from(&encrypt); |
87 | Self { encrypt, decrypt } |
88 | } |
89 | } |
90 | |
91 | impl From<$name_enc> for $name { |
92 | #[inline] |
93 | fn from(encrypt: $name_enc) -> $name { |
94 | let decrypt = (&encrypt).into(); |
95 | Self { encrypt, decrypt } |
96 | } |
97 | } |
98 | |
99 | impl From<&$name_enc> for $name { |
100 | #[inline] |
101 | fn from(encrypt: &$name_enc) -> $name { |
102 | let decrypt = encrypt.into(); |
103 | let encrypt = encrypt.clone(); |
104 | Self { encrypt, decrypt } |
105 | } |
106 | } |
107 | |
108 | impl BlockSizeUser for $name { |
109 | type BlockSize = U16; |
110 | } |
111 | |
112 | impl BlockEncrypt for $name { |
113 | fn encrypt_with_backend(&self, f: impl BlockClosure<BlockSize = U16>) { |
114 | self.encrypt.encrypt_with_backend(f) |
115 | } |
116 | } |
117 | |
118 | impl BlockDecrypt for $name { |
119 | fn decrypt_with_backend(&self, f: impl BlockClosure<BlockSize = U16>) { |
120 | self.decrypt.decrypt_with_backend(f) |
121 | } |
122 | } |
123 | |
124 | impl fmt::Debug for $name { |
125 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { |
126 | f.write_str(concat!(stringify!($name), " { .. }" )) |
127 | } |
128 | } |
129 | |
130 | impl AlgorithmName for $name { |
131 | fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { |
132 | f.write_str(stringify!($name)) |
133 | } |
134 | } |
135 | |
136 | #[cfg(feature = "zeroize" )] |
137 | impl zeroize::ZeroizeOnDrop for $name {} |
138 | |
139 | #[doc=$doc] |
140 | #[doc = "block cipher (encrypt-only)" ] |
141 | #[derive(Clone)] |
142 | pub struct $name_enc { |
143 | round_keys: $module::RoundKeys, |
144 | } |
145 | |
146 | impl $name_enc { |
147 | #[inline(always)] |
148 | pub(crate) fn get_enc_backend(&self) -> $name_back_enc<'_> { |
149 | $name_back_enc(self) |
150 | } |
151 | } |
152 | |
153 | impl BlockCipher for $name_enc {} |
154 | |
155 | impl KeySizeUser for $name_enc { |
156 | type KeySize = $key_size; |
157 | } |
158 | |
159 | impl KeyInit for $name_enc { |
160 | fn new(key: &Key<Self>) -> Self { |
161 | // SAFETY: we enforce that this code is called only when |
162 | // target features required by `expand` were properly checked. |
163 | Self { |
164 | round_keys: unsafe { $module::expand_key(key.as_ref()) }, |
165 | } |
166 | } |
167 | } |
168 | |
169 | impl BlockSizeUser for $name_enc { |
170 | type BlockSize = U16; |
171 | } |
172 | |
173 | impl BlockEncrypt for $name_enc { |
174 | fn encrypt_with_backend(&self, f: impl BlockClosure<BlockSize = U16>) { |
175 | f.call(&mut self.get_enc_backend()) |
176 | } |
177 | } |
178 | |
179 | impl fmt::Debug for $name_enc { |
180 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { |
181 | f.write_str(concat!(stringify!($name_enc), " { .. }" )) |
182 | } |
183 | } |
184 | |
185 | impl AlgorithmName for $name_enc { |
186 | fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { |
187 | f.write_str(stringify!($name_enc)) |
188 | } |
189 | } |
190 | |
191 | impl Drop for $name_enc { |
192 | #[inline] |
193 | fn drop(&mut self) { |
194 | #[cfg(feature = "zeroize" )] |
195 | zeroize::Zeroize::zeroize(&mut self.round_keys); |
196 | } |
197 | } |
198 | |
199 | #[cfg(feature = "zeroize" )] |
200 | impl zeroize::ZeroizeOnDrop for $name_enc {} |
201 | |
202 | #[doc=$doc] |
203 | #[doc = "block cipher (decrypt-only)" ] |
204 | #[derive(Clone)] |
205 | pub struct $name_dec { |
206 | round_keys: $module::RoundKeys, |
207 | } |
208 | |
209 | impl $name_dec { |
210 | #[inline(always)] |
211 | pub(crate) fn get_dec_backend(&self) -> $name_back_dec<'_> { |
212 | $name_back_dec(self) |
213 | } |
214 | } |
215 | |
216 | impl BlockCipher for $name_dec {} |
217 | |
218 | impl KeySizeUser for $name_dec { |
219 | type KeySize = $key_size; |
220 | } |
221 | |
222 | impl KeyInit for $name_dec { |
223 | fn new(key: &Key<Self>) -> Self { |
224 | $name_enc::new(key).into() |
225 | } |
226 | } |
227 | |
228 | impl From<$name_enc> for $name_dec { |
229 | #[inline] |
230 | fn from(enc: $name_enc) -> $name_dec { |
231 | Self::from(&enc) |
232 | } |
233 | } |
234 | |
235 | impl From<&$name_enc> for $name_dec { |
236 | #[inline] |
237 | fn from(enc: &$name_enc) -> $name_dec { |
238 | let round_keys = unsafe { $module::inv_expanded_keys(&enc.round_keys) }; |
239 | Self { round_keys } |
240 | } |
241 | } |
242 | |
243 | impl BlockSizeUser for $name_dec { |
244 | type BlockSize = U16; |
245 | } |
246 | |
247 | impl BlockDecrypt for $name_dec { |
248 | fn decrypt_with_backend(&self, f: impl BlockClosure<BlockSize = U16>) { |
249 | f.call(&mut self.get_dec_backend()); |
250 | } |
251 | } |
252 | |
253 | impl fmt::Debug for $name_dec { |
254 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { |
255 | f.write_str(concat!(stringify!($name_dec), " { .. }" )) |
256 | } |
257 | } |
258 | |
259 | impl AlgorithmName for $name_dec { |
260 | fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { |
261 | f.write_str(stringify!($name_dec)) |
262 | } |
263 | } |
264 | |
265 | impl Drop for $name_dec { |
266 | #[inline] |
267 | fn drop(&mut self) { |
268 | #[cfg(feature = "zeroize" )] |
269 | zeroize::Zeroize::zeroize(&mut self.round_keys); |
270 | } |
271 | } |
272 | |
273 | #[cfg(feature = "zeroize" )] |
274 | impl zeroize::ZeroizeOnDrop for $name_dec {} |
275 | |
276 | pub(crate) struct $name_back_enc<'a>(&'a $name_enc); |
277 | |
278 | impl<'a> BlockSizeUser for $name_back_enc<'a> { |
279 | type BlockSize = U16; |
280 | } |
281 | |
282 | impl<'a> ParBlocksSizeUser for $name_back_enc<'a> { |
283 | type ParBlocksSize = U8; |
284 | } |
285 | |
286 | impl<'a> BlockBackend for $name_back_enc<'a> { |
287 | #[inline(always)] |
288 | fn proc_block(&mut self, block: InOut<'_, '_, Block>) { |
289 | unsafe { |
290 | $module::encrypt1(&self.0.round_keys, block); |
291 | } |
292 | } |
293 | |
294 | #[inline(always)] |
295 | fn proc_par_blocks(&mut self, blocks: InOut<'_, '_, Block8>) { |
296 | unsafe { |
297 | $module::encrypt8(&self.0.round_keys, blocks); |
298 | } |
299 | } |
300 | } |
301 | |
302 | pub(crate) struct $name_back_dec<'a>(&'a $name_dec); |
303 | |
304 | impl<'a> BlockSizeUser for $name_back_dec<'a> { |
305 | type BlockSize = U16; |
306 | } |
307 | |
308 | impl<'a> ParBlocksSizeUser for $name_back_dec<'a> { |
309 | type ParBlocksSize = U8; |
310 | } |
311 | |
312 | impl<'a> BlockBackend for $name_back_dec<'a> { |
313 | #[inline(always)] |
314 | fn proc_block(&mut self, block: InOut<'_, '_, Block>) { |
315 | unsafe { |
316 | $module::decrypt1(&self.0.round_keys, block); |
317 | } |
318 | } |
319 | |
320 | #[inline(always)] |
321 | fn proc_par_blocks(&mut self, blocks: InOut<'_, '_, Block8>) { |
322 | unsafe { |
323 | $module::decrypt8(&self.0.round_keys, blocks); |
324 | } |
325 | } |
326 | } |
327 | }; |
328 | } |
329 | |
330 | define_aes_impl!( |
331 | Aes128, |
332 | Aes128Enc, |
333 | Aes128Dec, |
334 | Aes128BackEnc, |
335 | Aes128BackDec, |
336 | aes128, |
337 | U16, |
338 | "AES-128" , |
339 | ); |
340 | |
341 | define_aes_impl!( |
342 | Aes192, |
343 | Aes192Enc, |
344 | Aes192Dec, |
345 | Aes192BackEnc, |
346 | Aes192BackDec, |
347 | aes192, |
348 | U24, |
349 | "AES-192" , |
350 | ); |
351 | |
352 | define_aes_impl!( |
353 | Aes256, |
354 | Aes256Enc, |
355 | Aes256Dec, |
356 | Aes256BackEnc, |
357 | Aes256BackDec, |
358 | aes256, |
359 | U32, |
360 | "AES-256" , |
361 | ); |
362 | |