| // Copyright 2023 The BoringSSL Authors | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // https://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| //! Advanced Encryption Standard. | |
| //! | |
| //! AES is a 128-bit block cipher that supports key sizes of 128, 192, or 256 | |
| //! bits. (Although 192 isn't supported here.) | |
| //! | |
| //! Each key defines a permutation of the set of 128-bit blocks and AES can | |
| //! perform the forward and reverse permutation. (These directions are | |
| //! arbitrarily labeled "encryption" and "decryption".) | |
| //! | |
| //! AES requires relatively expensive preprocessing of keys and thus the | |
| //! processed form of the key is represented here using [`EncryptKey`] and | |
| //! [`DecryptKey`]. | |
| //! | |
| //! ``` | |
| //! use bssl_crypto::aes; | |
| //! | |
| //! let key_bytes = bssl_crypto::rand_array(); | |
| //! let enc_key = aes::EncryptKey::new_256(&key_bytes); | |
| //! let block = [0u8; aes::BLOCK_SIZE]; | |
| //! let mut transformed_block = enc_key.encrypt(&block); | |
| //! | |
| //! let dec_key = aes::DecryptKey::new_256(&key_bytes); | |
| //! dec_key.decrypt_in_place(&mut transformed_block); | |
| //! assert_eq!(block, transformed_block); | |
| //! ``` | |
| //! | |
| //! AES is a low-level primitive and must be used in a more complex construction | |
| //! in nearly every case. See the `aead` crate for usable encryption and | |
| //! decryption primitives. | |
| use crate::{initialized_struct_fallible, FfiMutSlice, FfiSlice}; | |
| use core::ffi::c_uint; | |
| /// AES block size in bytes. | |
| pub const BLOCK_SIZE: usize = bssl_sys::AES_BLOCK_SIZE as usize; | |
| /// A single AES block. | |
| pub type Block = [u8; BLOCK_SIZE]; | |
| /// An initialized key which can be used for encrypting. | |
| pub struct EncryptKey(bssl_sys::AES_KEY); | |
| impl EncryptKey { | |
| /// Initializes an encryption key from an appropriately sized array of bytes | |
| // for AES-128 operations. | |
| pub fn new_128(key: &[u8; 16]) -> Self { | |
| new_encrypt_key(key.as_slice()) | |
| } | |
| /// Initializes an encryption key from an appropriately sized array of bytes | |
| // for AES-256 operations. | |
| pub fn new_256(key: &[u8; 32]) -> Self { | |
| new_encrypt_key(key.as_slice()) | |
| } | |
| /// Return the encrypted version of the given block. | |
| pub fn encrypt(&self, block: &Block) -> Block { | |
| let mut ret = *block; | |
| self.encrypt_in_place(&mut ret); | |
| ret | |
| } | |
| /// Replace `block` with its encrypted version. | |
| pub fn encrypt_in_place(&self, block: &mut Block) { | |
| // Safety: | |
| // - block is always a valid size and key is guaranteed to already be initialized. | |
| unsafe { bssl_sys::AES_encrypt(block.as_ffi_ptr(), block.as_mut_ffi_ptr(), &self.0) } | |
| } | |
| } | |
| /// An initialized key which can be used for decrypting | |
| pub struct DecryptKey(bssl_sys::AES_KEY); | |
| impl DecryptKey { | |
| /// Initializes a decryption key from an appropriately sized array of bytes for AES-128 operations. | |
| pub fn new_128(key: &[u8; 16]) -> DecryptKey { | |
| new_decrypt_key(key.as_slice()) | |
| } | |
| /// Initializes a decryption key from an appropriately sized array of bytes for AES-256 operations. | |
| pub fn new_256(key: &[u8; 32]) -> DecryptKey { | |
| new_decrypt_key(key.as_slice()) | |
| } | |
| /// Return the decrypted version of the given block. | |
| pub fn decrypt(&self, block: &Block) -> Block { | |
| let mut ret = *block; | |
| self.decrypt_in_place(&mut ret); | |
| ret | |
| } | |
| /// Replace `block` with its decrypted version. | |
| pub fn decrypt_in_place(&self, block: &mut Block) { | |
| // Safety: | |
| // - block is always a valid size and key is guaranteed to already be initialized. | |
| unsafe { bssl_sys::AES_decrypt(block.as_ffi_ptr(), block.as_mut_ffi_ptr(), &self.0) } | |
| } | |
| } | |
| /// This should only be publicly exposed by wrapper types with the correct key lengths | |
| #[allow(clippy::unwrap_used)] | |
| fn new_encrypt_key(key: &[u8]) -> EncryptKey { | |
| EncryptKey( | |
| unsafe { | |
| initialized_struct_fallible(|aes_key| { | |
| // The return value of this function differs from the usual BoringSSL | |
| // convention. | |
| bssl_sys::AES_set_encrypt_key(key.as_ffi_ptr(), key.len() as c_uint * 8, aes_key) | |
| == 0 | |
| }) | |
| } | |
| // unwrap: this function only fails if `key` is the wrong length, which | |
| // must be prevented by the pub functions that call this. | |
| .unwrap(), | |
| ) | |
| } | |
| /// This should only be publicly exposed by wrapper types with the correct key lengths. | |
| #[allow(clippy::unwrap_used)] | |
| fn new_decrypt_key(key: &[u8]) -> DecryptKey { | |
| DecryptKey( | |
| unsafe { | |
| initialized_struct_fallible(|aes_key| { | |
| // The return value of this function differs from the usual BoringSSL | |
| // convention. | |
| bssl_sys::AES_set_decrypt_key(key.as_ffi_ptr(), key.len() as c_uint * 8, aes_key) | |
| == 0 | |
| }) | |
| } | |
| // unwrap: this function only fails if `key` is the wrong length, which | |
| // must be prevented by the pub functions that call this. | |
| .unwrap(), | |
| ) | |
| } | |
| #[cfg(test)] | |
| mod tests { | |
| use crate::{ | |
| aes::{DecryptKey, EncryptKey}, | |
| test_helpers::decode_hex, | |
| }; | |
| #[test] | |
| fn aes_128() { | |
| // test data from https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf F.1.1 | |
| let key = decode_hex("2b7e151628aed2a6abf7158809cf4f3c"); | |
| let plaintext = decode_hex("6bc1bee22e409f96e93d7e117393172a"); | |
| let ciphertext = decode_hex("3ad77bb40d7a3660a89ecaf32466ef97"); | |
| assert_eq!(ciphertext, EncryptKey::new_128(&key).encrypt(&plaintext)); | |
| assert_eq!(plaintext, DecryptKey::new_128(&key).decrypt(&ciphertext)); | |
| } | |
| #[test] | |
| fn aes_256() { | |
| // test data from https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf F.1.5 | |
| let key = decode_hex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"); | |
| let plaintext = decode_hex("6bc1bee22e409f96e93d7e117393172a"); | |
| let ciphertext = decode_hex("f3eed1bdb5d2a03c064b5a7e3db181f8"); | |
| assert_eq!(ciphertext, EncryptKey::new_256(&key).encrypt(&plaintext)); | |
| assert_eq!(plaintext, DecryptKey::new_256(&key).decrypt(&ciphertext)); | |
| } | |
| } |