From e0672497c5dcc1c0eece8e35c91841f6e78eab34 Mon Sep 17 00:00:00 2001 From: Mike Smoot Date: Sun, 18 Feb 2024 10:25:10 -0800 Subject: [PATCH 1/4] Enabled the psa_mac_compute and psa_mac_verify functions. Added new tests, fixed doc tests and formatted code. Signed-off-by: Mike Smoot --- psa-crypto/src/operations/mac.rs | 113 +++++++++---------- psa-crypto/src/operations/mod.rs | 4 +- psa-crypto/src/types/key.rs | 12 ++- psa-crypto/tests/mac.rs | 180 +++++++++++++++++++++++++++++++ psa-crypto/tests/mod.rs | 1 + 5 files changed, 250 insertions(+), 60 deletions(-) create mode 100644 psa-crypto/tests/mac.rs diff --git a/psa-crypto/src/operations/mac.rs b/psa-crypto/src/operations/mac.rs index 87ff6cf..1654aab 100644 --- a/psa-crypto/src/operations/mac.rs +++ b/psa-crypto/src/operations/mac.rs @@ -4,34 +4,32 @@ //! # Message Authentication Code (MAC) operations use crate::initialized; -use crate::types::key::Id; use crate::types::algorithm::Mac; -use crate::types::status::{Result, Status, Error}; - +use crate::types::key::Id; +use crate::types::status::{Result, Status}; /// Calculate the message authentication code (MAC) of a message -/// The key must allow `sign_message` +/// The key must allow `sign_hash` /// /// # Example /// /// ``` /// use psa_crypto::operations::{mac::compute_mac, key_management::generate}; -/// use psa_crypto::types::algorithm::{Hash, Mac, FullLengthMac}; +/// use psa_crypto::types::algorithm::{Algorithm, Hash, Mac, FullLengthMac}; /// use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags}; /// # const MESSAGE: [u8; 32] = [ /// # 0x69, 0x3E, 0xDB, 0x1B, 0x22, 0x79, 0x03, 0xF4, 0xC0, 0xBF, 0xD6, 0x91, 0x76, 0x37, 0x84, 0xA2, /// # 0x94, 0x8E, 0x92, 0x50, 0x35, 0xC2, 0x8C, 0x5C, 0x3C, 0xCA, 0xFE, 0x18, 0xE8, 0x81, 0x37, 0x78, /// # ]; +/// # let mut usage = UsageFlags::default(); +/// # let _ = usage.set_sign_hash().set_verify_hash(); /// # let mut attributes = Attributes { -/// # key_type: Type::RsaKeyPair, -/// # bits: 1024, +/// # key_type: Type::Hmac, +/// # bits: 256, /// # lifetime: Lifetime::Volatile, /// # policy: Policy { -/// # usage_flags: UsageFlags { -/// # sign_message: true, -/// # ..Default::default() -/// # }, -/// # permitted_algorithms: FullLengthMac::Hmac{hash_alg: Hash::Sha256}.into(), +/// # usage_flags: usage, +/// # permitted_algorithms: Algorithm::Mac(Mac::FullLength(FullLengthMac::Hmac{hash_alg: Hash::Sha256})), /// # }, /// # }; /// # @@ -42,60 +40,62 @@ use crate::types::status::{Result, Status, Error}; /// let mut mac = vec![0; buffer_size]; /// /// let size = compute_mac(my_key, -/// mac_alg, -/// &MESSAGE, -/// &mut mac).unwrap(); +/// mac_alg, +/// &MESSAGE, +/// &mut mac).unwrap(); /// mac.resize(size, 0); /// ``` -pub fn compute_mac(key_id: Id, mac_alg: Mac, input_message: &[u8], mac: &mut [u8]) -> Result { +pub fn compute_mac( + key_id: Id, + mac_alg: Mac, + input_message: &[u8], + mac: &mut [u8], +) -> Result { initialized()?; let mut output_length = 0; - let key_handle = key_id.handle()?; let mac_compute_res = Status::from(unsafe { psa_crypto_sys::psa_mac_compute( - key_handle, + key_id.0, mac_alg.into(), input_message.as_ptr(), input_message.len(), mac.as_mut_ptr(), mac.len(), &mut output_length, - )} - ).to_result(); - let close_handle_res = key_id.close_handle(key_handle); + ) + }) + .to_result(); mac_compute_res?; - close_handle_res?; Ok(output_length) } /// Calculate the message authentication code (MAC) of a message and compare it with a reference value -/// The key must allow `sign_message` +/// The key must allow `verify_hash` /// /// # Example /// /// ``` /// use psa_crypto::operations::{mac::{compute_mac, verify_mac}, key_management::generate}; -/// use psa_crypto::types::algorithm::{Hash, Mac, FullLengthMac}; +/// use psa_crypto::types::algorithm::{Algorithm, Hash, Mac, FullLengthMac}; /// use psa_crypto::types::key::{Attributes, Type, Lifetime, Policy, UsageFlags}; -/// # const MESSAGE: [u8; 32] = [ -/// # 0x69, 0x3E, 0xDB, 0x1B, 0x22, 0x79, 0x03, 0xF4, 0xC0, 0xBF, 0xD6, 0x91, 0x76, 0x37, 0x84, 0xA2, -/// # 0x94, 0x8E, 0x92, 0x50, 0x35, 0xC2, 0x8C, 0x5C, 0x3C, 0xCA, 0xFE, 0x18, 0xE8, 0x81, 0x37, 0x78, -/// # ]; -/// # let mut attributes = Attributes { -/// # key_type: Type::RsaKeyPair, -/// # bits: 1024, -/// # lifetime: Lifetime::Volatile, -/// # policy: Policy { -/// # usage_flags: UsageFlags { -/// # sign_message: true, -/// # ..Default::default() -/// # }, -/// # permitted_algorithms: Mac::FullLength(FullLengthMac::Hmac{hash_alg: Hash::Sha256}).into(), -/// # }, -/// # }; -/// # +/// const MESSAGE: [u8; 32] = [ +/// 0x69, 0x3E, 0xDB, 0x1B, 0x22, 0x79, 0x03, 0xF4, 0xC0, 0xBF, 0xD6, 0x91, 0x76, 0x37, 0x84, 0xA2, +/// 0x94, 0x8E, 0x92, 0x50, 0x35, 0xC2, 0x8C, 0x5C, 0x3C, 0xCA, 0xFE, 0x18, 0xE8, 0x81, 0x37, 0x78, +/// ]; +/// let mut usage = UsageFlags::default(); +/// let _ = usage.set_sign_hash().set_verify_hash(); +/// let mut attributes = Attributes { +/// key_type: Type::Hmac, +/// bits: 256, +/// lifetime: Lifetime::Volatile, +/// policy: Policy { +/// usage_flags: usage, +/// permitted_algorithms: Algorithm::Mac(Mac::FullLength(FullLengthMac::Hmac{hash_alg: Hash::Sha256})), +/// }, +/// }; +/// /// psa_crypto::init().unwrap(); /// let my_key = generate(attributes, None).unwrap(); /// let mac_alg = Mac::FullLength(FullLengthMac::Hmac{hash_alg: Hash::Sha256}); @@ -103,28 +103,29 @@ pub fn compute_mac(key_id: Id, mac_alg: Mac, input_message: &[u8], mac: &mut [u8 /// let mut mac = vec![0; buffer_size]; /// /// let size = compute_mac(my_key, -/// mac_alg, -/// &MESSAGE, -/// &mut mac).unwrap(); +/// mac_alg, +/// &MESSAGE, +/// &mut mac).unwrap(); /// mac.resize(size, 0); -/// assert!(verify_mac(my_key, mac_alg, &MESSAGE, &mac)); +/// verify_mac(my_key, mac_alg, &MESSAGE, &mac).unwrap(); /// ``` -pub fn verify_mac(key_id: Id, mac_alg: Mac, input_message: &[u8], expected_mac: &[u8]) -> Result<()> { +pub fn verify_mac( + key_id: Id, + mac_alg: Mac, + input_message: &[u8], + expected_mac: &[u8], +) -> Result<()> { initialized()?; - let key_handle = key_id.handle()?; - - let mac_verify_res = Status::from(unsafe { + Status::from(unsafe { psa_crypto_sys::psa_mac_verify( - key_handle, + key_id.0, mac_alg.into(), input_message.as_ptr(), input_message.len(), expected_mac.as_ptr(), expected_mac.len(), - )} - ).to_result(); - let close_handle_res = key_id.close_handle(key_handle); - mac_verify_res?; - close_handle_res -} \ No newline at end of file + ) + }) + .to_result() +} diff --git a/psa-crypto/src/operations/mod.rs b/psa-crypto/src/operations/mod.rs index 557aad9..bae7e7c 100644 --- a/psa-crypto/src/operations/mod.rs +++ b/psa-crypto/src/operations/mod.rs @@ -7,10 +7,10 @@ pub mod aead; pub mod asym_encryption; pub mod asym_signature; pub mod cipher; +pub mod hash; pub mod key_agreement; pub mod key_derivation; pub mod key_management; -//pub mod mac; Mbed Crypto does not support mac compute or verify yet (as of 16/07/20) -pub mod hash; +pub mod mac; pub mod message_digest; pub mod other; diff --git a/psa-crypto/src/types/key.rs b/psa-crypto/src/types/key.rs index ca359a3..41cac79 100644 --- a/psa-crypto/src/types/key.rs +++ b/psa-crypto/src/types/key.rs @@ -431,9 +431,17 @@ impl Attributes { #[cfg(feature = "interface")] pub fn mac_length(self, mac_alg: Mac) -> Result { self.compatible_with_alg(mac_alg.into())?; - Ok(unsafe { + let size = unsafe { psa_crypto_sys::PSA_MAC_LENGTH(self.key_type.try_into()?, self.bits, mac_alg.into()) - }) + }; + // PSA_MAC_LENGTH will return 0 for incompatible algorithms + // and other errors. Since we need > 0 mac_length to allocate + // space for the mac itself, treat 0 as an error. + if size > 0 { + Ok(size) + } else { + Err(Error::DataInvalid) + } } /// Sufficient buffer size for an encrypted message using the given aead algorithm diff --git a/psa-crypto/tests/mac.rs b/psa-crypto/tests/mac.rs new file mode 100644 index 0000000..1ef00bc --- /dev/null +++ b/psa-crypto/tests/mac.rs @@ -0,0 +1,180 @@ +use psa_crypto::operations::key_management::import; +use psa_crypto::operations::mac::{compute_mac, verify_mac}; +use psa_crypto::types::algorithm::{Algorithm, FullLengthMac, Hash, Mac}; +use psa_crypto::types::key::{Attributes, Lifetime, Policy, Type, UsageFlags}; +use psa_crypto::types::status::Result; + +const KEY: [u8; 32] = [ + 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, + 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, +]; + +// "hello mac" +const MESSAGE: [u8; 9] = [0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x6d, 0x61, 0x63]; + +const EXPECTED_HMAC_SHA256: [u8; 32] = [ + 0x6d, 0x20, 0x70, 0xf, 0x9, 0x82, 0x70, 0xf8, 0x6c, 0x42, 0x13, 0xbe, 0xff, 0x13, 0x68, 0x3c, + 0x31, 0x79, 0xce, 0xf5, 0x68, 0x56, 0xde, 0xf9, 0xb9, 0x5f, 0x72, 0x9, 0x62, 0xf4, 0xd, 0x8a, +]; +const EXPECTED_HMAC_RIPEMD160: [u8; 20] = [ + 0x39, 0xcf, 0x6b, 0xbd, 0x4a, 0xd6, 0xfd, 0x2c, 0x23, 0xb5, 0xa4, 0x1d, 0x94, 0xe3, 0xde, 0x7f, + 0x1c, 0xa3, 0xf0, 0x73, +]; +const EXPECTED_CMAC_AES: [u8; 16] = [ + 0x2b, 0x93, 0xe2, 0xaa, 0x77, 0xb2, 0xb1, 0xe7, 0xa, 0x12, 0xb, 0xfc, 0xaf, 0x47, 0x12, 0xc4, +]; + +const NOT_EXPECTED: [u8; 1] = [0x00]; + +fn get_attrs(alg: &Mac, key_type: Type) -> Attributes { + let mut usage = UsageFlags::default(); + let _ = usage.set_sign_hash().set_verify_hash(); + Attributes { + key_type: key_type.clone(), + bits: 256, + lifetime: Lifetime::Volatile, + policy: Policy { + usage_flags: usage, + permitted_algorithms: Algorithm::Mac(alg.clone()), + }, + } +} + +fn test_mac_compute(mac_alg: Mac, key_type: Type, expected: &[u8]) -> Result<()> { + println!("{:?}", &mac_alg); + let attributes = get_attrs(&mac_alg, key_type); + psa_crypto::init()?; + let my_key = import(attributes, None, &KEY)?; + let buffer_size = attributes.mac_length(mac_alg)?; + let mut mac = vec![0; buffer_size]; + let _size = compute_mac(my_key, mac_alg, &MESSAGE, &mut mac)?; + assert_eq!(expected, mac); + Ok(()) +} + +fn test_mac_verify(mac_alg: Mac, key_type: Type, expected: &[u8]) -> Result<()> { + println!("{:?}", &mac_alg); + let attributes = get_attrs(&mac_alg, key_type); + psa_crypto::init()?; + let my_key = import(attributes, None, &KEY)?; + let _size = verify_mac(my_key, mac_alg, &MESSAGE, &expected)?; + Ok(()) +} + +#[test] +fn mac_compute_full_hmac_sha256() { + let mac_alg = Mac::FullLength(FullLengthMac::Hmac { + hash_alg: Hash::Sha256, + }); + test_mac_compute(mac_alg, Type::Hmac, &EXPECTED_HMAC_SHA256).expect("successful mac"); +} + +#[test] +fn mac_compute_full_hmac_ripemd160() { + let mac_alg = Mac::FullLength(FullLengthMac::Hmac { + hash_alg: Hash::Ripemd160, + }); + test_mac_compute(mac_alg, Type::Hmac, &EXPECTED_HMAC_RIPEMD160).expect("successful mac"); +} + +#[test] +fn mac_compute_full_cmac() { + let mac_alg = Mac::FullLength(FullLengthMac::Cmac); + test_mac_compute(mac_alg, Type::Aes, &EXPECTED_CMAC_AES).expect("successful mac"); +} + +#[test] +fn mac_compute_full_cbcmac() { + let mac_alg = Mac::FullLength(FullLengthMac::CbcMac); + test_mac_compute(mac_alg, Type::Aes, &NOT_EXPECTED).expect_err("CbcMac not supported"); +} + +#[test] +fn mac_compute_truncated_hmac_sha256() { + let mac_alg = Mac::Truncated { + mac_alg: FullLengthMac::Hmac { + hash_alg: Hash::Sha256, + }, + mac_length: 10, + }; + test_mac_compute(mac_alg, Type::Hmac, &EXPECTED_HMAC_SHA256[0..10]).expect("successful mac"); +} + +#[test] +fn mac_compute_truncated_hmac_ripemd160() { + let mac_alg = Mac::Truncated { + mac_alg: FullLengthMac::Hmac { + hash_alg: Hash::Ripemd160, + }, + mac_length: 10, + }; + test_mac_compute(mac_alg, Type::Hmac, &EXPECTED_HMAC_RIPEMD160[0..10]).expect("successful mac"); +} + +#[test] +fn mac_compute_truncated_cmac() { + let mac_alg = Mac::Truncated { + mac_alg: FullLengthMac::Cmac, + mac_length: 10, + }; + test_mac_compute(mac_alg, Type::Aes, &EXPECTED_CMAC_AES[0..10]).expect("successful mac"); +} + +#[test] +fn mac_verify_full_hmac_sha256() { + let mac_alg = Mac::FullLength(FullLengthMac::Hmac { + hash_alg: Hash::Sha256, + }); + test_mac_verify(mac_alg, Type::Hmac, &EXPECTED_HMAC_SHA256).expect("successful mac"); +} + +#[test] +fn mac_verify_full_hmac_ripemd160() { + let mac_alg = Mac::FullLength(FullLengthMac::Hmac { + hash_alg: Hash::Ripemd160, + }); + test_mac_verify(mac_alg, Type::Hmac, &EXPECTED_HMAC_RIPEMD160).expect("successful mac"); +} + +#[test] +fn mac_verify_full_cmac() { + let mac_alg = Mac::FullLength(FullLengthMac::Cmac); + test_mac_verify(mac_alg, Type::Aes, &EXPECTED_CMAC_AES).expect("successful mac"); +} + +#[test] +fn mac_verify_full_cbcmac() { + let mac_alg = Mac::FullLength(FullLengthMac::CbcMac); + test_mac_verify(mac_alg, Type::Aes, &NOT_EXPECTED).expect_err("CbcMac not supported"); +} + +#[test] +fn mac_verify_truncated_hmac_sha256() { + let mac_alg = Mac::Truncated { + mac_alg: FullLengthMac::Hmac { + hash_alg: Hash::Sha256, + }, + mac_length: 10, + }; + test_mac_verify(mac_alg, Type::Hmac, &EXPECTED_HMAC_SHA256[0..10]).expect("successful mac"); +} + +#[test] +fn mac_verify_truncated_hmac_ripemd160() { + let mac_alg = Mac::Truncated { + mac_alg: FullLengthMac::Hmac { + hash_alg: Hash::Ripemd160, + }, + mac_length: 10, + }; + test_mac_verify(mac_alg, Type::Hmac, &EXPECTED_HMAC_RIPEMD160[0..10]).expect("successful mac"); +} + +#[test] +fn mac_verify_truncated_cmac() { + let mac_alg = Mac::Truncated { + mac_alg: FullLengthMac::Cmac, + mac_length: 10, + }; + test_mac_verify(mac_alg, Type::Aes, &EXPECTED_CMAC_AES[0..10]).expect("successful mac"); +} diff --git a/psa-crypto/tests/mod.rs b/psa-crypto/tests/mod.rs index d8aa07b..05a4b5e 100644 --- a/psa-crypto/tests/mod.rs +++ b/psa-crypto/tests/mod.rs @@ -9,6 +9,7 @@ use psa_crypto::types::key::{Attributes, EccFamily, Lifetime, Policy, Type, Usag mod aead; mod hash; mod key_agreement; +mod mac; #[test] fn generate_integration_test() { From 714c656c3c71e8012455af206e828f9bbd0c22fe Mon Sep 17 00:00:00 2001 From: Mike Smoot Date: Tue, 5 Mar 2024 20:04:51 -0800 Subject: [PATCH 2/4] Fixed format error. Signed-off-by: Mike Smoot --- psa-crypto/src/operations/mac.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/psa-crypto/src/operations/mac.rs b/psa-crypto/src/operations/mac.rs index 1654aab..3b8e5d8 100644 --- a/psa-crypto/src/operations/mac.rs +++ b/psa-crypto/src/operations/mac.rs @@ -95,7 +95,7 @@ pub fn compute_mac( /// permitted_algorithms: Algorithm::Mac(Mac::FullLength(FullLengthMac::Hmac{hash_alg: Hash::Sha256})), /// }, /// }; -/// +/// /// psa_crypto::init().unwrap(); /// let my_key = generate(attributes, None).unwrap(); /// let mac_alg = Mac::FullLength(FullLengthMac::Hmac{hash_alg: Hash::Sha256}); From b459b7061fd1ae8f9f49eda83c3472e87b4c6847 Mon Sep 17 00:00:00 2001 From: Mike Smoot Date: Sat, 16 Mar 2024 13:49:23 -0700 Subject: [PATCH 3/4] Fixed clippy complaints. Signed-off-by: Mike Smoot --- psa-crypto/tests/mac.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/psa-crypto/tests/mac.rs b/psa-crypto/tests/mac.rs index 1ef00bc..3d926a1 100644 --- a/psa-crypto/tests/mac.rs +++ b/psa-crypto/tests/mac.rs @@ -30,12 +30,12 @@ fn get_attrs(alg: &Mac, key_type: Type) -> Attributes { let mut usage = UsageFlags::default(); let _ = usage.set_sign_hash().set_verify_hash(); Attributes { - key_type: key_type.clone(), + key_type, bits: 256, lifetime: Lifetime::Volatile, policy: Policy { usage_flags: usage, - permitted_algorithms: Algorithm::Mac(alg.clone()), + permitted_algorithms: Algorithm::Mac(*alg), }, } } @@ -47,7 +47,7 @@ fn test_mac_compute(mac_alg: Mac, key_type: Type, expected: &[u8]) -> Result<()> let my_key = import(attributes, None, &KEY)?; let buffer_size = attributes.mac_length(mac_alg)?; let mut mac = vec![0; buffer_size]; - let _size = compute_mac(my_key, mac_alg, &MESSAGE, &mut mac)?; + compute_mac(my_key, mac_alg, &MESSAGE, &mut mac)?; assert_eq!(expected, mac); Ok(()) } @@ -57,7 +57,7 @@ fn test_mac_verify(mac_alg: Mac, key_type: Type, expected: &[u8]) -> Result<()> let attributes = get_attrs(&mac_alg, key_type); psa_crypto::init()?; let my_key = import(attributes, None, &KEY)?; - let _size = verify_mac(my_key, mac_alg, &MESSAGE, &expected)?; + verify_mac(my_key, mac_alg, &MESSAGE, expected)?; Ok(()) } From d59ecb0520f5f339834a6c2aa6d5c9a6fa3504a9 Mon Sep 17 00:00:00 2001 From: Mike Smoot Date: Mon, 18 Mar 2024 08:11:17 -0700 Subject: [PATCH 4/4] Fixed NEW clippy complaint. Signed-off-by: Mike Smoot --- psa-crypto/src/operations/cipher.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/psa-crypto/src/operations/cipher.rs b/psa-crypto/src/operations/cipher.rs index b61ada7..763d07a 100644 --- a/psa-crypto/src/operations/cipher.rs +++ b/psa-crypto/src/operations/cipher.rs @@ -32,7 +32,7 @@ fn crypt( let mut output_length = 0; let mut output_length_finish = 0; - match (|| { + let mut inner_crypt = || { Status::from(unsafe { psa_crypto_sys::psa_cipher_set_iv(&mut operation, iv.as_ptr(), iv.len()) }) @@ -61,7 +61,8 @@ fn crypt( .to_result()?; Ok(()) - })() { + }; + match inner_crypt() { Ok(()) => (), Err(x) => { Status::from(unsafe { psa_crypto_sys::psa_cipher_abort(&mut operation) })