1use crypto_core::{CryptoError, MacAlgorithm, MacFailureKind, MacHash};
6use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
7
8pub const HMAC_SHA256_TAG_LENGTH: usize = 32;
10pub const HMAC_SHA512_TAG_LENGTH: usize = 64;
12pub const HMAC_MAX_KEY_LENGTH: usize = 4096;
18
19#[derive(Zeroize, ZeroizeOnDrop)]
24pub struct HmacKey {
25 bytes: Zeroizing<Vec<u8>>,
26}
27
28impl HmacKey {
29 pub fn from_slice(input: &[u8]) -> Result<Self, CryptoError> {
35 if input.is_empty() || input.len() > HMAC_MAX_KEY_LENGTH {
36 return Err(CryptoError::Mac {
37 hash: MacHash::Sha2_256,
38 kind: MacFailureKind::InvalidKeyLength,
39 });
40 }
41
42 Ok(Self {
43 bytes: Zeroizing::new(input.to_vec()),
44 })
45 }
46
47 pub fn as_bytes(&self) -> &[u8] {
49 &self.bytes
50 }
51}
52
53#[derive(Clone, PartialEq, Eq, Zeroize, ZeroizeOnDrop)]
55pub struct HmacTag {
56 bytes: [u8; HMAC_SHA512_TAG_LENGTH],
57 len: usize,
58}
59
60impl HmacTag {
61 pub fn from_slice(algorithm: MacAlgorithm, input: &[u8]) -> Result<Self, CryptoError> {
63 let expected = tag_length(algorithm);
64 if input.len() != expected {
65 return Err(CryptoError::Mac {
66 hash: mac_hash(algorithm),
67 kind: MacFailureKind::InvalidTagLength,
68 });
69 }
70
71 let mut bytes = [0u8; HMAC_SHA512_TAG_LENGTH];
72 bytes[..expected].copy_from_slice(input);
73 Ok(Self {
74 bytes,
75 len: expected,
76 })
77 }
78
79 pub fn as_bytes(&self) -> &[u8] {
81 &self.bytes[..self.len]
82 }
83
84 pub fn len(&self) -> usize {
86 self.len
87 }
88
89 pub fn is_empty(&self) -> bool {
91 self.len == 0
92 }
93
94 pub fn into_vec(self) -> Vec<u8> {
96 self.as_bytes().to_vec()
97 }
98}
99
100impl core::fmt::Debug for HmacTag {
101 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
102 write!(f, "HmacTag(len={})", self.len)
103 }
104}
105
106pub(crate) fn tag_length(algorithm: MacAlgorithm) -> usize {
107 match algorithm {
108 MacAlgorithm::HmacSha256 => HMAC_SHA256_TAG_LENGTH,
109 MacAlgorithm::HmacSha512 => HMAC_SHA512_TAG_LENGTH,
110 }
111}
112
113pub(crate) fn mac_hash(algorithm: MacAlgorithm) -> MacHash {
114 match algorithm {
115 MacAlgorithm::HmacSha256 => MacHash::Sha2_256,
116 MacAlgorithm::HmacSha512 => MacHash::Sha2_512,
117 }
118}