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}