/* * Copyright (C) 2006-2026 wolfSSL Inc. * * This file is part of wolfSSL. * * wolfSSL is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * wolfSSL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ /*! This module provides a Rust wrapper for the wolfCrypt library's Advanced Encryption Standard (AES) functionality. */ #![cfg(aes)] use crate::sys; use core::mem::MaybeUninit; use zeroize::{Zeroize, ZeroizeOnDrop}; #[cfg(feature = "aead")] use aead::{AeadCore, AeadInPlace, KeyInit, KeySizeUser}; #[cfg(feature = "aead")] use aead::generic_array::typenum::{U0, U12, U16, U32}; #[cfg(all(feature = "cipher", not(feature = "aead")))] use cipher::typenum::consts::{U16, U32}; #[cfg(feature = "cipher")] use cipher::typenum::consts::U24; #[cfg(feature = "cipher")] use cipher::{ BlockModeDecBackend, BlockModeDecClosure, BlockModeDecrypt, BlockModeEncBackend, BlockModeEncClosure, BlockModeEncrypt, IvSizeUser, KeyIvInit, ParBlocksSizeUser, }; #[cfg(all(any(aes_ctr, aes_ofb), feature = "cipher"))] use cipher::{StreamCipher,StreamCipherError}; #[cfg(aes_wc_block_size)] pub const AES_BLOCK_SIZE: usize = sys::WC_AES_BLOCK_SIZE as usize; #[cfg(not(aes_wc_block_size))] pub const AES_BLOCK_SIZE: usize = sys::AES_BLOCK_SIZE as usize; /// AES Cipher Block Chaining (CBC) mode. /// /// # Example /// ```rust /// #[cfg(aes_cbc)] /// { /// use wolfssl_wolfcrypt::aes::CBC; /// let mut cbc = CBC::new().expect("Failed to create CBC"); /// let key: &[u8; 16] = b"0123456789abcdef"; /// let iv: &[u8; 16] = b"1234567890abcdef"; /// let msg: [u8; 16] = [ /// 0x6e, 0x6f, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74, /// 0x68, 0x65, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20, /// ]; /// let expected_cipher: [u8; 16] = [ /// 0x95, 0x94, 0x92, 0x57, 0x5f, 0x42, 0x81, 0x53, /// 0x2c, 0xcc, 0x9d, 0x46, 0x77, 0xa2, 0x33, 0xcb /// ]; /// cbc.init_encrypt(key, iv).expect("Error with init_encrypt()"); /// let mut cipher: [u8; 16] = [0; 16]; /// cbc.encrypt(&msg, &mut cipher).expect("Error with encrypt()"); /// assert_eq!(&cipher, &expected_cipher); /// let mut plain_out = [0; 16]; /// cbc.init_decrypt(key, iv).expect("Error with init_decrypt()"); /// cbc.decrypt(&cipher, &mut plain_out).expect("Error with decrypt()"); /// assert_eq!(&plain_out, &msg); /// } /// ``` #[cfg(aes_cbc)] pub struct CBC { ws_aes: sys::Aes, } #[cfg(aes_cbc)] impl CBC { /// Create a new `CBC` instance. /// /// # Returns /// /// A Result which is Ok(CBC) on success or an Err containing the wolfSSL /// library return code on failure. pub fn new() -> Result { Self::new_ex(None, None) } /// Create a new `CBC` instance with optional heap and device ID. /// /// # Parameters /// /// * `heap`: Optional heap hint. /// * `dev_id` Optional device ID to use with crypto callbacks or async hardware. /// /// # Returns /// /// A Result which is Ok(CBC) on success or an Err containing the wolfSSL /// library return code on failure. pub fn new_ex(heap: Option<*mut core::ffi::c_void>, dev_id: Option) -> Result { let ws_aes = new_ws_aes(heap, dev_id)?; let cbc = CBC {ws_aes}; Ok(cbc) } fn init(&mut self, key: &[u8], iv: &[u8], dir: i32) -> Result<(), i32> { let key_size = crate::buffer_len_to_u32(key.len())?; if iv.len() != AES_BLOCK_SIZE { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesSetKey(&mut self.ws_aes, key.as_ptr(), key_size, iv.as_ptr(), dir) }; if rc != 0 { return Err(rc); } Ok(()) } /// Initialize a CBC instance for encryption. /// /// This method must be called before calling `encrypt()`. /// /// # Parameters /// /// * `key`: A slice containing the encryption key to use. The key must be /// 16, 24, or 32 bytes in length. /// * `iv`: A slice containing the initialization vector (IV) to use. The /// IV must be 16 bytes in length. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn init_encrypt(&mut self, key: &[u8], iv: &[u8]) -> Result<(), i32> { self.init(key, iv, sys::AES_ENCRYPTION as i32) } /// Initialize a CBC instance for decryption. /// /// This method must be called before calling `decrypt()`. /// /// # Parameters /// /// * `key`: A slice containing the decryption key to use. The key must be /// 16, 24, or 32 bytes in length. /// * `iv`: A slice containing the initialization vector (IV) to use. The /// IV must be 16 bytes in length. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn init_decrypt(&mut self, key: &[u8], iv: &[u8]) -> Result<(), i32> { self.init(key, iv, sys::AES_DECRYPTION as i32) } /// Encrypt data. /// /// The `init_encrypt()` method must be called before calling this method. /// /// # Parameters /// /// * `din`: Data to encrypt. The size of the data must be a multiple of /// 16 bytes. /// * `dout`: Buffer in which to store the encrypted data. The size of /// the buffer must match that of the `din` buffer. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn encrypt(&mut self, din: &[u8], dout: &mut [u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesCbcEncrypt(&mut self.ws_aes, dout.as_mut_ptr(), din.as_ptr(), in_size) }; if rc != 0 { return Err(rc); } Ok(()) } /// Decrypt data. /// /// The `init_decrypt()` method must be called before calling this method. /// /// # Parameters /// /// * `din`: Data to decrypt. The size of the data must be a multiple of /// 16 bytes. /// * `dout`: Buffer in which to store the decrypted data. The size of /// the data must match that of the `din` slice. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn decrypt(&mut self, din: &[u8], dout: &mut [u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesCbcDecrypt(&mut self.ws_aes, dout.as_mut_ptr(), din.as_ptr(), in_size) }; if rc != 0 { return Err(rc); } Ok(()) } } #[cfg(aes_cbc)] impl CBC { fn zeroize(&mut self) { unsafe { crate::zeroize_raw(&mut self.ws_aes); } } } #[cfg(aes_cbc)] impl Drop for CBC { /// Safely free the wolfSSL resources. fn drop(&mut self) { unsafe { sys::wc_AesFree(&mut self.ws_aes); } self.zeroize(); } } /// AES Counter with CBC-MAC (CCM) mode. /// /// # Example /// ```rust /// #[cfg(aes_ccm)] /// { /// use wolfssl_wolfcrypt::aes::CCM; /// let key: [u8; 16] = [ /// 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /// 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf /// ]; /// let nonce: [u8; 13] = [ /// 0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0xa0, /// 0xa1, 0xa2, 0xa3, 0xa4, 0xa5 ]; /// let plaintext: [u8; 23] = [ /// 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /// 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /// 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e /// ]; /// let auth_data: [u8; 8] = [ /// 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 /// ]; /// let expected_ciphertext: [u8; 23] = [ /// 0x58, 0x8c, 0x97, 0x9a, 0x61, 0xc6, 0x63, 0xd2, /// 0xf0, 0x66, 0xd0, 0xc2, 0xc0, 0xf9, 0x89, 0x80, /// 0x6d, 0x5f, 0x6b, 0x61, 0xda, 0xc3, 0x84 /// ]; /// let expected_auth_tag: [u8; 8] = [ /// 0x17, 0xe8, 0xd1, 0x2c, 0xfd, 0xf9, 0x26, 0xe0 /// ]; /// /// let mut ccm = CCM::new().expect("Failed to create CCM"); /// ccm.init(&key).expect("Error with init()"); /// let mut auth_tag_out: [u8; 8] = [0; 8]; /// let mut cipher_out: [u8; 23] = [0; 23]; /// ccm.encrypt(&plaintext, &mut cipher_out, /// &nonce, &auth_data, &mut auth_tag_out).expect("Error with encrypt()"); /// assert_eq!(cipher_out, expected_ciphertext); /// assert_eq!(auth_tag_out, expected_auth_tag); /// ccm.init(&key).expect("Error with init()"); /// let mut plain_out: [u8; 23] = [0; 23]; /// ccm.decrypt(&cipher_out, &mut plain_out, /// &nonce, &auth_data, &auth_tag_out).expect("Error with decrypt()"); /// assert_eq!(plain_out, plaintext); /// } /// ``` #[cfg(aes_ccm)] pub struct CCM { ws_aes: sys::Aes, } #[cfg(aes_ccm)] impl CCM { /// Create a new `CCM` instance. /// /// # Returns /// /// A Result which is Ok(CCM) on success or an Err containing the wolfSSL /// library return code on failure. pub fn new() -> Result { Self::new_ex(None, None) } /// Create a new `CCM` instance with optional heap and device ID. /// /// # Parameters /// /// * `heap`: Optional heap hint. /// * `dev_id` Optional device ID to use with crypto callbacks or async hardware. /// /// # Returns /// /// A Result which is Ok(CCM) on success or an Err containing the wolfSSL /// library return code on failure. pub fn new_ex(heap: Option<*mut core::ffi::c_void>, dev_id: Option) -> Result { let ws_aes = new_ws_aes(heap, dev_id)?; let ccm = CCM {ws_aes}; Ok(ccm) } /// Initialize a CCM instance for encryption or decryption. /// /// This method must be called before calling `encrypt()` or `decrypt()`. /// /// # Parameters /// /// * `key`: A slice containing the encryption key to use. The key must be /// 16, 24, or 32 bytes in length. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn init(&mut self, key: &[u8]) -> Result<(), i32> { let key_size = crate::buffer_len_to_u32(key.len())?; let rc = unsafe { sys::wc_AesCcmSetKey(&mut self.ws_aes, key.as_ptr(), key_size) }; if rc != 0 { return Err(rc); } Ok(()) } /// Encrypt data. /// /// The `init()` method must be called before calling this method. /// /// # Parameters /// /// * `din`: Data to encrypt. /// * `dout`: Buffer in which to store the encrypted data. The size of /// the buffer must match that of the `din` buffer. /// * `nonce`: Nonce (number used once). /// * `auth`: Authentication data input. /// * `auth_tag`: Buffer in which to store the authentication tag. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn encrypt(&mut self, din: &[u8], dout: &mut [u8], nonce: &[u8], auth: &[u8], auth_tag: &mut [u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; let nonce_size = crate::buffer_len_to_u32(nonce.len())?; let auth_size = crate::buffer_len_to_u32(auth.len())?; let auth_tag_size = crate::buffer_len_to_u32(auth_tag.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesCcmEncrypt(&mut self.ws_aes, dout.as_mut_ptr(), din.as_ptr(), in_size, nonce.as_ptr(), nonce_size, auth_tag.as_mut_ptr(), auth_tag_size, auth.as_ptr(), auth_size) }; if rc != 0 { return Err(rc); } Ok(()) } /// Decrypt data. /// /// The `init()` method must be called before calling this method. /// /// # Parameters /// /// * `din`: Data to decrypt. /// * `dout`: Buffer in which to store the decrypted data. The size of /// the buffer must match that of the `din` buffer. /// * `nonce`: Nonce (number used once). /// * `auth`: Authentication data input. /// * `auth_tag`: Authentication tag input to verify. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn decrypt(&mut self, din: &[u8], dout: &mut [u8], nonce: &[u8], auth: &[u8], auth_tag: &[u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; let nonce_size = crate::buffer_len_to_u32(nonce.len())?; let auth_size = crate::buffer_len_to_u32(auth.len())?; let auth_tag_size = crate::buffer_len_to_u32(auth_tag.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesCcmDecrypt(&mut self.ws_aes, dout.as_mut_ptr(), din.as_ptr(), in_size, nonce.as_ptr(), nonce_size, auth_tag.as_ptr(), auth_tag_size, auth.as_ptr(), auth_size) }; if rc != 0 { return Err(rc); } Ok(()) } } #[cfg(aes_ccm)] impl CCM { fn zeroize(&mut self) { unsafe { crate::zeroize_raw(&mut self.ws_aes); } } } #[cfg(aes_ccm)] impl Drop for CCM { /// Safely free the wolfSSL resources. fn drop(&mut self) { unsafe { sys::wc_AesFree(&mut self.ws_aes); } self.zeroize(); } } // --------------------------------------------------------------------------- // AES-CCM aead trait implementations // --------------------------------------------------------------------------- /// Encrypt `buffer` in-place using AES-CCM (12-byte nonce, 16-byte tag). #[cfg(all(aes_ccm, feature = "aead"))] fn ccm_encrypt_in_place( key: &[u8], nonce: &[u8], aad: &[u8], buffer: &mut [u8], tag: &mut [u8], ) -> Result<(), aead::Error> { if buffer.len() > u32::MAX as usize || nonce.len() > u32::MAX as usize || tag.len() > u32::MAX as usize || aad.len() > u32::MAX as usize { return Err(aead::Error); } let mut ccm = CCM::new().map_err(|_| aead::Error)?; ccm.init(key).map_err(|_| aead::Error)?; // wolfCrypt CCM supports in-place operation (out == in). let buf_ptr = buffer.as_mut_ptr(); let in_ptr = buf_ptr as *const u8; let rc = unsafe { sys::wc_AesCcmEncrypt( &mut ccm.ws_aes, buf_ptr, in_ptr, buffer.len() as u32, nonce.as_ptr(), nonce.len() as u32, tag.as_mut_ptr(), tag.len() as u32, aad.as_ptr(), aad.len() as u32, ) }; if rc != 0 { return Err(aead::Error); } Ok(()) } /// Decrypt `buffer` in-place using AES-CCM and verify `tag`. #[cfg(all(aes_ccm, feature = "aead"))] fn ccm_decrypt_in_place( key: &[u8], nonce: &[u8], aad: &[u8], buffer: &mut [u8], tag: &[u8], ) -> Result<(), aead::Error> { if buffer.len() > u32::MAX as usize || nonce.len() > u32::MAX as usize || tag.len() > u32::MAX as usize || aad.len() > u32::MAX as usize { return Err(aead::Error); } let mut ccm = CCM::new().map_err(|_| aead::Error)?; ccm.init(key).map_err(|_| aead::Error)?; let buf_ptr = buffer.as_mut_ptr(); let in_ptr = buf_ptr as *const u8; let rc = unsafe { sys::wc_AesCcmDecrypt( &mut ccm.ws_aes, buf_ptr, in_ptr, buffer.len() as u32, nonce.as_ptr(), nonce.len() as u32, tag.as_ptr(), tag.len() as u32, aad.as_ptr(), aad.len() as u32, ) }; if rc != 0 { return Err(aead::Error); } Ok(()) } /// AES-128-CCM authenticated encryption (12-byte nonce, 16-byte tag). #[cfg(all(aes_ccm, feature = "aead"))] #[derive(Zeroize, ZeroizeOnDrop)] pub struct Aes128Ccm { key: [u8; 16], } #[cfg(all(aes_ccm, feature = "aead"))] impl KeySizeUser for Aes128Ccm { type KeySize = U16; } #[cfg(all(aes_ccm, feature = "aead"))] impl AeadCore for Aes128Ccm { type NonceSize = U12; type TagSize = U16; type CiphertextOverhead = U0; } #[cfg(all(aes_ccm, feature = "aead"))] impl KeyInit for Aes128Ccm { fn new(key: &aead::Key) -> Self { let mut k = [0u8; 16]; k.copy_from_slice(key.as_ref()); Aes128Ccm { key: k } } } #[cfg(all(aes_ccm, feature = "aead"))] impl AeadInPlace for Aes128Ccm { fn encrypt_in_place_detached( &self, nonce: &aead::Nonce, associated_data: &[u8], buffer: &mut [u8], ) -> Result, aead::Error> { let mut tag = aead::Tag::::default(); ccm_encrypt_in_place(&self.key, nonce.as_ref(), associated_data, buffer, tag.as_mut())?; Ok(tag) } fn decrypt_in_place_detached( &self, nonce: &aead::Nonce, associated_data: &[u8], buffer: &mut [u8], tag: &aead::Tag, ) -> Result<(), aead::Error> { ccm_decrypt_in_place(&self.key, nonce.as_ref(), associated_data, buffer, tag.as_ref()) } } /// AES-256-CCM authenticated encryption (12-byte nonce, 16-byte tag). #[cfg(all(aes_ccm, feature = "aead"))] #[derive(Zeroize, ZeroizeOnDrop)] pub struct Aes256Ccm { key: [u8; 32], } #[cfg(all(aes_ccm, feature = "aead"))] impl KeySizeUser for Aes256Ccm { type KeySize = U32; } #[cfg(all(aes_ccm, feature = "aead"))] impl AeadCore for Aes256Ccm { type NonceSize = U12; type TagSize = U16; type CiphertextOverhead = U0; } #[cfg(all(aes_ccm, feature = "aead"))] impl KeyInit for Aes256Ccm { fn new(key: &aead::Key) -> Self { let mut k = [0u8; 32]; k.copy_from_slice(key.as_ref()); Aes256Ccm { key: k } } } #[cfg(all(aes_ccm, feature = "aead"))] impl AeadInPlace for Aes256Ccm { fn encrypt_in_place_detached( &self, nonce: &aead::Nonce, associated_data: &[u8], buffer: &mut [u8], ) -> Result, aead::Error> { let mut tag = aead::Tag::::default(); ccm_encrypt_in_place(&self.key, nonce.as_ref(), associated_data, buffer, tag.as_mut())?; Ok(tag) } fn decrypt_in_place_detached( &self, nonce: &aead::Nonce, associated_data: &[u8], buffer: &mut [u8], tag: &aead::Tag, ) -> Result<(), aead::Error> { ccm_decrypt_in_place(&self.key, nonce.as_ref(), associated_data, buffer, tag.as_ref()) } } /// AES Cipher FeedBack (CFB) mode. /// /// # Example /// ```rust /// #[cfg(aes_cfb)] /// { /// use wolfssl_wolfcrypt::aes::CFB; /// let mut cfb = CFB::new().expect("Failed to create CFB"); /// let key: [u8; 16] = [ /// 0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6, /// 0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c /// ]; /// let iv: [u8; 16] = [ /// 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, /// 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f /// ]; /// let msg: [u8; 48] = [ /// 0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96, /// 0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a, /// 0xae,0x2d,0x8a,0x57,0x1e,0x03,0xac,0x9c, /// 0x9e,0xb7,0x6f,0xac,0x45,0xaf,0x8e,0x51, /// 0x30,0xc8,0x1c,0x46,0xa3,0x5c,0xe4,0x11, /// 0xe5,0xfb,0xc1,0x19,0x1a,0x0a,0x52,0xef /// ]; /// let cipher: [u8; 48] = [ /// 0x3b,0x3f,0xd9,0x2e,0xb7,0x2d,0xad,0x20, /// 0x33,0x34,0x49,0xf8,0xe8,0x3c,0xfb,0x4a, /// 0xc8,0xa6,0x45,0x37,0xa0,0xb3,0xa9,0x3f, /// 0xcd,0xe3,0xcd,0xad,0x9f,0x1c,0xe5,0x8b, /// 0x26,0x75,0x1f,0x67,0xa3,0xcb,0xb1,0x40, /// 0xb1,0x80,0x8c,0xf1,0x87,0xa4,0xf4,0xdf /// ]; /// cfb.init(&key, &iv).expect("Error with init()"); /// let mut outbuf: [u8; 48] = [0; 48]; /// cfb.encrypt(&msg[0..32], &mut outbuf[0..32]).expect("Error with encrypt()"); /// cfb.encrypt(&msg[32..48], &mut outbuf[32..48]).expect("Error with encrypt()"); /// assert_eq!(outbuf, cipher); /// cfb.init(&key, &iv).expect("Error with init()"); /// let mut plain: [u8; 48] = [0; 48]; /// #[cfg(aes_decrypt)] /// { /// cfb.decrypt(&outbuf, &mut plain).expect("Error with decrypt()"); /// assert_eq!(plain, msg); /// } /// } /// ``` #[cfg(aes_cfb)] pub struct CFB { ws_aes: sys::Aes, } #[cfg(aes_cfb)] impl CFB { /// Create a new `CFB` instance. /// /// # Returns /// /// A Result which is Ok(CFB) on success or an Err containing the wolfSSL /// library return code on failure. pub fn new() -> Result { Self::new_ex(None, None) } /// Create a new `CFB` instance with optional heap and device ID. /// /// # Parameters /// /// * `heap`: Optional heap hint. /// * `dev_id` Optional device ID to use with crypto callbacks or async hardware. /// /// # Returns /// /// A Result which is Ok(CFB) on success or an Err containing the wolfSSL /// library return code on failure. pub fn new_ex(heap: Option<*mut core::ffi::c_void>, dev_id: Option) -> Result { let ws_aes = new_ws_aes(heap, dev_id)?; let cfb = CFB {ws_aes}; Ok(cfb) } /// Initialize a CFB instance for encryption or decryption. /// /// This method must be called before calling `encrypt()`, `encrypt1()`, /// `encrypt8()`, `decrypt()`, `decrypt1()`, or `decrypt8()`. /// /// # Parameters /// /// * `key`: A slice containing the encryption key to use. The key must be /// 16, 24, or 32 bytes in length. /// * `iv`: A slice containing the initialization vector (IV) to use. The /// IV must be 16 bytes in length. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn init(&mut self, key: &[u8], iv: &[u8]) -> Result<(), i32> { let key_size = crate::buffer_len_to_u32(key.len())?; if iv.len() != AES_BLOCK_SIZE { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesSetKey(&mut self.ws_aes, key.as_ptr(), key_size, iv.as_ptr(), sys::AES_ENCRYPTION as i32) }; if rc != 0 { return Err(rc); } Ok(()) } /// Encrypt data in full-block CFB mode. /// /// The `init()` method must be called before calling this method. /// /// # Parameters /// /// * `din`: Data to encrypt. /// * `dout`: Buffer in which to store the encrypted data. The size of /// the buffer must match that of the `din` buffer. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn encrypt(&mut self, din: &[u8], dout: &mut [u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesCfbEncrypt(&mut self.ws_aes, dout.as_mut_ptr(), din.as_ptr(), in_size) }; if rc != 0 { return Err(rc); } Ok(()) } /// Encrypt data in 1-bit CFB mode. /// /// The `init()` method must be called before calling this method. /// /// # Parameters /// /// * `din`: Data to encrypt. /// * `dout`: Buffer in which to store the encrypted data. The size of /// the buffer must match that of the `din` buffer. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn encrypt1(&mut self, din: &[u8], dout: &mut [u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesCfb1Encrypt(&mut self.ws_aes, dout.as_mut_ptr(), din.as_ptr(), in_size) }; if rc != 0 { return Err(rc); } Ok(()) } /// Encrypt data in 8-bit CFB mode. /// /// The `init()` method must be called before calling this method. /// /// # Parameters /// /// * `din`: Data to encrypt. /// * `dout`: Buffer in which to store the encrypted data. The size of /// the buffer must match that of the `din` buffer. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn encrypt8(&mut self, din: &[u8], dout: &mut [u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesCfb8Encrypt(&mut self.ws_aes, dout.as_mut_ptr(), din.as_ptr(), in_size) }; if rc != 0 { return Err(rc); } Ok(()) } /// Decrypt data in full-block CFB mode. /// /// The `init()` method must be called before calling this method. /// /// # Parameters /// /// * `din`: Data to decrypt. /// * `dout`: Buffer in which to store the decrypted data. The size of /// the buffer must match that of the `din` buffer. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. #[cfg(aes_decrypt)] pub fn decrypt(&mut self, din: &[u8], dout: &mut [u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesCfbDecrypt(&mut self.ws_aes, dout.as_mut_ptr(), din.as_ptr(), in_size) }; if rc != 0 { return Err(rc); } Ok(()) } /// Decrypt data in 1-bit CFB mode. /// /// The `init()` method must be called before calling this method. /// /// # Parameters /// /// * `din`: Data to decrypt. /// * `dout`: Buffer in which to store the decrypted data. The size of /// the buffer must match that of the `din` buffer. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. #[cfg(aes_decrypt)] pub fn decrypt1(&mut self, din: &[u8], dout: &mut [u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesCfb1Decrypt(&mut self.ws_aes, dout.as_mut_ptr(), din.as_ptr(), in_size) }; if rc != 0 { return Err(rc); } Ok(()) } /// Decrypt data in 8-bit CFB mode. /// /// The `init()` method must be called before calling this method. /// /// # Parameters /// /// * `din`: Data to decrypt. /// * `dout`: Buffer in which to store the decrypted data. The size of /// the buffer must match that of the `din` buffer. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. #[cfg(aes_decrypt)] pub fn decrypt8(&mut self, din: &[u8], dout: &mut [u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesCfb8Decrypt(&mut self.ws_aes, dout.as_mut_ptr(), din.as_ptr(), in_size) }; if rc != 0 { return Err(rc); } Ok(()) } } #[cfg(aes_cfb)] impl CFB { fn zeroize(&mut self) { unsafe { crate::zeroize_raw(&mut self.ws_aes); } } } #[cfg(aes_cfb)] impl Drop for CFB { /// Safely free the wolfSSL resources. fn drop(&mut self) { unsafe { sys::wc_AesFree(&mut self.ws_aes); } self.zeroize(); } } /// AES Counter (CTR) mode. /// /// # Example /// ```rust /// #[cfg(aes_ctr)] /// { /// use wolfssl_wolfcrypt::aes::CTR; /// let iv: [u8; 16] = [ /// 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, /// 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff /// ]; /// let msg: [u8; 64] = [ /// 0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96, /// 0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a, /// 0xae,0x2d,0x8a,0x57,0x1e,0x03,0xac,0x9c, /// 0x9e,0xb7,0x6f,0xac,0x45,0xaf,0x8e,0x51, /// 0x30,0xc8,0x1c,0x46,0xa3,0x5c,0xe4,0x11, /// 0xe5,0xfb,0xc1,0x19,0x1a,0x0a,0x52,0xef, /// 0xf6,0x9f,0x24,0x45,0xdf,0x4f,0x9b,0x17, /// 0xad,0x2b,0x41,0x7b,0xe6,0x6c,0x37,0x10 /// ]; /// let key: [u8; 16] = [ /// 0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6, /// 0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c /// ]; /// let cipher: [u8; 64] = [ /// 0x87,0x4d,0x61,0x91,0xb6,0x20,0xe3,0x26, /// 0x1b,0xef,0x68,0x64,0x99,0x0d,0xb6,0xce, /// 0x98,0x06,0xf6,0x6b,0x79,0x70,0xfd,0xff, /// 0x86,0x17,0x18,0x7b,0xb9,0xff,0xfd,0xff, /// 0x5a,0xe4,0xdf,0x3e,0xdb,0xd5,0xd3,0x5e, /// 0x5b,0x4f,0x09,0x02,0x0d,0xb0,0x3e,0xab, /// 0x1e,0x03,0x1d,0xda,0x2f,0xbe,0x03,0xd1, /// 0x79,0x21,0x70,0xa0,0xf3,0x00,0x9c,0xee /// ]; /// let mut ctr = CTR::new().expect("Failed to create CTR"); /// ctr.init(&key, &iv).expect("Error with init()"); /// let mut outbuf: [u8; 64] = [0; 64]; /// ctr.encrypt(&msg, &mut outbuf).expect("Error with encrypt()"); /// assert_eq!(outbuf, cipher); /// ctr.init(&key, &iv).expect("Error with init()"); /// let mut plain: [u8; 64] = [0; 64]; /// ctr.decrypt(&outbuf, &mut plain).expect("Error with decrypt()"); /// assert_eq!(plain, msg); /// } /// ``` #[cfg(aes_ctr)] pub struct CTR { ws_aes: sys::Aes, } #[cfg(aes_ctr)] impl CTR { /// Create a new `CTR` instance. /// /// # Returns /// /// A Result which is Ok(CTR) on success or an Err containing the wolfSSL /// library return code on failure. pub fn new() -> Result { Self::new_ex(None, None) } /// Create a new `CTR` instance with optional heap and device ID. /// /// # Parameters /// /// * `heap`: Optional heap hint. /// * `dev_id` Optional device ID to use with crypto callbacks or async hardware. /// /// # Returns /// /// A Result which is Ok(CTR) on success or an Err containing the wolfSSL /// library return code on failure. pub fn new_ex(heap: Option<*mut core::ffi::c_void>, dev_id: Option) -> Result { let ws_aes = new_ws_aes(heap, dev_id)?; let ctr = CTR {ws_aes}; Ok(ctr) } /// Initialize a CTR instance for encryption or decryption. /// /// This method must be called before calling `encrypt()` or `decrypt()`. /// /// # Parameters /// /// * `key`: A slice containing the encryption key to use. The key must be /// 16, 24, or 32 bytes in length. /// * `iv`: A slice containing the initialization vector (IV) to use. The /// IV must be 16 bytes in length. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn init(&mut self, key: &[u8], iv: &[u8]) -> Result<(), i32> { let key_size = crate::buffer_len_to_u32(key.len())?; if iv.len() != AES_BLOCK_SIZE { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesSetKeyDirect(&mut self.ws_aes, key.as_ptr(), key_size, iv.as_ptr(), sys::AES_ENCRYPTION as i32) }; if rc != 0 { return Err(rc); } Ok(()) } fn encrypt_decrypt(&mut self, din: &[u8], dout: &mut [u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesCtrEncrypt(&mut self.ws_aes, dout.as_mut_ptr(), din.as_ptr(), in_size) }; if rc != 0 { return Err(rc); } Ok(()) } /// Encrypt data. /// /// The `init()` method must be called before calling this method. /// /// # Parameters /// /// * `din`: Data to encrypt. /// * `dout`: Buffer in which to store the encrypted data. The size of /// the buffer must match that of the `din` buffer. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn encrypt(&mut self, din: &[u8], dout: &mut [u8]) -> Result<(), i32> { self.encrypt_decrypt(din, dout) } /// Decrypt data. /// /// The `init()` method must be called before calling this method. /// /// # Parameters /// /// * `din`: Data to decrypt. /// * `dout`: Buffer in which to store the decrypted data. The size of /// the buffer must match that of the `din` buffer. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn decrypt(&mut self, din: &[u8], dout: &mut [u8]) -> Result<(), i32> { self.encrypt_decrypt(din, dout) } } #[cfg(aes_ctr)] impl CTR { fn zeroize(&mut self) { unsafe { crate::zeroize_raw(&mut self.ws_aes); } } } #[cfg(aes_ctr)] impl Drop for CTR { /// Safely free the wolfSSL resources. fn drop(&mut self) { unsafe { sys::wc_AesFree(&mut self.ws_aes); } self.zeroize(); } } /// AES Encrypt-Then-Authenticate-Then-Translate (EAX) mode. /// /// # Example /// ```rust /// #[cfg(aes_eax)] /// { /// use wolfssl_wolfcrypt::aes::EAX; /// let key: [u8; 16] = [ /// 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /// 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f /// ]; /// let nonce: [u8; 16] = [ /// 0x3c, 0x8c, 0xc2, 0x97, 0x0a, 0x00, 0x8f, 0x75, /// 0xcc, 0x5b, 0xea, 0xe2, 0x84, 0x72, 0x58, 0xc2 /// ]; /// let auth: &[u8] = &[]; /// let msg: [u8; 32] = [ /// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /// 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, /// 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 /// ]; /// let expected_cipher: [u8; 32] = [ /// 0x3c, 0x44, 0x1f, 0x32, 0xce, 0x07, 0x82, 0x23, /// 0x64, 0xd7, 0xa2, 0x99, 0x0e, 0x50, 0xbb, 0x13, /// 0xd7, 0xb0, 0x2a, 0x26, 0x96, 0x9e, 0x4a, 0x93, /// 0x7e, 0x5e, 0x90, 0x73, 0xb0, 0xd9, 0xc9, 0x68 /// ]; /// let expected_auth_tag: [u8; 16] = [ /// 0xdb, 0x90, 0xbd, 0xb3, 0xda, 0x3d, 0x00, 0xaf, /// 0xd0, 0xfc, 0x6a, 0x83, 0x55, 0x1d, 0xa9, 0x5e /// ]; /// let mut cipher: [u8; 32] = [0; 32]; /// let mut auth_tag: [u8; 16] = [0; 16]; /// EAX::encrypt(&msg, &mut cipher, &key, &nonce, auth, &mut auth_tag).expect("Error with encrypt()"); /// assert_eq!(cipher, expected_cipher); /// assert_eq!(auth_tag, expected_auth_tag); /// let mut plain: [u8; 32] = [0; 32]; /// EAX::decrypt(&cipher, &mut plain, &key, &nonce, auth, &auth_tag).expect("Error with decrypt()"); /// assert_eq!(plain, msg); /// } /// ``` #[cfg(aes_eax)] pub struct EAX { } #[cfg(aes_eax)] impl EAX { /// Encrypt data. /// /// # Parameters /// /// * `din`: Data to encrypt. /// * `dout`: Buffer in which to store the encrypted data. The size of /// the buffer must match that of the `din` buffer. /// * `key`: Encryption key to use. The key size must be 16, 24, or 32 /// bytes. /// * `nonce`: Nonce (number used once). /// * `auth`: Authentication data input. /// * `auth_tag`: Buffer in which to store the authentication tag. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn encrypt(din: &[u8], dout: &mut [u8], key: &[u8], nonce: &[u8], auth: &[u8], auth_tag: &mut [u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; let key_size = crate::buffer_len_to_u32(key.len())?; let nonce_size = crate::buffer_len_to_u32(nonce.len())?; let auth_size = crate::buffer_len_to_u32(auth.len())?; let auth_tag_size = crate::buffer_len_to_u32(auth_tag.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesEaxEncryptAuth(key.as_ptr(), key_size, dout.as_mut_ptr(), din.as_ptr(), in_size, nonce.as_ptr(), nonce_size, auth_tag.as_mut_ptr(), auth_tag_size, auth.as_ptr(), auth_size) }; if rc != 0 { return Err(rc); } Ok(()) } /// Decrypt data. /// /// # Parameters /// /// * `din`: Data to decrypt. /// * `dout`: Buffer in which to store the decrypted data. The size of /// the buffer must match that of the `din` buffer. /// * `key`: Decryption key to use. The key size must be 16, 24, or 32 /// bytes. /// * `nonce`: Nonce (number used once). /// * `auth`: Authentication data input. /// * `auth_tag`: Authentication tag input to verify. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn decrypt(din: &[u8], dout: &mut [u8], key: &[u8], nonce: &[u8], auth: &[u8], auth_tag: &[u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; let key_size = crate::buffer_len_to_u32(key.len())?; let nonce_size = crate::buffer_len_to_u32(nonce.len())?; let auth_size = crate::buffer_len_to_u32(auth.len())?; let auth_tag_size = crate::buffer_len_to_u32(auth_tag.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesEaxDecryptAuth(key.as_ptr(), key_size, dout.as_mut_ptr(), din.as_ptr(), in_size, nonce.as_ptr(), nonce_size, auth_tag.as_ptr(), auth_tag_size, auth.as_ptr(), auth_size) }; if rc != 0 { return Err(rc); } Ok(()) } } /// AES Electronic CodeBook (ECB) mode. /// /// # Example /// ```rust /// #[cfg(aes_ecb)] /// { /// use wolfssl_wolfcrypt::aes::ECB; /// let mut ecb = ECB::new().expect("Failed to create ECB"); /// let key_128: &[u8; 16] = b"0123456789abcdef"; /// let msg: [u8; 16] = [ /// 0x6e, 0x6f, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74, /// 0x68, 0x65, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20 /// ]; /// let verify_ecb_128: [u8; 16] = [ /// 0xd0, 0xc9, 0xd9, 0xc9, 0x40, 0xe8, 0x97, 0xb6, /// 0xc8, 0x8c, 0x33, 0x3b, 0xb5, 0x8f, 0x85, 0xd1 /// ]; /// ecb.init_encrypt(key_128).expect("Error with init_encrypt()"); /// let mut outbuf: [u8; 16] = [0; 16]; /// ecb.encrypt(&msg, &mut outbuf).expect("Error with encrypt()"); /// assert_eq!(&outbuf, &verify_ecb_128); /// outbuf = [0; 16]; /// ecb.init_decrypt(key_128).expect("Error with init_decrypt()"); /// ecb.decrypt(&verify_ecb_128, &mut outbuf).expect("Error with decrypt()"); /// assert_eq!(&outbuf, &msg); /// } /// ``` #[cfg(aes_ecb)] pub struct ECB { ws_aes: sys::Aes, } #[cfg(aes_ecb)] impl ECB { /// Create a new `ECB` instance. /// /// # Returns /// /// A Result which is Ok(ECB) on success or an Err containing the wolfSSL /// library return code on failure. pub fn new() -> Result { Self::new_ex(None, None) } /// Create a new `ECB` instance with optional heap and device ID. /// /// # Parameters /// /// * `heap`: Optional heap hint. /// * `dev_id` Optional device ID to use with crypto callbacks or async hardware. /// /// # Returns /// /// A Result which is Ok(ECB) on success or an Err containing the wolfSSL /// library return code on failure. pub fn new_ex(heap: Option<*mut core::ffi::c_void>, dev_id: Option) -> Result { let ws_aes = new_ws_aes(heap, dev_id)?; let ecb = ECB {ws_aes}; Ok(ecb) } fn init(&mut self, key: &[u8], dir: i32) -> Result<(), i32> { let key_size = crate::buffer_len_to_u32(key.len())?; let rc = unsafe { sys::wc_AesSetKey(&mut self.ws_aes, key.as_ptr(), key_size, core::ptr::null(), dir) }; if rc != 0 { return Err(rc); } Ok(()) } /// Initialize a ECB instance for encryption. /// /// This method must be called before calling `encrypt()`. /// /// # Parameters /// /// * `key`: A slice containing the encryption key to use. The key must be /// 16, 24, or 32 bytes in length. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn init_encrypt(&mut self, key: &[u8]) -> Result<(), i32> { self.init(key, sys::AES_ENCRYPTION as i32) } /// Initialize a ECB instance for decryption. /// /// This method must be called before calling `decrypt()`. /// /// # Parameters /// /// * `key`: A slice containing the decryption key to use. The key must be /// 16, 24, or 32 bytes in length. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn init_decrypt(&mut self, key: &[u8]) -> Result<(), i32> { self.init(key, sys::AES_DECRYPTION as i32) } /// Encrypt data. /// /// The `init_encrypt()` method must be called before calling this method. /// /// # Parameters /// /// * `din`: Data to encrypt. The size of the data must be a multiple of /// 16 bytes. /// * `dout`: Buffer in which to store the encrypted data. The size of /// the buffer must match that of the `din` buffer. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn encrypt(&mut self, din: &[u8], dout: &mut [u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesEcbEncrypt(&mut self.ws_aes, dout.as_mut_ptr(), din.as_ptr(), in_size) }; if rc != 0 { return Err(rc); } Ok(()) } /// Decrypt data. /// /// The `init_decrypt()` method must be called before calling this method. /// /// # Parameters /// /// * `din`: Data to decrypt. The size of the data must be a multiple of /// 16 bytes. /// * `dout`: Buffer in which to store the decrypted data. The size of /// the buffer must match that of the `din` buffer. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn decrypt(&mut self, din: &[u8], dout: &mut [u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesEcbDecrypt(&mut self.ws_aes, dout.as_mut_ptr(), din.as_ptr(), in_size) }; if rc != 0 { return Err(rc); } Ok(()) } } #[cfg(aes_ecb)] impl ECB { fn zeroize(&mut self) { unsafe { crate::zeroize_raw(&mut self.ws_aes); } } } #[cfg(aes_ecb)] impl Drop for ECB { /// Safely free the wolfSSL resources. fn drop(&mut self) { unsafe { sys::wc_AesFree(&mut self.ws_aes); } self.zeroize(); } } /// AES Galois/Counter Mode (GCM) mode (one shot functionality). /// /// This struct provides one-shot encryption and decryption functionality. /// For streaming/chunking functionality, see the `GCMStream` struct instead. /// /// # Example /// ```rust /// #[cfg(aes_gcm)] /// { /// use wolfssl_wolfcrypt::aes::GCM; /// let key: [u8; 16] = [ /// 0x29, 0x8e, 0xfa, 0x1c, 0xcf, 0x29, 0xcf, 0x62, /// 0xae, 0x68, 0x24, 0xbf, 0xc1, 0x95, 0x57, 0xfc /// ]; /// let iv: [u8; 12] = [ /// 0x6f, 0x58, 0xa9, 0x3f, 0xe1, 0xd2, 0x07, 0xfa, /// 0xe4, 0xed, 0x2f, 0x6d /// ]; /// let plain: [u8; 32] = [ /// 0xcc, 0x38, 0xbc, 0xcd, 0x6b, 0xc5, 0x36, 0xad, /// 0x91, 0x9b, 0x13, 0x95, 0xf5, 0xd6, 0x38, 0x01, /// 0xf9, 0x9f, 0x80, 0x68, 0xd6, 0x5c, 0xa5, 0xac, /// 0x63, 0x87, 0x2d, 0xaf, 0x16, 0xb9, 0x39, 0x01 /// ]; /// let auth: [u8; 16] = [ /// 0x02, 0x1f, 0xaf, 0xd2, 0x38, 0x46, 0x39, 0x73, /// 0xff, 0xe8, 0x02, 0x56, 0xe5, 0xb1, 0xc6, 0xb1 /// ]; /// let expected_cipher: [u8; 32] = [ /// 0xdf, 0xce, 0x4e, 0x9c, 0xd2, 0x91, 0x10, 0x3d, /// 0x7f, 0xe4, 0xe6, 0x33, 0x51, 0xd9, 0xe7, 0x9d, /// 0x3d, 0xfd, 0x39, 0x1e, 0x32, 0x67, 0x10, 0x46, /// 0x58, 0x21, 0x2d, 0xa9, 0x65, 0x21, 0xb7, 0xdb /// ]; /// let expected_auth_tag: [u8; 16] = [ /// 0x54, 0x24, 0x65, 0xef, 0x59, 0x93, 0x16, 0xf7, /// 0x3a, 0x7a, 0x56, 0x05, 0x09, 0xa2, 0xd9, 0xf2 /// ]; /// let mut gcm = GCM::new().expect("Failed to create GCM"); /// gcm.init(&key).expect("Error with init()"); /// let mut cipher: [u8; 32] = [0; 32]; /// let mut auth_tag: [u8; 16] = [0; 16]; /// gcm.encrypt(&plain, &mut cipher, &iv, &auth, &mut auth_tag).expect("Error with encrypt()"); /// assert_eq!(cipher, expected_cipher); /// assert_eq!(auth_tag, expected_auth_tag); /// let mut plain_out: [u8; 32] = [0; 32]; /// gcm.decrypt(&cipher, &mut plain_out, &iv, &auth, &auth_tag).expect("Error with decrypt()"); /// assert_eq!(plain_out, plain); /// } /// ``` #[cfg(aes_gcm)] pub struct GCM { ws_aes: sys::Aes, } #[cfg(aes_gcm)] impl GCM { /// Create a new `GCM` instance. /// /// # Returns /// /// A Result which is Ok(GCM) on success or an Err containing the wolfSSL /// library return code on failure. pub fn new() -> Result { Self::new_ex(None, None) } /// Create a new `GCM` instance with optional heap and device ID. /// /// # Parameters /// /// * `heap`: Optional heap hint. /// * `dev_id` Optional device ID to use with crypto callbacks or async hardware. /// /// # Returns /// /// A Result which is Ok(GCM) on success or an Err containing the wolfSSL /// library return code on failure. pub fn new_ex(heap: Option<*mut core::ffi::c_void>, dev_id: Option) -> Result { let ws_aes = new_ws_aes(heap, dev_id)?; let gcm = GCM {ws_aes}; Ok(gcm) } /// Initialize a GCM instance for encryption or decryption. /// /// This method must be called before calling `encrypt()` or `decrypt()`. /// /// # Parameters /// /// * `key`: A slice containing the encryption key to use. The key must be /// 16, 24, or 32 bytes in length. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn init(&mut self, key: &[u8]) -> Result<(), i32> { let key_size = crate::buffer_len_to_u32(key.len())?; let rc = unsafe { sys::wc_AesGcmSetKey(&mut self.ws_aes, key.as_ptr(), key_size) }; if rc != 0 { return Err(rc); } Ok(()) } /// Encrypt data. /// /// The `init()` method must be called before calling this method. /// /// # Parameters /// /// * `din`: Data to encrypt. /// * `dout`: Buffer in which to store the encrypted data. The size of /// the buffer must match that of the `din` buffer. /// * `iv`: Initialization vector to use for the encryption operation. /// * `auth`: Authentication data input. /// * `auth_tag`: Buffer in which to store the authentication tag. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn encrypt(&mut self, din: &[u8], dout: &mut [u8], iv: &[u8], auth: &[u8], auth_tag: &mut [u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; let iv_size = crate::buffer_len_to_u32(iv.len())?; let auth_size = crate::buffer_len_to_u32(auth.len())?; let auth_tag_size = crate::buffer_len_to_u32(auth_tag.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesGcmEncrypt(&mut self.ws_aes, dout.as_mut_ptr(), din.as_ptr(), in_size, iv.as_ptr(), iv_size, auth_tag.as_mut_ptr(), auth_tag_size, auth.as_ptr(), auth_size) }; if rc != 0 { return Err(rc); } Ok(()) } /// Decrypt data. /// /// The `init()` method must be called before calling this method. /// /// # Parameters /// /// * `din`: Data to decrypt. /// * `dout`: Buffer in which to store the decrypted data. The size of /// the buffer must match that of the `din` buffer. /// * `iv`: Initialization vector to use for the decryption operation. /// * `auth`: Authentication data input. /// * `auth_tag`: Authentication tag input to verify. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn decrypt(&mut self, din: &[u8], dout: &mut [u8], iv: &[u8], auth: &[u8], auth_tag: &[u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; let iv_size = crate::buffer_len_to_u32(iv.len())?; let auth_size = crate::buffer_len_to_u32(auth.len())?; let auth_tag_size = crate::buffer_len_to_u32(auth_tag.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesGcmDecrypt(&mut self.ws_aes, dout.as_mut_ptr(), din.as_ptr(), in_size, iv.as_ptr(), iv_size, auth_tag.as_ptr(), auth_tag_size, auth.as_ptr(), auth_size) }; if rc != 0 { return Err(rc); } Ok(()) } } #[cfg(aes_gcm)] impl GCM { fn zeroize(&mut self) { unsafe { crate::zeroize_raw(&mut self.ws_aes); } } } #[cfg(aes_gcm)] impl Drop for GCM { /// Safely free the wolfSSL resources. fn drop(&mut self) { unsafe { sys::wc_AesFree(&mut self.ws_aes); } self.zeroize(); } } // --------------------------------------------------------------------------- // AES-GCM aead trait implementations // --------------------------------------------------------------------------- /// Encrypt `buffer` in-place using AES-GCM (12-byte nonce, 16-byte tag). /// /// wolfCrypt's `wc_AesGcmEncrypt` supports in-place operation (out == in). #[cfg(all(aes_gcm, feature = "aead"))] fn gcm_encrypt_in_place( key: &[u8], nonce: &[u8], aad: &[u8], buffer: &mut [u8], tag: &mut [u8], ) -> Result<(), aead::Error> { if buffer.len() > u32::MAX as usize || nonce.len() > u32::MAX as usize || tag.len() > u32::MAX as usize || aad.len() > u32::MAX as usize { return Err(aead::Error); } let mut gcm = GCM::new().map_err(|_| aead::Error)?; gcm.init(key).map_err(|_| aead::Error)?; let buf_ptr = buffer.as_mut_ptr(); let in_ptr = buf_ptr as *const u8; let rc = unsafe { sys::wc_AesGcmEncrypt( &mut gcm.ws_aes, buf_ptr, in_ptr, buffer.len() as u32, nonce.as_ptr(), nonce.len() as u32, tag.as_mut_ptr(), tag.len() as u32, aad.as_ptr(), aad.len() as u32, ) }; if rc != 0 { return Err(aead::Error); } Ok(()) } /// Decrypt `buffer` in-place using AES-GCM and verify `tag`. #[cfg(all(aes_gcm, feature = "aead"))] fn gcm_decrypt_in_place( key: &[u8], nonce: &[u8], aad: &[u8], buffer: &mut [u8], tag: &[u8], ) -> Result<(), aead::Error> { if buffer.len() > u32::MAX as usize || nonce.len() > u32::MAX as usize || tag.len() > u32::MAX as usize || aad.len() > u32::MAX as usize { return Err(aead::Error); } let mut gcm = GCM::new().map_err(|_| aead::Error)?; gcm.init(key).map_err(|_| aead::Error)?; let buf_ptr = buffer.as_mut_ptr(); let in_ptr = buf_ptr as *const u8; let rc = unsafe { sys::wc_AesGcmDecrypt( &mut gcm.ws_aes, buf_ptr, in_ptr, buffer.len() as u32, nonce.as_ptr(), nonce.len() as u32, tag.as_ptr(), tag.len() as u32, aad.as_ptr(), aad.len() as u32, ) }; if rc != 0 { return Err(aead::Error); } Ok(()) } /// AES-128-GCM authenticated encryption (12-byte nonce, 16-byte tag). #[cfg(all(aes_gcm, feature = "aead"))] #[derive(Zeroize, ZeroizeOnDrop)] pub struct Aes128Gcm { key: [u8; 16], } #[cfg(all(aes_gcm, feature = "aead"))] impl KeySizeUser for Aes128Gcm { type KeySize = U16; } #[cfg(all(aes_gcm, feature = "aead"))] impl AeadCore for Aes128Gcm { type NonceSize = U12; type TagSize = U16; type CiphertextOverhead = U0; } #[cfg(all(aes_gcm, feature = "aead"))] impl KeyInit for Aes128Gcm { fn new(key: &aead::Key) -> Self { let mut k = [0u8; 16]; k.copy_from_slice(key.as_ref()); Aes128Gcm { key: k } } } #[cfg(all(aes_gcm, feature = "aead"))] impl AeadInPlace for Aes128Gcm { fn encrypt_in_place_detached( &self, nonce: &aead::Nonce, associated_data: &[u8], buffer: &mut [u8], ) -> Result, aead::Error> { let mut tag = aead::Tag::::default(); gcm_encrypt_in_place(&self.key, nonce.as_ref(), associated_data, buffer, tag.as_mut())?; Ok(tag) } fn decrypt_in_place_detached( &self, nonce: &aead::Nonce, associated_data: &[u8], buffer: &mut [u8], tag: &aead::Tag, ) -> Result<(), aead::Error> { gcm_decrypt_in_place(&self.key, nonce.as_ref(), associated_data, buffer, tag.as_ref()) } } /// AES-256-GCM authenticated encryption (12-byte nonce, 16-byte tag). #[cfg(all(aes_gcm, feature = "aead"))] #[derive(Zeroize, ZeroizeOnDrop)] pub struct Aes256Gcm { key: [u8; 32], } #[cfg(all(aes_gcm, feature = "aead"))] impl KeySizeUser for Aes256Gcm { type KeySize = U32; } #[cfg(all(aes_gcm, feature = "aead"))] impl AeadCore for Aes256Gcm { type NonceSize = U12; type TagSize = U16; type CiphertextOverhead = U0; } #[cfg(all(aes_gcm, feature = "aead"))] impl KeyInit for Aes256Gcm { fn new(key: &aead::Key) -> Self { let mut k = [0u8; 32]; k.copy_from_slice(key.as_ref()); Aes256Gcm { key: k } } } #[cfg(all(aes_gcm, feature = "aead"))] impl AeadInPlace for Aes256Gcm { fn encrypt_in_place_detached( &self, nonce: &aead::Nonce, associated_data: &[u8], buffer: &mut [u8], ) -> Result, aead::Error> { let mut tag = aead::Tag::::default(); gcm_encrypt_in_place(&self.key, nonce.as_ref(), associated_data, buffer, tag.as_mut())?; Ok(tag) } fn decrypt_in_place_detached( &self, nonce: &aead::Nonce, associated_data: &[u8], buffer: &mut [u8], tag: &aead::Tag, ) -> Result<(), aead::Error> { gcm_decrypt_in_place(&self.key, nonce.as_ref(), associated_data, buffer, tag.as_ref()) } } /// AES Galois/Counter Mode (GCM) mode (streaming functionality). /// /// This struct provides streaming/chunking encryption and decryption /// functionality. For one-shot functionality, see the `GCM` struct instead. /// /// # Example /// ```rust /// #[cfg(aes_gcm_stream)] /// { /// use wolfssl_wolfcrypt::aes::GCMStream; /// let plain: [u8; 60] = [ /// 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, /// 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, /// 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, /// 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, /// 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, /// 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, /// 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, /// 0xba, 0x63, 0x7b, 0x39 /// ]; /// let auth: [u8; 20] = [ /// 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, /// 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, /// 0xab, 0xad, 0xda, 0xd2 /// ]; /// let key: [u8; 32] = [ /// 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, /// 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, /// 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, /// 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 /// ]; /// let iv: [u8; 12] = [ /// 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, /// 0xde, 0xca, 0xf8, 0x88 /// ]; /// let expected_cipher: [u8; 60] = [ /// 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, /// 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d, /// 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, /// 0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa, /// 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, /// 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, /// 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a, /// 0xbc, 0xc9, 0xf6, 0x62 /// ]; /// let expected_auth_tag: [u8; 16] = [ /// 0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68, /// 0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b /// ]; /// let mut gcmstream = GCMStream::new().expect("Failed to create GCMStream"); /// for chunk_size in 1..=auth.len() { /// gcmstream.init(&key, &iv).expect("Error with init()"); /// let mut cipher: [u8; 60] = [0; 60]; /// let mut i = 0; /// while i < auth.len() { /// let mut end = i + chunk_size; /// if end > auth.len() { /// end = auth.len() /// } /// gcmstream.encrypt_update(&plain[0..0], &mut cipher[0..0], &auth[i..end]).expect("Error with encrypt_update()"); /// i += chunk_size; /// } /// i = 0; /// while i < plain.len() { /// let mut end = i + chunk_size; /// if end > plain.len() { /// end = plain.len() /// } /// gcmstream.encrypt_update(&plain[i..end], &mut cipher[i..end], &auth[0..0]).expect("Error with encrypt_update()"); /// i += chunk_size; /// } /// let mut auth_tag: [u8; 16] = [0; 16]; /// gcmstream.encrypt_final(&mut auth_tag).expect("Error with encrypt_final()"); /// assert_eq!(cipher, expected_cipher); /// assert_eq!(auth_tag, expected_auth_tag); /// } /// } /// ``` #[cfg(aes_gcm_stream)] pub struct GCMStream { ws_aes: sys::Aes, } #[cfg(aes_gcm_stream)] impl GCMStream { /// Create a new `GCMStream` instance. /// /// # Returns /// /// A Result which is Ok(GCMStream) on success or an Err containing the /// wolfSSL library return code on failure. pub fn new() -> Result { Self::new_ex(None, None) } /// Create a new `GCMStream` instance with heap and device ID. /// /// # Parameters /// /// * `heap`: Optional heap hint. /// * `dev_id` Optional device ID to use with crypto callbacks or async hardware. /// /// # Returns /// /// A Result which is Ok(GCMStream) on success or an Err containing the /// wolfSSL library return code on failure. pub fn new_ex(heap: Option<*mut core::ffi::c_void>, dev_id: Option) -> Result { let ws_aes = new_ws_aes(heap, dev_id)?; let gcmstream = GCMStream {ws_aes}; Ok(gcmstream) } /// Initialize a GCMStream instance for encryption or decryption. /// /// This method must be called before calling `encrypt_update()`, /// `encrypt_final()`, `decrypt_update()`, or `decrypt_final()`. /// /// # Parameters /// /// * `key`: A slice containing the encryption key to use. The key must be /// 16, 24, or 32 bytes in length. /// * `iv`: A slice containing the initialization vector (IV) to use. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn init(&mut self, key: &[u8], iv: &[u8]) -> Result<(), i32> { let key_size = crate::buffer_len_to_u32(key.len())?; let iv_size = crate::buffer_len_to_u32(iv.len())?; let rc = unsafe { sys::wc_AesGcmInit(&mut self.ws_aes, key.as_ptr(), key_size, iv.as_ptr(), iv_size) }; if rc != 0 { return Err(rc); } Ok(()) } /// Add a chunk of data to encrypt or authentication data. /// /// All authentication data must be passed in to update before the /// plaintext to encrypt. The last part of the authentication data can be /// passed in with the same call as the first part of the plaintext data. /// /// The `init()` method must be called before calling this method. /// The `encrypt_final()` method must be called to finalize the encryption /// operation and retrieve the calculated authentication tag. /// /// # Parameters /// /// * `din`: Data to encrypt. /// * `dout`: Buffer in which to store the encrypted data. The size of /// the buffer must match that of the `din` buffer. /// * `auth`: Authentication data input. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn encrypt_update(&mut self, din: &[u8], dout: &mut [u8], auth: &[u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; let auth_size = crate::buffer_len_to_u32(auth.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesGcmEncryptUpdate(&mut self.ws_aes, dout.as_mut_ptr(), din.as_ptr(), in_size, auth.as_ptr(), auth_size) }; if rc != 0 { return Err(rc); } Ok(()) } /// Finalize encryption. /// /// The `init()` method must be called before calling this method. /// The `encrypt_update()` method must be called one or more times before /// calling this method to supply authentication data and plaintext input /// for encryption. /// /// # Parameters /// /// * `auth_tag`: Buffer in which to store the authentication tag. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn encrypt_final(&mut self, auth_tag: &mut [u8]) -> Result<(), i32> { let auth_tag_size = crate::buffer_len_to_u32(auth_tag.len())?; let rc = unsafe { sys::wc_AesGcmEncryptFinal(&mut self.ws_aes, auth_tag.as_mut_ptr(), auth_tag_size) }; if rc != 0 { return Err(rc); } Ok(()) } /// Add a chunk of data to decrypt or authentication data. /// /// All authentication data must be passed in to update before the /// ciphertext to decrypt. The last part of the authentication data can be /// passed in with the same call as the first part of the ciphertext data. /// /// The `init()` method must be called before calling this method. /// The `decrypt_final()` method must be called to finalize the decryption /// operation and verify the authentication tag. /// /// # Parameters /// /// * `din`: Data to encrypt. /// * `dout`: Buffer in which to store the decrypted data. The size of /// the buffer must match that of the `din` buffer. /// * `auth`: Authentication data input. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn decrypt_update(&mut self, din: &[u8], dout: &mut [u8], auth: &[u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; let auth_size = crate::buffer_len_to_u32(auth.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesGcmDecryptUpdate(&mut self.ws_aes, dout.as_mut_ptr(), din.as_ptr(), in_size, auth.as_ptr(), auth_size) }; if rc != 0 { return Err(rc); } Ok(()) } /// Finalize decryption. /// /// The `init()` method must be called before calling this method. /// The `decrypt_update()` method must be called one or more times before /// calling this method to supply authentication data and ciphertext input /// for decryption. /// /// # Parameters /// /// * `auth_tag`: Authentication tag input to verify. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn decrypt_final(&mut self, auth_tag: &[u8]) -> Result<(), i32> { let auth_tag_size = crate::buffer_len_to_u32(auth_tag.len())?; let rc = unsafe { sys::wc_AesGcmDecryptFinal(&mut self.ws_aes, auth_tag.as_ptr(), auth_tag_size) }; if rc != 0 { return Err(rc); } Ok(()) } } #[cfg(aes_gcm_stream)] impl GCMStream { fn zeroize(&mut self) { unsafe { crate::zeroize_raw(&mut self.ws_aes); } } } #[cfg(aes_gcm_stream)] impl Drop for GCMStream { /// Safely free the wolfSSL resources. fn drop(&mut self) { unsafe { sys::wc_AesFree(&mut self.ws_aes); } self.zeroize(); } } /// AES Output FeedBack (OFB) mode. /// /// # Example /// ```rust /// #[cfg(aes_ofb)] /// { /// use wolfssl_wolfcrypt::aes::OFB; /// let key: [u8; 32] = [ /// 0xc4,0xc7,0xfa,0xd6,0x53,0x5c,0xb8,0x71, /// 0x4a,0x5c,0x40,0x77,0x9a,0x8b,0xa1,0xd2, /// 0x53,0x3e,0x23,0xb4,0xb2,0x58,0x73,0x2a, /// 0x5b,0x78,0x01,0xf4,0xe3,0x71,0xa7,0x94 /// ]; /// let iv: [u8; 16] = [ /// 0x5e,0xb9,0x33,0x13,0xb8,0x71,0xff,0x16, /// 0xb9,0x8a,0x9b,0xcb,0x43,0x33,0x0d,0x6f /// ]; /// let plain: [u8; 48] = [ /// 0x6d,0x0b,0xb0,0x79,0x63,0x84,0x71,0xe9, /// 0x39,0xd4,0x53,0x14,0x86,0xc1,0x4c,0x25, /// 0x9a,0xee,0xc6,0xf3,0xc0,0x0d,0xfd,0xd6, /// 0xc0,0x50,0xa8,0xba,0xa8,0x20,0xdb,0x71, /// 0xcc,0x12,0x2c,0x4e,0x0c,0x17,0x15,0xef, /// 0x55,0xf3,0x99,0x5a,0x6b,0xf0,0x2a,0x4c /// ]; /// let expected_cipher: [u8; 48] = [ /// 0x0f,0x54,0x61,0x71,0x59,0xd0,0x3f,0xfc, /// 0x1b,0xfa,0xfb,0x60,0x29,0x30,0xd7,0x00, /// 0xf4,0xa4,0xa8,0xe6,0xdd,0x93,0x94,0x46, /// 0x64,0xd2,0x19,0xc4,0xc5,0x4d,0xde,0x1b, /// 0x04,0x53,0xe1,0x73,0xf5,0x18,0x74,0xae, /// 0xfd,0x64,0xa2,0xe1,0xe2,0x76,0x13,0xb0 /// ]; /// let mut ofb = OFB::new().expect("Failed to create OFB"); /// ofb.init(&key, &iv).expect("Error with init()"); /// let mut cipher: [u8; 48] = [0; 48]; /// ofb.encrypt(&plain, &mut cipher).expect("Error with encrypt()"); /// assert_eq!(cipher, expected_cipher); /// ofb.init(&key, &iv).expect("Error with init()"); /// let mut plain_out: [u8; 48] = [0; 48]; /// #[cfg(aes_decrypt)] /// { /// ofb.decrypt(&cipher, &mut plain_out).expect("Error with decrypt()"); /// assert_eq!(plain_out, plain); /// } /// } /// ``` #[cfg(aes_ofb)] pub struct OFB { ws_aes: sys::Aes, } #[cfg(aes_ofb)] impl OFB { /// Create a new `OFB` instance. /// /// # Returns /// /// A Result which is Ok(OFB) on success or an Err containing the wolfSSL /// library return code on failure. pub fn new() -> Result { Self::new_ex(None, None) } /// Create a new `OFB` instance with optional heap and device ID. /// /// # Parameters /// /// * `heap`: Optional heap hint. /// * `dev_id` Optional device ID to use with crypto callbacks or async hardware. /// /// # Returns /// /// A Result which is Ok(OFB) on success or an Err containing the wolfSSL /// library return code on failure. pub fn new_ex(heap: Option<*mut core::ffi::c_void>, dev_id: Option) -> Result { let ws_aes = new_ws_aes(heap, dev_id)?; let ofb = OFB {ws_aes}; Ok(ofb) } /// Initialize a OFB instance for encryption or decryption. /// /// This method must be called before calling `encrypt()` or `decrypt()`. /// /// # Parameters /// /// * `key`: A slice containing the encryption key to use. The key must be /// 16, 24, or 32 bytes in length. /// * `iv`: A slice containing the initialization vector (IV) to use. The /// IV must be 16 bytes in length. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn init(&mut self, key: &[u8], iv: &[u8]) -> Result<(), i32> { let key_size = crate::buffer_len_to_u32(key.len())?; if iv.len() != AES_BLOCK_SIZE { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesSetKey(&mut self.ws_aes, key.as_ptr(), key_size, iv.as_ptr(), sys::AES_ENCRYPTION as i32) }; if rc != 0 { return Err(rc); } Ok(()) } /// Encrypt data. /// /// The `init()` method must be called before calling this method. /// /// # Parameters /// /// * `din`: Data to encrypt. /// * `dout`: Buffer in which to store the encrypted data. The size of /// the buffer must match that of the `din` buffer. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn encrypt(&mut self, din: &[u8], dout: &mut [u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesOfbEncrypt(&mut self.ws_aes, dout.as_mut_ptr(), din.as_ptr(), in_size) }; if rc != 0 { return Err(rc); } Ok(()) } /// Decrypt data. /// /// The `init()` method must be called before calling this method. /// /// # Parameters /// /// * `din`: Data to decrypt. /// * `dout`: Buffer in which to store the decrypted data. The size of /// the buffer must match that of the `din` buffer. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. #[cfg(aes_decrypt)] pub fn decrypt(&mut self, din: &[u8], dout: &mut [u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesOfbDecrypt(&mut self.ws_aes, dout.as_mut_ptr(), din.as_ptr(), in_size) }; if rc != 0 { return Err(rc); } Ok(()) } } #[cfg(aes_ofb)] impl OFB { fn zeroize(&mut self) { unsafe { crate::zeroize_raw(&mut self.ws_aes); } } } #[cfg(aes_ofb)] impl Drop for OFB { /// Safely free the wolfSSL resources. fn drop(&mut self) { unsafe { sys::wc_AesFree(&mut self.ws_aes); } self.zeroize(); } } /// AES XEX-based Tweaked-Codebook Mode With Ciphertext Stealing (XTS) support /// (one shot functionality). /// /// This struct provides one-shot encryption and decryption functionality. /// For streaming/chunking functionality, see the `XTSStream` struct instead. /// /// # Example /// ```rust /// #[cfg(aes_xts)] /// { /// use wolfssl_wolfcrypt::aes::XTS; /// let key: [u8; 32] = [ /// 0xa1, 0xb9, 0x0c, 0xba, 0x3f, 0x06, 0xac, 0x35, /// 0x3b, 0x2c, 0x34, 0x38, 0x76, 0x08, 0x17, 0x62, /// 0x09, 0x09, 0x23, 0x02, 0x6e, 0x91, 0x77, 0x18, /// 0x15, 0xf2, 0x9d, 0xab, 0x01, 0x93, 0x2f, 0x2f /// ]; /// let tweak: [u8; 16] = [ /// 0x4f, 0xae, 0xf7, 0x11, 0x7c, 0xda, 0x59, 0xc6, /// 0x6e, 0x4b, 0x92, 0x01, 0x3e, 0x76, 0x8a, 0xd5 /// ]; /// let plain: [u8; 16] = [ /// 0xeb, 0xab, 0xce, 0x95, 0xb1, 0x4d, 0x3c, 0x8d, /// 0x6f, 0xb3, 0x50, 0x39, 0x07, 0x90, 0x31, 0x1c /// ]; /// let expected_cipher: [u8; 16] = [ /// 0x77, 0x8a, 0xe8, 0xb4, 0x3c, 0xb9, 0x8d, 0x5a, /// 0x82, 0x50, 0x81, 0xd5, 0xbe, 0x47, 0x1c, 0x63 /// ]; /// let partial: [u8; 24] = [ /// 0xeb, 0xab, 0xce, 0x95, 0xb1, 0x4d, 0x3c, 0x8d, /// 0x6f, 0xb3, 0x50, 0x39, 0x07, 0x90, 0x31, 0x1c, /// 0x6e, 0x4b, 0x92, 0x01, 0x3e, 0x76, 0x8a, 0xd5 /// ]; /// let expected_partial_cipher: [u8; 24] = [ /// 0x2b, 0xf7, 0x2c, 0xf3, 0xeb, 0x85, 0xef, 0x7b, /// 0x0b, 0x76, 0xa0, 0xaa, 0xf3, 0x3f, 0x25, 0x8b, /// 0x77, 0x8a, 0xe8, 0xb4, 0x3c, 0xb9, 0x8d, 0x5a /// ]; /// /// let mut xts = XTS::new().expect("Failed to create XTS"); /// xts.init_encrypt(&key).expect("Error with init_encrypt()"); /// let mut cipher: [u8; 16] = [0; 16]; /// xts.encrypt(&plain, &mut cipher, &tweak).expect("Error with encrypt()"); /// assert_eq!(cipher, expected_cipher); /// xts.init_decrypt(&key).expect("Error with init_decrypt()"); /// let mut plain_out: [u8; 16] = [0; 16]; /// xts.decrypt(&cipher, &mut plain_out, &tweak).expect("Error with decrypt()"); /// assert_eq!(plain_out, plain); /// /// xts.init_encrypt(&key).expect("Error with init_encrypt()"); /// let mut partial_cipher: [u8; 24] = [0; 24]; /// xts.encrypt(&partial, &mut partial_cipher, &tweak).expect("Error with encrypt()"); /// assert_eq!(partial_cipher, expected_partial_cipher); /// xts.init_decrypt(&key).expect("Error with init_decrypt()"); /// let mut partial_out: [u8; 24] = [0; 24]; /// xts.decrypt(&partial_cipher, &mut partial_out, &tweak).expect("Error with decrypt()"); /// assert_eq!(partial_out, partial); /// } /// ``` #[cfg(aes_xts)] pub struct XTS { ws_xtsaes: sys::XtsAes, } #[cfg(aes_xts)] impl XTS { /// Create a new `XTS` instance. /// /// # Returns /// /// A Result which is Ok(XTS) on success or an Err containing the wolfSSL /// library return code on failure. pub fn new() -> Result { Self::new_ex(None, None) } /// Create a new `XTS` instance with optional heap and device ID. /// /// # Parameters /// /// * `heap`: Optional heap hint. /// * `dev_id` Optional device ID to use with crypto callbacks or async hardware. /// /// # Returns /// /// A Result which is Ok(XTS) on success or an Err containing the wolfSSL /// library return code on failure. pub fn new_ex(heap: Option<*mut core::ffi::c_void>, dev_id: Option) -> Result { let ws_xtsaes = new_ws_xtsaes(heap, dev_id)?; let xts = XTS {ws_xtsaes}; Ok(xts) } fn init(&mut self, key: &[u8], dir: i32) -> Result<(), i32> { let key_size = crate::buffer_len_to_u32(key.len())?; let rc = unsafe { sys::wc_AesXtsSetKeyNoInit(&mut self.ws_xtsaes, key.as_ptr(), key_size, dir) }; if rc != 0 { return Err(rc); } Ok(()) } /// Initialize a XTS instance for encryption. /// /// This method must be called before calling any encryption methods. /// /// # Parameters /// /// * `key`: A slice containing the encryption key to use. The key must be /// 16, 24, or 32 bytes in length. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn init_encrypt(&mut self, key: &[u8]) -> Result<(), i32> { self.init(key, sys::AES_ENCRYPTION as i32) } /// Initialize a XTS instance for decryption. /// /// This method must be called before calling any decryption methods. /// /// # Parameters /// /// * `key`: A slice containing the decryption key to use. The key must be /// 16, 24, or 32 bytes in length. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn init_decrypt(&mut self, key: &[u8]) -> Result<(), i32> { self.init(key, sys::AES_DECRYPTION as i32) } /// Encrypt data. /// /// The `init_encrypt()` method must be called before calling this method. /// /// # Parameters /// /// * `din`: Data to encrypt. /// * `dout`: Buffer in which to store the encrypted data. The size of /// the buffer must match that of the `din` buffer. /// * `tweak`: Tweak value to use for the encryption operation. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn encrypt(&mut self, din: &[u8], dout: &mut [u8], tweak: &[u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; let tweak_size = crate::buffer_len_to_u32(tweak.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesXtsEncrypt(&mut self.ws_xtsaes, dout.as_mut_ptr(), din.as_ptr(), in_size, tweak.as_ptr(), tweak_size) }; if rc != 0 { return Err(rc); } Ok(()) } /// Encrypt a sector of data. /// /// The `init_encrypt()` method must be called before calling this method. /// /// This method is the same as `encrypt()` except that a sector number is /// taken instead of a tweak buffer. Internally the sector number is /// expanded into the tweak value to use. /// /// # Parameters /// /// * `din`: Data to encrypt. /// * `dout`: Buffer in which to store the encrypted data. The size of /// the buffer must match that of the `din` buffer. /// * `sector`: Sector number to use for encryption operation. This value /// is expanded into a tweak value. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn encrypt_sector(&mut self, din: &[u8], dout: &mut [u8], sector: u64) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesXtsEncryptSector(&mut self.ws_xtsaes, dout.as_mut_ptr(), din.as_ptr(), in_size, sector) }; if rc != 0 { return Err(rc); } Ok(()) } /// Encrypt consecutive sectors of data. /// /// The `init_encrypt()` method must be called before calling this method. /// /// This method is the same as `encrypt_sector()` except that the sector /// number is automatically incremented every `sector_size` bytes. /// /// # Parameters /// /// * `din`: Data to encrypt. /// * `dout`: Buffer in which to store the encrypted data. The size of /// the buffer must match that of the `din` buffer. /// * `sector`: Sector number to use for encryption operation. This value /// is expanded into a tweak value. /// * `sector_size`: Sector size. The `sector` value is internally /// incremented every `sector_size` bytes. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn encrypt_consecutive_sectors(&mut self, din: &[u8], dout: &mut [u8], sector: u64, sector_size: u32) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesXtsEncryptConsecutiveSectors(&mut self.ws_xtsaes, dout.as_mut_ptr(), din.as_ptr(), in_size, sector, sector_size) }; if rc != 0 { return Err(rc); } Ok(()) } /// Decrypt data. /// /// The `init_decrypt()` method must be called before calling this method. /// /// # Parameters /// /// * `din`: Data to decrypt. /// * `dout`: Buffer in which to store the decrypted data. The size of /// the buffer must match that of the `din` buffer. /// * `tweak`: Tweak value to use for the decryption operation. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn decrypt(&mut self, din: &[u8], dout: &mut [u8], tweak: &[u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; let tweak_size = crate::buffer_len_to_u32(tweak.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesXtsDecrypt(&mut self.ws_xtsaes, dout.as_mut_ptr(), din.as_ptr(), in_size, tweak.as_ptr(), tweak_size) }; if rc != 0 { return Err(rc); } Ok(()) } /// Decrypt a sector of data. /// /// The `init_decrypt()` method must be called before calling this method. /// /// This method is the same as `decrypt()` except that a sector number is /// taken instead of a tweak buffer. Internally the sector number is /// expanded into the tweak value to use. /// /// # Parameters /// /// * `din`: Data to decrypt. /// * `dout`: Buffer in which to store the decrypted data. The size of /// the buffer must match that of the `din` buffer. /// * `sector`: Sector number to use for decryption operation. This value /// is expanded into a tweak value. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn decrypt_sector(&mut self, din: &[u8], dout: &mut [u8], sector: u64) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesXtsDecryptSector(&mut self.ws_xtsaes, dout.as_mut_ptr(), din.as_ptr(), in_size, sector) }; if rc != 0 { return Err(rc); } Ok(()) } /// Decrypt consecutive sectors of data. /// /// The `init_decrypt()` method must be called before calling this method. /// /// This method is the same as `decrypt_sector()` except that the sector /// number is automatically incremented every `sector_size` bytes. /// /// # Parameters /// /// * `din`: Data to decrypt. /// * `dout`: Buffer in which to store the decrypted data. The size of /// the buffer must match that of the `din` buffer. /// * `sector`: Sector number to use for decryption operation. This value /// is expanded into a tweak value. /// * `sector_size`: Sector size. The `sector` value is internally /// incremented every `sector_size` bytes. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn decrypt_consecutive_sectors(&mut self, din: &[u8], dout: &mut [u8], sector: u64, sector_size: u32) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesXtsDecryptConsecutiveSectors(&mut self.ws_xtsaes, dout.as_mut_ptr(), din.as_ptr(), in_size, sector, sector_size) }; if rc != 0 { return Err(rc); } Ok(()) } } #[cfg(aes_xts)] impl XTS { fn zeroize(&mut self) { unsafe { crate::zeroize_raw(&mut self.ws_xtsaes); } } } #[cfg(aes_xts)] impl Drop for XTS { /// Safely free the wolfSSL resources. fn drop(&mut self) { unsafe { sys::wc_AesXtsFree(&mut self.ws_xtsaes); } self.zeroize(); } } /// AES XEX-based Tweaked-Codebook Mode With Ciphertext Stealing (XTS) support /// (streaming functionality). /// /// This struct provides streaming/chunking encryption and decryption /// functionality. For one-shot functionality, see the `XTS` struct instead. /// /// # Example /// ```rust /// #[cfg(aes_xts_stream)] /// { /// use wolfssl_wolfcrypt::aes::XTSStream; /// let keys: [u8; 32] = [ /// 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /// 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /// 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /// 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /// ]; /// let tweak: [u8; 16] = [ /// 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /// 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /// ]; /// let plain: [u8; 40] = [ /// 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /// 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /// 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /// 0x20, 0xff, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, /// 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 /// ]; /// let expected_cipher: [u8; 40] = [ /// 0xA2, 0x07, 0x47, 0x76, 0x3F, 0xEC, 0x0C, 0x23, /// 0x1B, 0xD0, 0xBD, 0x46, 0x9A, 0x27, 0x38, 0x12, /// 0x95, 0x02, 0x3D, 0x5D, 0xC6, 0x94, 0x51, 0x36, /// 0xA0, 0x85, 0xD2, 0x69, 0x6E, 0x87, 0x0A, 0xBF, /// 0xB5, 0x5A, 0xDD, 0xCB, 0x80, 0xE0, 0xFC, 0xCD /// ]; /// /// let mut xtsstream = XTSStream::new().expect("Failed to create XTSStream"); /// xtsstream.init_encrypt(&keys, &tweak).expect("Error with init_encrypt()"); /// let mut cipher: [u8; 40] = [0; 40]; /// xtsstream.encrypt_update(&plain[0..16], &mut cipher[0..16]).expect("Error with encrypt_update()"); /// xtsstream.encrypt_final(&plain[16..40], &mut cipher[16..40]).expect("Error with encrypt_final()"); /// assert_eq!(cipher, expected_cipher); /// /// xtsstream.init_decrypt(&keys, &tweak).expect("Error with init_decrypt()"); /// let mut plain_out: [u8; 40] = [0; 40]; /// xtsstream.decrypt_update(&cipher[0..16], &mut plain_out[0..16]).expect("Error with decrypt_update()"); /// xtsstream.decrypt_final(&cipher[16..40], &mut plain_out[16..40]).expect("Error with decrypt_final()"); /// assert_eq!(plain_out, plain); /// } /// ``` #[cfg(aes_xts_stream)] pub struct XTSStream { ws_xtsaes: sys::XtsAes, ws_xtsaesstreamdata: sys::XtsAesStreamData, } #[cfg(aes_xts_stream)] impl XTSStream { /// Create a new `XTSStream` instance. /// /// # Returns /// /// A Result which is Ok(XTSStream) on success or an Err containing the /// wolfSSL library return code on failure. pub fn new() -> Result { Self::new_ex(None, None) } /// Create a new `XTSStream` instance with optional heap and device ID. /// /// # Parameters /// /// * `heap`: Optional heap hint. /// * `dev_id` Optional device ID to use with crypto callbacks or async hardware. /// /// # Returns /// /// A Result which is Ok(XTSStream) on success or an Err containing the /// wolfSSL library return code on failure. pub fn new_ex(heap: Option<*mut core::ffi::c_void>, dev_id: Option) -> Result { let ws_xtsaes = new_ws_xtsaes(heap, dev_id)?; let ws_xtsaesstreamdata: MaybeUninit = MaybeUninit::zeroed(); let ws_xtsaesstreamdata = unsafe { ws_xtsaesstreamdata.assume_init() }; let xtsstream = XTSStream {ws_xtsaes, ws_xtsaesstreamdata}; Ok(xtsstream) } /// Initialize a XTSStream instance for encryption. /// /// This method must be called before calling `encrypt_update()`. /// /// # Parameters /// /// * `key`: A slice containing the encryption key to use. The key must be /// 16, 24, or 32 bytes in length. /// * `tweak`: Tweak value to use for the encryption operation. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn init_encrypt(&mut self, key: &[u8], tweak: &[u8]) -> Result<(), i32> { let key_size = crate::buffer_len_to_u32(key.len())?; let rc = unsafe { sys::wc_AesXtsSetKeyNoInit(&mut self.ws_xtsaes, key.as_ptr(), key_size, sys::AES_ENCRYPTION as i32) }; if rc != 0 { return Err(rc); } let tweak_size = crate::buffer_len_to_u32(tweak.len())?; let rc = unsafe { sys::wc_AesXtsEncryptInit(&mut self.ws_xtsaes, tweak.as_ptr(), tweak_size, &mut self.ws_xtsaesstreamdata) }; if rc != 0 { return Err(rc); } Ok(()) } /// Initialize a XTSStream instance for decryption. /// /// This method must be called before calling `decrypt_update()`. /// /// # Parameters /// /// * `key`: A slice containing the decryption key to use. The key must be /// 16, 24, or 32 bytes in length. /// * `tweak`: Tweak value to use for the decryption operation. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn init_decrypt(&mut self, key: &[u8], tweak: &[u8]) -> Result<(), i32> { let key_size = crate::buffer_len_to_u32(key.len())?; let rc = unsafe { sys::wc_AesXtsSetKeyNoInit(&mut self.ws_xtsaes, key.as_ptr(), key_size, sys::AES_DECRYPTION as i32) }; if rc != 0 { return Err(rc); } let tweak_size = crate::buffer_len_to_u32(tweak.len())?; let rc = unsafe { sys::wc_AesXtsDecryptInit(&mut self.ws_xtsaes, tweak.as_ptr(), tweak_size, &mut self.ws_xtsaesstreamdata) }; if rc != 0 { return Err(rc); } Ok(()) } /// Add a chunk of data to encrypt. /// /// The `init_encrypt()` method must be called before calling this method. /// The `encrypt_final()` method must be called to finalize the encryption /// operation. /// /// # Parameters /// /// * `din`: Data to encrypt. The size of the data must be a multiple of /// 16 bytes. A final chunk of data that is not a multiple of 16 bytes /// can be passed in to `encrypt_final()`. /// * `dout`: Buffer in which to store the encrypted data. The size of /// the buffer must match that of the `din` buffer. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn encrypt_update(&mut self, din: &[u8], dout: &mut [u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesXtsEncryptUpdate(&mut self.ws_xtsaes, dout.as_mut_ptr(), din.as_ptr(), in_size, &mut self.ws_xtsaesstreamdata) }; if rc != 0 { return Err(rc); } Ok(()) } /// Encrypt the final chunk of data. /// /// The `init_encrypt()` method must be called before calling this method. /// The `encrypt_update()` method may be called prior to this to encrypt /// blocks of data in chunks. /// /// # Parameters /// /// * `din`: Data to encrypt. The size of the data must be 0 or at least /// 16 bytes. It does not need to be a multiple of 16 bytes. /// * `dout`: Buffer in which to store the encrypted data. The size of /// the buffer must match that of the `din` buffer. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn encrypt_final(&mut self, din: &[u8], dout: &mut [u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesXtsEncryptFinal(&mut self.ws_xtsaes, dout.as_mut_ptr(), din.as_ptr(), in_size, &mut self.ws_xtsaesstreamdata) }; if rc != 0 { return Err(rc); } Ok(()) } /// Add a chunk of data to decrypt. /// /// The `init_decrypt()` method must be called before calling this method. /// The `decrypt_final()` method must be called to finalize the decryption /// operation. /// /// # Parameters /// /// * `din`: Data to decrypt. The size of the data must be a multiple of /// 16 bytes. A final chunk of data that is not a multiple of 16 bytes /// can be passed in to `decrypt_final()`. /// * `dout`: Buffer in which to store the decrypted data. The size of /// the buffer must match that of the `din` buffer. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn decrypt_update(&mut self, din: &[u8], dout: &mut [u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesXtsDecryptUpdate(&mut self.ws_xtsaes, dout.as_mut_ptr(), din.as_ptr(), in_size, &mut self.ws_xtsaesstreamdata) }; if rc != 0 { return Err(rc); } Ok(()) } /// Decrypt the final chunk of data. /// /// The `init_decrypt()` method must be called before calling this method. /// The `decrypt_update()` method may be called prior to this to decrypt /// blocks of data in chunks. /// /// # Parameters /// /// * `din`: Data to decrypt. The size of the data must be 0 or at least /// 16 bytes. It does not need to be a multiple of 16 bytes. /// * `dout`: Buffer in which to store the decrypted data. The size of /// the buffer must match that of the `din` buffer. /// /// # Returns /// /// A Result which is Ok(()) on success or an Err containing the wolfSSL /// library return code on failure. pub fn decrypt_final(&mut self, din: &[u8], dout: &mut [u8]) -> Result<(), i32> { let in_size = crate::buffer_len_to_u32(din.len())?; let out_size = crate::buffer_len_to_u32(dout.len())?; if in_size != out_size { return Err(sys::wolfCrypt_ErrorCodes_BAD_FUNC_ARG); } let rc = unsafe { sys::wc_AesXtsDecryptFinal(&mut self.ws_xtsaes, dout.as_mut_ptr(), din.as_ptr(), in_size, &mut self.ws_xtsaesstreamdata) }; if rc != 0 { return Err(rc); } Ok(()) } } #[cfg(aes_xts_stream)] impl XTSStream { fn zeroize(&mut self) { unsafe { crate::zeroize_raw(&mut self.ws_xtsaes); } } } #[cfg(aes_xts_stream)] impl Drop for XTSStream { /// Safely free the wolfSSL resources. fn drop(&mut self) { unsafe { sys::wc_AesXtsFree(&mut self.ws_xtsaes); } self.zeroize(); } } // --------------------------------------------------------------------------- // AES-ECB cipher trait implementations // --------------------------------------------------------------------------- /// AES-128 ECB block cipher (encryption) implementing [`cipher::BlockModeEncrypt`]. /// /// The key schedule is computed once during construction via /// [`cipher::KeyInit::new`] or [`cipher::KeyInit::new_from_slice`]. #[cfg(all(aes_ecb, feature = "cipher"))] pub struct Aes128EcbEnc { inner: ECB, } #[cfg(all(aes_ecb, feature = "cipher"))] impl cipher::KeySizeUser for Aes128EcbEnc { type KeySize = U16; } #[cfg(all(aes_ecb, feature = "cipher"))] impl cipher::BlockSizeUser for Aes128EcbEnc { type BlockSize = U16; } #[cfg(all(aes_ecb, feature = "cipher"))] impl cipher::KeyInit for Aes128EcbEnc { fn new(key: &cipher::Key) -> Self { let mut ecb = ECB::new().expect("wc_AesInit failed"); ecb.init_encrypt(key.as_ref()).expect("wc_AesSetKey failed"); Self { inner: ecb } } } #[cfg(all(aes_ecb, feature = "cipher"))] struct Aes128EcbEncBackend<'a>(&'a mut Aes128EcbEnc); #[cfg(all(aes_ecb, feature = "cipher"))] impl cipher::BlockSizeUser for Aes128EcbEncBackend<'_> { type BlockSize = U16; } #[cfg(all(aes_ecb, feature = "cipher"))] impl ParBlocksSizeUser for Aes128EcbEncBackend<'_> { type ParBlocksSize = cipher::typenum::consts::U1; } #[cfg(all(aes_ecb, feature = "cipher"))] impl BlockModeEncBackend for Aes128EcbEncBackend<'_> { fn encrypt_block(&mut self, mut block: cipher::InOut<'_, '_, cipher::Block>) { let in_block = *block.get_in(); let out = block.get_out(); self.0.inner.encrypt(in_block.as_ref(), out.as_mut()).expect("wc_AesEcbEncrypt failed"); } } #[cfg(all(aes_ecb, feature = "cipher"))] impl BlockModeEncrypt for Aes128EcbEnc { fn encrypt_with_backend(&mut self, f: impl BlockModeEncClosure) { f.call(&mut Aes128EcbEncBackend(self)); } } /// AES-192 ECB block cipher (encryption) implementing [`cipher::BlockModeEncrypt`]. #[cfg(all(aes_ecb, feature = "cipher"))] pub struct Aes192EcbEnc { inner: ECB, } #[cfg(all(aes_ecb, feature = "cipher"))] impl cipher::KeySizeUser for Aes192EcbEnc { type KeySize = U24; } #[cfg(all(aes_ecb, feature = "cipher"))] impl cipher::BlockSizeUser for Aes192EcbEnc { type BlockSize = U16; } #[cfg(all(aes_ecb, feature = "cipher"))] impl cipher::KeyInit for Aes192EcbEnc { fn new(key: &cipher::Key) -> Self { let mut ecb = ECB::new().expect("wc_AesInit failed"); ecb.init_encrypt(key.as_ref()).expect("wc_AesSetKey failed"); Self { inner: ecb } } } #[cfg(all(aes_ecb, feature = "cipher"))] struct Aes192EcbEncBackend<'a>(&'a mut Aes192EcbEnc); #[cfg(all(aes_ecb, feature = "cipher"))] impl cipher::BlockSizeUser for Aes192EcbEncBackend<'_> { type BlockSize = U16; } #[cfg(all(aes_ecb, feature = "cipher"))] impl ParBlocksSizeUser for Aes192EcbEncBackend<'_> { type ParBlocksSize = cipher::typenum::consts::U1; } #[cfg(all(aes_ecb, feature = "cipher"))] impl BlockModeEncBackend for Aes192EcbEncBackend<'_> { fn encrypt_block(&mut self, mut block: cipher::InOut<'_, '_, cipher::Block>) { let in_block = *block.get_in(); let out = block.get_out(); self.0.inner.encrypt(in_block.as_ref(), out.as_mut()).expect("wc_AesEcbEncrypt failed"); } } #[cfg(all(aes_ecb, feature = "cipher"))] impl BlockModeEncrypt for Aes192EcbEnc { fn encrypt_with_backend(&mut self, f: impl BlockModeEncClosure) { f.call(&mut Aes192EcbEncBackend(self)); } } /// AES-256 ECB block cipher (encryption) implementing [`cipher::BlockModeEncrypt`]. #[cfg(all(aes_ecb, feature = "cipher"))] pub struct Aes256EcbEnc { inner: ECB, } #[cfg(all(aes_ecb, feature = "cipher"))] impl cipher::KeySizeUser for Aes256EcbEnc { type KeySize = U32; } #[cfg(all(aes_ecb, feature = "cipher"))] impl cipher::BlockSizeUser for Aes256EcbEnc { type BlockSize = U16; } #[cfg(all(aes_ecb, feature = "cipher"))] impl cipher::KeyInit for Aes256EcbEnc { fn new(key: &cipher::Key) -> Self { let mut ecb = ECB::new().expect("wc_AesInit failed"); ecb.init_encrypt(key.as_ref()).expect("wc_AesSetKey failed"); Self { inner: ecb } } } #[cfg(all(aes_ecb, feature = "cipher"))] struct Aes256EcbEncBackend<'a>(&'a mut Aes256EcbEnc); #[cfg(all(aes_ecb, feature = "cipher"))] impl cipher::BlockSizeUser for Aes256EcbEncBackend<'_> { type BlockSize = U16; } #[cfg(all(aes_ecb, feature = "cipher"))] impl ParBlocksSizeUser for Aes256EcbEncBackend<'_> { type ParBlocksSize = cipher::typenum::consts::U1; } #[cfg(all(aes_ecb, feature = "cipher"))] impl BlockModeEncBackend for Aes256EcbEncBackend<'_> { fn encrypt_block(&mut self, mut block: cipher::InOut<'_, '_, cipher::Block>) { let in_block = *block.get_in(); let out = block.get_out(); self.0.inner.encrypt(in_block.as_ref(), out.as_mut()).expect("wc_AesEcbEncrypt failed"); } } #[cfg(all(aes_ecb, feature = "cipher"))] impl BlockModeEncrypt for Aes256EcbEnc { fn encrypt_with_backend(&mut self, f: impl BlockModeEncClosure) { f.call(&mut Aes256EcbEncBackend(self)); } } /// AES-128 ECB block cipher (decryption) implementing [`cipher::BlockModeDecrypt`]. /// /// The key schedule is computed once during construction via /// [`cipher::KeyInit::new`] or [`cipher::KeyInit::new_from_slice`]. #[cfg(all(aes_ecb, feature = "cipher"))] pub struct Aes128EcbDec { inner: ECB, } #[cfg(all(aes_ecb, feature = "cipher"))] impl cipher::KeySizeUser for Aes128EcbDec { type KeySize = U16; } #[cfg(all(aes_ecb, feature = "cipher"))] impl cipher::BlockSizeUser for Aes128EcbDec { type BlockSize = U16; } #[cfg(all(aes_ecb, feature = "cipher"))] impl cipher::KeyInit for Aes128EcbDec { fn new(key: &cipher::Key) -> Self { let mut ecb = ECB::new().expect("wc_AesInit failed"); ecb.init_decrypt(key.as_ref()).expect("wc_AesSetKey failed"); Self { inner: ecb } } } #[cfg(all(aes_ecb, feature = "cipher"))] struct Aes128EcbDecBackend<'a>(&'a mut Aes128EcbDec); #[cfg(all(aes_ecb, feature = "cipher"))] impl cipher::BlockSizeUser for Aes128EcbDecBackend<'_> { type BlockSize = U16; } #[cfg(all(aes_ecb, feature = "cipher"))] impl ParBlocksSizeUser for Aes128EcbDecBackend<'_> { type ParBlocksSize = cipher::typenum::consts::U1; } #[cfg(all(aes_ecb, feature = "cipher"))] impl BlockModeDecBackend for Aes128EcbDecBackend<'_> { fn decrypt_block(&mut self, mut block: cipher::InOut<'_, '_, cipher::Block>) { let in_block = *block.get_in(); let out = block.get_out(); self.0.inner.decrypt(in_block.as_ref(), out.as_mut()).expect("wc_AesEcbDecrypt failed"); } } #[cfg(all(aes_ecb, feature = "cipher"))] impl BlockModeDecrypt for Aes128EcbDec { fn decrypt_with_backend(&mut self, f: impl BlockModeDecClosure) { f.call(&mut Aes128EcbDecBackend(self)); } } /// AES-192 ECB block cipher (decryption) implementing [`cipher::BlockModeDecrypt`]. #[cfg(all(aes_ecb, feature = "cipher"))] pub struct Aes192EcbDec { inner: ECB, } #[cfg(all(aes_ecb, feature = "cipher"))] impl cipher::KeySizeUser for Aes192EcbDec { type KeySize = U24; } #[cfg(all(aes_ecb, feature = "cipher"))] impl cipher::BlockSizeUser for Aes192EcbDec { type BlockSize = U16; } #[cfg(all(aes_ecb, feature = "cipher"))] impl cipher::KeyInit for Aes192EcbDec { fn new(key: &cipher::Key) -> Self { let mut ecb = ECB::new().expect("wc_AesInit failed"); ecb.init_decrypt(key.as_ref()).expect("wc_AesSetKey failed"); Self { inner: ecb } } } #[cfg(all(aes_ecb, feature = "cipher"))] struct Aes192EcbDecBackend<'a>(&'a mut Aes192EcbDec); #[cfg(all(aes_ecb, feature = "cipher"))] impl cipher::BlockSizeUser for Aes192EcbDecBackend<'_> { type BlockSize = U16; } #[cfg(all(aes_ecb, feature = "cipher"))] impl ParBlocksSizeUser for Aes192EcbDecBackend<'_> { type ParBlocksSize = cipher::typenum::consts::U1; } #[cfg(all(aes_ecb, feature = "cipher"))] impl BlockModeDecBackend for Aes192EcbDecBackend<'_> { fn decrypt_block(&mut self, mut block: cipher::InOut<'_, '_, cipher::Block>) { let in_block = *block.get_in(); let out = block.get_out(); self.0.inner.decrypt(in_block.as_ref(), out.as_mut()).expect("wc_AesEcbDecrypt failed"); } } #[cfg(all(aes_ecb, feature = "cipher"))] impl BlockModeDecrypt for Aes192EcbDec { fn decrypt_with_backend(&mut self, f: impl BlockModeDecClosure) { f.call(&mut Aes192EcbDecBackend(self)); } } /// AES-256 ECB block cipher (decryption) implementing [`cipher::BlockModeDecrypt`]. #[cfg(all(aes_ecb, feature = "cipher"))] pub struct Aes256EcbDec { inner: ECB, } #[cfg(all(aes_ecb, feature = "cipher"))] impl cipher::KeySizeUser for Aes256EcbDec { type KeySize = U32; } #[cfg(all(aes_ecb, feature = "cipher"))] impl cipher::BlockSizeUser for Aes256EcbDec { type BlockSize = U16; } #[cfg(all(aes_ecb, feature = "cipher"))] impl cipher::KeyInit for Aes256EcbDec { fn new(key: &cipher::Key) -> Self { let mut ecb = ECB::new().expect("wc_AesInit failed"); ecb.init_decrypt(key.as_ref()).expect("wc_AesSetKey failed"); Self { inner: ecb } } } #[cfg(all(aes_ecb, feature = "cipher"))] struct Aes256EcbDecBackend<'a>(&'a mut Aes256EcbDec); #[cfg(all(aes_ecb, feature = "cipher"))] impl cipher::BlockSizeUser for Aes256EcbDecBackend<'_> { type BlockSize = U16; } #[cfg(all(aes_ecb, feature = "cipher"))] impl ParBlocksSizeUser for Aes256EcbDecBackend<'_> { type ParBlocksSize = cipher::typenum::consts::U1; } #[cfg(all(aes_ecb, feature = "cipher"))] impl BlockModeDecBackend for Aes256EcbDecBackend<'_> { fn decrypt_block(&mut self, mut block: cipher::InOut<'_, '_, cipher::Block>) { let in_block = *block.get_in(); let out = block.get_out(); self.0.inner.decrypt(in_block.as_ref(), out.as_mut()).expect("wc_AesEcbDecrypt failed"); } } #[cfg(all(aes_ecb, feature = "cipher"))] impl BlockModeDecrypt for Aes256EcbDec { fn decrypt_with_backend(&mut self, f: impl BlockModeDecClosure) { f.call(&mut Aes256EcbDecBackend(self)); } } // --------------------------------------------------------------------------- // AES-CTR cipher trait implementations // --------------------------------------------------------------------------- /// AES-128 CTR stream cipher implementing [`cipher::StreamCipher`]. /// /// wolfCrypt AES-CTR supports in-place operation, so the in/out pointers from /// the [`cipher::inout::InOutBuf`] are passed directly to `wc_AesCtrEncrypt`. #[cfg(all(aes_ctr, feature = "cipher"))] pub struct Aes128Ctr { inner: CTR, } #[cfg(all(aes_ctr, feature = "cipher"))] impl cipher::KeySizeUser for Aes128Ctr { type KeySize = U16; } #[cfg(all(aes_ctr, feature = "cipher"))] impl IvSizeUser for Aes128Ctr { type IvSize = U16; } #[cfg(all(aes_ctr, feature = "cipher"))] impl KeyIvInit for Aes128Ctr { fn new(key: &cipher::Key, iv: &cipher::Iv) -> Self { let mut ctr = CTR::new().expect("wc_AesInit failed"); ctr.init(key.as_ref(), iv.as_ref()).expect("wc_AesSetKeyDirect failed"); Self { inner: ctr } } } #[cfg(all(aes_ctr, feature = "cipher"))] impl StreamCipher for Aes128Ctr { fn check_remaining(&self, _data_len: usize) -> Result<(), StreamCipherError> { Ok(()) } fn unchecked_apply_keystream_inout(&mut self, mut buf: cipher::InOutBuf<'_, '_, u8>) { let len = buf.len(); if len == 0 { return; } assert!(len <= u32::MAX as usize, "buffer too large for wc_AesCtrEncrypt"); // wolfCrypt AES-CTR supports in-place operation (out == in). let in_ptr = buf.get_in().as_ptr(); let out_ptr = buf.get_out().as_mut_ptr(); // SAFETY: CTR in-place is valid; C function called directly to avoid // creating aliasing slices. let rc = unsafe { sys::wc_AesCtrEncrypt(&mut self.inner.ws_aes, out_ptr, in_ptr, len as u32) }; assert_eq!(rc, 0, "wc_AesCtrEncrypt failed"); } fn unchecked_write_keystream(&mut self, buf: &mut [u8]) { buf.fill(0); self.unchecked_apply_keystream_inout(buf.into()); } } /// AES-192 CTR stream cipher implementing [`cipher::StreamCipher`]. #[cfg(all(aes_ctr, feature = "cipher"))] pub struct Aes192Ctr { inner: CTR, } #[cfg(all(aes_ctr, feature = "cipher"))] impl cipher::KeySizeUser for Aes192Ctr { type KeySize = U24; } #[cfg(all(aes_ctr, feature = "cipher"))] impl IvSizeUser for Aes192Ctr { type IvSize = U16; } #[cfg(all(aes_ctr, feature = "cipher"))] impl KeyIvInit for Aes192Ctr { fn new(key: &cipher::Key, iv: &cipher::Iv) -> Self { let mut ctr = CTR::new().expect("wc_AesInit failed"); ctr.init(key.as_ref(), iv.as_ref()).expect("wc_AesSetKeyDirect failed"); Self { inner: ctr } } } #[cfg(all(aes_ctr, feature = "cipher"))] impl StreamCipher for Aes192Ctr { fn check_remaining(&self, _data_len: usize) -> Result<(), StreamCipherError> { Ok(()) } fn unchecked_apply_keystream_inout(&mut self, mut buf: cipher::InOutBuf<'_, '_, u8>) { let len = buf.len(); if len == 0 { return; } assert!(len <= u32::MAX as usize, "buffer too large for wc_AesCtrEncrypt"); let in_ptr = buf.get_in().as_ptr(); let out_ptr = buf.get_out().as_mut_ptr(); // SAFETY: CTR in-place is valid; C function called directly to avoid // creating aliasing slices. let rc = unsafe { sys::wc_AesCtrEncrypt(&mut self.inner.ws_aes, out_ptr, in_ptr, len as u32) }; assert_eq!(rc, 0, "wc_AesCtrEncrypt failed"); } fn unchecked_write_keystream(&mut self, buf: &mut [u8]) { buf.fill(0); self.unchecked_apply_keystream_inout(buf.into()); } } /// AES-256 CTR stream cipher implementing [`cipher::StreamCipher`]. #[cfg(all(aes_ctr, feature = "cipher"))] pub struct Aes256Ctr { inner: CTR, } #[cfg(all(aes_ctr, feature = "cipher"))] impl cipher::KeySizeUser for Aes256Ctr { type KeySize = U32; } #[cfg(all(aes_ctr, feature = "cipher"))] impl IvSizeUser for Aes256Ctr { type IvSize = U16; } #[cfg(all(aes_ctr, feature = "cipher"))] impl KeyIvInit for Aes256Ctr { fn new(key: &cipher::Key, iv: &cipher::Iv) -> Self { let mut ctr = CTR::new().expect("wc_AesInit failed"); ctr.init(key.as_ref(), iv.as_ref()).expect("wc_AesSetKeyDirect failed"); Self { inner: ctr } } } #[cfg(all(aes_ctr, feature = "cipher"))] impl StreamCipher for Aes256Ctr { fn check_remaining(&self, _data_len: usize) -> Result<(), StreamCipherError> { Ok(()) } fn unchecked_apply_keystream_inout(&mut self, mut buf: cipher::InOutBuf<'_, '_, u8>) { let len = buf.len(); if len == 0 { return; } assert!(len <= u32::MAX as usize, "buffer too large for wc_AesCtrEncrypt"); let in_ptr = buf.get_in().as_ptr(); let out_ptr = buf.get_out().as_mut_ptr(); // SAFETY: CTR in-place is valid; C function called directly to avoid // creating aliasing slices. let rc = unsafe { sys::wc_AesCtrEncrypt(&mut self.inner.ws_aes, out_ptr, in_ptr, len as u32) }; assert_eq!(rc, 0, "wc_AesCtrEncrypt failed"); } fn unchecked_write_keystream(&mut self, buf: &mut [u8]) { buf.fill(0); self.unchecked_apply_keystream_inout(buf.into()); } } // --------------------------------------------------------------------------- // AES-OFB cipher trait implementations // --------------------------------------------------------------------------- /// AES-128 OFB stream cipher implementing [`cipher::StreamCipher`]. /// /// OFB (Output FeedBack) generates a keystream independent of the data, so /// [`StreamCipher::apply_keystream`] is self-inverse and wolfCrypt supports /// in-place operation. #[cfg(all(aes_ofb, feature = "cipher"))] pub struct Aes128Ofb { inner: OFB, } #[cfg(all(aes_ofb, feature = "cipher"))] impl cipher::KeySizeUser for Aes128Ofb { type KeySize = U16; } #[cfg(all(aes_ofb, feature = "cipher"))] impl IvSizeUser for Aes128Ofb { type IvSize = U16; } #[cfg(all(aes_ofb, feature = "cipher"))] impl KeyIvInit for Aes128Ofb { fn new(key: &cipher::Key, iv: &cipher::Iv) -> Self { let mut ofb = OFB::new().expect("wc_AesInit failed"); ofb.init(key.as_ref(), iv.as_ref()).expect("wc_AesSetKey failed"); Self { inner: ofb } } } #[cfg(all(aes_ofb, feature = "cipher"))] impl StreamCipher for Aes128Ofb { fn check_remaining(&self, _data_len: usize) -> Result<(), StreamCipherError> { Ok(()) } fn unchecked_apply_keystream_inout(&mut self, mut buf: cipher::InOutBuf<'_, '_, u8>) { let len = buf.len(); if len == 0 { return; } assert!(len <= u32::MAX as usize, "buffer too large for wc_AesOfbEncrypt"); // wolfCrypt AES-OFB supports in-place operation (out == in). let in_ptr = buf.get_in().as_ptr(); let out_ptr = buf.get_out().as_mut_ptr(); // SAFETY: OFB in-place is valid; C function called directly to avoid // creating aliasing slices. let rc = unsafe { sys::wc_AesOfbEncrypt(&mut self.inner.ws_aes, out_ptr, in_ptr, len as u32) }; assert_eq!(rc, 0, "wc_AesOfbEncrypt failed"); } fn unchecked_write_keystream(&mut self, buf: &mut [u8]) { buf.fill(0); self.unchecked_apply_keystream_inout(buf.into()); } } /// AES-192 OFB stream cipher implementing [`cipher::StreamCipher`]. #[cfg(all(aes_ofb, feature = "cipher"))] pub struct Aes192Ofb { inner: OFB, } #[cfg(all(aes_ofb, feature = "cipher"))] impl cipher::KeySizeUser for Aes192Ofb { type KeySize = U24; } #[cfg(all(aes_ofb, feature = "cipher"))] impl IvSizeUser for Aes192Ofb { type IvSize = U16; } #[cfg(all(aes_ofb, feature = "cipher"))] impl KeyIvInit for Aes192Ofb { fn new(key: &cipher::Key, iv: &cipher::Iv) -> Self { let mut ofb = OFB::new().expect("wc_AesInit failed"); ofb.init(key.as_ref(), iv.as_ref()).expect("wc_AesSetKey failed"); Self { inner: ofb } } } #[cfg(all(aes_ofb, feature = "cipher"))] impl StreamCipher for Aes192Ofb { fn check_remaining(&self, _data_len: usize) -> Result<(), StreamCipherError> { Ok(()) } fn unchecked_apply_keystream_inout(&mut self, mut buf: cipher::InOutBuf<'_, '_, u8>) { let len = buf.len(); if len == 0 { return; } assert!(len <= u32::MAX as usize, "buffer too large for wc_AesOfbEncrypt"); let in_ptr = buf.get_in().as_ptr(); let out_ptr = buf.get_out().as_mut_ptr(); // SAFETY: OFB in-place is valid; C function called directly to avoid // creating aliasing slices. let rc = unsafe { sys::wc_AesOfbEncrypt(&mut self.inner.ws_aes, out_ptr, in_ptr, len as u32) }; assert_eq!(rc, 0, "wc_AesOfbEncrypt failed"); } fn unchecked_write_keystream(&mut self, buf: &mut [u8]) { buf.fill(0); self.unchecked_apply_keystream_inout(buf.into()); } } /// AES-256 OFB stream cipher implementing [`cipher::StreamCipher`]. #[cfg(all(aes_ofb, feature = "cipher"))] pub struct Aes256Ofb { inner: OFB, } #[cfg(all(aes_ofb, feature = "cipher"))] impl cipher::KeySizeUser for Aes256Ofb { type KeySize = U32; } #[cfg(all(aes_ofb, feature = "cipher"))] impl IvSizeUser for Aes256Ofb { type IvSize = U16; } #[cfg(all(aes_ofb, feature = "cipher"))] impl KeyIvInit for Aes256Ofb { fn new(key: &cipher::Key, iv: &cipher::Iv) -> Self { let mut ofb = OFB::new().expect("wc_AesInit failed"); ofb.init(key.as_ref(), iv.as_ref()).expect("wc_AesSetKey failed"); Self { inner: ofb } } } #[cfg(all(aes_ofb, feature = "cipher"))] impl StreamCipher for Aes256Ofb { fn check_remaining(&self, _data_len: usize) -> Result<(), StreamCipherError> { Ok(()) } fn unchecked_apply_keystream_inout(&mut self, mut buf: cipher::InOutBuf<'_, '_, u8>) { let len = buf.len(); if len == 0 { return; } assert!(len <= u32::MAX as usize, "buffer too large for wc_AesOfbEncrypt"); let in_ptr = buf.get_in().as_ptr(); let out_ptr = buf.get_out().as_mut_ptr(); // SAFETY: OFB in-place is valid; C function called directly to avoid // creating aliasing slices. let rc = unsafe { sys::wc_AesOfbEncrypt(&mut self.inner.ws_aes, out_ptr, in_ptr, len as u32) }; assert_eq!(rc, 0, "wc_AesOfbEncrypt failed"); } fn unchecked_write_keystream(&mut self, buf: &mut [u8]) { buf.fill(0); self.unchecked_apply_keystream_inout(buf.into()); } } // --------------------------------------------------------------------------- // AES-CBC block mode trait implementations // --------------------------------------------------------------------------- /// AES-128 CBC block cipher (encryption) implementing [`cipher::BlockModeEncrypt`]. /// /// CBC chains ciphertext blocks: each plaintext block is XORed with the /// previous ciphertext block (or the IV for the first block) before /// encryption. wolfCrypt maintains the IV state internally between calls, /// so blocks can be encrypted one at a time and the chaining is preserved. #[cfg(all(aes_cbc, feature = "cipher"))] pub struct Aes128CbcEnc { inner: CBC, } #[cfg(all(aes_cbc, feature = "cipher"))] impl cipher::KeySizeUser for Aes128CbcEnc { type KeySize = U16; } #[cfg(all(aes_cbc, feature = "cipher"))] impl cipher::BlockSizeUser for Aes128CbcEnc { type BlockSize = U16; } #[cfg(all(aes_cbc, feature = "cipher"))] impl IvSizeUser for Aes128CbcEnc { type IvSize = U16; } #[cfg(all(aes_cbc, feature = "cipher"))] impl KeyIvInit for Aes128CbcEnc { fn new(key: &cipher::Key, iv: &cipher::Iv) -> Self { let mut cbc = CBC::new().expect("wc_AesInit failed"); cbc.init_encrypt(key.as_ref(), iv.as_ref()).expect("wc_AesSetKey failed"); Self { inner: cbc } } } #[cfg(all(aes_cbc, feature = "cipher"))] struct Aes128CbcEncBackend<'a>(&'a mut Aes128CbcEnc); #[cfg(all(aes_cbc, feature = "cipher"))] impl cipher::BlockSizeUser for Aes128CbcEncBackend<'_> { type BlockSize = U16; } #[cfg(all(aes_cbc, feature = "cipher"))] impl ParBlocksSizeUser for Aes128CbcEncBackend<'_> { type ParBlocksSize = cipher::typenum::consts::U1; } #[cfg(all(aes_cbc, feature = "cipher"))] impl BlockModeEncBackend for Aes128CbcEncBackend<'_> { fn encrypt_block(&mut self, mut block: cipher::InOut<'_, '_, cipher::Block>) { let in_block = *block.get_in(); let out = block.get_out(); self.0.inner.encrypt(in_block.as_ref(), out.as_mut()).expect("wc_AesCbcEncrypt failed"); } } #[cfg(all(aes_cbc, feature = "cipher"))] impl BlockModeEncrypt for Aes128CbcEnc { fn encrypt_with_backend(&mut self, f: impl BlockModeEncClosure) { f.call(&mut Aes128CbcEncBackend(self)); } } /// AES-192 CBC block cipher (encryption) implementing [`cipher::BlockModeEncrypt`]. #[cfg(all(aes_cbc, feature = "cipher"))] pub struct Aes192CbcEnc { inner: CBC, } #[cfg(all(aes_cbc, feature = "cipher"))] impl cipher::KeySizeUser for Aes192CbcEnc { type KeySize = U24; } #[cfg(all(aes_cbc, feature = "cipher"))] impl cipher::BlockSizeUser for Aes192CbcEnc { type BlockSize = U16; } #[cfg(all(aes_cbc, feature = "cipher"))] impl IvSizeUser for Aes192CbcEnc { type IvSize = U16; } #[cfg(all(aes_cbc, feature = "cipher"))] impl KeyIvInit for Aes192CbcEnc { fn new(key: &cipher::Key, iv: &cipher::Iv) -> Self { let mut cbc = CBC::new().expect("wc_AesInit failed"); cbc.init_encrypt(key.as_ref(), iv.as_ref()).expect("wc_AesSetKey failed"); Self { inner: cbc } } } #[cfg(all(aes_cbc, feature = "cipher"))] struct Aes192CbcEncBackend<'a>(&'a mut Aes192CbcEnc); #[cfg(all(aes_cbc, feature = "cipher"))] impl cipher::BlockSizeUser for Aes192CbcEncBackend<'_> { type BlockSize = U16; } #[cfg(all(aes_cbc, feature = "cipher"))] impl ParBlocksSizeUser for Aes192CbcEncBackend<'_> { type ParBlocksSize = cipher::typenum::consts::U1; } #[cfg(all(aes_cbc, feature = "cipher"))] impl BlockModeEncBackend for Aes192CbcEncBackend<'_> { fn encrypt_block(&mut self, mut block: cipher::InOut<'_, '_, cipher::Block>) { let in_block = *block.get_in(); let out = block.get_out(); self.0.inner.encrypt(in_block.as_ref(), out.as_mut()).expect("wc_AesCbcEncrypt failed"); } } #[cfg(all(aes_cbc, feature = "cipher"))] impl BlockModeEncrypt for Aes192CbcEnc { fn encrypt_with_backend(&mut self, f: impl BlockModeEncClosure) { f.call(&mut Aes192CbcEncBackend(self)); } } /// AES-256 CBC block cipher (encryption) implementing [`cipher::BlockModeEncrypt`]. #[cfg(all(aes_cbc, feature = "cipher"))] pub struct Aes256CbcEnc { inner: CBC, } #[cfg(all(aes_cbc, feature = "cipher"))] impl cipher::KeySizeUser for Aes256CbcEnc { type KeySize = U32; } #[cfg(all(aes_cbc, feature = "cipher"))] impl cipher::BlockSizeUser for Aes256CbcEnc { type BlockSize = U16; } #[cfg(all(aes_cbc, feature = "cipher"))] impl IvSizeUser for Aes256CbcEnc { type IvSize = U16; } #[cfg(all(aes_cbc, feature = "cipher"))] impl KeyIvInit for Aes256CbcEnc { fn new(key: &cipher::Key, iv: &cipher::Iv) -> Self { let mut cbc = CBC::new().expect("wc_AesInit failed"); cbc.init_encrypt(key.as_ref(), iv.as_ref()).expect("wc_AesSetKey failed"); Self { inner: cbc } } } #[cfg(all(aes_cbc, feature = "cipher"))] struct Aes256CbcEncBackend<'a>(&'a mut Aes256CbcEnc); #[cfg(all(aes_cbc, feature = "cipher"))] impl cipher::BlockSizeUser for Aes256CbcEncBackend<'_> { type BlockSize = U16; } #[cfg(all(aes_cbc, feature = "cipher"))] impl ParBlocksSizeUser for Aes256CbcEncBackend<'_> { type ParBlocksSize = cipher::typenum::consts::U1; } #[cfg(all(aes_cbc, feature = "cipher"))] impl BlockModeEncBackend for Aes256CbcEncBackend<'_> { fn encrypt_block(&mut self, mut block: cipher::InOut<'_, '_, cipher::Block>) { let in_block = *block.get_in(); let out = block.get_out(); self.0.inner.encrypt(in_block.as_ref(), out.as_mut()).expect("wc_AesCbcEncrypt failed"); } } #[cfg(all(aes_cbc, feature = "cipher"))] impl BlockModeEncrypt for Aes256CbcEnc { fn encrypt_with_backend(&mut self, f: impl BlockModeEncClosure) { f.call(&mut Aes256CbcEncBackend(self)); } } /// AES-128 CBC block cipher (decryption) implementing [`cipher::BlockModeDecrypt`]. /// /// wolfCrypt maintains the IV state (last ciphertext block) internally, so /// blocks can be decrypted one at a time and the chaining is preserved. #[cfg(all(aes_cbc, feature = "cipher"))] pub struct Aes128CbcDec { inner: CBC, } #[cfg(all(aes_cbc, feature = "cipher"))] impl cipher::KeySizeUser for Aes128CbcDec { type KeySize = U16; } #[cfg(all(aes_cbc, feature = "cipher"))] impl cipher::BlockSizeUser for Aes128CbcDec { type BlockSize = U16; } #[cfg(all(aes_cbc, feature = "cipher"))] impl IvSizeUser for Aes128CbcDec { type IvSize = U16; } #[cfg(all(aes_cbc, feature = "cipher"))] impl KeyIvInit for Aes128CbcDec { fn new(key: &cipher::Key, iv: &cipher::Iv) -> Self { let mut cbc = CBC::new().expect("wc_AesInit failed"); cbc.init_decrypt(key.as_ref(), iv.as_ref()).expect("wc_AesSetKey failed"); Self { inner: cbc } } } #[cfg(all(aes_cbc, feature = "cipher"))] struct Aes128CbcDecBackend<'a>(&'a mut Aes128CbcDec); #[cfg(all(aes_cbc, feature = "cipher"))] impl cipher::BlockSizeUser for Aes128CbcDecBackend<'_> { type BlockSize = U16; } #[cfg(all(aes_cbc, feature = "cipher"))] impl ParBlocksSizeUser for Aes128CbcDecBackend<'_> { type ParBlocksSize = cipher::typenum::consts::U1; } #[cfg(all(aes_cbc, feature = "cipher"))] impl BlockModeDecBackend for Aes128CbcDecBackend<'_> { fn decrypt_block(&mut self, mut block: cipher::InOut<'_, '_, cipher::Block>) { let in_block = *block.get_in(); let out = block.get_out(); self.0.inner.decrypt(in_block.as_ref(), out.as_mut()).expect("wc_AesCbcDecrypt failed"); } } #[cfg(all(aes_cbc, feature = "cipher"))] impl BlockModeDecrypt for Aes128CbcDec { fn decrypt_with_backend(&mut self, f: impl BlockModeDecClosure) { f.call(&mut Aes128CbcDecBackend(self)); } } /// AES-192 CBC block cipher (decryption) implementing [`cipher::BlockModeDecrypt`]. #[cfg(all(aes_cbc, feature = "cipher"))] pub struct Aes192CbcDec { inner: CBC, } #[cfg(all(aes_cbc, feature = "cipher"))] impl cipher::KeySizeUser for Aes192CbcDec { type KeySize = U24; } #[cfg(all(aes_cbc, feature = "cipher"))] impl cipher::BlockSizeUser for Aes192CbcDec { type BlockSize = U16; } #[cfg(all(aes_cbc, feature = "cipher"))] impl IvSizeUser for Aes192CbcDec { type IvSize = U16; } #[cfg(all(aes_cbc, feature = "cipher"))] impl KeyIvInit for Aes192CbcDec { fn new(key: &cipher::Key, iv: &cipher::Iv) -> Self { let mut cbc = CBC::new().expect("wc_AesInit failed"); cbc.init_decrypt(key.as_ref(), iv.as_ref()).expect("wc_AesSetKey failed"); Self { inner: cbc } } } #[cfg(all(aes_cbc, feature = "cipher"))] struct Aes192CbcDecBackend<'a>(&'a mut Aes192CbcDec); #[cfg(all(aes_cbc, feature = "cipher"))] impl cipher::BlockSizeUser for Aes192CbcDecBackend<'_> { type BlockSize = U16; } #[cfg(all(aes_cbc, feature = "cipher"))] impl ParBlocksSizeUser for Aes192CbcDecBackend<'_> { type ParBlocksSize = cipher::typenum::consts::U1; } #[cfg(all(aes_cbc, feature = "cipher"))] impl BlockModeDecBackend for Aes192CbcDecBackend<'_> { fn decrypt_block(&mut self, mut block: cipher::InOut<'_, '_, cipher::Block>) { let in_block = *block.get_in(); let out = block.get_out(); self.0.inner.decrypt(in_block.as_ref(), out.as_mut()).expect("wc_AesCbcDecrypt failed"); } } #[cfg(all(aes_cbc, feature = "cipher"))] impl BlockModeDecrypt for Aes192CbcDec { fn decrypt_with_backend(&mut self, f: impl BlockModeDecClosure) { f.call(&mut Aes192CbcDecBackend(self)); } } /// AES-256 CBC block cipher (decryption) implementing [`cipher::BlockModeDecrypt`]. #[cfg(all(aes_cbc, feature = "cipher"))] pub struct Aes256CbcDec { inner: CBC, } #[cfg(all(aes_cbc, feature = "cipher"))] impl cipher::KeySizeUser for Aes256CbcDec { type KeySize = U32; } #[cfg(all(aes_cbc, feature = "cipher"))] impl cipher::BlockSizeUser for Aes256CbcDec { type BlockSize = U16; } #[cfg(all(aes_cbc, feature = "cipher"))] impl IvSizeUser for Aes256CbcDec { type IvSize = U16; } #[cfg(all(aes_cbc, feature = "cipher"))] impl KeyIvInit for Aes256CbcDec { fn new(key: &cipher::Key, iv: &cipher::Iv) -> Self { let mut cbc = CBC::new().expect("wc_AesInit failed"); cbc.init_decrypt(key.as_ref(), iv.as_ref()).expect("wc_AesSetKey failed"); Self { inner: cbc } } } #[cfg(all(aes_cbc, feature = "cipher"))] struct Aes256CbcDecBackend<'a>(&'a mut Aes256CbcDec); #[cfg(all(aes_cbc, feature = "cipher"))] impl cipher::BlockSizeUser for Aes256CbcDecBackend<'_> { type BlockSize = U16; } #[cfg(all(aes_cbc, feature = "cipher"))] impl ParBlocksSizeUser for Aes256CbcDecBackend<'_> { type ParBlocksSize = cipher::typenum::consts::U1; } #[cfg(all(aes_cbc, feature = "cipher"))] impl BlockModeDecBackend for Aes256CbcDecBackend<'_> { fn decrypt_block(&mut self, mut block: cipher::InOut<'_, '_, cipher::Block>) { let in_block = *block.get_in(); let out = block.get_out(); self.0.inner.decrypt(in_block.as_ref(), out.as_mut()).expect("wc_AesCbcDecrypt failed"); } } #[cfg(all(aes_cbc, feature = "cipher"))] impl BlockModeDecrypt for Aes256CbcDec { fn decrypt_with_backend(&mut self, f: impl BlockModeDecClosure) { f.call(&mut Aes256CbcDecBackend(self)); } } fn new_ws_aes(heap: Option<*mut core::ffi::c_void>, dev_id: Option) -> Result { let heap = match heap { Some(heap) => heap, None => core::ptr::null_mut(), }; let dev_id = match dev_id { Some(dev_id) => dev_id, None => sys::INVALID_DEVID, }; let mut ws_aes: MaybeUninit = MaybeUninit::uninit(); let rc = unsafe { sys::wc_AesInit(ws_aes.as_mut_ptr(), heap, dev_id) }; if rc != 0 { return Err(rc); } let ws_aes = unsafe { ws_aes.assume_init() }; Ok(ws_aes) } #[cfg(any(aes_xts, aes_xts_stream))] fn new_ws_xtsaes(heap: Option<*mut core::ffi::c_void>, dev_id: Option) -> Result { let heap = match heap { Some(heap) => heap, None => core::ptr::null_mut(), }; let dev_id = match dev_id { Some(dev_id) => dev_id, None => sys::INVALID_DEVID, }; let mut ws_xtsaes: MaybeUninit = MaybeUninit::uninit(); let rc = unsafe { sys::wc_AesXtsInit(ws_xtsaes.as_mut_ptr(), heap, dev_id) }; if rc != 0 { return Err(rc); } let ws_xtsaes = unsafe { ws_xtsaes.assume_init() }; Ok(ws_xtsaes) }