Coverage Report

Created: 2025-07-23 06:21

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