1#[cfg(feature = "alloc")]
87use alloc::vec::Vec;
88use core::marker::PhantomData;
89
90use subtle::ConstantTimeEq;
91use zeroize::Zeroize;
92
93use crate::classic::crypto_auth_hmacsha256::{
94 HmacSha256State, crypto_auth_hmacsha256, crypto_auth_hmacsha256_final,
95 crypto_auth_hmacsha256_init, crypto_auth_hmacsha256_update, crypto_auth_hmacsha256_verify,
96};
97use crate::classic::crypto_auth_hmacsha512::{
98 HmacSha512State, crypto_auth_hmacsha512, crypto_auth_hmacsha512_final,
99 crypto_auth_hmacsha512_init, crypto_auth_hmacsha512_update, crypto_auth_hmacsha512_verify,
100};
101use crate::classic::crypto_auth_hmacsha512256::{
102 HmacSha512256State, crypto_auth_hmacsha512256, crypto_auth_hmacsha512256_final,
103 crypto_auth_hmacsha512256_init, crypto_auth_hmacsha512256_update,
104 crypto_auth_hmacsha512256_verify,
105};
106use crate::constants::{
107 CRYPTO_AUTH_HMACSHA256_BYTES, CRYPTO_AUTH_HMACSHA256_KEYBYTES, CRYPTO_AUTH_HMACSHA512_BYTES,
108 CRYPTO_AUTH_HMACSHA512_KEYBYTES, CRYPTO_AUTH_HMACSHA512256_BYTES,
109 CRYPTO_AUTH_HMACSHA512256_KEYBYTES,
110};
111use crate::error::Error;
112use crate::types::*;
113
114pub type HmacSha256Key = StackByteArray<CRYPTO_AUTH_HMACSHA256_KEYBYTES>;
116pub type HmacSha256Mac = StackByteArray<CRYPTO_AUTH_HMACSHA256_BYTES>;
118pub type HmacSha512Key = StackByteArray<CRYPTO_AUTH_HMACSHA512_KEYBYTES>;
120pub type HmacSha512Mac = StackByteArray<CRYPTO_AUTH_HMACSHA512_BYTES>;
122pub type HmacSha512256Key = StackByteArray<CRYPTO_AUTH_HMACSHA512256_KEYBYTES>;
124pub type HmacSha512256Mac = StackByteArray<CRYPTO_AUTH_HMACSHA512256_BYTES>;
126
127#[cfg(any(
128 all(feature = "protected", any(unix, windows)),
129 all(doc, not(doctest), feature = "std")
130))]
131#[cfg_attr(all(feature = "nightly", doc), doc(cfg(feature = "protected")))]
132pub mod protected {
133 use super::*;
149 pub use crate::protected::*;
150
151 pub type HmacSha256Key = HeapByteArray<CRYPTO_AUTH_HMACSHA256_KEYBYTES>;
153 pub type HmacSha256Mac = HeapByteArray<CRYPTO_AUTH_HMACSHA256_BYTES>;
155 pub type HmacSha512Key = HeapByteArray<CRYPTO_AUTH_HMACSHA512_KEYBYTES>;
157 pub type HmacSha512Mac = HeapByteArray<CRYPTO_AUTH_HMACSHA512_BYTES>;
159 pub type HmacSha512256Key = HeapByteArray<CRYPTO_AUTH_HMACSHA512256_KEYBYTES>;
161 pub type HmacSha512256Mac = HeapByteArray<CRYPTO_AUTH_HMACSHA512256_BYTES>;
163}
164
165mod sealed {
166 use crate::error::Error;
167 use crate::types::NewByteArray;
168
169 pub trait Sealed<const KEY_LENGTH: usize, const MAC_LENGTH: usize> {
172 type State;
174 type Mac: NewByteArray<MAC_LENGTH> + zeroize::Zeroize;
176
177 fn compute(mac: &mut [u8; MAC_LENGTH], input: &[u8], key: &[u8; KEY_LENGTH]);
179 fn verify(
181 mac: &[u8; MAC_LENGTH],
182 input: &[u8],
183 key: &[u8; KEY_LENGTH],
184 ) -> Result<(), Error>;
185 fn init(key: &[u8; KEY_LENGTH]) -> Self::State;
187 fn update(state: &mut Self::State, input: &[u8]);
189 fn finalize(state: Self::State, mac: &mut [u8; MAC_LENGTH]);
191 }
192}
193
194pub trait HmacVariant<const KEY_LENGTH: usize, const MAC_LENGTH: usize>:
201 sealed::Sealed<KEY_LENGTH, MAC_LENGTH>
202{
203}
204
205pub struct Hmac<Variant, const KEY_LENGTH: usize, const MAC_LENGTH: usize>
207where
208 Variant: HmacVariant<KEY_LENGTH, MAC_LENGTH>,
209{
210 state: Variant::State,
211 _variant: PhantomData<Variant>,
212}
213
214#[derive(Clone, Copy, Debug, Default)]
216pub struct HmacSha256Variant;
217#[derive(Clone, Copy, Debug, Default)]
219pub struct HmacSha512Variant;
220#[derive(Clone, Copy, Debug, Default)]
222pub struct HmacSha512256Variant;
223
224pub type HmacSha256 =
226 Hmac<HmacSha256Variant, CRYPTO_AUTH_HMACSHA256_KEYBYTES, CRYPTO_AUTH_HMACSHA256_BYTES>;
227pub type HmacSha512 =
229 Hmac<HmacSha512Variant, CRYPTO_AUTH_HMACSHA512_KEYBYTES, CRYPTO_AUTH_HMACSHA512_BYTES>;
230pub type HmacSha512256 =
232 Hmac<HmacSha512256Variant, CRYPTO_AUTH_HMACSHA512256_KEYBYTES, CRYPTO_AUTH_HMACSHA512256_BYTES>;
233
234macro_rules! impl_hmac_variant {
235 (
236 $variant:ty,
237 $key_len:expr,
238 $mac_len:expr,
239 $state:ty,
240 $mac:ty,
241 $compute:path,
242 $verify:path,
243 $init:path,
244 $update:path,
245 $finalize:path
246 ) => {
247 impl HmacVariant<$key_len, $mac_len> for $variant {}
248
249 impl sealed::Sealed<$key_len, $mac_len> for $variant {
250 type Mac = $mac;
251 type State = $state;
252
253 fn compute(mac: &mut [u8; $mac_len], input: &[u8], key: &[u8; $key_len]) {
254 $compute(mac, input, key);
255 }
256
257 fn verify(
258 mac: &[u8; $mac_len],
259 input: &[u8],
260 key: &[u8; $key_len],
261 ) -> Result<(), Error> {
262 $verify(mac, input, key)
263 }
264
265 fn init(key: &[u8; $key_len]) -> Self::State {
266 $init(key)
267 }
268
269 fn update(state: &mut Self::State, input: &[u8]) {
270 $update(state, input);
271 }
272
273 fn finalize(state: Self::State, mac: &mut [u8; $mac_len]) {
274 $finalize(state, mac);
275 }
276 }
277 };
278}
279
280impl_hmac_variant!(
281 HmacSha256Variant,
282 CRYPTO_AUTH_HMACSHA256_KEYBYTES,
283 CRYPTO_AUTH_HMACSHA256_BYTES,
284 HmacSha256State,
285 HmacSha256Mac,
286 crypto_auth_hmacsha256,
287 crypto_auth_hmacsha256_verify,
288 crypto_auth_hmacsha256_init,
289 crypto_auth_hmacsha256_update,
290 crypto_auth_hmacsha256_final
291);
292
293impl_hmac_variant!(
294 HmacSha512Variant,
295 CRYPTO_AUTH_HMACSHA512_KEYBYTES,
296 CRYPTO_AUTH_HMACSHA512_BYTES,
297 HmacSha512State,
298 HmacSha512Mac,
299 crypto_auth_hmacsha512,
300 crypto_auth_hmacsha512_verify,
301 crypto_auth_hmacsha512_init,
302 crypto_auth_hmacsha512_update,
303 crypto_auth_hmacsha512_final
304);
305
306impl_hmac_variant!(
307 HmacSha512256Variant,
308 CRYPTO_AUTH_HMACSHA512256_KEYBYTES,
309 CRYPTO_AUTH_HMACSHA512256_BYTES,
310 HmacSha512256State,
311 HmacSha512256Mac,
312 crypto_auth_hmacsha512256,
313 crypto_auth_hmacsha512256_verify,
314 crypto_auth_hmacsha512256_init,
315 crypto_auth_hmacsha512256_update,
316 crypto_auth_hmacsha512256_final
317);
318
319impl<Variant, const KEY_LENGTH: usize, const MAC_LENGTH: usize>
320 Hmac<Variant, KEY_LENGTH, MAC_LENGTH>
321where
322 Variant: HmacVariant<KEY_LENGTH, MAC_LENGTH>,
323{
324 #[must_use]
327 pub fn compute<
328 Output: NewByteArray<MAC_LENGTH>,
329 Key: ByteArray<KEY_LENGTH>,
330 Input: Bytes + ?Sized,
331 >(
332 key: &Key,
333 input: &Input,
334 ) -> Output {
335 let mut output = Output::new_byte_array();
336 Variant::compute(output.as_mut_array(), input.as_slice(), key.as_array());
337 output
338 }
339
340 #[cfg(feature = "alloc")]
342 #[must_use]
343 pub fn compute_to_vec<Key: ByteArray<KEY_LENGTH>, Input: Bytes + ?Sized>(
344 key: &Key,
345 input: &Input,
346 ) -> Vec<u8> {
347 Self::compute::<StackByteArray<MAC_LENGTH>, _, _>(key, input).to_vec()
348 }
349
350 pub fn compute_and_verify<
357 OtherMac: ByteArray<MAC_LENGTH>,
358 Key: ByteArray<KEY_LENGTH>,
359 Input: Bytes + ?Sized,
360 >(
361 other_mac: &OtherMac,
362 key: &Key,
363 input: &Input,
364 ) -> Result<(), Error> {
365 Variant::verify(other_mac.as_array(), input.as_slice(), key.as_array())
366 }
367
368 #[must_use]
370 pub fn new<Key: ByteArray<KEY_LENGTH>>(key: &Key) -> Self {
371 Self {
372 state: Variant::init(key.as_array()),
373 _variant: PhantomData,
374 }
375 }
376
377 pub fn update<Input: Bytes + ?Sized>(&mut self, input: &Input) {
379 Variant::update(&mut self.state, input.as_slice())
380 }
381
382 #[must_use]
384 pub fn finalize<Output: NewByteArray<MAC_LENGTH>>(self) -> Output {
385 let mut output = Output::new_byte_array();
386 Variant::finalize(self.state, output.as_mut_array());
387 output
388 }
389
390 #[cfg(feature = "alloc")]
393 #[must_use]
394 pub fn finalize_to_vec(self) -> Vec<u8> {
395 self.finalize::<StackByteArray<MAC_LENGTH>>().to_vec()
396 }
397
398 pub fn verify<OtherMac: ByteArray<MAC_LENGTH>>(
406 self,
407 other_mac: &OtherMac,
408 ) -> Result<(), Error> {
409 let mut computed_mac = Variant::Mac::new_byte_array();
410 Variant::finalize(self.state, computed_mac.as_mut_array());
411 let valid = other_mac
412 .as_array()
413 .ct_eq(computed_mac.as_array())
414 .unwrap_u8();
415 computed_mac.as_mut_slice().zeroize();
416
417 if valid == 1 {
418 Ok(())
419 } else {
420 Err(Error::AuthenticationFailed)
421 }
422 }
423}
424
425#[cfg(all(test, feature = "alloc"))]
426mod tests {
427 use super::*;
428 use crate::classic::crypto_auth_hmac_impl::test_util::RFC4231_PADDABLE_KEYS as CASES;
433
434 fn padded_key<const KEY_LENGTH: usize>(key: &[u8]) -> StackByteArray<KEY_LENGTH> {
435 let mut padded = StackByteArray::<KEY_LENGTH>::default();
436 padded[..key.len()].copy_from_slice(key);
437 padded
438 }
439
440 fn assert_variant<Variant, const KEY_LENGTH: usize, const MAC_LENGTH: usize>(
442 key: StackByteArray<KEY_LENGTH>,
443 message: &[u8],
444 expected: &[u8],
445 ) where
446 Variant: HmacVariant<KEY_LENGTH, MAC_LENGTH>,
447 {
448 type H<V, const K: usize, const M: usize> = Hmac<V, K, M>;
449
450 assert_eq!(
451 H::<Variant, KEY_LENGTH, MAC_LENGTH>::compute_to_vec(&key, message),
452 expected
453 );
454 let fixed: StackByteArray<MAC_LENGTH> =
455 H::<Variant, KEY_LENGTH, MAC_LENGTH>::compute(&key, message);
456 assert_eq!(fixed.as_slice(), expected);
457 H::<Variant, KEY_LENGTH, MAC_LENGTH>::compute_and_verify(&fixed, &key, message)
458 .expect("one-shot verify failed");
459
460 let split = message.len() / 3;
461 for parts in [
462 vec![message],
463 vec![&message[..split], &message[split..]],
464 vec![
465 &[][..],
466 &message[..1],
467 &message[1..split],
468 &message[split..],
469 &[][..],
470 ],
471 ] {
472 let mut auth = H::<Variant, KEY_LENGTH, MAC_LENGTH>::new(&key);
473 for part in &parts {
474 auth.update(*part);
475 }
476 assert_eq!(auth.finalize_to_vec(), expected);
477
478 let mut verifier = H::<Variant, KEY_LENGTH, MAC_LENGTH>::new(&key);
479 for part in &parts {
480 verifier.update(*part);
481 }
482 verifier.verify(&fixed).expect("incremental verify failed");
483 }
484
485 for index in [0, MAC_LENGTH / 2, MAC_LENGTH - 1] {
486 let mut flipped = fixed.clone();
487 flipped[index] ^= 1;
488 assert!(matches!(
489 H::<Variant, KEY_LENGTH, MAC_LENGTH>::compute_and_verify(&flipped, &key, message),
490 Err(Error::AuthenticationFailed)
491 ));
492 let mut verifier = H::<Variant, KEY_LENGTH, MAC_LENGTH>::new(&key);
493 verifier.update(message);
494 assert!(matches!(
495 verifier.verify(&flipped),
496 Err(Error::AuthenticationFailed)
497 ));
498 }
499
500 let mut wrong_key = key.clone();
501 wrong_key[KEY_LENGTH - 1] ^= 1;
502 assert!(matches!(
503 H::<Variant, KEY_LENGTH, MAC_LENGTH>::compute_and_verify(&fixed, &wrong_key, message),
504 Err(Error::AuthenticationFailed)
505 ));
506 let mut verifier = H::<Variant, KEY_LENGTH, MAC_LENGTH>::new(&key);
507 verifier.update(&message[..message.len() - 1]);
508 assert!(matches!(
509 verifier.verify(&fixed),
510 Err(Error::AuthenticationFailed)
511 ));
512 }
513
514 #[test]
515 fn rfc4231_vectors_through_all_three_variants() {
516 for case in CASES {
517 let sha256 = case.sha256();
518 let sha512 = case.sha512();
519 assert_variant::<
520 HmacSha256Variant,
521 CRYPTO_AUTH_HMACSHA256_KEYBYTES,
522 CRYPTO_AUTH_HMACSHA256_BYTES,
523 >(padded_key(case.key), case.data, &sha256);
524 assert_variant::<
525 HmacSha512Variant,
526 CRYPTO_AUTH_HMACSHA512_KEYBYTES,
527 CRYPTO_AUTH_HMACSHA512_BYTES,
528 >(padded_key(case.key), case.data, &sha512);
529 assert_variant::<
530 HmacSha512256Variant,
531 CRYPTO_AUTH_HMACSHA512256_KEYBYTES,
532 CRYPTO_AUTH_HMACSHA512256_BYTES,
533 >(
534 padded_key(case.key),
535 case.data,
536 &sha512[..CRYPTO_AUTH_HMACSHA512256_BYTES],
537 );
538 }
539 }
540
541 #[test]
542 fn rustaceous_and_classic_macs_verify_each_other() {
543 for case in CASES {
544 let key256: HmacSha256Key = padded_key(case.key);
545 let mac = HmacSha256::compute_to_vec(&key256, case.data);
546 crypto_auth_hmacsha256_verify(
547 mac.as_slice().try_into().expect("MAC length"),
548 case.data,
549 key256.as_array(),
550 )
551 .expect("classic verify");
552 let mut classic = [0u8; CRYPTO_AUTH_HMACSHA256_BYTES];
553 crypto_auth_hmacsha256(&mut classic, case.data, key256.as_array());
554 HmacSha256::compute_and_verify(&classic, &key256, case.data)
555 .expect("rustaceous verify");
556 let mut verifier = HmacSha256::new(&key256);
557 verifier.update(case.data);
558 verifier.verify(&classic).expect("incremental verify");
559
560 let key512: HmacSha512Key = padded_key(case.key);
561 let mac = HmacSha512::compute_to_vec(&key512, case.data);
562 crypto_auth_hmacsha512_verify(
563 mac.as_slice().try_into().expect("MAC length"),
564 case.data,
565 key512.as_array(),
566 )
567 .expect("classic verify");
568 let mut classic = [0u8; CRYPTO_AUTH_HMACSHA512_BYTES];
569 crypto_auth_hmacsha512(&mut classic, case.data, key512.as_array());
570 HmacSha512::compute_and_verify(&classic, &key512, case.data)
571 .expect("rustaceous verify");
572 let mut verifier = HmacSha512::new(&key512);
573 verifier.update(case.data);
574 verifier.verify(&classic).expect("incremental verify");
575
576 let key512256: HmacSha512256Key = padded_key(case.key);
577 let mac = HmacSha512256::compute_to_vec(&key512256, case.data);
578 crypto_auth_hmacsha512256_verify(
579 mac.as_slice().try_into().expect("MAC length"),
580 case.data,
581 key512256.as_array(),
582 )
583 .expect("classic verify");
584 let mut classic = [0u8; CRYPTO_AUTH_HMACSHA512256_BYTES];
585 crypto_auth_hmacsha512256(&mut classic, case.data, key512256.as_array());
586 HmacSha512256::compute_and_verify(&classic, &key512256, case.data)
587 .expect("rustaceous verify");
588 let mut verifier = HmacSha512256::new(&key512256);
589 verifier.update(case.data);
590 verifier.verify(&classic).expect("incremental verify");
591 }
592 }
593
594 #[test]
595 fn variants_are_distinct_and_the_generic_api_matches_the_aliases() {
596 fn compute_with_variant<Variant, const KEY_LENGTH: usize, const MAC_LENGTH: usize>(
597 key: StackByteArray<KEY_LENGTH>,
598 input: &[u8],
599 ) -> Vec<u8>
600 where
601 Variant: HmacVariant<KEY_LENGTH, MAC_LENGTH>,
602 {
603 Hmac::<Variant, KEY_LENGTH, MAC_LENGTH>::compute_to_vec(&key, input)
604 }
605
606 let case = CASES[0];
607 let sha256 = case.sha256();
608 let sha512 = case.sha512();
609 assert_eq!(
610 compute_with_variant::<
611 HmacSha256Variant,
612 CRYPTO_AUTH_HMACSHA256_KEYBYTES,
613 CRYPTO_AUTH_HMACSHA256_BYTES,
614 >(padded_key(case.key), case.data),
615 sha256
616 );
617 assert_eq!(
618 compute_with_variant::<
619 HmacSha512Variant,
620 CRYPTO_AUTH_HMACSHA512_KEYBYTES,
621 CRYPTO_AUTH_HMACSHA512_BYTES,
622 >(padded_key(case.key), case.data),
623 sha512
624 );
625 let truncated = compute_with_variant::<
626 HmacSha512256Variant,
627 CRYPTO_AUTH_HMACSHA512256_KEYBYTES,
628 CRYPTO_AUTH_HMACSHA512256_BYTES,
629 >(padded_key(case.key), case.data);
630 assert_eq!(truncated, &sha512[..CRYPTO_AUTH_HMACSHA512256_BYTES]);
631 assert_ne!(truncated, sha256);
634 }
635
636 #[cfg(dryoc_native_tests)]
637 #[test]
638 fn rfc4231_keys_match_libsodium() {
639 use crate::native_test_util::{auth_hmacsha256, auth_hmacsha512, auth_hmacsha512256};
640
641 for case in CASES {
642 let key: HmacSha256Key = padded_key(case.key);
643 let so_tag = auth_hmacsha256(case.data, key.as_slice());
644 assert_eq!(HmacSha256::compute_to_vec(&key, case.data), so_tag);
645
646 let key: HmacSha512Key = padded_key(case.key);
647 let so_tag = auth_hmacsha512(case.data, key.as_slice());
648 assert_eq!(HmacSha512::compute_to_vec(&key, case.data), so_tag);
649
650 let key: HmacSha512256Key = padded_key(case.key);
651 let so_tag = auth_hmacsha512256(case.data, key.as_slice());
652 assert_eq!(HmacSha512256::compute_to_vec(&key, case.data), so_tag);
653 }
654 }
655}