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_set_decrypt_key, AES_set_encrypt_key, AES_unwrap_key, AES_wrap_key, AES_CMAC, AES_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        match AES_wrap_key(
181            self.as_ptr(),
182            iv,
183            output.as_mut_ptr(), // Must have sufficient capacity.
184            input.as_ptr(),
185            input.len().try_into().expect("buffer length overflow"),
186        ) {
187            -1 => Err(()),
188            n => Ok(n),
189        }
190    }
191
192    /// The `AES_unwrap_key` function from BoringSSL.
193    ///
194    /// If `iv` is `None`, then the default IV is used. Client code must maintain important
195    /// invariants. See `aes::unwrap_key`.
196    ///
197    /// # Errors
198    ///
199    /// `AES_unwrap_key` does not distinguish between different error conditions, so this function
200    /// does not provide detailed error information. Client code must derive more detail from
201    /// context.
202    ///
203    /// # Safety
204    ///
205    /// The length of the `output` slice must be longer than eight bytes (the block size) less than
206    /// the length of the `input` slice. That is, if the length of the `input` slice is `i` bytes,
207    /// then the `output` slice must be at least `i - 8` bytes long. **If `output` is too short,
208    /// then this function will write beyond its bounds.**
209    unsafe fn aes_unwrap_key(
210        &self,
211        iv: Option<&[u8; KEY_WRAP_IV_LEN]>,
212        output: &mut [u8],
213        input: &[u8],
214    ) -> Result<i32, ()> {
215        let iv = if let Some(iv) = iv { iv as *const _ } else { ptr::null() };
216        match AES_unwrap_key(
217            self.as_ptr(),
218            iv,
219            output.as_mut_ptr(), // Must have sufficient capacity.
220            input.as_ptr(),
221            input.len().try_into().expect("buffer length overflow"),
222        ) {
223            -1 => Err(()),
224            n => Ok(n),
225        }
226    }
227}
228
229// TODO: This could use `Cow<[u8]>` to avoid copying key data. To prevent arbitrary mutations, an
230//       additional opaque type must be introduced.
231/// Sized AES key data.
232///
233/// AES keys must be 128, 192, or 256 bits (16, 24, or 32 bytes) in length.
234/// `SizedKey` provides variants with a fixed-sized buffer for each key length.
235/// Keys can be constructed from slices and arrays of a suitable length or size.
236///
237/// Note that slices and arrays specify their size in bytes, not bits. For
238/// example, for a 128-bit key, a 16-byte slice or array is required.
239pub enum SizedKey {
240    /// 128-bit AES key.
241    Key128Bit([u8; 16]),
242    /// 192-bit AES key.
243    Key192Bit([u8; 24]),
244    /// 256-bit AES key.
245    Key256Bit([u8; 32]),
246}
247
248impl SizedKey {
249    /// Constructs an AES key from an appropriately sized byte slice.
250    pub fn try_from_slice(key: &[u8]) -> Result<Self, AesError> {
251        match key.len() {
252            16 => {
253                let mut key128 = [0; 16];
254                key128[..].copy_from_slice(key);
255                Ok(SizedKey::Key128Bit(key128))
256            }
257            24 => {
258                let mut key192 = [0; 24];
259                key192[..].copy_from_slice(key);
260                Ok(SizedKey::Key192Bit(key192))
261            }
262            32 => {
263                let mut key256 = [0; 32];
264                key256[..].copy_from_slice(key);
265                Ok(SizedKey::Key256Bit(key256))
266            }
267            n => Err(AesError::KeySize(n)),
268        }
269    }
270
271    /// Gets the length of the key in **bytes**.
272    pub fn byte_len(&self) -> usize {
273        match self {
274            SizedKey::Key128Bit(..) => 16,
275            SizedKey::Key192Bit(..) => 24,
276            SizedKey::Key256Bit(..) => 32,
277        }
278    }
279
280    /// Gets the length of the key in **bits**.
281    // TODO(https://fxbug.dev/335283785): Remove or explain unused code.
282    #[allow(dead_code)]
283    pub fn bit_len(&self) -> usize {
284        match self {
285            SizedKey::Key128Bit(..) => 128,
286            SizedKey::Key192Bit(..) => 192,
287            SizedKey::Key256Bit(..) => 256,
288        }
289    }
290}
291
292impl AsMut<[u8]> for SizedKey {
293    fn as_mut(&mut self) -> &mut [u8] {
294        match self {
295            SizedKey::Key128Bit(ref mut key) => key.as_mut(),
296            SizedKey::Key192Bit(ref mut key) => key.as_mut(),
297            SizedKey::Key256Bit(ref mut key) => key.as_mut(),
298        }
299    }
300}
301
302impl AsRef<[u8]> for SizedKey {
303    fn as_ref(&self) -> &[u8] {
304        match self {
305            SizedKey::Key128Bit(ref key) => key.as_ref(),
306            SizedKey::Key192Bit(ref key) => key.as_ref(),
307            SizedKey::Key256Bit(ref key) => key.as_ref(),
308        }
309    }
310}
311
312impl From<[u8; 16]> for SizedKey {
313    fn from(key128: [u8; 16]) -> Self {
314        SizedKey::Key128Bit(key128)
315    }
316}
317
318impl From<[u8; 24]> for SizedKey {
319    fn from(key192: [u8; 24]) -> Self {
320        SizedKey::Key192Bit(key192)
321    }
322}
323
324impl From<[u8; 32]> for SizedKey {
325    fn from(key256: [u8; 32]) -> Self {
326        SizedKey::Key256Bit(key256)
327    }
328}
329
330/// I/O buffers that have interdependent requirements, such as length.
331struct BufferIo<I, O>
332where
333    I: AsRef<[u8]>,
334    O: AsMut<[u8]>,
335{
336    input: I,
337    output: O,
338}
339
340/// RFC 3394 key wrapping I/O.
341///
342/// This type exposes buffers for key wrapping and ensures that those buffers are properly sized
343/// before use.
344pub struct KeyWrapIo<I, O>(BufferIo<I, O>)
345where
346    I: AsRef<[u8]>,
347    O: AsMut<[u8]>;
348
349impl<I, O> KeyWrapIo<I, O>
350where
351    I: AsRef<[u8]>,
352    O: AsMut<[u8]>,
353{
354    /// Constructs key wrapping I/O from existing input and output buffers.
355    pub fn try_from_io(input: I, mut output: O) -> Result<Self, AesError> {
356        // See RFC 3394, 2.2.1. Section 2 requires at least two blocks of plaintext.
357        let n = input.as_ref().len();
358        let m = output.as_mut().len();
359        match (
360            n >= (KEY_WRAP_BLOCK_LEN * 2) && n % KEY_WRAP_BLOCK_LEN == 0,
361            m >= (n + KEY_WRAP_BLOCK_LEN),
362        ) {
363            (true, true) => Ok(KeyWrapIo(BufferIo { input, output })),
364            // Report input buffer size errors first.
365            (false, _) => Err(KeyWrapError::InputSize.into()),
366            (_, false) => Err(KeyWrapError::OutputSize.into()),
367        }
368    }
369
370    /// Gets the input and output buffers.
371    pub fn io(&mut self) -> (&[u8], &mut [u8]) {
372        (self.0.input.as_ref(), self.0.output.as_mut())
373    }
374
375    /// Gets the input buffer.
376    // TODO(https://fxbug.dev/335283785): Remove or explain unused code.
377    #[allow(dead_code)]
378    pub fn input(&self) -> &[u8] {
379        self.0.input.as_ref()
380    }
381
382    /// Gets the output buffer.
383    // TODO(https://fxbug.dev/335283785): Remove or explain unused code.
384    #[allow(dead_code)]
385    pub fn output(&mut self) -> &mut [u8] {
386        self.0.output.as_mut()
387    }
388
389    /// Consumes the key wrapping I/O and releases its output buffer.
390    pub fn into_output(self) -> O {
391        self.0.output
392    }
393}
394
395impl<I> KeyWrapIo<I, Vec<u8>>
396where
397    I: AsRef<[u8]>,
398{
399    /// Constructs key wrapping I/O from an existing input buffer.
400    ///
401    /// A sufficiently sized output buffer is allocated.
402    pub fn try_from_input(input: I) -> Result<Self, AesError> {
403        let n = input.as_ref().len();
404        KeyWrapIo::try_from_io(input, vec![0; n + KEY_WRAP_BLOCK_LEN])
405    }
406}
407
408/// RFC 3394 key unwrapping I/O.
409///
410/// This type exposes buffers for key unwrapping and ensures that those buffers are properly sized
411/// before use.
412pub struct KeyUnwrapIo<I, O>(BufferIo<I, O>)
413where
414    I: AsRef<[u8]>,
415    O: AsMut<[u8]>;
416
417impl<I, O> KeyUnwrapIo<I, O>
418where
419    I: AsRef<[u8]>,
420    O: AsMut<[u8]>,
421{
422    /// Constructs key unwrapping I/O from existing input and output buffers.
423    pub fn try_from_io(input: I, mut output: O) -> Result<Self, AesError> {
424        // See RFC 3394, 2.2.2. Section 2 requires at least two blocks of plaintext, so there must
425        // be at least three blocks of ciphertext.
426        let n = input.as_ref().len();
427        let m = output.as_mut().len();
428        match (
429            n >= (KEY_WRAP_BLOCK_LEN * 3) && n % KEY_WRAP_BLOCK_LEN == 0,
430            m >= (n - KEY_WRAP_BLOCK_LEN),
431        ) {
432            (true, true) => Ok(KeyUnwrapIo(BufferIo { input, output })),
433            // Report input buffer size errors first.
434            (false, _) => Err(KeyWrapError::InputSize.into()),
435            (_, false) => Err(KeyWrapError::OutputSize.into()),
436        }
437    }
438
439    /// Gets the input and output buffers.
440    pub fn io(&mut self) -> (&[u8], &mut [u8]) {
441        (self.0.input.as_ref(), self.0.output.as_mut())
442    }
443
444    /// Gets the input buffer.
445    // TODO(https://fxbug.dev/335283785): Remove or explain unused code.
446    #[allow(dead_code)]
447    pub fn input(&self) -> &[u8] {
448        self.0.input.as_ref()
449    }
450
451    /// Gets the output buffer.
452    // TODO(https://fxbug.dev/335283785): Remove or explain unused code.
453    #[allow(dead_code)]
454    pub fn output(&mut self) -> &mut [u8] {
455        self.0.output.as_mut()
456    }
457
458    /// Consumes the key unwrapping I/O and releases its output buffer.
459    pub fn into_output(self) -> O {
460        self.0.output
461    }
462}
463
464impl<I> KeyUnwrapIo<I, Vec<u8>>
465where
466    I: AsRef<[u8]>,
467{
468    /// Constructs key unwrapping I/O from an existing input buffer.
469    ///
470    /// A sufficiently sized output buffer is allocated.
471    pub fn try_from_input(input: I) -> Result<Self, AesError> {
472        let n = input.as_ref().len();
473        if n < (KEY_WRAP_BLOCK_LEN * 3) {
474            Err(KeyWrapError::InputSize.into()) // Avoid underflow when creating the output buffer.
475        } else {
476            KeyUnwrapIo::try_from_io(input, vec![0; n - KEY_WRAP_BLOCK_LEN])
477        }
478    }
479}
480
481/// RFC 4493 AES-CMAC.
482pub fn cmac(key: &SizedKey, message: &[u8]) -> Result<[u8; CMAC_LEN], AesError> {
483    // Keys must be 128 or 256 bits in length.
484    let n = match key.byte_len() {
485        16 => Ok(16),
486        32 => Ok(32),
487        n => Err(AesError::KeySize(n)),
488    }?;
489    let mut mac = [0u8; CMAC_LEN];
490    unsafe {
491        if 0 == AES_CMAC(
492            mac.as_mut().as_mut_ptr(),
493            key.as_ref().as_ptr(),
494            n.try_into().expect("key length overflow"),
495            message.as_ptr(),
496            message.len().try_into().expect("message length overflow"),
497        ) {
498            // This should never occur; the key and MAC are prepared before `AES_CMAC` is used.
499            // However, to remain robust and avoid incorrectness or UB, this branch panics.
500            panic!("AES-CMAC failed: invalid parameters")
501        } else {
502            Ok(mac)
503        }
504    }
505}
506
507/// RFC 3394 AES key wrapping.
508pub fn wrap_key<I, O>(
509    key: &SizedKey,
510    iv: Option<&[u8; KEY_WRAP_IV_LEN]>,
511    mut kio: KeyWrapIo<I, O>,
512) -> Result<O, AesError>
513where
514    I: AsRef<[u8]>,
515    O: AsMut<[u8]>,
516{
517    let aes = AesKey::with_encrypt_key(key);
518    let (input, output) = kio.io();
519    // This is safe, because `KeyWrapIo` always exposes properly sized buffers.
520    unsafe {
521        // Errors should never occur here; the key and buffers are prepared beforehand.
522        aes.aes_wrap_key(iv, output, input).expect("AES key wrap failed: invalid parameters");
523    }
524    Ok(kio.into_output())
525}
526
527/// RFC 3394 AES key unwrapping.
528pub fn unwrap_key<I, O>(
529    key: &SizedKey,
530    iv: Option<&[u8; KEY_WRAP_IV_LEN]>,
531    mut kio: KeyUnwrapIo<I, O>,
532) -> Result<O, AesError>
533where
534    I: AsRef<[u8]>,
535    O: AsMut<[u8]>,
536{
537    let aes = AesKey::with_decrypt_key(key);
538    let (input, output) = kio.io();
539    // This is safe, because `KeyUnwrapIo` always exposes properly sized buffers.
540    unsafe {
541        // The only error that can occur here is an unmatched AES key.
542        aes.aes_unwrap_key(iv, output, input).map_err(|_| KeyWrapError::UnwrapKey)?;
543    }
544    Ok(kio.into_output())
545}