1 | // Copyright 2018-2024 Brian Smith. |
2 | // |
3 | // Permission to use, copy, modify, and/or distribute this software for any |
4 | // purpose with or without fee is hereby granted, provided that the above |
5 | // copyright notice and this permission notice appear in all copies. |
6 | // |
7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES |
8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY |
10 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
12 | // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
13 | // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
14 | |
15 | use super::{Block, KeyBytes, Overlapping, BLOCK_LEN}; |
16 | use crate::{bits::BitLength, c, error}; |
17 | use core::num::{NonZeroU32, NonZeroUsize}; |
18 | |
19 | /// nonce || big-endian counter. |
20 | #[repr (transparent)] |
21 | pub(in super::super) struct Counter(pub(super) [u8; BLOCK_LEN]); |
22 | |
23 | // Keep this in sync with AES_KEY in aes.h. |
24 | #[repr (C)] |
25 | #[derive (Clone)] |
26 | pub(in super::super) struct AES_KEY { |
27 | pub rd_key: [u32; 4 * (MAX_ROUNDS + 1)], |
28 | pub rounds: c::uint, |
29 | } |
30 | |
31 | // Keep this in sync with `AES_MAXNR` in aes.h. |
32 | const MAX_ROUNDS: usize = 14; |
33 | |
34 | impl AES_KEY { |
35 | #[inline ] |
36 | pub(super) unsafe fn new( |
37 | f: unsafe extern "C" fn(*const u8, BitLength<c::int>, *mut AES_KEY) -> c::int, |
38 | bytes: KeyBytes<'_>, |
39 | ) -> Result<Self, error::Unspecified> { |
40 | let mut key = Self { |
41 | rd_key: [0; 4 * (MAX_ROUNDS + 1)], |
42 | rounds: 0, |
43 | }; |
44 | |
45 | let (bytes, key_bits) = match bytes { |
46 | KeyBytes::AES_128(bytes) => (&bytes[..], BitLength::from_bits(128)), |
47 | KeyBytes::AES_256(bytes) => (&bytes[..], BitLength::from_bits(256)), |
48 | }; |
49 | |
50 | // Unusually, in this case zero means success and non-zero means failure. |
51 | if 0 == unsafe { f(bytes.as_ptr(), key_bits, &mut key) } { |
52 | debug_assert_ne!(key.rounds, 0); // Sanity check initialization. |
53 | Ok(key) |
54 | } else { |
55 | Err(error::Unspecified) |
56 | } |
57 | } |
58 | } |
59 | |
60 | #[cfg (all(target_arch = "arm" , target_endian = "little" ))] |
61 | impl AES_KEY { |
62 | pub(super) unsafe fn derive( |
63 | f: for<'a> unsafe extern "C" fn(*mut AES_KEY, &'a AES_KEY), |
64 | src: &Self, |
65 | ) -> Self { |
66 | let mut r = AES_KEY { |
67 | rd_key: [0u32; 4 * (MAX_ROUNDS + 1)], |
68 | rounds: 0, |
69 | }; |
70 | unsafe { f(&mut r, src) }; |
71 | r |
72 | } |
73 | |
74 | pub(super) fn rounds(&self) -> u32 { |
75 | self.rounds |
76 | } |
77 | } |
78 | |
79 | // SAFETY: |
80 | // * The function `$name` must read `bits` bits from `user_key`; `bits` will |
81 | // always be a valid AES key length, i.e. a whole number of bytes. |
82 | // * `$name` must set `key.rounds` to the value expected by the corresponding |
83 | // encryption/decryption functions and return 0, or otherwise must return |
84 | // non-zero to indicate failure. |
85 | // * `$name` may inspect CPU features. |
86 | // |
87 | // In BoringSSL, the C prototypes for these are in |
88 | // crypto/fipsmodule/aes/internal.h. |
89 | macro_rules! set_encrypt_key { |
90 | ( $name:ident, $key_bytes:expr $(,)? ) => {{ |
91 | use crate::{bits::BitLength, c}; |
92 | prefixed_extern! { |
93 | fn $name(user_key: *const u8, bits: BitLength<c::int>, key: *mut AES_KEY) -> c::int; |
94 | } |
95 | $crate::aead::aes::ffi::AES_KEY::new($name, $key_bytes) |
96 | }}; |
97 | } |
98 | |
99 | macro_rules! encrypt_block { |
100 | ($name:ident, $block:expr, $key:expr) => {{ |
101 | use crate::aead::aes::{ffi::AES_KEY, Block}; |
102 | prefixed_extern! { |
103 | fn $name(a: &Block, r: *mut Block, key: &AES_KEY); |
104 | } |
105 | $key.encrypt_block($name, $block) |
106 | }}; |
107 | } |
108 | |
109 | impl AES_KEY { |
110 | #[inline ] |
111 | pub(super) unsafe fn encrypt_block( |
112 | &self, |
113 | f: unsafe extern "C" fn(&Block, *mut Block, &AES_KEY), |
114 | a: Block, |
115 | ) -> Block { |
116 | let mut result: MaybeUninit<[u8; 16]> = core::mem::MaybeUninit::uninit(); |
117 | unsafe { |
118 | f(&a, result.as_mut_ptr(), self); |
119 | result.assume_init() |
120 | } |
121 | } |
122 | } |
123 | |
124 | /// SAFETY: |
125 | /// * The caller must ensure that `$key` was initialized with the |
126 | /// `set_encrypt_key!` invocation that `$name` requires. |
127 | /// * The caller must ensure that fhe function `$name` satisfies the conditions |
128 | /// for the `f` parameter to `ctr32_encrypt_blocks`. |
129 | macro_rules! ctr32_encrypt_blocks { |
130 | ($name:ident, $in_out:expr, $key:expr, $ctr:expr $(,)? ) => {{ |
131 | use crate::{ |
132 | aead::aes::{ffi::AES_KEY, Counter, BLOCK_LEN}, |
133 | c, |
134 | }; |
135 | prefixed_extern! { |
136 | fn $name( |
137 | input: *const [u8; BLOCK_LEN], |
138 | output: *mut [u8; BLOCK_LEN], |
139 | blocks: c::NonZero_size_t, |
140 | key: &AES_KEY, |
141 | ivec: &Counter, |
142 | ); |
143 | } |
144 | $key.ctr32_encrypt_blocks($name, $in_out, $ctr) |
145 | }}; |
146 | } |
147 | |
148 | impl AES_KEY { |
149 | /// SAFETY: |
150 | /// * `f` must not read more than `blocks` blocks from `input`. |
151 | /// * `f` must write exactly `block` blocks to `output`. |
152 | /// * In particular, `f` must handle blocks == 0 without reading from `input` |
153 | /// or writing to `output`. |
154 | /// * `f` must support the input overlapping with the output exactly or |
155 | /// with any nonnegative offset `n` (i.e. `input == output.add(n)`); |
156 | /// `f` does NOT need to support the cases where input < output. |
157 | /// * `key` must have been initialized with the `set_encrypt_key!` invocation |
158 | /// that corresponds to `f`. |
159 | /// * `f` may inspect CPU features. |
160 | #[inline ] |
161 | pub(super) unsafe fn ctr32_encrypt_blocks( |
162 | &self, |
163 | f: unsafe extern "C" fn( |
164 | input: *const [u8; BLOCK_LEN], |
165 | output: *mut [u8; BLOCK_LEN], |
166 | blocks: c::NonZero_size_t, |
167 | key: &AES_KEY, |
168 | ivec: &Counter, |
169 | ), |
170 | in_out: Overlapping<'_>, |
171 | ctr: &mut Counter, |
172 | ) { |
173 | in_out.with_input_output_len(|input, output, len| { |
174 | debug_assert_eq!(len % BLOCK_LEN, 0); |
175 | |
176 | let blocks = match NonZeroUsize::new(len / BLOCK_LEN) { |
177 | Some(blocks) => blocks, |
178 | None => { |
179 | return; |
180 | } |
181 | }; |
182 | |
183 | let input: *const [u8; BLOCK_LEN] = input.cast(); |
184 | let output: *mut [u8; BLOCK_LEN] = output.cast(); |
185 | let blocks_u32: NonZeroU32 = blocks.try_into().unwrap(); |
186 | |
187 | // SAFETY: |
188 | // * `input` points to `blocks` blocks. |
189 | // * `output` points to space for `blocks` blocks to be written. |
190 | // * input == output.add(n), where n == src.start, and the caller is |
191 | // responsible for ensuing this sufficient for `f` to work correctly. |
192 | // * `blocks` is non-zero so `f` doesn't have to work for empty slices. |
193 | // * The caller is responsible for ensuring `key` was initialized by the |
194 | // `set_encrypt_key!` invocation required by `f`. |
195 | unsafe { |
196 | f(input, output, blocks, self, ctr); |
197 | } |
198 | |
199 | ctr.increment_by_less_safe(blocks_u32); |
200 | }); |
201 | } |
202 | } |
203 | |