bssl_crypto/aes.rs
1/* Copyright 2023 The BoringSSL Authors
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 */
15
16//! Advanced Encryption Standard.
17//!
18//! AES is a 128-bit block cipher that supports key sizes of 128, 192, or 256
19//! bits. (Although 192 isn't supported here.)
20//!
21//! Each key defines a permutation of the set of 128-bit blocks and AES can
22//! perform the forward and reverse permutation. (These directions are
23//! arbitrarily labeled "encryption" and "decryption".)
24//!
25//! AES requires relatively expensive preprocessing of keys and thus the
26//! processed form of the key is represented here using [`EncryptKey`] and
27//! [`DecryptKey`].
28//!
29//! ```
30//! use bssl_crypto::aes;
31//!
32//! let key_bytes = bssl_crypto::rand_array();
33//! let enc_key = aes::EncryptKey::new_256(&key_bytes);
34//! let block = [0u8; aes::BLOCK_SIZE];
35//! let mut transformed_block = enc_key.encrypt(&block);
36//!
37//! let dec_key = aes::DecryptKey::new_256(&key_bytes);
38//! dec_key.decrypt_in_place(&mut transformed_block);
39//! assert_eq!(block, transformed_block);
40//! ```
41//!
42//! AES is a low-level primitive and must be used in a more complex construction
43//! in nearly every case. See the `aead` crate for usable encryption and
44//! decryption primitives.
45
46use crate::{initialized_struct_fallible, FfiMutSlice, FfiSlice};
47use core::ffi::c_uint;
48
49/// AES block size in bytes.
50pub const BLOCK_SIZE: usize = bssl_sys::AES_BLOCK_SIZE as usize;
51
52/// A single AES block.
53pub type Block = [u8; BLOCK_SIZE];
54
55/// An initialized key which can be used for encrypting.
56pub struct EncryptKey(bssl_sys::AES_KEY);
57
58impl EncryptKey {
59 /// Initializes an encryption key from an appropriately sized array of bytes
60 // for AES-128 operations.
61 pub fn new_128(key: &[u8; 16]) -> Self {
62 new_encrypt_key(key.as_slice())
63 }
64
65 /// Initializes an encryption key from an appropriately sized array of bytes
66 // for AES-256 operations.
67 pub fn new_256(key: &[u8; 32]) -> Self {
68 new_encrypt_key(key.as_slice())
69 }
70
71 /// Return the encrypted version of the given block.
72 pub fn encrypt(&self, block: &Block) -> Block {
73 let mut ret = *block;
74 self.encrypt_in_place(&mut ret);
75 ret
76 }
77
78 /// Replace `block` with its encrypted version.
79 pub fn encrypt_in_place(&self, block: &mut Block) {
80 // Safety:
81 // - block is always a valid size and key is guaranteed to already be initialized.
82 unsafe { bssl_sys::AES_encrypt(block.as_ffi_ptr(), block.as_mut_ffi_ptr(), &self.0) }
83 }
84}
85
86/// An initialized key which can be used for decrypting
87pub struct DecryptKey(bssl_sys::AES_KEY);
88
89impl DecryptKey {
90 /// Initializes a decryption key from an appropriately sized array of bytes for AES-128 operations.
91 pub fn new_128(key: &[u8; 16]) -> DecryptKey {
92 new_decrypt_key(key.as_slice())
93 }
94
95 /// Initializes a decryption key from an appropriately sized array of bytes for AES-256 operations.
96 pub fn new_256(key: &[u8; 32]) -> DecryptKey {
97 new_decrypt_key(key.as_slice())
98 }
99
100 /// Return the decrypted version of the given block.
101 pub fn decrypt(&self, block: &Block) -> Block {
102 let mut ret = *block;
103 self.decrypt_in_place(&mut ret);
104 ret
105 }
106
107 /// Replace `block` with its decrypted version.
108 pub fn decrypt_in_place(&self, block: &mut Block) {
109 // Safety:
110 // - block is always a valid size and key is guaranteed to already be initialized.
111 unsafe { bssl_sys::AES_decrypt(block.as_ffi_ptr(), block.as_mut_ffi_ptr(), &self.0) }
112 }
113}
114
115/// This should only be publicly exposed by wrapper types with the correct key lengths
116#[allow(clippy::unwrap_used)]
117fn new_encrypt_key(key: &[u8]) -> EncryptKey {
118 EncryptKey(
119 unsafe {
120 initialized_struct_fallible(|aes_key| {
121 // The return value of this function differs from the usual BoringSSL
122 // convention.
123 bssl_sys::AES_set_encrypt_key(key.as_ffi_ptr(), key.len() as c_uint * 8, aes_key)
124 == 0
125 })
126 }
127 // unwrap: this function only fails if `key` is the wrong length, which
128 // must be prevented by the pub functions that call this.
129 .unwrap(),
130 )
131}
132
133/// This should only be publicly exposed by wrapper types with the correct key lengths.
134#[allow(clippy::unwrap_used)]
135fn new_decrypt_key(key: &[u8]) -> DecryptKey {
136 DecryptKey(
137 unsafe {
138 initialized_struct_fallible(|aes_key| {
139 // The return value of this function differs from the usual BoringSSL
140 // convention.
141 bssl_sys::AES_set_decrypt_key(key.as_ffi_ptr(), key.len() as c_uint * 8, aes_key)
142 == 0
143 })
144 }
145 // unwrap: this function only fails if `key` is the wrong length, which
146 // must be prevented by the pub functions that call this.
147 .unwrap(),
148 )
149}
150
151#[cfg(test)]
152mod tests {
153 use crate::{
154 aes::{DecryptKey, EncryptKey},
155 test_helpers::decode_hex,
156 };
157
158 #[test]
159 fn aes_128() {
160 // test data from https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf F.1.1
161 let key = decode_hex("2b7e151628aed2a6abf7158809cf4f3c");
162 let plaintext = decode_hex("6bc1bee22e409f96e93d7e117393172a");
163 let ciphertext = decode_hex("3ad77bb40d7a3660a89ecaf32466ef97");
164 assert_eq!(ciphertext, EncryptKey::new_128(&key).encrypt(&plaintext));
165 assert_eq!(plaintext, DecryptKey::new_128(&key).decrypt(&ciphertext));
166 }
167
168 #[test]
169 fn aes_256() {
170 // test data from https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf F.1.5
171 let key = decode_hex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4");
172 let plaintext = decode_hex("6bc1bee22e409f96e93d7e117393172a");
173 let ciphertext = decode_hex("f3eed1bdb5d2a03c064b5a7e3db181f8");
174 assert_eq!(ciphertext, EncryptKey::new_256(&key).encrypt(&plaintext));
175 assert_eq!(plaintext, DecryptKey::new_256(&key).decrypt(&ciphertext));
176 }
177}