From 34d5398163c16ab3f97865778c2088ae8af4ebfc Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mon, 6 Jan 2025 18:39:52 -0500 Subject: [PATCH] Add doc string for the AES modules Signed-off-by: Simo Sorce --- src/aes.rs | 38 +++++++++++ src/ossl/aes.rs | 166 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 199 insertions(+), 5 deletions(-) diff --git a/src/aes.rs b/src/aes.rs index 6fb7cc8..af37571 100644 --- a/src/aes.rs +++ b/src/aes.rs @@ -13,9 +13,15 @@ use crate::ossl::aes::*; use once_cell::sync::Lazy; +/// Smallest AES Key Size (128 bits) pub const MIN_AES_SIZE_BYTES: usize = 16; /* 128 bits */ +/// Medium AES Key size (192 bits) pub const MID_AES_SIZE_BYTES: usize = 24; /* 192 bits */ +/// Biggest AES Key Size (256 bits) pub const MAX_AES_SIZE_BYTES: usize = 32; /* 256 bits */ + +/// The AES block size is 128 bits (16 bytes) for all currently implemented +/// variants pub const AES_BLOCK_SIZE: usize = 16; pub(crate) fn check_key_len(len: usize) -> Result<()> { @@ -25,6 +31,14 @@ pub(crate) fn check_key_len(len: usize) -> Result<()> { } } +/// The AES Key Factory object +/// +/// Derives from the generic ObjectFactory, CommonKeyFactory and +/// SecretKeyFactory +/// +/// This is used to store the list of attributes allowed for an AES Key object, as well as provide +/// method for generic manipulation of AES key objects (generation, derivation, wrapping ...) + #[derive(Debug)] pub struct AesKeyFactory { attributes: Vec, @@ -169,9 +183,22 @@ impl SecretKeyFactory for AesKeyFactory { } } +/// A statically allocated Key Factory facility. +/// +/// Static allocation allows a single implementation to be shared by all users. +/// Factories store data that does not change for the life of the application +/// so it is safe to allocate them only once. static AES_KEY_FACTORY: Lazy> = Lazy::new(|| Box::new(AesKeyFactory::new())); +/// The Generic AES Mechanism object +/// +/// Implements access to the Mechanisms functions applicable to the AES +/// cryptosystem. +/// The mechanism function can implement a crypto operation directly or return +/// an allocated [AesOperation] object for operations that need to keep data +/// around until they complete. + #[derive(Debug)] pub(crate) struct AesMechanism { info: CK_MECHANISM_INFO, @@ -405,6 +432,12 @@ impl Mechanism for AesMechanism { } } +/// AES KDF Operation implementation +/// +/// An AES Operation specific for Key Derivation that uses the AES cipher +/// with various modes as the PRF to compute a derived key +/// Implements [Derive] + #[derive(Debug)] struct AesKDFOperation<'a> { mech: CK_MECHANISM_TYPE, @@ -416,6 +449,7 @@ struct AesKDFOperation<'a> { } impl AesKDFOperation<'_> { + /// Helper function to register the AES KDF Mechanisms fn register_mechanisms(mechs: &mut Mechanisms) { if mechs.get(CKM_AES_ECB).is_ok() { mechs.add_mechanism( @@ -439,6 +473,7 @@ impl AesKDFOperation<'_> { } } + /// Instantiates a new CKM_AES_ECB based KDF operation fn aes_ecb_new<'a>( params: CK_KEY_DERIVATION_STRING_DATA, ) -> Result> { @@ -463,6 +498,7 @@ impl AesKDFOperation<'_> { }) } + /// Instantiates a new CKM_AES_CBC based KDF operation fn aes_cbc_new<'a>( params: CK_AES_CBC_ENCRYPT_DATA_PARAMS, ) -> Result> { @@ -499,6 +535,7 @@ impl MechOperation for AesKDFOperation<'_> { } impl Derive for AesKDFOperation<'_> { + /// Derives a Key using the parameters set on the AESKDFOperation object fn derive( &mut self, key: &Object, @@ -546,6 +583,7 @@ impl Derive for AesKDFOperation<'_> { } } +/// Registers all implemented AES Mechanisms and Factories pub fn register(mechs: &mut Mechanisms, ot: &mut ObjectFactories) { AesOperation::register_mechanisms(mechs); AesKDFOperation::register_mechanisms(mechs); diff --git a/src/ossl/aes.rs b/src/ossl/aes.rs index 43db389..9d92e42 100644 --- a/src/ossl/aes.rs +++ b/src/ossl/aes.rs @@ -35,9 +35,14 @@ const AES_128_WRAP_PAD_NAME: &[u8; 17] = b"AES-128-WRAP-PAD\0"; const AES_192_WRAP_PAD_NAME: &[u8; 17] = b"AES-192-WRAP-PAD\0"; const AES_256_WRAP_PAD_NAME: &[u8; 17] = b"AES-256-WRAP-PAD\0"; -/* It is safe to share const ciphers as they do not change once they have been - * created, and reference static function pointers and other data that is - * always valid */ +/// AES EVP_CIPHER Object Wrapper +/// +/// Gives access to the underlying OpenSSL Cipher context for a specific +/// OpenSSL AES cipher mode. +/// +/// It is safe to share const ciphers as they do not change once they have +/// been created, and reference static function pointers and other data that +/// is always valid struct AesCipher { cipher: Option, } @@ -120,6 +125,10 @@ aes_cipher!(AES_128_WRAP_PAD; AES_128_WRAP_PAD_NAME); aes_cipher!(AES_192_WRAP_PAD; AES_192_WRAP_PAD_NAME); aes_cipher!(AES_256_WRAP_PAD; AES_256_WRAP_PAD_NAME); +/// A raw AES Key wrapper +/// +/// Ensures the data is zeroized on deallocation + #[derive(Debug)] struct AesKey { raw: Vec, @@ -131,12 +140,14 @@ impl Drop for AesKey { } } +/// Returns an allocated [AesKey] object, given a AES Key Object fn object_to_raw_key(key: &Object) -> Result { let val = key.get_attr_as_bytes(CKA_VALUE)?; check_key_len(val.len())?; Ok(AesKey { raw: val.clone() }) } +/// Helper function to allocate AesMechanism definition objects fn new_mechanism(flags: CK_FLAGS) -> Box { Box::new(AesMechanism::new( CK_ULONG::try_from(MIN_AES_SIZE_BYTES).unwrap(), @@ -145,6 +156,11 @@ fn new_mechanism(flags: CK_FLAGS) -> Box { )) } +/// AES Initialization Vector Object +/// +/// Defines the characteristics of the IV to be used in the AES operation +/// it is referenced from. Size, generation method, counter, etc.. + #[derive(Debug)] struct AesIvData { buf: Vec, @@ -181,6 +197,13 @@ impl Drop for AesIvData { } } +/// AES Parameters Object +/// +/// Defines the parameters used for the associated AES operation. Holds +/// the IV definitions, maximum number of blocks that can be encrypted, +/// whether Cipher stealing mode is on. As well as data length, Additional +/// Authenticated Data and the Tag length for authenticated modes. + #[derive(Debug)] struct AesParams { iv: AesIvData, @@ -199,6 +222,11 @@ impl AesParams { } } +/// The Generic AES Operation data structure +/// +/// Provides access to all the low level encryption.decryption/etc functions +/// required to implement the AES cryptosystem + #[derive(Debug)] pub struct AesOperation { mech: CK_MECHANISM_TYPE, @@ -221,6 +249,7 @@ impl Drop for AesOperation { } impl AesOperation { + /// Helper function to register all AES Mechanisms pub fn register_mechanisms(mechs: &mut Mechanisms) { for ckm in &[ CKM_AES_ECB, @@ -267,6 +296,8 @@ impl AesOperation { mechs.add_mechanism(CKM_AES_KEY_GEN, new_mechanism(CKF_GENERATE)); } + /// Helper function to initialize the AES operation parameters based on + /// the provided CK_MECHANISM structure fn init_params(mech: &CK_MECHANISM) -> Result { match mech.mechanism { CKM_AES_CCM => { @@ -488,6 +519,8 @@ impl AesOperation { } } + /// Helper function to get the correct EVP_CIPHER context from the + /// provided AES mechanism type. fn get_cipher( mech: CK_MECHANISM_TYPE, keylen: usize, @@ -579,6 +612,11 @@ impl AesOperation { }) } + /// Helper function that generate IVs according to the parameters + /// stored in the object. + /// + /// Each call returns the next IV and updates counters or any other + /// data in the operation object as needed. fn generate_iv(&mut self) -> Result<()> { let genbits = self.params.iv.buf.len() * 8 - self.params.iv.fixedbits; if self.params.iv.counter == 0 { @@ -644,6 +682,9 @@ impl AesOperation { Ok(()) } + /// Helper function to prepare the IV for the next operation. + /// It may generate a new IV or use what is provided (eg in the + /// decryption case) fn prep_iv(&mut self) -> Result<()> { if self.params.iv.gen != CKG_NO_GENERATE { self.generate_iv()?; @@ -664,6 +705,8 @@ impl AesOperation { Ok(()) } + /// Helper function to add CTS mode to the parameters + /// array to be passed to OpenSSL functions. fn cts_params(&mut self, params: &mut OsslParam) -> Result<()> { params.add_const_c_string( name_as_char(OSSL_CIPHER_PARAM_CTS_MODE), @@ -676,6 +719,8 @@ impl AesOperation { ) } + /// Helper function for setting up CCM tag lengths on the + /// underlying EVP_CIPHER_CTX OpenSSL context. fn ccm_tag_len(&mut self) -> Result<()> { let res = unsafe { EVP_CIPHER_CTX_ctrl( @@ -692,6 +737,11 @@ impl AesOperation { } } + /// Encryption Initialization helper + /// + /// Sets up all the required context or parameters setting to direct + /// the underlying OpenSSL crypto library, based on the configured + /// mechanism and all the parameters stored on the object. fn encrypt_initialize(&mut self) -> Result<()> { let evpcipher = match Self::get_cipher(self.mech, self.key.raw.len()) { Ok(c) => c, @@ -793,6 +843,11 @@ impl AesOperation { Ok(()) } + /// Decryption Initialization helper + /// + /// Sets up all the required context or parameters setting to direct + /// the underlying OpenSSL crypto library, based on the configured + /// mechanism and all the parameters stored on the object. fn decrypt_initialize(&mut self) -> Result<()> { let evpcipher = match Self::get_cipher(self.mech, self.key.raw.len()) { Ok(c) => c, @@ -898,6 +953,7 @@ impl AesOperation { Ok(()) } + /// Instantiates a new Encryption AES Operation pub fn encrypt_new( mech: &CK_MECHANISM, key: &Object, @@ -917,6 +973,7 @@ impl AesOperation { }) } + /// Instantiates a new Decryption AES Operation pub fn decrypt_new( mech: &CK_MECHANISM, key: &Object, @@ -936,6 +993,7 @@ impl AesOperation { }) } + /// Instantiates a new AES Key-Wrap Operation pub fn wrap( mech: &CK_MECHANISM, wrapping_key: &Object, @@ -972,6 +1030,7 @@ impl AesOperation { result } + /// Instantiates a new AES Key-Unwrap Operation pub fn unwrap( mech: &CK_MECHANISM, wrapping_key: &Object, @@ -984,12 +1043,15 @@ impl AesOperation { Ok(result) } + /// Internal helper for dealing with fatal errors fn op_err(&mut self, err: CK_RV) -> error::Error { self.finalized = true; error::Error::ck_rv(err) } - /* returns pointer to IV */ + /// Helper to set paramters for Message Based operations + /// + /// Returns a pointer to the IV/Nonce buffer provided by the application fn init_msg_params( &mut self, parameter: CK_VOID_PTR, @@ -1152,7 +1214,9 @@ impl AesOperation { } } - /* returns pointer to tag */ + /// Verifies the message encryption parameters on subsequent calls + /// + /// Returns a pointer to the Tag/Mac buffer provided by the application fn check_msg_params( &mut self, parameter: CK_VOID_PTR, @@ -1238,6 +1302,7 @@ impl AesOperation { } } + /// Instantiates a messaged-based encryption operation pub fn msg_encrypt_init( mech: &CK_MECHANISM, key: &Object, @@ -1262,6 +1327,7 @@ impl AesOperation { }) } + /// Inintializes a new messaged-based encryption fn msg_encrypt_new( &mut self, parameter: CK_VOID_PTR, @@ -1304,6 +1370,7 @@ impl AesOperation { Ok(()) } + /// Instantiates a messaged-based decryption operation pub fn msg_decrypt_init( mech: &CK_MECHANISM, key: &Object, @@ -1328,6 +1395,7 @@ impl AesOperation { }) } + /// Inintializes a new messaged-based decryption fn msg_decrypt_new( &mut self, parameter: CK_VOID_PTR, @@ -1365,6 +1433,7 @@ impl AesOperation { Ok(()) } + /// AEAD specific FIPS checks #[cfg(feature = "fips")] fn fips_approval_aead(&mut self) -> Result<()> { /* For AEAD we handle indicators directly because OpenSSL has an @@ -1426,6 +1495,10 @@ impl MechOperation for AesOperation { } impl Encryption for AesOperation { + /// One shot encryption implementation + /// + /// Internally calls [AesOperation::encrypt_update] and + /// [AesOperation::encrypt_final] fn encrypt(&mut self, plain: &[u8], cipher: &mut [u8]) -> Result { if self.finalized { return Err(CKR_OPERATION_NOT_INITIALIZED)?; @@ -1437,6 +1510,8 @@ impl Encryption for AesOperation { Ok(outl + self.encrypt_final(&mut cipher[outl..])?) } + /// Calls the underlying OpenSSL function to encrypt the plaintext buffer + /// provided, according to the configured mode fn encrypt_update( &mut self, plain: &[u8], @@ -1543,6 +1618,10 @@ impl Encryption for AesOperation { Ok(usize::try_from(outl)?) } + /// Calls the underlying OpenSSL function to finalize the encryption + /// operation, according to the configured mode + /// + /// May return additional data in the cipher buffer fn encrypt_final(&mut self, cipher: &mut [u8]) -> Result { if self.finalized { return Err(CKR_OPERATION_NOT_INITIALIZED)?; @@ -1661,6 +1740,11 @@ impl Encryption for AesOperation { Ok(outlen) } + /// Provides the expect buffer size for the provided input plaintext length + /// based on the selected mode of operation. + /// + /// May return different values depending on the internal status and the + /// mode of operation. fn encryption_len(&mut self, data_len: usize, fin: bool) -> Result { if self.finalized { return Err(CKR_OPERATION_NOT_INITIALIZED)?; @@ -1723,6 +1807,10 @@ impl Encryption for AesOperation { } impl Decryption for AesOperation { + /// One shot decryption implementation + /// + /// Internally calls [AesOperation::decrypt_update] and + /// [AesOperation::decrypt_final] fn decrypt(&mut self, cipher: &[u8], plain: &mut [u8]) -> Result { if self.finalized { return Err(CKR_OPERATION_NOT_INITIALIZED)?; @@ -1741,6 +1829,8 @@ impl Decryption for AesOperation { Ok(outlen + self.decrypt_final(&mut plain[outlen..])?) } + /// Calls the underlying OpenSSL function to decrypt the ciphertext buffer + /// provided, according to the configured mode fn decrypt_update( &mut self, cipher: &[u8], @@ -1940,6 +2030,10 @@ impl Decryption for AesOperation { Ok(outlen) } + /// Calls the underlying OpenSSL function to finalize the decryption + /// operation, according to the configured mode + /// + /// May return additional data in the plain buffer fn decrypt_final(&mut self, plain: &mut [u8]) -> Result { if self.finalized { return Err(CKR_OPERATION_NOT_INITIALIZED)?; @@ -2056,6 +2150,11 @@ impl Decryption for AesOperation { Ok(outlen) } + /// Provides the expect buffer size for the provided input ciphertext length + /// based on the selected mode of operation. + /// + /// May return different values depending on the internal status and the + /// mode of operation. fn decryption_len(&mut self, data_len: usize, fin: bool) -> Result { if self.finalized { return Err(CKR_OPERATION_NOT_INITIALIZED)?; @@ -2142,6 +2241,10 @@ impl MessageOperation for AesOperation { } impl MsgEncryption for AesOperation { + /// One Shot message-based encryption implementation + /// + /// Internally calls [AesOperation::msg_encrypt_begin] and + /// [AesOperation::msg_encrypt_final] fn msg_encrypt( &mut self, param: CK_VOID_PTR, @@ -2154,6 +2257,7 @@ impl MsgEncryption for AesOperation { self.msg_encrypt_final(param, paramlen, plain, cipher) } + /// Begin a new message based encryption fn msg_encrypt_begin( &mut self, param: CK_VOID_PTR, @@ -2166,6 +2270,9 @@ impl MsgEncryption for AesOperation { self.msg_encrypt_new(param, paramlen, aad) } + /// Feed the next plaintext buffer to be encrypted + /// + /// Returns output data in the provided cipher buffer fn msg_encrypt_next( &mut self, param: CK_VOID_PTR, @@ -2218,6 +2325,9 @@ impl MsgEncryption for AesOperation { Ok(usize::try_from(outl)?) } + /// Feed the final plaintext buffer to be encrypted + /// + /// Returns output data in the provided cipher buffer fn msg_encrypt_final( &mut self, param: CK_VOID_PTR, @@ -2310,6 +2420,8 @@ impl MsgEncryption for AesOperation { Ok(outlen) } + /// Provides the expect buffer size for the provided input plaintext length + /// based on the selected mode of operation. fn msg_encryption_len( &mut self, data_len: usize, @@ -2327,6 +2439,10 @@ impl MsgEncryption for AesOperation { } impl MsgDecryption for AesOperation { + /// One Shot message-based decryption implementation + /// + /// Internally calls [AesOperation::msg_decrypt_begin] and + /// [AesOperation::msg_decrypt_final] fn msg_decrypt( &mut self, param: CK_VOID_PTR, @@ -2339,6 +2455,7 @@ impl MsgDecryption for AesOperation { self.msg_decrypt_final(param, paramlen, cipher, plain) } + /// Begin a new message based decryption fn msg_decrypt_begin( &mut self, param: CK_VOID_PTR, @@ -2351,6 +2468,9 @@ impl MsgDecryption for AesOperation { self.msg_decrypt_new(param, paramlen, aad) } + /// Feed the next ciphertext buffer to be decrypted + /// + /// Returns output data in the provided plain buffer fn msg_decrypt_next( &mut self, param: CK_VOID_PTR, @@ -2403,6 +2523,9 @@ impl MsgDecryption for AesOperation { Ok(usize::try_from(outl)?) } + /// Feed the final ciphertext buffer to be decrypted + /// + /// Returns output data in the provided plain buffer fn msg_decrypt_final( &mut self, param: CK_VOID_PTR, @@ -2499,6 +2622,8 @@ impl MsgDecryption for AesOperation { Ok(outlen) } + /// Provides the expect buffer size for the provided input plaintext length + /// based on the selected mode of operation. fn msg_decryption_len( &mut self, data_len: usize, @@ -2532,12 +2657,14 @@ pub struct AesCmacOperation { } impl AesCmacOperation { + /// Helper to register the CMAC mechanisms pub fn register_mechanisms(mechs: &mut Mechanisms) { for ckm in &[CKM_AES_CMAC, CKM_AES_CMAC_GENERAL] { mechs.add_mechanism(*ckm, new_mechanism(CKF_SIGN | CKF_VERIFY)); } } + /// Initializes and returns a CMAC operation pub fn init(mech: &CK_MECHANISM, key: &Object) -> Result { let maclen = match mech.mechanism { CKM_AES_CMAC_GENERAL => { @@ -2593,6 +2720,7 @@ impl AesCmacOperation { }) } + /// Begins a CMAC computation fn begin(&mut self) -> Result<()> { if self.in_use { return Err(CKR_OPERATION_NOT_INITIALIZED)?; @@ -2600,6 +2728,7 @@ impl AesCmacOperation { Ok(()) } + /// Feeds the next data buffer into the CMAC computation fn update(&mut self, data: &[u8]) -> Result<()> { if self.finalized { return Err(CKR_OPERATION_NOT_INITIALIZED)?; @@ -2616,6 +2745,8 @@ impl AesCmacOperation { Ok(()) } + /// Finalizes the CMAC computation and returns the output in the + /// provided buffer fn finalize(&mut self, output: &mut [u8]) -> Result<()> { if self.finalized { return Err(CKR_OPERATION_NOT_INITIALIZED)?; @@ -2650,6 +2781,7 @@ impl AesCmacOperation { Ok(()) } + /// CMAC specific FIPS checks #[cfg(feature = "fips")] fn fips_approval_cmac(&mut self) -> Result<()> { /* @@ -2679,6 +2811,9 @@ impl MechOperation for AesCmacOperation { } } +/// Implements the (internal) Mac interface for the AES CMAC operation +/// +/// All methods just call the related the internal method impl Mac for AesCmacOperation { fn mac(&mut self, data: &[u8], mac: &mut [u8]) -> Result<()> { self.begin()?; @@ -2701,6 +2836,9 @@ impl Mac for AesCmacOperation { } } +/// Implements the Sign interface for the AES CMAC operation +/// +/// All methods just call the related the internal method impl Sign for AesCmacOperation { fn sign(&mut self, data: &[u8], signature: &mut [u8]) -> Result<()> { self.begin()?; @@ -2723,6 +2861,9 @@ impl Sign for AesCmacOperation { } } +/// Implements the Verify interface for the AES CMAC operation +/// +/// All methods just call the related the internal method impl Verify for AesCmacOperation { fn verify(&mut self, data: &[u8], signature: &[u8]) -> Result<()> { self.begin()?; @@ -2750,6 +2891,9 @@ impl Verify for AesCmacOperation { } } +/// The AES MAC operation object +/// +/// This object is used to hold data for any AES MAC operation #[derive(Debug)] pub struct AesMacOperation { mech: CK_MECHANISM_TYPE, @@ -2773,12 +2917,14 @@ impl Drop for AesMacOperation { #[allow(dead_code)] impl AesMacOperation { + /// Helper to register the MAC mechanisms pub fn register_mechanisms(mechs: &mut Mechanisms) { for ckm in &[CKM_AES_MAC, CKM_AES_MAC_GENERAL] { mechs.add_mechanism(*ckm, new_mechanism(CKF_SIGN | CKF_VERIFY)); } } + /// Initializes and returns a MAC operation pub fn init(mech: &CK_MECHANISM, key: &Object) -> Result { let maclen = match mech.mechanism { CKM_AES_MAC_GENERAL => { @@ -2819,6 +2965,7 @@ impl AesMacOperation { }) } + /// Begins a MAC computation fn begin(&mut self) -> Result<()> { if self.in_use { return Err(CKR_OPERATION_NOT_INITIALIZED)?; @@ -2826,6 +2973,7 @@ impl AesMacOperation { Ok(()) } + /// Feeds the next data buffer into the MAC computation fn update(&mut self, data: &[u8]) -> Result<()> { if self.finalized { return Err(CKR_OPERATION_NOT_INITIALIZED)?; @@ -2874,6 +3022,8 @@ impl AesMacOperation { Ok(()) } + /// Finalizes the MAC computation and returns the output in the + /// provided buffer fn finalize(&mut self, output: &mut [u8]) -> Result<()> { if !self.in_use { return Err(CKR_OPERATION_NOT_INITIALIZED)?; @@ -2921,6 +3071,9 @@ impl MechOperation for AesMacOperation { } } +/// Implements the Sign interface for the AES MAC operation +/// +/// All methods just call the related the internal method impl Sign for AesMacOperation { fn sign(&mut self, data: &[u8], signature: &mut [u8]) -> Result<()> { self.begin()?; @@ -2941,6 +3094,9 @@ impl Sign for AesMacOperation { } } +/// Implements the Verify interface for the AES MAC operation +/// +/// All methods just call the related the internal method impl Verify for AesMacOperation { fn verify(&mut self, data: &[u8], signature: &[u8]) -> Result<()> { self.begin()?;