Skip to content

Commit

Permalink
Enabled the psa_mac_compute and psa_mac_verify functions.
Browse files Browse the repository at this point in the history
Added new tests, fixed doc tests and formatted code.

Signed-off-by: Mike Smoot <[email protected]>
  • Loading branch information
mes5k committed Mar 4, 2024
1 parent 7695a58 commit e067249
Show file tree
Hide file tree
Showing 5 changed files with 250 additions and 60 deletions.
113 changes: 57 additions & 56 deletions psa-crypto/src/operations/mac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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})),
/// # },
/// # };
/// #
Expand All @@ -42,89 +40,92 @@ 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<usize> {
pub fn compute_mac(
key_id: Id,
mac_alg: Mac,
input_message: &[u8],
mac: &mut [u8],
) -> Result<usize> {
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});
/// let buffer_size = attributes.mac_length(mac_alg).unwrap();
/// 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
}
)
})
.to_result()
}
4 changes: 2 additions & 2 deletions psa-crypto/src/operations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
12 changes: 10 additions & 2 deletions psa-crypto/src/types/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,9 +431,17 @@ impl Attributes {
#[cfg(feature = "interface")]
pub fn mac_length(self, mac_alg: Mac) -> Result<usize> {
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
Expand Down
180 changes: 180 additions & 0 deletions psa-crypto/tests/mac.rs
Original file line number Diff line number Diff line change
@@ -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");
}
Loading

0 comments on commit e067249

Please sign in to comment.