1 //! AES block cipher implementation using the ARMv8 Cryptography Extensions.
2 //!
3 //! Based on this C intrinsics implementation:
4 //! <https://github.com/noloader/AES-Intrinsics/blob/master/aes-arm.c>
5 //!
6 //! Original C written and placed in public domain by Jeffrey Walton.
7 //! Based on code from ARM, and by Johannes Schneiders, Skip Hovsmith and
8 //! Barry O'Rourke for the mbedTLS project.
9 
10 #![allow(clippy::needless_range_loop)]
11 
12 #[cfg(feature = "hazmat")]
13 pub(crate) mod hazmat;
14 
15 mod decrypt;
16 mod encrypt;
17 mod expand;
18 
19 use self::{
20     decrypt::{decrypt, decrypt8},
21     encrypt::{encrypt, encrypt8},
22     expand::{expand_key, inv_expanded_keys},
23 };
24 use crate::{Block, ParBlocks};
25 use cipher::{
26     consts::{U16, U24, U32, U8},
27     generic_array::GenericArray,
28     BlockCipher, BlockDecrypt, BlockEncrypt, NewBlockCipher,
29 };
30 use core::arch::aarch64::*;
31 
32 macro_rules! define_aes_impl {
33     (
34         $name:ident,
35         $name_enc:ident,
36         $name_dec:ident,
37         $key_size:ty,
38         $rounds:tt,
39         $doc:expr
40     ) => {
41         #[doc=$doc]
42         #[doc = "block cipher"]
43         #[derive(Clone)]
44         pub struct $name {
45             encrypt: $name_enc,
46             decrypt: $name_dec,
47         }
48 
49         impl NewBlockCipher for $name {
50             type KeySize = $key_size;
51 
52             #[inline]
53             fn new(key: &GenericArray<u8, $key_size>) -> Self {
54                 let encrypt = $name_enc::new(key);
55                 let decrypt = $name_dec::from(&encrypt);
56                 Self { encrypt, decrypt }
57             }
58         }
59 
60         impl BlockCipher for $name {
61             type BlockSize = U16;
62             type ParBlocks = U8;
63         }
64 
65         impl BlockEncrypt for $name {
66             #[inline]
67             fn encrypt_block(&self, block: &mut Block) {
68                 self.encrypt.encrypt_block(block)
69             }
70 
71             #[inline]
72             fn encrypt_par_blocks(&self, blocks: &mut ParBlocks) {
73                 self.encrypt.encrypt_par_blocks(blocks)
74             }
75         }
76 
77         impl BlockDecrypt for $name {
78             #[inline]
79             fn decrypt_block(&self, block: &mut Block) {
80                 self.decrypt.decrypt_block(block)
81             }
82 
83             #[inline]
84             fn decrypt_par_blocks(&self, blocks: &mut ParBlocks) {
85                 self.decrypt.decrypt_par_blocks(blocks)
86             }
87         }
88 
89         #[doc=$doc]
90         #[doc = "block cipher (encrypt-only)"]
91         #[derive(Clone)]
92         pub struct $name_enc {
93             round_keys: [uint8x16_t; $rounds],
94         }
95 
96         impl NewBlockCipher for $name_enc {
97             type KeySize = $key_size;
98 
99             fn new(key: &GenericArray<u8, $key_size>) -> Self {
100                 Self {
101                     round_keys: expand_key(key.as_ref()),
102                 }
103             }
104         }
105 
106         impl BlockCipher for $name_enc {
107             type BlockSize = U16;
108             type ParBlocks = U8;
109         }
110 
111         impl BlockEncrypt for $name_enc {
112             fn encrypt_block(&self, block: &mut Block) {
113                 unsafe { encrypt(&self.round_keys, block) }
114             }
115 
116             fn encrypt_par_blocks(&self, blocks: &mut ParBlocks) {
117                 unsafe { encrypt8(&self.round_keys, blocks) }
118             }
119         }
120 
121         #[doc=$doc]
122         #[doc = "block cipher (decrypt-only)"]
123         #[derive(Clone)]
124         pub struct $name_dec {
125             round_keys: [uint8x16_t; $rounds],
126         }
127 
128         impl NewBlockCipher for $name_dec {
129             type KeySize = $key_size;
130 
131             fn new(key: &GenericArray<u8, $key_size>) -> Self {
132                 $name_enc::new(key).into()
133             }
134         }
135 
136         impl From<$name_enc> for $name_dec {
137             fn from(enc: $name_enc) -> $name_dec {
138                 Self::from(&enc)
139             }
140         }
141 
142         impl From<&$name_enc> for $name_dec {
143             fn from(enc: &$name_enc) -> $name_dec {
144                 let mut round_keys = enc.round_keys;
145                 inv_expanded_keys(&mut round_keys);
146                 Self { round_keys }
147             }
148         }
149 
150         impl BlockCipher for $name_dec {
151             type BlockSize = U16;
152             type ParBlocks = U8;
153         }
154 
155         impl BlockDecrypt for $name_dec {
156             fn decrypt_block(&self, block: &mut Block) {
157                 unsafe { decrypt(&self.round_keys, block) }
158             }
159 
160             fn decrypt_par_blocks(&self, blocks: &mut ParBlocks) {
161                 unsafe { decrypt8(&self.round_keys, blocks) }
162             }
163         }
164 
165         opaque_debug::implement!($name);
166         opaque_debug::implement!($name_enc);
167         opaque_debug::implement!($name_dec);
168     };
169 }
170 
171 define_aes_impl!(Aes128, Aes128Enc, Aes128Dec, U16, 11, "AES-128");
172 define_aes_impl!(Aes192, Aes192Enc, Aes192Dec, U24, 13, "AES-192");
173 define_aes_impl!(Aes256, Aes256Enc, Aes256Dec, U32, 15, "AES-256");
174 
175 #[cfg(test)]
176 mod tests {
177     use super::{decrypt, decrypt8, encrypt, encrypt8, expand_key, inv_expanded_keys, ParBlocks};
178     use core::{arch::aarch64::*, convert::TryInto};
179     use hex_literal::hex;
180 
181     /// FIPS 197, Appendix A.1: AES-128 Cipher Key
182     /// user input, unaligned buffer
183     const AES128_KEY: [u8; 16] = hex!("2b7e151628aed2a6abf7158809cf4f3c");
184 
185     /// FIPS 197 Appendix A.1: Expansion of a 128-bit Cipher Key
186     /// library controlled, aligned buffer
187     const AES128_EXP_KEYS: [[u8; 16]; 11] = [
188         AES128_KEY,
189         hex!("a0fafe1788542cb123a339392a6c7605"),
190         hex!("f2c295f27a96b9435935807a7359f67f"),
191         hex!("3d80477d4716fe3e1e237e446d7a883b"),
192         hex!("ef44a541a8525b7fb671253bdb0bad00"),
193         hex!("d4d1c6f87c839d87caf2b8bc11f915bc"),
194         hex!("6d88a37a110b3efddbf98641ca0093fd"),
195         hex!("4e54f70e5f5fc9f384a64fb24ea6dc4f"),
196         hex!("ead27321b58dbad2312bf5607f8d292f"),
197         hex!("ac7766f319fadc2128d12941575c006e"),
198         hex!("d014f9a8c9ee2589e13f0cc8b6630ca6"),
199     ];
200 
201     /// Inverse expanded keys for [`AES128_EXPANDED_KEYS`]
202     const AES128_EXP_INVKEYS: [[u8; 16]; 11] = [
203         hex!("d014f9a8c9ee2589e13f0cc8b6630ca6"),
204         hex!("0c7b5a631319eafeb0398890664cfbb4"),
205         hex!("df7d925a1f62b09da320626ed6757324"),
206         hex!("12c07647c01f22c7bc42d2f37555114a"),
207         hex!("6efcd876d2df54807c5df034c917c3b9"),
208         hex!("6ea30afcbc238cf6ae82a4b4b54a338d"),
209         hex!("90884413d280860a12a128421bc89739"),
210         hex!("7c1f13f74208c219c021ae480969bf7b"),
211         hex!("cc7505eb3e17d1ee82296c51c9481133"),
212         hex!("2b3708a7f262d405bc3ebdbf4b617d62"),
213         AES128_KEY,
214     ];
215 
216     /// FIPS 197, Appendix A.2: AES-192 Cipher Key
217     /// user input, unaligned buffer
218     const AES192_KEY: [u8; 24] = hex!("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b");
219 
220     /// FIPS 197 Appendix A.2: Expansion of a 192-bit Cipher Key
221     /// library controlled, aligned buffer
222     const AES192_EXP_KEYS: [[u8; 16]; 13] = [
223         hex!("8e73b0f7da0e6452c810f32b809079e5"),
224         hex!("62f8ead2522c6b7bfe0c91f72402f5a5"),
225         hex!("ec12068e6c827f6b0e7a95b95c56fec2"),
226         hex!("4db7b4bd69b5411885a74796e92538fd"),
227         hex!("e75fad44bb095386485af05721efb14f"),
228         hex!("a448f6d94d6dce24aa326360113b30e6"),
229         hex!("a25e7ed583b1cf9a27f939436a94f767"),
230         hex!("c0a69407d19da4e1ec1786eb6fa64971"),
231         hex!("485f703222cb8755e26d135233f0b7b3"),
232         hex!("40beeb282f18a2596747d26b458c553e"),
233         hex!("a7e1466c9411f1df821f750aad07d753"),
234         hex!("ca4005388fcc5006282d166abc3ce7b5"),
235         hex!("e98ba06f448c773c8ecc720401002202"),
236     ];
237 
238     /// FIPS 197, Appendix A.3: AES-256 Cipher Key
239     /// user input, unaligned buffer
240     const AES256_KEY: [u8; 32] =
241         hex!("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4");
242 
243     /// FIPS 197 Appendix A.3: Expansion of a 256-bit Cipher Key
244     /// library controlled, aligned buffer
245     const AES256_EXP_KEYS: [[u8; 16]; 15] = [
246         hex!("603deb1015ca71be2b73aef0857d7781"),
247         hex!("1f352c073b6108d72d9810a30914dff4"),
248         hex!("9ba354118e6925afa51a8b5f2067fcde"),
249         hex!("a8b09c1a93d194cdbe49846eb75d5b9a"),
250         hex!("d59aecb85bf3c917fee94248de8ebe96"),
251         hex!("b5a9328a2678a647983122292f6c79b3"),
252         hex!("812c81addadf48ba24360af2fab8b464"),
253         hex!("98c5bfc9bebd198e268c3ba709e04214"),
254         hex!("68007bacb2df331696e939e46c518d80"),
255         hex!("c814e20476a9fb8a5025c02d59c58239"),
256         hex!("de1369676ccc5a71fa2563959674ee15"),
257         hex!("5886ca5d2e2f31d77e0af1fa27cf73c3"),
258         hex!("749c47ab18501ddae2757e4f7401905a"),
259         hex!("cafaaae3e4d59b349adf6acebd10190d"),
260         hex!("fe4890d1e6188d0b046df344706c631e"),
261     ];
262 
263     /// FIPS 197, Appendix B input
264     /// user input, unaligned buffer
265     const INPUT: [u8; 16] = hex!("3243f6a8885a308d313198a2e0370734");
266 
267     /// FIPS 197, Appendix B output
268     const EXPECTED: [u8; 16] = hex!("3925841d02dc09fbdc118597196a0b32");
269 
load_expanded_keys<const N: usize>(input: [[u8; 16]; N]) -> [uint8x16_t; N]270     fn load_expanded_keys<const N: usize>(input: [[u8; 16]; N]) -> [uint8x16_t; N] {
271         let mut output = [unsafe { vdupq_n_u8(0) }; N];
272 
273         for (src, dst) in input.iter().zip(output.iter_mut()) {
274             *dst = unsafe { vld1q_u8(src.as_ptr()) }
275         }
276 
277         output
278     }
279 
store_expanded_keys<const N: usize>(input: [uint8x16_t; N]) -> [[u8; 16]; N]280     fn store_expanded_keys<const N: usize>(input: [uint8x16_t; N]) -> [[u8; 16]; N] {
281         let mut output = [[0u8; 16]; N];
282 
283         for (src, dst) in input.iter().zip(output.iter_mut()) {
284             unsafe { vst1q_u8(dst.as_mut_ptr(), *src) }
285         }
286 
287         output
288     }
289 
290     #[test]
aes128_key_expansion()291     fn aes128_key_expansion() {
292         let ek = expand_key(&AES128_KEY);
293         assert_eq!(store_expanded_keys(ek), AES128_EXP_KEYS);
294     }
295 
296     #[test]
aes128_key_expansion_inv()297     fn aes128_key_expansion_inv() {
298         let mut ek = load_expanded_keys(AES128_EXP_KEYS);
299         inv_expanded_keys(&mut ek);
300         assert_eq!(store_expanded_keys(ek), AES128_EXP_INVKEYS);
301     }
302 
303     #[test]
aes192_key_expansion()304     fn aes192_key_expansion() {
305         let ek = expand_key(&AES192_KEY);
306         assert_eq!(store_expanded_keys(ek), AES192_EXP_KEYS);
307     }
308 
309     #[test]
aes256_key_expansion()310     fn aes256_key_expansion() {
311         let ek = expand_key(&AES256_KEY);
312         assert_eq!(store_expanded_keys(ek), AES256_EXP_KEYS);
313     }
314 
315     #[test]
aes128_encrypt()316     fn aes128_encrypt() {
317         // Intentionally misaligned block
318         let mut block = [0u8; 19];
319         block[3..].copy_from_slice(&INPUT);
320 
321         unsafe {
322             encrypt(
323                 &load_expanded_keys(AES128_EXP_KEYS),
324                 (&mut block[3..]).try_into().unwrap(),
325             )
326         };
327 
328         assert_eq!(&block[3..], &EXPECTED);
329     }
330 
331     #[test]
aes128_encrypt8()332     fn aes128_encrypt8() {
333         let mut blocks = ParBlocks::default();
334 
335         for block in &mut blocks {
336             block.copy_from_slice(&INPUT);
337         }
338 
339         unsafe { encrypt8(&load_expanded_keys(AES128_EXP_KEYS), &mut blocks) };
340 
341         for block in &blocks {
342             assert_eq!(block.as_slice(), &EXPECTED);
343         }
344     }
345 
346     #[test]
aes128_decrypt()347     fn aes128_decrypt() {
348         // Intentionally misaligned block
349         let mut block = [0u8; 19];
350         block[3..].copy_from_slice(&EXPECTED);
351 
352         unsafe {
353             decrypt(
354                 &load_expanded_keys(AES128_EXP_INVKEYS),
355                 (&mut block[3..]).try_into().unwrap(),
356             )
357         };
358 
359         assert_eq!(&block[3..], &INPUT);
360     }
361 
362     #[test]
aes128_decrypt8()363     fn aes128_decrypt8() {
364         let mut blocks = ParBlocks::default();
365 
366         for block in &mut blocks {
367             block.copy_from_slice(&EXPECTED);
368         }
369 
370         unsafe { decrypt8(&load_expanded_keys(AES128_EXP_INVKEYS), &mut blocks) };
371 
372         for block in &blocks {
373             assert_eq!(block.as_slice(), &INPUT);
374         }
375     }
376 }
377