1use std::marker::PhantomData;
84
85use subtle::ConstantTimeEq;
86use zeroize::Zeroize;
87
88use crate::classic::crypto_auth_hmacsha256::{
89 HmacSha256State, crypto_auth_hmacsha256, crypto_auth_hmacsha256_final,
90 crypto_auth_hmacsha256_init, crypto_auth_hmacsha256_update, crypto_auth_hmacsha256_verify,
91};
92use crate::classic::crypto_auth_hmacsha512::{
93 HmacSha512State, crypto_auth_hmacsha512, crypto_auth_hmacsha512_final,
94 crypto_auth_hmacsha512_init, crypto_auth_hmacsha512_update, crypto_auth_hmacsha512_verify,
95};
96use crate::classic::crypto_auth_hmacsha512256::{
97 HmacSha512256State, crypto_auth_hmacsha512256, crypto_auth_hmacsha512256_final,
98 crypto_auth_hmacsha512256_init, crypto_auth_hmacsha512256_update,
99 crypto_auth_hmacsha512256_verify,
100};
101use crate::constants::{
102 CRYPTO_AUTH_HMACSHA256_BYTES, CRYPTO_AUTH_HMACSHA256_KEYBYTES, CRYPTO_AUTH_HMACSHA512_BYTES,
103 CRYPTO_AUTH_HMACSHA512_KEYBYTES, CRYPTO_AUTH_HMACSHA512256_BYTES,
104 CRYPTO_AUTH_HMACSHA512256_KEYBYTES,
105};
106use crate::error::Error;
107use crate::types::*;
108
109pub type HmacSha256Key = StackByteArray<CRYPTO_AUTH_HMACSHA256_KEYBYTES>;
111pub type HmacSha256Mac = StackByteArray<CRYPTO_AUTH_HMACSHA256_BYTES>;
113pub type HmacSha512Key = StackByteArray<CRYPTO_AUTH_HMACSHA512_KEYBYTES>;
115pub type HmacSha512Mac = StackByteArray<CRYPTO_AUTH_HMACSHA512_BYTES>;
117pub type HmacSha512256Key = StackByteArray<CRYPTO_AUTH_HMACSHA512256_KEYBYTES>;
119pub type HmacSha512256Mac = StackByteArray<CRYPTO_AUTH_HMACSHA512256_BYTES>;
121
122#[cfg(any(all(feature = "protected", any(unix, windows)), all(doc, not(doctest))))]
123#[cfg_attr(all(feature = "nightly", doc), doc(cfg(feature = "protected")))]
124pub mod protected {
125 use super::*;
141 pub use crate::protected::*;
142
143 pub type HmacSha256Key = HeapByteArray<CRYPTO_AUTH_HMACSHA256_KEYBYTES>;
145 pub type HmacSha256Mac = HeapByteArray<CRYPTO_AUTH_HMACSHA256_BYTES>;
147 pub type HmacSha512Key = HeapByteArray<CRYPTO_AUTH_HMACSHA512_KEYBYTES>;
149 pub type HmacSha512Mac = HeapByteArray<CRYPTO_AUTH_HMACSHA512_BYTES>;
151 pub type HmacSha512256Key = HeapByteArray<CRYPTO_AUTH_HMACSHA512256_KEYBYTES>;
153 pub type HmacSha512256Mac = HeapByteArray<CRYPTO_AUTH_HMACSHA512256_BYTES>;
155}
156
157pub trait HmacVariant<const KEY_LENGTH: usize, const MAC_LENGTH: usize> {
159 type State;
161 type Mac: NewByteArray<MAC_LENGTH> + Zeroize;
163
164 fn compute(mac: &mut [u8; MAC_LENGTH], input: &[u8], key: &[u8; KEY_LENGTH]);
166 fn verify(mac: &[u8; MAC_LENGTH], input: &[u8], key: &[u8; KEY_LENGTH]) -> Result<(), Error>;
172 fn init(key: &[u8; KEY_LENGTH]) -> Self::State;
174 fn update(state: &mut Self::State, input: &[u8]);
176 fn finalize(state: Self::State, mac: &mut [u8; MAC_LENGTH]);
178}
179
180pub struct Hmac<Variant, const KEY_LENGTH: usize, const MAC_LENGTH: usize>
182where
183 Variant: HmacVariant<KEY_LENGTH, MAC_LENGTH>,
184{
185 state: Variant::State,
186 _variant: PhantomData<Variant>,
187}
188
189#[derive(Clone, Copy, Debug, Default)]
191pub struct HmacSha256Variant;
192#[derive(Clone, Copy, Debug, Default)]
194pub struct HmacSha512Variant;
195#[derive(Clone, Copy, Debug, Default)]
197pub struct HmacSha512256Variant;
198
199pub type HmacSha256 =
201 Hmac<HmacSha256Variant, CRYPTO_AUTH_HMACSHA256_KEYBYTES, CRYPTO_AUTH_HMACSHA256_BYTES>;
202pub type HmacSha512 =
204 Hmac<HmacSha512Variant, CRYPTO_AUTH_HMACSHA512_KEYBYTES, CRYPTO_AUTH_HMACSHA512_BYTES>;
205pub type HmacSha512256 =
207 Hmac<HmacSha512256Variant, CRYPTO_AUTH_HMACSHA512256_KEYBYTES, CRYPTO_AUTH_HMACSHA512256_BYTES>;
208
209macro_rules! impl_hmac_variant {
210 (
211 $variant:ty,
212 $key_len:expr,
213 $mac_len:expr,
214 $state:ty,
215 $mac:ty,
216 $compute:path,
217 $verify:path,
218 $init:path,
219 $update:path,
220 $finalize:path
221 ) => {
222 impl HmacVariant<$key_len, $mac_len> for $variant {
223 type Mac = $mac;
224 type State = $state;
225
226 fn compute(mac: &mut [u8; $mac_len], input: &[u8], key: &[u8; $key_len]) {
227 $compute(mac, input, key);
228 }
229
230 fn verify(
231 mac: &[u8; $mac_len],
232 input: &[u8],
233 key: &[u8; $key_len],
234 ) -> Result<(), Error> {
235 $verify(mac, input, key)
236 }
237
238 fn init(key: &[u8; $key_len]) -> Self::State {
239 $init(key)
240 }
241
242 fn update(state: &mut Self::State, input: &[u8]) {
243 $update(state, input);
244 }
245
246 fn finalize(state: Self::State, mac: &mut [u8; $mac_len]) {
247 $finalize(state, mac);
248 }
249 }
250 };
251}
252
253impl_hmac_variant!(
254 HmacSha256Variant,
255 CRYPTO_AUTH_HMACSHA256_KEYBYTES,
256 CRYPTO_AUTH_HMACSHA256_BYTES,
257 HmacSha256State,
258 HmacSha256Mac,
259 crypto_auth_hmacsha256,
260 crypto_auth_hmacsha256_verify,
261 crypto_auth_hmacsha256_init,
262 crypto_auth_hmacsha256_update,
263 crypto_auth_hmacsha256_final
264);
265
266impl_hmac_variant!(
267 HmacSha512Variant,
268 CRYPTO_AUTH_HMACSHA512_KEYBYTES,
269 CRYPTO_AUTH_HMACSHA512_BYTES,
270 HmacSha512State,
271 HmacSha512Mac,
272 crypto_auth_hmacsha512,
273 crypto_auth_hmacsha512_verify,
274 crypto_auth_hmacsha512_init,
275 crypto_auth_hmacsha512_update,
276 crypto_auth_hmacsha512_final
277);
278
279impl_hmac_variant!(
280 HmacSha512256Variant,
281 CRYPTO_AUTH_HMACSHA512256_KEYBYTES,
282 CRYPTO_AUTH_HMACSHA512256_BYTES,
283 HmacSha512256State,
284 HmacSha512256Mac,
285 crypto_auth_hmacsha512256,
286 crypto_auth_hmacsha512256_verify,
287 crypto_auth_hmacsha512256_init,
288 crypto_auth_hmacsha512256_update,
289 crypto_auth_hmacsha512256_final
290);
291
292impl<Variant, const KEY_LENGTH: usize, const MAC_LENGTH: usize>
293 Hmac<Variant, KEY_LENGTH, MAC_LENGTH>
294where
295 Variant: HmacVariant<KEY_LENGTH, MAC_LENGTH>,
296{
297 pub fn compute<
303 Key: ByteArray<KEY_LENGTH>,
304 Input: Bytes + ?Sized,
305 Output: NewByteArray<MAC_LENGTH>,
306 >(
307 key: Key,
308 input: &Input,
309 ) -> Output {
310 let mut output = Output::new_byte_array();
311 Variant::compute(output.as_mut_array(), input.as_slice(), key.as_array());
312 output
313 }
314
315 pub fn compute_to_vec<Key: ByteArray<KEY_LENGTH>, Input: Bytes + ?Sized>(
317 key: Key,
318 input: &Input,
319 ) -> Vec<u8> {
320 Self::compute(key, input)
321 }
322
323 pub fn compute_and_verify<
330 OtherMac: ByteArray<MAC_LENGTH>,
331 Key: ByteArray<KEY_LENGTH>,
332 Input: Bytes + ?Sized,
333 >(
334 other_mac: &OtherMac,
335 key: Key,
336 input: &Input,
337 ) -> Result<(), Error> {
338 Variant::verify(other_mac.as_array(), input.as_slice(), key.as_array())
339 }
340
341 pub fn new<Key: ByteArray<KEY_LENGTH>>(key: Key) -> Self {
346 Self {
347 state: Variant::init(key.as_array()),
348 _variant: PhantomData,
349 }
350 }
351
352 pub fn update<Input: Bytes + ?Sized>(&mut self, input: &Input) {
354 Variant::update(&mut self.state, input.as_slice())
355 }
356
357 pub fn finalize<Output: NewByteArray<MAC_LENGTH>>(self) -> Output {
359 let mut output = Output::new_byte_array();
360 Variant::finalize(self.state, output.as_mut_array());
361 output
362 }
363
364 pub fn finalize_to_vec(self) -> Vec<u8> {
367 self.finalize()
368 }
369
370 pub fn verify<OtherMac: ByteArray<MAC_LENGTH>>(
378 self,
379 other_mac: &OtherMac,
380 ) -> Result<(), Error> {
381 let mut computed_mac = Variant::Mac::new_byte_array();
382 Variant::finalize(self.state, computed_mac.as_mut_array());
383 let valid = other_mac
384 .as_array()
385 .ct_eq(computed_mac.as_array())
386 .unwrap_u8();
387 computed_mac.as_mut_slice().zeroize();
388
389 if valid == 1 {
390 Ok(())
391 } else {
392 Err(Error::AuthenticationFailed)
393 }
394 }
395}
396
397#[cfg(test)]
398mod tests {
399 use super::*;
400
401 #[test]
402 fn test_hmac_sha256() {
403 let key = HmacSha256Key::generate();
404 let mac = HmacSha256::compute_to_vec(key.clone(), b"Data to authenticate");
405
406 HmacSha256::compute_and_verify(&mac, key, b"Data to authenticate").expect("verify failed");
407 }
408
409 #[test]
410 fn test_hmac_sha512() {
411 let key = HmacSha512Key::generate();
412 let mut auth = HmacSha512::new(key.clone());
413 auth.update(b"Multi-part");
414 auth.update(b"data");
415 let mac = auth.finalize_to_vec();
416
417 let mut verifier = HmacSha512::new(key);
418 verifier.update(b"Multi-part");
419 verifier.update(b"data");
420 verifier.verify(&mac).expect("verify failed");
421 }
422
423 #[test]
424 fn test_hmac_sha512256_rejects_invalid_input() {
425 let key = HmacSha512256Key::generate();
426 let mac = HmacSha512256::compute_to_vec(key.clone(), b"Data to authenticate");
427
428 HmacSha512256::compute_and_verify(&mac, key, b"Invalid data")
429 .expect_err("verify should fail");
430 }
431
432 #[test]
433 fn test_hmac_variant_generic_api() {
434 fn compute_with_variant<Variant, const KEY_LENGTH: usize, const MAC_LENGTH: usize>(
435 key: StackByteArray<KEY_LENGTH>,
436 input: &[u8],
437 ) -> Vec<u8>
438 where
439 Variant: HmacVariant<KEY_LENGTH, MAC_LENGTH>,
440 {
441 Hmac::<Variant, KEY_LENGTH, MAC_LENGTH>::compute_to_vec(key, input)
442 }
443
444 let key = HmacSha256Key::generate();
445 let generic_mac = compute_with_variant::<
446 HmacSha256Variant,
447 CRYPTO_AUTH_HMACSHA256_KEYBYTES,
448 CRYPTO_AUTH_HMACSHA256_BYTES,
449 >(key.clone(), b"Data to authenticate");
450 let concrete_mac = HmacSha256::compute_to_vec(key, b"Data to authenticate");
451
452 assert_eq!(generic_mac, concrete_mac);
453 }
454}