Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enabled psa_mac_compute and psa_mac_verify functions. #143

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
bits: 256,
lifetime: Lifetime::Volatile,
policy: Policy {
usage_flags: usage,
permitted_algorithms: Algorithm::Mac(*alg),
},
}
}

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];
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)?;
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
Loading