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}