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