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