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 // TODO(tarcieri): use `stdarch` intrinsic for this when it becomes available
176 #[inline(always)]
vst1q_u8(dst: *mut u8, src: uint8x16_t)177 unsafe fn vst1q_u8(dst: *mut u8, src: uint8x16_t) {
178     dst.copy_from_nonoverlapping(&src as *const _ as *const u8, 16);
179 }
180 
181 #[cfg(test)]
182 mod tests {
183     use super::{
184         decrypt, decrypt8, encrypt, encrypt8, expand_key, inv_expanded_keys, vst1q_u8, ParBlocks,
185     };
186     use core::{arch::aarch64::*, convert::TryInto};
187     use hex_literal::hex;
188 
189     /// FIPS 197, Appendix A.1: AES-128 Cipher Key
190     /// user input, unaligned buffer
191     const AES128_KEY: [u8; 16] = hex!("2b7e151628aed2a6abf7158809cf4f3c");
192 
193     /// FIPS 197 Appendix A.1: Expansion of a 128-bit Cipher Key
194     /// library controlled, aligned buffer
195     const AES128_EXP_KEYS: [[u8; 16]; 11] = [
196         AES128_KEY,
197         hex!("a0fafe1788542cb123a339392a6c7605"),
198         hex!("f2c295f27a96b9435935807a7359f67f"),
199         hex!("3d80477d4716fe3e1e237e446d7a883b"),
200         hex!("ef44a541a8525b7fb671253bdb0bad00"),
201         hex!("d4d1c6f87c839d87caf2b8bc11f915bc"),
202         hex!("6d88a37a110b3efddbf98641ca0093fd"),
203         hex!("4e54f70e5f5fc9f384a64fb24ea6dc4f"),
204         hex!("ead27321b58dbad2312bf5607f8d292f"),
205         hex!("ac7766f319fadc2128d12941575c006e"),
206         hex!("d014f9a8c9ee2589e13f0cc8b6630ca6"),
207     ];
208 
209     /// Inverse expanded keys for [`AES128_EXPANDED_KEYS`]
210     const AES128_EXP_INVKEYS: [[u8; 16]; 11] = [
211         hex!("d014f9a8c9ee2589e13f0cc8b6630ca6"),
212         hex!("0c7b5a631319eafeb0398890664cfbb4"),
213         hex!("df7d925a1f62b09da320626ed6757324"),
214         hex!("12c07647c01f22c7bc42d2f37555114a"),
215         hex!("6efcd876d2df54807c5df034c917c3b9"),
216         hex!("6ea30afcbc238cf6ae82a4b4b54a338d"),
217         hex!("90884413d280860a12a128421bc89739"),
218         hex!("7c1f13f74208c219c021ae480969bf7b"),
219         hex!("cc7505eb3e17d1ee82296c51c9481133"),
220         hex!("2b3708a7f262d405bc3ebdbf4b617d62"),
221         AES128_KEY,
222     ];
223 
224     /// FIPS 197, Appendix A.2: AES-192 Cipher Key
225     /// user input, unaligned buffer
226     const AES192_KEY: [u8; 24] = hex!("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b");
227 
228     /// FIPS 197 Appendix A.2: Expansion of a 192-bit Cipher Key
229     /// library controlled, aligned buffer
230     const AES192_EXP_KEYS: [[u8; 16]; 13] = [
231         hex!("8e73b0f7da0e6452c810f32b809079e5"),
232         hex!("62f8ead2522c6b7bfe0c91f72402f5a5"),
233         hex!("ec12068e6c827f6b0e7a95b95c56fec2"),
234         hex!("4db7b4bd69b5411885a74796e92538fd"),
235         hex!("e75fad44bb095386485af05721efb14f"),
236         hex!("a448f6d94d6dce24aa326360113b30e6"),
237         hex!("a25e7ed583b1cf9a27f939436a94f767"),
238         hex!("c0a69407d19da4e1ec1786eb6fa64971"),
239         hex!("485f703222cb8755e26d135233f0b7b3"),
240         hex!("40beeb282f18a2596747d26b458c553e"),
241         hex!("a7e1466c9411f1df821f750aad07d753"),
242         hex!("ca4005388fcc5006282d166abc3ce7b5"),
243         hex!("e98ba06f448c773c8ecc720401002202"),
244     ];
245 
246     /// FIPS 197, Appendix A.3: AES-256 Cipher Key
247     /// user input, unaligned buffer
248     const AES256_KEY: [u8; 32] =
249         hex!("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4");
250 
251     /// FIPS 197 Appendix A.3: Expansion of a 256-bit Cipher Key
252     /// library controlled, aligned buffer
253     const AES256_EXP_KEYS: [[u8; 16]; 15] = [
254         hex!("603deb1015ca71be2b73aef0857d7781"),
255         hex!("1f352c073b6108d72d9810a30914dff4"),
256         hex!("9ba354118e6925afa51a8b5f2067fcde"),
257         hex!("a8b09c1a93d194cdbe49846eb75d5b9a"),
258         hex!("d59aecb85bf3c917fee94248de8ebe96"),
259         hex!("b5a9328a2678a647983122292f6c79b3"),
260         hex!("812c81addadf48ba24360af2fab8b464"),
261         hex!("98c5bfc9bebd198e268c3ba709e04214"),
262         hex!("68007bacb2df331696e939e46c518d80"),
263         hex!("c814e20476a9fb8a5025c02d59c58239"),
264         hex!("de1369676ccc5a71fa2563959674ee15"),
265         hex!("5886ca5d2e2f31d77e0af1fa27cf73c3"),
266         hex!("749c47ab18501ddae2757e4f7401905a"),
267         hex!("cafaaae3e4d59b349adf6acebd10190d"),
268         hex!("fe4890d1e6188d0b046df344706c631e"),
269     ];
270 
271     /// FIPS 197, Appendix B input
272     /// user input, unaligned buffer
273     const INPUT: [u8; 16] = hex!("3243f6a8885a308d313198a2e0370734");
274 
275     /// FIPS 197, Appendix B output
276     const EXPECTED: [u8; 16] = hex!("3925841d02dc09fbdc118597196a0b32");
277 
load_expanded_keys<const N: usize>(input: [[u8; 16]; N]) -> [uint8x16_t; N]278     fn load_expanded_keys<const N: usize>(input: [[u8; 16]; N]) -> [uint8x16_t; N] {
279         let mut output = [unsafe { vdupq_n_u8(0) }; N];
280 
281         for (src, dst) in input.iter().zip(output.iter_mut()) {
282             *dst = unsafe { vld1q_u8(src.as_ptr()) }
283         }
284 
285         output
286     }
287 
store_expanded_keys<const N: usize>(input: [uint8x16_t; N]) -> [[u8; 16]; N]288     fn store_expanded_keys<const N: usize>(input: [uint8x16_t; N]) -> [[u8; 16]; N] {
289         let mut output = [[0u8; 16]; N];
290 
291         for (src, dst) in input.iter().zip(output.iter_mut()) {
292             unsafe { vst1q_u8(dst.as_mut_ptr(), *src) }
293         }
294 
295         output
296     }
297 
298     #[test]
aes128_key_expansion()299     fn aes128_key_expansion() {
300         let ek = expand_key(&AES128_KEY);
301         assert_eq!(store_expanded_keys(ek), AES128_EXP_KEYS);
302     }
303 
304     #[test]
aes128_key_expansion_inv()305     fn aes128_key_expansion_inv() {
306         let mut ek = load_expanded_keys(AES128_EXP_KEYS);
307         inv_expanded_keys(&mut ek);
308         assert_eq!(store_expanded_keys(ek), AES128_EXP_INVKEYS);
309     }
310 
311     #[test]
aes192_key_expansion()312     fn aes192_key_expansion() {
313         let ek = expand_key(&AES192_KEY);
314         assert_eq!(store_expanded_keys(ek), AES192_EXP_KEYS);
315     }
316 
317     #[test]
aes256_key_expansion()318     fn aes256_key_expansion() {
319         let ek = expand_key(&AES256_KEY);
320         assert_eq!(store_expanded_keys(ek), AES256_EXP_KEYS);
321     }
322 
323     #[test]
aes128_encrypt()324     fn aes128_encrypt() {
325         // Intentionally misaligned block
326         let mut block = [0u8; 19];
327         block[3..].copy_from_slice(&INPUT);
328 
329         unsafe {
330             encrypt(
331                 &load_expanded_keys(AES128_EXP_KEYS),
332                 (&mut block[3..]).try_into().unwrap(),
333             )
334         };
335 
336         assert_eq!(&block[3..], &EXPECTED);
337     }
338 
339     #[test]
aes128_encrypt8()340     fn aes128_encrypt8() {
341         let mut blocks = ParBlocks::default();
342 
343         for block in &mut blocks {
344             block.copy_from_slice(&INPUT);
345         }
346 
347         unsafe { encrypt8(&load_expanded_keys(AES128_EXP_KEYS), &mut blocks) };
348 
349         for block in &blocks {
350             assert_eq!(block.as_slice(), &EXPECTED);
351         }
352     }
353 
354     #[test]
aes128_decrypt()355     fn aes128_decrypt() {
356         // Intentionally misaligned block
357         let mut block = [0u8; 19];
358         block[3..].copy_from_slice(&EXPECTED);
359 
360         unsafe {
361             decrypt(
362                 &load_expanded_keys(AES128_EXP_INVKEYS),
363                 (&mut block[3..]).try_into().unwrap(),
364             )
365         };
366 
367         assert_eq!(&block[3..], &INPUT);
368     }
369 
370     #[test]
aes128_decrypt8()371     fn aes128_decrypt8() {
372         let mut blocks = ParBlocks::default();
373 
374         for block in &mut blocks {
375             block.copy_from_slice(&EXPECTED);
376         }
377 
378         unsafe { decrypt8(&load_expanded_keys(AES128_EXP_INVKEYS), &mut blocks) };
379 
380         for block in &blocks {
381             assert_eq!(block.as_slice(), &INPUT);
382         }
383     }
384 }
385