// Licensed under the Apache License, Version 2.0 or the MIT license // , at your // 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, 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) }