wlan_rsn/
aes.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! AES cryptography.
6//!
7//! This module exposes AES primitives provided by `bssl-sys`. Namely, RSN requires the AES
8//! cipher for protocols employing RFC 3394 AES key wrapping and RFC 4493 AES-CMAC.
9//!
10//! # Security
11//!
12//! **RSN uses insecure AES primitives. This module exposes insecure primitives to implement legacy
13//! protocols that are insecure. Do not use these primitives outside of this crate or context.**
14//! While the AES cipher is considered secure, some protocols that employ the cipher are insecure.
15//!
16//! In general, avoid using the AES cipher directly. Prefer AE or AEAD modes like AES-GCM so that
17//! ciphertext can be authenticated. Without authenticated ciphertext, it is possible to introduce
18//! vulnerabilities when using AES.
19
20use bssl_sys::{
21    AES_CMAC, AES_KEY, AES_set_decrypt_key, AES_set_encrypt_key, AES_unwrap_key, AES_wrap_key,
22};
23use std::ptr;
24use thiserror::Error;
25
26/// Size of the RFC 4493 AES-CMAC output MAC in bytes.
27pub const CMAC_LEN: usize = 16;
28/// Size of the RFC 3394 AES key wrapping IV in bytes.
29pub const KEY_WRAP_IV_LEN: usize = 8;
30
31/// Size of the RFC 3394 AES key wrapping block in bytes.
32const KEY_WRAP_BLOCK_LEN: usize = 8;
33
34/// Errors concerning AES primitives.
35///
36/// This is the top-level error exposed by this module and its APIs.
37#[derive(Clone, Debug, Error)]
38#[non_exhaustive]
39pub enum AesError {
40    // TODO(68448): Use a type that makes it clear in code and text that this size is expressed in
41    //              bytes.
42    #[error("invalid AES key size: {}", _0)]
43    KeySize(usize),
44    #[error("RFC 3394 AES key wrap failed: {}", _0)]
45    KeyWrap(KeyWrapError),
46}
47
48impl From<KeyWrapError> for AesError {
49    fn from(error: KeyWrapError) -> Self {
50        AesError::KeyWrap(error)
51    }
52}
53
54/// Errors concerning RFC 3394 AES key wrapping.
55///
56/// These errors are typically exposed via `AesError`.
57#[derive(Clone, Debug, Error)]
58#[non_exhaustive]
59pub enum KeyWrapError {
60    /// The AES key used to unwrap does not match the key used to wrap.
61    #[error("incorrect AES key")]
62    UnwrapKey,
63    /// The input buffer is an invalid size.
64    ///
65    /// The input buffer is expected to contain either a wrapped or unwrapped key depending on the
66    /// operation.
67    #[error("invalid input buffer size")]
68    InputSize,
69    /// The output buffer is an invalid size.
70    ///
71    /// Depending on the operation, either a wrapped or unwrapped key is written to the output
72    /// buffer. The output buffer's minimum size depends on the operation and corresponding input
73    /// buffer size.
74    #[error("invalid output buffer size")]
75    OutputSize,
76}
77
78/// AES cipher.
79struct AesKey {
80    inner: AES_KEY,
81}
82
83impl AesKey {
84    /// Constructs an `AES_KEY` configured for encryption with the given key.
85    ///
86    /// **The `AES_KEY` must only be used with encryption functions unless it is reconfigured. See
87    /// the `aes_set_decrypt_key` and `aes_set_encrypt_key` functions.
88    fn with_encrypt_key(key: &SizedKey) -> Self {
89        let mut aes = AesKey::zeroed();
90        // `SizedKey` only provides supported key sizes, so this should never panic.
91        aes.aes_set_encrypt_key(key.as_ref()).unwrap();
92        aes
93    }
94
95    /// Constructs an `AES_KEY` configured for decryption with the given key.
96    ///
97    /// **The `AES_KEY` must only be used with decryption functions unless it is reconfigured. See
98    /// the `aes_set_decrypt_key` and `aes_set_encrypt_key` functions.
99    fn with_decrypt_key(key: &SizedKey) -> Self {
100        let mut aes = AesKey::zeroed();
101        // `SizedKey` only provides supported key sizes, so this should never panic.
102        aes.aes_set_decrypt_key(key.as_ref()).unwrap();
103        aes
104    }
105
106    /// Constructs a zeroed `AES_KEY`.
107    ///
108    /// **Care must be taken to configure the `AES_KEY` for use with encryption or decryption
109    /// functions before use.** See the `aes_set_decrypt_key` and `aes_set_encrypt_key` functions.
110    fn zeroed() -> Self {
111        AesKey { inner: AES_KEY { rd_key: [0u32; 60], rounds: 0 } }
112    }
113
114    fn as_ptr(&self) -> *const AES_KEY {
115        &self.inner as *const AES_KEY
116    }
117}
118
119/// `AES_KEY` FFI functions.
120///
121/// These functions interact directly with `boringssl_sys` items concerning `AES_KEY`. They provide
122/// a minimal wrapper, but must still be used with care and should never be exported outside of
123/// this module. Wrappers primarily expose more idiomatic parameter and output types and marshal
124/// errors into `Result`s. Client code is responsible for maintaining invariants.
125impl AesKey {
126    /// The `AES_set_encrypt_key` function from BoringSSL.
127    ///
128    /// This is a safe wrapper.
129    fn aes_set_encrypt_key(&mut self, key: &[u8]) -> Result<(), AesError> {
130        let n = key.len();
131        // This is safe, because the length `n` of `key` is managed by the compiler.
132        unsafe {
133            if 0 > AES_set_encrypt_key(key.as_ptr(), (n * 8) as u32, &mut self.inner) {
134                Err(AesError::KeySize(n))
135            } else {
136                Ok(())
137            }
138        }
139    }
140
141    /// The `AES_set_decrypt_key` function from BoringSSL.
142    ///
143    /// This is a safe wrapper.
144    fn aes_set_decrypt_key(&mut self, key: &[u8]) -> Result<(), AesError> {
145        let n = key.len();
146        // This is safe, because the length `n` of `key` is managed by the compiler.
147        unsafe {
148            if 0 > AES_set_decrypt_key(key.as_ptr(), (n * 8) as u32, &mut self.inner) {
149                Err(AesError::KeySize(n))
150            } else {
151                Ok(())
152            }
153        }
154    }
155
156    /// The `AES_wrap_key` function from BoringSSL.
157    ///
158    /// If `iv` is `None`, then the default IV is used. Client code must maintain important
159    /// invariants. See `aes::wrap_key`.
160    ///
161    /// # Errors
162    ///
163    /// `AES_wrap_key` does not distinguish between different error conditions, so this function
164    /// does not provide detailed error information. Client code must derive more detail from
165    /// context.
166    ///
167    /// # Safety
168    ///
169    /// The length of the `output` slice must be at least eight bytes (the block size) more than
170    /// the length of the `input` slice. That is, if the length of the `input` slice is `i` bytes,
171    /// then the `output` slice must be at least `i + 8` bytes long. **If `output` is too short,
172    /// then this function will write beyond its bounds.**
173    unsafe fn aes_wrap_key(
174        &self,
175        iv: Option<&[u8; KEY_WRAP_IV_LEN]>,
176        output: &mut [u8],
177        input: &[u8],
178    ) -> Result<i32, ()> {
179        let iv = if let Some(iv) = iv { iv as *const _ } else { ptr::null() };
180        unsafe {
181            match AES_wrap_key(
182                self.as_ptr(),
183                iv,
184                output.as_mut_ptr(), // Must have sufficient capacity.
185                input.as_ptr(),
186                input.len().try_into().expect("buffer length overflow"),
187            ) {
188                -1 => Err(()),
189                n => Ok(n),
190            }
191        }
192    }
193
194    /// The `AES_unwrap_key` function from BoringSSL.
195    ///
196    /// If `iv` is `None`, then the default IV is used. Client code must maintain important
197    /// invariants. See `aes::unwrap_key`.
198    ///
199    /// # Errors
200    ///
201    /// `AES_unwrap_key` does not distinguish between different error conditions, so this function
202    /// does not provide detailed error information. Client code must derive more detail from
203    /// context.
204    ///
205    /// # Safety
206    ///
207    /// The length of the `output` slice must be longer than eight bytes (the block size) less than
208    /// the length of the `input` slice. That is, if the length of the `input` slice is `i` bytes,
209    /// then the `output` slice must be at least `i - 8` bytes long. **If `output` is too short,
210    /// then this function will write beyond its bounds.**
211    unsafe fn aes_unwrap_key(
212        &self,
213        iv: Option<&[u8; KEY_WRAP_IV_LEN]>,
214        output: &mut [u8],
215        input: &[u8],
216    ) -> Result<i32, ()> {
217        let iv = if let Some(iv) = iv { iv as *const _ } else { ptr::null() };
218        unsafe {
219            match AES_unwrap_key(
220                self.as_ptr(),
221                iv,
222                output.as_mut_ptr(), // Must have sufficient capacity.
223                input.as_ptr(),
224                input.len().try_into().expect("buffer length overflow"),
225            ) {
226                -1 => Err(()),
227                n => Ok(n),
228            }
229        }
230    }
231}
232
233// TODO: This could use `Cow<[u8]>` to avoid copying key data. To prevent arbitrary mutations, an
234//       additional opaque type must be introduced.
235/// Sized AES key data.
236///
237/// AES keys must be 128, 192, or 256 bits (16, 24, or 32 bytes) in length.
238/// `SizedKey` provides variants with a fixed-sized buffer for each key length.
239/// Keys can be constructed from slices and arrays of a suitable length or size.
240///
241/// Note that slices and arrays specify their size in bytes, not bits. For
242/// example, for a 128-bit key, a 16-byte slice or array is required.
243pub enum SizedKey {
244    /// 128-bit AES key.
245    Key128Bit([u8; 16]),
246    /// 192-bit AES key.
247    Key192Bit([u8; 24]),
248    /// 256-bit AES key.
249    Key256Bit([u8; 32]),
250}
251
252impl SizedKey {
253    /// Constructs an AES key from an appropriately sized byte slice.
254    pub fn try_from_slice(key: &[u8]) -> Result<Self, AesError> {
255        match key.len() {
256            16 => {
257                let mut key128 = [0; 16];
258                key128[..].copy_from_slice(key);
259                Ok(SizedKey::Key128Bit(key128))
260            }
261            24 => {
262                let mut key192 = [0; 24];
263                key192[..].copy_from_slice(key);
264                Ok(SizedKey::Key192Bit(key192))
265            }
266            32 => {
267                let mut key256 = [0; 32];
268                key256[..].copy_from_slice(key);
269                Ok(SizedKey::Key256Bit(key256))
270            }
271            n => Err(AesError::KeySize(n)),
272        }
273    }
274
275    /// Gets the length of the key in **bytes**.
276    pub fn byte_len(&self) -> usize {
277        match self {
278            SizedKey::Key128Bit(..) => 16,
279            SizedKey::Key192Bit(..) => 24,
280            SizedKey::Key256Bit(..) => 32,
281        }
282    }
283
284    /// Gets the length of the key in **bits**.
285    // TODO(https://fxbug.dev/335283785): Remove or explain unused code.
286    #[allow(dead_code)]
287    pub fn bit_len(&self) -> usize {
288        match self {
289            SizedKey::Key128Bit(..) => 128,
290            SizedKey::Key192Bit(..) => 192,
291            SizedKey::Key256Bit(..) => 256,
292        }
293    }
294}
295
296impl AsMut<[u8]> for SizedKey {
297    fn as_mut(&mut self) -> &mut [u8] {
298        match self {
299            SizedKey::Key128Bit(key) => key.as_mut(),
300            SizedKey::Key192Bit(key) => key.as_mut(),
301            SizedKey::Key256Bit(key) => key.as_mut(),
302        }
303    }
304}
305
306impl AsRef<[u8]> for SizedKey {
307    fn as_ref(&self) -> &[u8] {
308        match self {
309            SizedKey::Key128Bit(key) => key.as_ref(),
310            SizedKey::Key192Bit(key) => key.as_ref(),
311            SizedKey::Key256Bit(key) => key.as_ref(),
312        }
313    }
314}
315
316impl From<[u8; 16]> for SizedKey {
317    fn from(key128: [u8; 16]) -> Self {
318        SizedKey::Key128Bit(key128)
319    }
320}
321
322impl From<[u8; 24]> for SizedKey {
323    fn from(key192: [u8; 24]) -> Self {
324        SizedKey::Key192Bit(key192)
325    }
326}
327
328impl From<[u8; 32]> for SizedKey {
329    fn from(key256: [u8; 32]) -> Self {
330        SizedKey::Key256Bit(key256)
331    }
332}
333
334/// I/O buffers that have interdependent requirements, such as length.
335struct BufferIo<I, O>
336where
337    I: AsRef<[u8]>,
338    O: AsMut<[u8]>,
339{
340    input: I,
341    output: O,
342}
343
344/// RFC 3394 key wrapping I/O.
345///
346/// This type exposes buffers for key wrapping and ensures that those buffers are properly sized
347/// before use.
348pub struct KeyWrapIo<I, O>(BufferIo<I, O>)
349where
350    I: AsRef<[u8]>,
351    O: AsMut<[u8]>;
352
353impl<I, O> KeyWrapIo<I, O>
354where
355    I: AsRef<[u8]>,
356    O: AsMut<[u8]>,
357{
358    /// Constructs key wrapping I/O from existing input and output buffers.
359    pub fn try_from_io(input: I, mut output: O) -> Result<Self, AesError> {
360        // See RFC 3394, 2.2.1. Section 2 requires at least two blocks of plaintext.
361        let n = input.as_ref().len();
362        let m = output.as_mut().len();
363        match (
364            n >= (KEY_WRAP_BLOCK_LEN * 2) && n % KEY_WRAP_BLOCK_LEN == 0,
365            m >= (n + KEY_WRAP_BLOCK_LEN),
366        ) {
367            (true, true) => Ok(KeyWrapIo(BufferIo { input, output })),
368            // Report input buffer size errors first.
369            (false, _) => Err(KeyWrapError::InputSize.into()),
370            (_, false) => Err(KeyWrapError::OutputSize.into()),
371        }
372    }
373
374    /// Gets the input and output buffers.
375    pub fn io(&mut self) -> (&[u8], &mut [u8]) {
376        (self.0.input.as_ref(), self.0.output.as_mut())
377    }
378
379    /// Gets the input buffer.
380    // TODO(https://fxbug.dev/335283785): Remove or explain unused code.
381    #[allow(dead_code)]
382    pub fn input(&self) -> &[u8] {
383        self.0.input.as_ref()
384    }
385
386    /// Gets the output buffer.
387    // TODO(https://fxbug.dev/335283785): Remove or explain unused code.
388    #[allow(dead_code)]
389    pub fn output(&mut self) -> &mut [u8] {
390        self.0.output.as_mut()
391    }
392
393    /// Consumes the key wrapping I/O and releases its output buffer.
394    pub fn into_output(self) -> O {
395        self.0.output
396    }
397}
398
399impl<I> KeyWrapIo<I, Vec<u8>>
400where
401    I: AsRef<[u8]>,
402{
403    /// Constructs key wrapping I/O from an existing input buffer.
404    ///
405    /// A sufficiently sized output buffer is allocated.
406    pub fn try_from_input(input: I) -> Result<Self, AesError> {
407        let n = input.as_ref().len();
408        KeyWrapIo::try_from_io(input, vec![0; n + KEY_WRAP_BLOCK_LEN])
409    }
410}
411
412/// RFC 3394 key unwrapping I/O.
413///
414/// This type exposes buffers for key unwrapping and ensures that those buffers are properly sized
415/// before use.
416pub struct KeyUnwrapIo<I, O>(BufferIo<I, O>)
417where
418    I: AsRef<[u8]>,
419    O: AsMut<[u8]>;
420
421impl<I, O> KeyUnwrapIo<I, O>
422where
423    I: AsRef<[u8]>,
424    O: AsMut<[u8]>,
425{
426    /// Constructs key unwrapping I/O from existing input and output buffers.
427    pub fn try_from_io(input: I, mut output: O) -> Result<Self, AesError> {
428        // See RFC 3394, 2.2.2. Section 2 requires at least two blocks of plaintext, so there must
429        // be at least three blocks of ciphertext.
430        let n = input.as_ref().len();
431        let m = output.as_mut().len();
432        match (
433            n >= (KEY_WRAP_BLOCK_LEN * 3) && n % KEY_WRAP_BLOCK_LEN == 0,
434            m >= (n - KEY_WRAP_BLOCK_LEN),
435        ) {
436            (true, true) => Ok(KeyUnwrapIo(BufferIo { input, output })),
437            // Report input buffer size errors first.
438            (false, _) => Err(KeyWrapError::InputSize.into()),
439            (_, false) => Err(KeyWrapError::OutputSize.into()),
440        }
441    }
442
443    /// Gets the input and output buffers.
444    pub fn io(&mut self) -> (&[u8], &mut [u8]) {
445        (self.0.input.as_ref(), self.0.output.as_mut())
446    }
447
448    /// Gets the input buffer.
449    // TODO(https://fxbug.dev/335283785): Remove or explain unused code.
450    #[allow(dead_code)]
451    pub fn input(&self) -> &[u8] {
452        self.0.input.as_ref()
453    }
454
455    /// Gets the output buffer.
456    // TODO(https://fxbug.dev/335283785): Remove or explain unused code.
457    #[allow(dead_code)]
458    pub fn output(&mut self) -> &mut [u8] {
459        self.0.output.as_mut()
460    }
461
462    /// Consumes the key unwrapping I/O and releases its output buffer.
463    pub fn into_output(self) -> O {
464        self.0.output
465    }
466}
467
468impl<I> KeyUnwrapIo<I, Vec<u8>>
469where
470    I: AsRef<[u8]>,
471{
472    /// Constructs key unwrapping I/O from an existing input buffer.
473    ///
474    /// A sufficiently sized output buffer is allocated.
475    pub fn try_from_input(input: I) -> Result<Self, AesError> {
476        let n = input.as_ref().len();
477        if n < (KEY_WRAP_BLOCK_LEN * 3) {
478            Err(KeyWrapError::InputSize.into()) // Avoid underflow when creating the output buffer.
479        } else {
480            KeyUnwrapIo::try_from_io(input, vec![0; n - KEY_WRAP_BLOCK_LEN])
481        }
482    }
483}
484
485/// RFC 4493 AES-CMAC.
486pub fn cmac(key: &SizedKey, message: &[u8]) -> Result<[u8; CMAC_LEN], AesError> {
487    // Keys must be 128 or 256 bits in length.
488    let n = match key.byte_len() {
489        16 => Ok(16),
490        32 => Ok(32),
491        n => Err(AesError::KeySize(n)),
492    }?;
493    let mut mac = [0u8; CMAC_LEN];
494    unsafe {
495        if 0 == AES_CMAC(
496            mac.as_mut().as_mut_ptr(),
497            key.as_ref().as_ptr(),
498            n.try_into().expect("key length overflow"),
499            message.as_ptr(),
500            message.len().try_into().expect("message length overflow"),
501        ) {
502            // This should never occur; the key and MAC are prepared before `AES_CMAC` is used.
503            // However, to remain robust and avoid incorrectness or UB, this branch panics.
504            panic!("AES-CMAC failed: invalid parameters")
505        } else {
506            Ok(mac)
507        }
508    }
509}
510
511/// RFC 3394 AES key wrapping.
512pub fn wrap_key<I, O>(
513    key: &SizedKey,
514    iv: Option<&[u8; KEY_WRAP_IV_LEN]>,
515    mut kio: KeyWrapIo<I, O>,
516) -> Result<O, AesError>
517where
518    I: AsRef<[u8]>,
519    O: AsMut<[u8]>,
520{
521    let aes = AesKey::with_encrypt_key(key);
522    let (input, output) = kio.io();
523    // This is safe, because `KeyWrapIo` always exposes properly sized buffers.
524    unsafe {
525        // Errors should never occur here; the key and buffers are prepared beforehand.
526        aes.aes_wrap_key(iv, output, input).expect("AES key wrap failed: invalid parameters");
527    }
528    Ok(kio.into_output())
529}
530
531/// RFC 3394 AES key unwrapping.
532pub fn unwrap_key<I, O>(
533    key: &SizedKey,
534    iv: Option<&[u8; KEY_WRAP_IV_LEN]>,
535    mut kio: KeyUnwrapIo<I, O>,
536) -> Result<O, AesError>
537where
538    I: AsRef<[u8]>,
539    O: AsMut<[u8]>,
540{
541    let aes = AesKey::with_decrypt_key(key);
542    let (input, output) = kio.io();
543    // This is safe, because `KeyUnwrapIo` always exposes properly sized buffers.
544    unsafe {
545        // The only error that can occur here is an unmatched AES key.
546        aes.aes_unwrap_key(iv, output, input).map_err(|_| KeyWrapError::UnwrapKey)?;
547    }
548    Ok(kio.into_output())
549}