aes/
ni.rs

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]
19mod utils;
20
21mod aes128;
22mod aes192;
23mod aes256;
24
25#[cfg(test)]
26mod test_expand;
27
28#[cfg(feature = "hazmat")]
29pub(crate) mod hazmat;
30
31#[cfg(target_arch = "x86")]
32use core::arch::x86 as arch;
33#[cfg(target_arch = "x86_64")]
34use core::arch::x86_64 as arch;
35
36use crate::{Block, Block8};
37use cipher::{
38    consts::{U16, U24, U32, U8},
39    inout::InOut,
40    AlgorithmName, BlockBackend, BlockCipher, BlockClosure, BlockDecrypt, BlockEncrypt,
41    BlockSizeUser, Key, KeyInit, KeySizeUser, ParBlocksSizeUser,
42};
43use core::fmt;
44
45macro_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
330define_aes_impl!(
331    Aes128,
332    Aes128Enc,
333    Aes128Dec,
334    Aes128BackEnc,
335    Aes128BackDec,
336    aes128,
337    U16,
338    "AES-128",
339);
340
341define_aes_impl!(
342    Aes192,
343    Aes192Enc,
344    Aes192Dec,
345    Aes192BackEnc,
346    Aes192BackDec,
347    aes192,
348    U24,
349    "AES-192",
350);
351
352define_aes_impl!(
353    Aes256,
354    Aes256Enc,
355    Aes256Dec,
356    Aes256BackEnc,
357    Aes256BackDec,
358    aes256,
359    U32,
360    "AES-256",
361);