| 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 | |