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
14use crate::{soft::fixslice::hazmat as soft, Block, Block8};
15
16#[cfg(all(target_arch = "aarch64", aes_armv8, not(aes_force_soft)))]
17use crate::armv8::hazmat as intrinsics;
18
19#[cfg(all(any(target_arch = "x86_64", target_arch = "x86"), not(aes_force_soft)))]
20use 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))]
30cpufeatures::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?
34macro_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.
66pub 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.
83pub 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.
106pub 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.
123pub 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.
137pub 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.
153pub 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