1 | //! ⚠️ Low-level "hazmat" AES functions. |
2 | //! |
3 | //! # ☢️️ WARNING: HAZARDOUS API ☢️ |
4 | //! |
5 | //! This module contains an extremely low-level cryptographic primitive |
6 | //! which is likewise extremely difficult to use correctly. |
7 | //! |
8 | //! There are very few valid uses cases for this API. It's intended to be used |
9 | //! for implementing well-reviewed higher-level constructions. |
10 | //! |
11 | //! We do NOT recommend using it to implement any algorithm which has not |
12 | //! received extensive peer review by cryptographers. |
13 | |
14 | use crate::{soft::fixslice::hazmat as soft, Block, Block8}; |
15 | |
16 | #[cfg (all(target_arch = "aarch64" , aes_armv8, not(aes_force_soft)))] |
17 | use crate::armv8::hazmat as intrinsics; |
18 | |
19 | #[cfg (all(any(target_arch = "x86_64" , target_arch = "x86" ), not(aes_force_soft)))] |
20 | use crate::ni::hazmat as intrinsics; |
21 | |
22 | #[cfg (all( |
23 | any( |
24 | target_arch = "x86" , |
25 | target_arch = "x86_64" , |
26 | all(target_arch = "aarch64" , aes_armv8) |
27 | ), |
28 | not(aes_force_soft) |
29 | ))] |
30 | cpufeatures::new!(aes_intrinsics, "aes" ); |
31 | |
32 | /// Execute the provided body if CPU intrinsics are available. |
33 | // TODO(tarcieri): more `cfg-if`-like macro with an else branch? |
34 | macro_rules! if_intrinsics_available { |
35 | ($body:expr) => {{ |
36 | #[cfg(all( |
37 | any( |
38 | target_arch = "x86" , |
39 | target_arch = "x86_64" , |
40 | all(target_arch = "aarch64" , aes_armv8) |
41 | ), |
42 | not(aes_force_soft) |
43 | ))] |
44 | if aes_intrinsics::get() { |
45 | unsafe { $body } |
46 | return; |
47 | } |
48 | }}; |
49 | } |
50 | |
51 | /// ⚠️ AES cipher (encrypt) round function. |
52 | /// |
53 | /// This API performs the following steps as described in FIPS 197 Appendix C: |
54 | /// |
55 | /// - `s_box`: state after `SubBytes()` |
56 | /// - `s_row`: state after `ShiftRows()` |
57 | /// - `m_col`: state after `MixColumns()` |
58 | /// - `k_sch`: key schedule value for `round[r]` |
59 | /// |
60 | /// This series of operations is equivalent to the Intel AES-NI `AESENC` instruction. |
61 | /// |
62 | /// # ☢️️ WARNING: HAZARDOUS API ☢️ |
63 | /// |
64 | /// Use this function with great care! See the [module-level documentation][crate::hazmat] |
65 | /// for more information. |
66 | pub fn cipher_round(block: &mut Block, round_key: &Block) { |
67 | if_intrinsics_available! { |
68 | intrinsics::cipher_round(block, round_key) |
69 | } |
70 | |
71 | soft::cipher_round(block, round_key); |
72 | } |
73 | |
74 | /// ⚠️ AES cipher (encrypt) round function: parallel version. |
75 | /// |
76 | /// Equivalent to [`cipher_round`], but acts on 8 blocks-at-a-time, applying |
77 | /// the same number of round keys. |
78 | /// |
79 | /// # ☢️️ WARNING: HAZARDOUS API ☢️ |
80 | /// |
81 | /// Use this function with great care! See the [module-level documentation][crate::hazmat] |
82 | /// for more information. |
83 | pub fn cipher_round_par(blocks: &mut Block8, round_keys: &Block8) { |
84 | if_intrinsics_available! { |
85 | intrinsics::cipher_round_par(blocks, round_keys) |
86 | } |
87 | |
88 | soft::cipher_round_par(blocks, round_keys); |
89 | } |
90 | |
91 | /// ⚠️ AES equivalent inverse cipher (decrypt) round function. |
92 | /// |
93 | /// This API performs the following steps as described in FIPS 197 Appendix C: |
94 | /// |
95 | /// - `is_box`: state after `InvSubBytes()` |
96 | /// - `is_row`: state after `InvShiftRows()` |
97 | /// - `im_col`: state after `InvMixColumns()` |
98 | /// - `ik_sch`: key schedule value for `round[r]` |
99 | /// |
100 | /// This series of operations is equivalent to the Intel AES-NI `AESDEC` instruction. |
101 | /// |
102 | /// # ☢️️ WARNING: HAZARDOUS API ☢️ |
103 | /// |
104 | /// Use this function with great care! See the [module-level documentation][crate::hazmat] |
105 | /// for more information. |
106 | pub fn equiv_inv_cipher_round(block: &mut Block, round_key: &Block) { |
107 | if_intrinsics_available! { |
108 | intrinsics::equiv_inv_cipher_round(block, round_key) |
109 | } |
110 | |
111 | soft::equiv_inv_cipher_round(block, round_key); |
112 | } |
113 | |
114 | /// ⚠️ AES equivalent inverse cipher (decrypt) round function: parallel version. |
115 | /// |
116 | /// Equivalent to [`equiv_inv_cipher_round`], but acts on 8 blocks-at-a-time, |
117 | /// applying the same number of round keys. |
118 | /// |
119 | /// # ☢️️ WARNING: HAZARDOUS API ☢️ |
120 | /// |
121 | /// Use this function with great care! See the [module-level documentation][crate::hazmat] |
122 | /// for more information. |
123 | pub fn equiv_inv_cipher_round_par(blocks: &mut Block8, round_keys: &Block8) { |
124 | if_intrinsics_available! { |
125 | intrinsics::equiv_inv_cipher_round_par(blocks, round_keys) |
126 | } |
127 | |
128 | soft::equiv_inv_cipher_round_par(blocks, round_keys); |
129 | } |
130 | |
131 | /// ⚠️ AES mix columns function. |
132 | /// |
133 | /// # ☢️️ WARNING: HAZARDOUS API ☢️ |
134 | /// |
135 | /// Use this function with great care! See the [module-level documentation][crate::hazmat] |
136 | /// for more information. |
137 | pub fn mix_columns(block: &mut Block) { |
138 | if_intrinsics_available! { |
139 | intrinsics::mix_columns(block) |
140 | } |
141 | |
142 | soft::mix_columns(block); |
143 | } |
144 | |
145 | /// ⚠️ AES inverse mix columns function. |
146 | /// |
147 | /// This function is equivalent to the Intel AES-NI `AESIMC` instruction. |
148 | /// |
149 | /// # ☢️️ WARNING: HAZARDOUS API ☢️ |
150 | /// |
151 | /// Use this function with great care! See the [module-level documentation][crate::hazmat] |
152 | /// for more information. |
153 | pub fn inv_mix_columns(block: &mut Block) { |
154 | if_intrinsics_available! { |
155 | intrinsics::inv_mix_columns(block) |
156 | } |
157 | |
158 | soft::inv_mix_columns(block); |
159 | } |
160 | |