Source code
Revision control
Copy as Markdown
Other Tools
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(non_camel_case_types)]
use std::{convert::TryFrom as _, ptr};
use pkcs11_bindings::CKA_SIGN;
use crate::{
Error, SECItemBorrowed,
err::IntoResult as _,
hash,
hash::HashAlgorithm,
p11,
p11::{
PK11_CreateContextBySymKey, PK11_DigestFinal, PK11_DigestOp, PK11_ImportSymKey, PK11Origin,
Slot,
},
};
//
// Constants
//
pub enum HmacAlgorithm {
HMAC_SHA2_256,
HMAC_SHA2_384,
HMAC_SHA2_512,
}
#[allow(clippy::allow_attributes)]
#[allow(clippy::useless_conversion)]
fn hmac_alg_to_ckm(alg: &HmacAlgorithm) -> p11::CK_MECHANISM_TYPE {
match alg {
HmacAlgorithm::HMAC_SHA2_256 => p11::CKM_SHA256_HMAC.into(),
HmacAlgorithm::HMAC_SHA2_384 => p11::CKM_SHA384_HMAC.into(),
HmacAlgorithm::HMAC_SHA2_512 => p11::CKM_SHA512_HMAC.into(),
}
}
#[must_use]
pub const fn hmac_alg_to_hash_alg(alg: &HmacAlgorithm) -> HashAlgorithm {
match alg {
HmacAlgorithm::HMAC_SHA2_256 => HashAlgorithm::SHA2_256,
HmacAlgorithm::HMAC_SHA2_384 => HashAlgorithm::SHA2_384,
HmacAlgorithm::HMAC_SHA2_512 => HashAlgorithm::SHA2_512,
}
}
#[must_use]
pub const fn hmac_alg_to_hmac_len(alg: &HmacAlgorithm) -> usize {
let hash_alg = hmac_alg_to_hash_alg(alg);
hash::hash_alg_to_hash_len(&hash_alg)
}
#[expect(clippy::cast_possible_truncation)]
pub fn hmac(alg: &HmacAlgorithm, key: &[u8], data: &[u8]) -> Result<Vec<u8>, Error> {
crate::init()?;
let Ok(data_len) = u32::try_from(data.len()) else {
return Err(Error::Internal);
};
let slot = Slot::internal()?;
let sym_key = unsafe {
PK11_ImportSymKey(
*slot,
hmac_alg_to_ckm(alg),
PK11Origin::PK11_OriginUnwrap,
CKA_SIGN,
SECItemBorrowed::wrap(key)?.as_mut(),
ptr::null_mut(),
)
.into_result()?
};
let param = SECItemBorrowed::make_empty();
let context = unsafe {
PK11_CreateContextBySymKey(hmac_alg_to_ckm(alg), CKA_SIGN, *sym_key, param.as_ref())
.into_result()?
};
unsafe {
PK11_DigestOp(*context, data.as_ptr(), data_len).into_result()?;
}
let expected_len = hmac_alg_to_hmac_len(alg);
let mut digest = vec![0u8; expected_len];
let mut digest_len = 0u32;
unsafe {
PK11_DigestFinal(
*context,
digest.as_mut_ptr(),
&raw mut digest_len,
digest.len() as u32,
)
.into_result()?;
}
assert_eq!(digest_len as usize, expected_len);
Ok(digest)
}