1#![forbid(unsafe_code)]
2
3extern crate alloc;
15
16use digest::KeyInit;
17use hmac::Mac as HmacMac;
18use oxicrypto_core::{CryptoError, Mac, StreamingMac};
19use subtle::ConstantTimeEq;
20
21#[derive(Debug, Default, Clone, Copy)]
25pub struct HmacSha256;
26
27impl Mac for HmacSha256 {
28 fn name(&self) -> &'static str {
29 "HMAC-SHA-256"
30 }
31 fn key_len(&self) -> usize {
32 32
33 }
34 fn output_len(&self) -> usize {
35 32
36 }
37 fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
38 if out.len() < 32 {
39 return Err(CryptoError::BufferTooSmall);
40 }
41 let mut mac =
42 hmac::Hmac::<sha2::Sha256>::new_from_slice(key).map_err(|_| CryptoError::InvalidKey)?;
43 mac.update(msg);
44 let result = mac.finalize().into_bytes();
45 out[..32].copy_from_slice(&result);
46 Ok(())
47 }
48 fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
49 if tag.len() != 32 {
50 return Err(CryptoError::InvalidTag);
51 }
52 let mut expected = [0u8; 32];
53 self.mac(key, msg, &mut expected)?;
54 if expected.ct_eq(tag).into() {
55 Ok(())
56 } else {
57 Err(CryptoError::InvalidTag)
58 }
59 }
60}
61
62impl HmacSha256 {
63 pub fn mac_truncated(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
69 let n = out.len();
70 if n < 16 {
71 return Err(CryptoError::BadInput);
72 }
73 let mut full = [0u8; 32];
74 self.mac(key, msg, &mut full)?;
75 out.copy_from_slice(&full[..n]);
76 Ok(())
77 }
78
79 pub fn verify_truncated(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
84 let n = tag.len();
85 if n < 16 {
86 return Err(CryptoError::BadInput);
87 }
88 let mut buf = [0u8; 32];
89 self.mac(key, msg, &mut buf)?;
90 if buf[..n].ct_eq(tag).into() {
91 Ok(())
92 } else {
93 Err(CryptoError::InvalidTag)
94 }
95 }
96}
97
98#[derive(Debug, Default, Clone, Copy)]
102pub struct HmacSha512;
103
104impl Mac for HmacSha512 {
105 fn name(&self) -> &'static str {
106 "HMAC-SHA-512"
107 }
108 fn key_len(&self) -> usize {
109 64
110 }
111 fn output_len(&self) -> usize {
112 64
113 }
114 fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
115 if out.len() < 64 {
116 return Err(CryptoError::BufferTooSmall);
117 }
118 let mut mac =
119 hmac::Hmac::<sha2::Sha512>::new_from_slice(key).map_err(|_| CryptoError::InvalidKey)?;
120 mac.update(msg);
121 let result = mac.finalize().into_bytes();
122 out[..64].copy_from_slice(&result);
123 Ok(())
124 }
125 fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
126 if tag.len() != 64 {
127 return Err(CryptoError::InvalidTag);
128 }
129 let mut expected = [0u8; 64];
130 self.mac(key, msg, &mut expected)?;
131 if expected.ct_eq(tag).into() {
132 Ok(())
133 } else {
134 Err(CryptoError::InvalidTag)
135 }
136 }
137}
138
139impl HmacSha512 {
140 pub fn mac_truncated(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
145 let n = out.len();
146 if n < 16 {
147 return Err(CryptoError::BadInput);
148 }
149 let mut full = [0u8; 64];
150 self.mac(key, msg, &mut full)?;
151 out.copy_from_slice(&full[..n]);
152 Ok(())
153 }
154
155 pub fn verify_truncated(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
160 let n = tag.len();
161 if n < 16 {
162 return Err(CryptoError::BadInput);
163 }
164 let mut buf = [0u8; 64];
165 self.mac(key, msg, &mut buf)?;
166 if buf[..n].ct_eq(tag).into() {
167 Ok(())
168 } else {
169 Err(CryptoError::InvalidTag)
170 }
171 }
172}
173
174#[derive(Debug, Default, Clone, Copy)]
178pub struct HmacSha384;
179
180impl Mac for HmacSha384 {
181 fn name(&self) -> &'static str {
182 "HMAC-SHA-384"
183 }
184 fn key_len(&self) -> usize {
185 48
186 }
187 fn output_len(&self) -> usize {
188 48
189 }
190 fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
191 if out.len() < 48 {
192 return Err(CryptoError::BufferTooSmall);
193 }
194 let mut mac =
195 hmac::Hmac::<sha2::Sha384>::new_from_slice(key).map_err(|_| CryptoError::InvalidKey)?;
196 mac.update(msg);
197 let result = mac.finalize().into_bytes();
198 out[..48].copy_from_slice(&result);
199 Ok(())
200 }
201 fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
202 if tag.len() != 48 {
203 return Err(CryptoError::InvalidTag);
204 }
205 let mut expected = [0u8; 48];
206 self.mac(key, msg, &mut expected)?;
207 if expected.ct_eq(tag).into() {
208 Ok(())
209 } else {
210 Err(CryptoError::InvalidTag)
211 }
212 }
213}
214
215impl HmacSha384 {
216 pub fn mac_truncated(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
221 let n = out.len();
222 if n < 16 {
223 return Err(CryptoError::BadInput);
224 }
225 let mut full = [0u8; 48];
226 self.mac(key, msg, &mut full)?;
227 out.copy_from_slice(&full[..n]);
228 Ok(())
229 }
230
231 pub fn verify_truncated(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
236 let n = tag.len();
237 if n < 16 {
238 return Err(CryptoError::BadInput);
239 }
240 let mut buf = [0u8; 48];
241 self.mac(key, msg, &mut buf)?;
242 if buf[..n].ct_eq(tag).into() {
243 Ok(())
244 } else {
245 Err(CryptoError::InvalidTag)
246 }
247 }
248}
249
250pub struct HmacStreamingAdapter<D: hmac::digest::block_api::EagerHash>
257where
258 hmac::Hmac<D>: HmacMac + KeyInit,
259{
260 inner: hmac::Hmac<D>,
261}
262
263impl<D: hmac::digest::block_api::EagerHash> HmacStreamingAdapter<D>
264where
265 hmac::Hmac<D>: HmacMac + KeyInit,
266{
267 pub fn new(key: &[u8]) -> Result<Self, CryptoError> {
271 let inner = hmac::Hmac::<D>::new_from_slice(key).map_err(|_| CryptoError::InvalidKey)?;
272 Ok(Self { inner })
273 }
274}
275
276impl<D: hmac::digest::block_api::EagerHash + Send> StreamingMac for HmacStreamingAdapter<D>
277where
278 hmac::Hmac<D>: HmacMac + KeyInit + Send,
279{
280 fn update(&mut self, data: &[u8]) {
281 self.inner.update(data);
282 }
283
284 fn finalize(self, out: &mut [u8]) -> Result<(), CryptoError> {
285 let tag = self.inner.finalize().into_bytes();
286 if out.len() < tag.len() {
287 return Err(CryptoError::BufferTooSmall);
288 }
289 out[..tag.len()].copy_from_slice(&tag);
290 Ok(())
291 }
292
293 fn verify(self, expected: &[u8]) -> Result<(), CryptoError> {
294 let tag = self.inner.finalize().into_bytes();
295 if tag.len() != expected.len() {
296 return Err(CryptoError::InvalidTag);
297 }
298 if tag.as_slice().ct_eq(expected).into() {
299 Ok(())
300 } else {
301 Err(CryptoError::InvalidTag)
302 }
303 }
304}
305
306pub type HmacSha256Streaming = HmacStreamingAdapter<sha2::Sha256>;
308pub type HmacSha384Streaming = HmacStreamingAdapter<sha2::Sha384>;
310pub type HmacSha512Streaming = HmacStreamingAdapter<sha2::Sha512>;
312
313#[derive(Debug, Default, Clone, Copy)]
320pub struct HmacSha3_256;
321
322impl Mac for HmacSha3_256 {
323 fn name(&self) -> &'static str {
324 "HMAC-SHA3-256"
325 }
326 fn key_len(&self) -> usize {
327 32
328 }
329 fn output_len(&self) -> usize {
330 32
331 }
332 fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
333 use digest::KeyInit as _;
334
335 if out.len() < 32 {
336 return Err(CryptoError::BufferTooSmall);
337 }
338 let mut mac = hmac::SimpleHmac::<sha3::Sha3_256>::new_from_slice(key)
339 .map_err(|_| CryptoError::InvalidKey)?;
340 HmacMac::update(&mut mac, msg);
341 let result = HmacMac::finalize(mac).into_bytes();
342 out[..32].copy_from_slice(&result);
343 Ok(())
344 }
345 fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
346 if tag.len() != 32 {
347 return Err(CryptoError::InvalidTag);
348 }
349 let mut expected = [0u8; 32];
350 self.mac(key, msg, &mut expected)?;
351 if expected.ct_eq(tag).into() {
352 Ok(())
353 } else {
354 Err(CryptoError::InvalidTag)
355 }
356 }
357}
358
359#[derive(Debug, Default, Clone, Copy)]
366pub struct HmacSha3_512;
367
368impl Mac for HmacSha3_512 {
369 fn name(&self) -> &'static str {
370 "HMAC-SHA3-512"
371 }
372 fn key_len(&self) -> usize {
373 64
374 }
375 fn output_len(&self) -> usize {
376 64
377 }
378 fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
379 use digest::KeyInit as _;
380
381 if out.len() < 64 {
382 return Err(CryptoError::BufferTooSmall);
383 }
384 let mut mac = hmac::SimpleHmac::<sha3::Sha3_512>::new_from_slice(key)
385 .map_err(|_| CryptoError::InvalidKey)?;
386 HmacMac::update(&mut mac, msg);
387 let result = HmacMac::finalize(mac).into_bytes();
388 out[..64].copy_from_slice(&result);
389 Ok(())
390 }
391 fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
392 if tag.len() != 64 {
393 return Err(CryptoError::InvalidTag);
394 }
395 let mut expected = [0u8; 64];
396 self.mac(key, msg, &mut expected)?;
397 if expected.ct_eq(tag).into() {
398 Ok(())
399 } else {
400 Err(CryptoError::InvalidTag)
401 }
402 }
403}
404
405#[derive(Debug, Default, Clone, Copy)]
416pub struct Poly1305Mac;
417
418impl Mac for Poly1305Mac {
419 fn name(&self) -> &'static str {
420 "Poly1305"
421 }
422 fn key_len(&self) -> usize {
423 32
424 }
425 fn output_len(&self) -> usize {
426 16
427 }
428 fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
429 use poly1305::universal_hash::KeyInit as _;
430
431 if key.len() != 32 {
432 return Err(CryptoError::InvalidKey);
433 }
434 if out.len() < 16 {
435 return Err(CryptoError::BufferTooSmall);
436 }
437 let key_arr = poly1305::Key::try_from(key).map_err(|_| CryptoError::InvalidKey)?;
438 let mac = poly1305::Poly1305::new(&key_arr);
439 let tag = mac.compute_unpadded(msg);
443 out[..16].copy_from_slice(tag.as_slice());
444 Ok(())
445 }
446 fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
447 if tag.len() != 16 {
448 return Err(CryptoError::InvalidTag);
449 }
450 let mut computed = [0u8; 16];
451 self.mac(key, msg, &mut computed)?;
452 if computed.ct_eq(tag).into() {
453 Ok(())
454 } else {
455 Err(CryptoError::InvalidTag)
456 }
457 }
458}
459
460#[derive(Debug, Default, Clone, Copy)]
466pub struct CmacAes128;
467
468impl Mac for CmacAes128 {
469 fn name(&self) -> &'static str {
470 "CMAC-AES-128"
471 }
472 fn key_len(&self) -> usize {
473 16
474 }
475 fn output_len(&self) -> usize {
476 16
477 }
478 fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
479 use cmac::Mac as _;
480 use digest::KeyInit as _;
481
482 if out.len() < 16 {
483 return Err(CryptoError::BufferTooSmall);
484 }
485 let mut mac = cmac::Cmac::<aes_cipher05::Aes128>::new_from_slice(key)
486 .map_err(|_| CryptoError::InvalidKey)?;
487 mac.update(msg);
488 let result = mac.finalize().into_bytes();
489 out[..16].copy_from_slice(&result);
490 Ok(())
491 }
492 fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
493 if tag.len() != 16 {
494 return Err(CryptoError::InvalidTag);
495 }
496 let mut expected = [0u8; 16];
497 self.mac(key, msg, &mut expected)?;
498 if expected.ct_eq(tag).into() {
499 Ok(())
500 } else {
501 Err(CryptoError::InvalidTag)
502 }
503 }
504}
505
506#[derive(Debug, Default, Clone, Copy)]
512pub struct CmacAes256;
513
514impl Mac for CmacAes256 {
515 fn name(&self) -> &'static str {
516 "CMAC-AES-256"
517 }
518 fn key_len(&self) -> usize {
519 32
520 }
521 fn output_len(&self) -> usize {
522 16
523 }
524 fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
525 use cmac::Mac as _;
526 use digest::KeyInit as _;
527
528 if out.len() < 16 {
529 return Err(CryptoError::BufferTooSmall);
530 }
531 let mut mac = cmac::Cmac::<aes_cipher05::Aes256>::new_from_slice(key)
532 .map_err(|_| CryptoError::InvalidKey)?;
533 mac.update(msg);
534 let result = mac.finalize().into_bytes();
535 out[..16].copy_from_slice(&result);
536 Ok(())
537 }
538 fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
539 if tag.len() != 16 {
540 return Err(CryptoError::InvalidTag);
541 }
542 let mut expected = [0u8; 16];
543 self.mac(key, msg, &mut expected)?;
544 if expected.ct_eq(tag).into() {
545 Ok(())
546 } else {
547 Err(CryptoError::InvalidTag)
548 }
549 }
550}
551
552pub struct Kmac128 {
559 custom: alloc::vec::Vec<u8>,
561 output_len: usize,
563}
564
565impl Kmac128 {
566 pub fn new(custom: &[u8], output_len: usize) -> Result<Self, CryptoError> {
570 if output_len == 0 {
571 return Err(CryptoError::BadInput);
572 }
573 Ok(Self {
574 custom: custom.to_vec(),
575 output_len,
576 })
577 }
578}
579
580impl core::fmt::Debug for Kmac128 {
581 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
582 f.debug_struct("Kmac128")
583 .field("output_len", &self.output_len)
584 .finish()
585 }
586}
587
588impl Mac for Kmac128 {
589 fn name(&self) -> &'static str {
590 "KMAC128"
591 }
592 fn key_len(&self) -> usize {
593 16
595 }
596 fn output_len(&self) -> usize {
597 self.output_len
598 }
599 fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
600 use tiny_keccak::Hasher as _;
601 if out.len() < self.output_len {
602 return Err(CryptoError::BufferTooSmall);
603 }
604 let mut kmac = tiny_keccak::Kmac::v128(key, &self.custom);
605 kmac.update(msg);
606 kmac.finalize(&mut out[..self.output_len]);
607 Ok(())
608 }
609 fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
610 if tag.len() != self.output_len {
611 return Err(CryptoError::InvalidTag);
612 }
613 let mut computed = alloc::vec![0u8; self.output_len];
614 self.mac(key, msg, &mut computed)?;
615 if computed.ct_eq(tag).into() {
616 Ok(())
617 } else {
618 Err(CryptoError::InvalidTag)
619 }
620 }
621}
622
623pub struct Kmac256 {
630 custom: alloc::vec::Vec<u8>,
632 output_len: usize,
634}
635
636impl Kmac256 {
637 pub fn new(custom: &[u8], output_len: usize) -> Result<Self, CryptoError> {
641 if output_len == 0 {
642 return Err(CryptoError::BadInput);
643 }
644 Ok(Self {
645 custom: custom.to_vec(),
646 output_len,
647 })
648 }
649}
650
651impl core::fmt::Debug for Kmac256 {
652 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
653 f.debug_struct("Kmac256")
654 .field("output_len", &self.output_len)
655 .finish()
656 }
657}
658
659impl Mac for Kmac256 {
660 fn name(&self) -> &'static str {
661 "KMAC256"
662 }
663 fn key_len(&self) -> usize {
664 32
665 }
666 fn output_len(&self) -> usize {
667 self.output_len
668 }
669 fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
670 use tiny_keccak::Hasher as _;
671 if out.len() < self.output_len {
672 return Err(CryptoError::BufferTooSmall);
673 }
674 let mut kmac = tiny_keccak::Kmac::v256(key, &self.custom);
675 kmac.update(msg);
676 kmac.finalize(&mut out[..self.output_len]);
677 Ok(())
678 }
679 fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
680 if tag.len() != self.output_len {
681 return Err(CryptoError::InvalidTag);
682 }
683 let mut computed = alloc::vec![0u8; self.output_len];
684 self.mac(key, msg, &mut computed)?;
685 if computed.ct_eq(tag).into() {
686 Ok(())
687 } else {
688 Err(CryptoError::InvalidTag)
689 }
690 }
691}
692
693pub fn kmac128_xof(
708 key: &[u8],
709 custom: &[u8],
710 msg: &[u8],
711 output_len: usize,
712) -> Result<alloc::vec::Vec<u8>, CryptoError> {
713 use tiny_keccak::Hasher as _;
714 if output_len == 0 {
715 return Err(CryptoError::BadInput);
716 }
717 let mut k = tiny_keccak::Kmac::v128(key, custom);
718 k.update(msg);
719 let mut out = alloc::vec![0u8; output_len];
720 k.finalize(&mut out);
721 Ok(out)
722}
723
724pub fn kmac256_xof(
737 key: &[u8],
738 custom: &[u8],
739 msg: &[u8],
740 output_len: usize,
741) -> Result<alloc::vec::Vec<u8>, CryptoError> {
742 use tiny_keccak::Hasher as _;
743 if output_len == 0 {
744 return Err(CryptoError::BadInput);
745 }
746 let mut k = tiny_keccak::Kmac::v256(key, custom);
747 k.update(msg);
748 let mut out = alloc::vec![0u8; output_len];
749 k.finalize(&mut out);
750 Ok(out)
751}
752
753pub fn blake3_keyed_mac(key: &[u8; 32], msg: &[u8]) -> [u8; 32] {
766 *blake3::Hasher::new_keyed(key)
767 .update(msg)
768 .finalize()
769 .as_bytes()
770}
771
772pub fn blake3_keyed_mac_verify(
777 key: &[u8; 32],
778 msg: &[u8],
779 expected: &[u8; 32],
780) -> Result<(), CryptoError> {
781 let actual = blake3_keyed_mac(key, msg);
782 if actual.ct_eq(expected).into() {
783 Ok(())
784 } else {
785 Err(CryptoError::InvalidTag)
786 }
787}
788
789pub fn hmac_sha256_verify_truncated(
804 key: &[u8],
805 msg: &[u8],
806 truncated_tag: &[u8],
807) -> Result<(), CryptoError> {
808 if truncated_tag.is_empty() || truncated_tag.len() > 32 {
809 return Err(CryptoError::BadInput);
810 }
811 let mut buf = [0u8; 32];
812 HmacSha256.mac(key, msg, &mut buf)?;
813 if buf[..truncated_tag.len()].ct_eq(truncated_tag).into() {
814 Ok(())
815 } else {
816 Err(CryptoError::InvalidTag)
817 }
818}
819
820#[must_use = "MAC result must be used or verified"]
831pub fn hmac_sha256_to_vec(key: &[u8], msg: &[u8]) -> Result<alloc::vec::Vec<u8>, CryptoError> {
832 let mut out = alloc::vec![0u8; 32];
833 HmacSha256.mac(key, msg, &mut out)?;
834 Ok(out)
835}
836
837#[must_use = "MAC result must be used or verified"]
846pub fn hmac_sha384_to_vec(key: &[u8], msg: &[u8]) -> Result<alloc::vec::Vec<u8>, CryptoError> {
847 let mut out = alloc::vec![0u8; 48];
848 HmacSha384.mac(key, msg, &mut out)?;
849 Ok(out)
850}
851
852#[must_use = "MAC result must be used or verified"]
861pub fn hmac_sha512_to_vec(key: &[u8], msg: &[u8]) -> Result<alloc::vec::Vec<u8>, CryptoError> {
862 let mut out = alloc::vec![0u8; 64];
863 HmacSha512.mac(key, msg, &mut out)?;
864 Ok(out)
865}
866
867#[cfg(test)]
870mod tests {
871 use super::*;
872
873 fn hex_decode(s: &str) -> alloc::vec::Vec<u8> {
874 (0..s.len())
875 .step_by(2)
876 .map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap())
877 .collect()
878 }
879
880 #[test]
884 fn hmac_sha256_rfc4231_tc1() {
885 let key = hex_decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
886 let data = b"Hi There";
887 let expected =
888 hex_decode("b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7");
889
890 let mac = HmacSha256;
891 let mut out = [0u8; 32];
892 mac.mac(&key, data, &mut out).unwrap();
893 assert_eq!(&out[..], expected.as_slice(), "HMAC-SHA-256 RFC4231 TC1");
894 }
895
896 #[test]
897 fn hmac_sha256_verify_ok() {
898 let key = b"secret-key";
899 let msg = b"the message";
900 let mac_impl = HmacSha256;
901 let mut tag = [0u8; 32];
902 mac_impl.mac(key, msg, &mut tag).unwrap();
903 mac_impl
904 .verify(key, msg, &tag)
905 .expect("verify should succeed");
906 }
907
908 #[test]
909 fn hmac_sha256_verify_fail() {
910 let key = b"secret-key";
911 let msg = b"the message";
912 let mac_impl = HmacSha256;
913 let mut tag = [0u8; 32];
914 mac_impl.mac(key, msg, &mut tag).unwrap();
915 tag[0] ^= 0xff;
916 let result = mac_impl.verify(key, msg, &tag);
917 assert_eq!(result, Err(CryptoError::InvalidTag));
918 }
919
920 #[test]
923 fn hmac_sha512_round_trip() {
924 let key = b"another-secret-key";
925 let msg = b"another message";
926 let mac_impl = HmacSha512;
927 let mut tag = [0u8; 64];
928 mac_impl.mac(key, msg, &mut tag).unwrap();
929 mac_impl
930 .verify(key, msg, &tag)
931 .expect("verify should succeed");
932 }
933
934 #[test]
935 fn hmac_sha512_verify_fail() {
936 let key = b"key";
937 let msg = b"msg";
938 let mac_impl = HmacSha512;
939 let mut tag = [0u8; 64];
940 mac_impl.mac(key, msg, &mut tag).unwrap();
941 tag[0] ^= 1;
942 assert_eq!(
943 mac_impl.verify(key, msg, &tag),
944 Err(CryptoError::InvalidTag)
945 );
946 }
947
948 #[test]
952 fn hmac_sha384_rfc4231_tc1() {
953 let key = hex_decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
954 let data = b"Hi There";
955 let expected = hex_decode(
956 "afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59c\
957 faea9ea9076ede7f4af152e8b2fa9cb6",
958 );
959
960 let mac = HmacSha384;
961 let mut out = [0u8; 48];
962 mac.mac(&key, data, &mut out).unwrap();
963 assert_eq!(&out[..], expected.as_slice(), "HMAC-SHA-384 RFC4231 TC1");
964 }
965
966 #[test]
967 fn hmac_sha384_round_trip() {
968 let key = b"hmac-sha384-test-key";
969 let msg = b"test message for sha384";
970 let mac = HmacSha384;
971 let mut tag = [0u8; 48];
972 mac.mac(key, msg, &mut tag).unwrap();
973 mac.verify(key, msg, &tag).expect("verify should succeed");
974 }
975
976 #[test]
977 fn hmac_sha384_verify_fail() {
978 let key = b"key";
979 let msg = b"msg";
980 let mac = HmacSha384;
981 let mut tag = [0u8; 48];
982 mac.mac(key, msg, &mut tag).unwrap();
983 tag[0] ^= 1;
984 assert_eq!(mac.verify(key, msg, &tag), Err(CryptoError::InvalidTag));
985 }
986
987 #[test]
992 fn hmac_sha256_streaming_matches_oneshot() {
993 let key = b"streaming-key";
994 let msg_a = b"hello ";
995 let msg_b = b"world";
996 let full_msg = b"hello world";
997
998 let one_shot = HmacSha256;
1000 let mut expected = [0u8; 32];
1001 one_shot.mac(key, full_msg, &mut expected).unwrap();
1002
1003 let mut streaming = HmacSha256Streaming::new(key).unwrap();
1005 streaming.update(msg_a);
1006 streaming.update(msg_b);
1007 let mut got = [0u8; 32];
1008 streaming.finalize(&mut got).unwrap();
1009
1010 assert_eq!(expected, got, "streaming must match one-shot");
1011 }
1012
1013 #[test]
1014 fn hmac_sha256_streaming_verify_ok() {
1015 let key = b"verify-key";
1016 let msg = b"verify message";
1017
1018 let mut one_shot_tag = [0u8; 32];
1019 HmacSha256.mac(key, msg, &mut one_shot_tag).unwrap();
1020
1021 let mut streaming = HmacSha256Streaming::new(key).unwrap();
1022 streaming.update(msg);
1023 streaming
1024 .verify(&one_shot_tag)
1025 .expect("streaming verify must succeed");
1026 }
1027
1028 #[test]
1029 fn hmac_sha256_streaming_verify_fail() {
1030 let key = b"k";
1031 let msg = b"m";
1032 let bad_tag = [0xffu8; 32];
1033
1034 let mut streaming = HmacSha256Streaming::new(key).unwrap();
1035 streaming.update(msg);
1036 assert_eq!(
1037 streaming.verify(&bad_tag),
1038 Err(CryptoError::InvalidTag),
1039 "streaming verify must fail on wrong tag"
1040 );
1041 }
1042
1043 #[test]
1048 fn hmac_sha3_256_round_trip() {
1049 let key = b"hmac-sha3-256-key";
1050 let msg = b"test message";
1051 let mac = HmacSha3_256;
1052 let mut tag = [0u8; 32];
1053 mac.mac(key, msg, &mut tag).unwrap();
1054 mac.verify(key, msg, &tag)
1055 .expect("HMAC-SHA3-256 verify must succeed");
1056 }
1057
1058 #[test]
1059 fn hmac_sha3_256_verify_fail() {
1060 let key = b"k";
1061 let msg = b"m";
1062 let mac = HmacSha3_256;
1063 let mut tag = [0u8; 32];
1064 mac.mac(key, msg, &mut tag).unwrap();
1065 tag[0] ^= 1;
1066 assert_eq!(mac.verify(key, msg, &tag), Err(CryptoError::InvalidTag));
1067 }
1068
1069 #[test]
1072 fn hmac_sha3_512_round_trip() {
1073 let key = b"hmac-sha3-512-test-key";
1074 let msg = b"test message for sha3-512";
1075 let mac = HmacSha3_512;
1076 let mut tag = [0u8; 64];
1077 mac.mac(key, msg, &mut tag).unwrap();
1078 mac.verify(key, msg, &tag)
1079 .expect("HMAC-SHA3-512 verify must succeed");
1080 }
1081
1082 #[test]
1091 fn poly1305_rfc8439_s2_5_2() {
1092 let key = hex_decode(
1093 "85d6be7857556d337f4452fe42d506a8\
1094 0103808afb0db2fd4abff6af4149f51b",
1095 );
1096 let msg = b"Cryptographic Forum Research Group";
1097 let expected = hex_decode("a8061dc1305136c6c22b8baf0c0127a9");
1098
1099 let mac = Poly1305Mac;
1100 let mut out = [0u8; 16];
1101 mac.mac(&key, msg, &mut out).unwrap();
1102 assert_eq!(&out[..], expected.as_slice(), "Poly1305 RFC8439 §2.5.2");
1103 }
1104
1105 #[test]
1106 fn poly1305_verify_ok() {
1107 let key = [0u8; 32];
1108 let msg = b"test";
1109 let mac = Poly1305Mac;
1110 let mut tag = [0u8; 16];
1111 mac.mac(&key, msg, &mut tag).unwrap();
1112 mac.verify(&key, msg, &tag)
1113 .expect("Poly1305 verify must succeed");
1114 }
1115
1116 #[test]
1117 fn poly1305_verify_fail() {
1118 let key = [1u8; 32];
1119 let msg = b"test";
1120 let mac = Poly1305Mac;
1121 let mut tag = [0u8; 16];
1122 mac.mac(&key, msg, &mut tag).unwrap();
1123 tag[0] ^= 0xff;
1124 assert_eq!(mac.verify(&key, msg, &tag), Err(CryptoError::InvalidTag));
1125 }
1126
1127 #[test]
1128 fn poly1305_bad_key_len() {
1129 let key = [0u8; 16]; let mac = Poly1305Mac;
1131 let mut out = [0u8; 16];
1132 assert_eq!(
1133 mac.mac(&key, b"msg", &mut out),
1134 Err(CryptoError::InvalidKey)
1135 );
1136 }
1137
1138 #[test]
1146 fn cmac_aes128_nist_sp800_38b_example1() {
1147 let key = hex_decode("2b7e151628aed2a6abf7158809cf4f3c");
1148 let expected = hex_decode("bb1d6929e95937287fa37d129b756746");
1149
1150 let mac = CmacAes128;
1151 let mut out = [0u8; 16];
1152 mac.mac(&key, b"", &mut out).unwrap();
1153 assert_eq!(&out[..], expected.as_slice(), "CMAC-AES-128 SP 800-38B Ex1");
1154 }
1155
1156 #[test]
1157 fn cmac_aes128_round_trip() {
1158 let key = [0x2b_u8; 16];
1159 let msg = b"hello cmac aes128";
1160 let mac = CmacAes128;
1161 let mut tag = [0u8; 16];
1162 mac.mac(&key, msg, &mut tag).unwrap();
1163 mac.verify(&key, msg, &tag)
1164 .expect("CMAC-AES-128 verify must succeed");
1165 }
1166
1167 #[test]
1168 fn cmac_aes128_verify_fail() {
1169 let key = [0u8; 16];
1170 let msg = b"msg";
1171 let mac = CmacAes128;
1172 let mut tag = [0u8; 16];
1173 mac.mac(&key, msg, &mut tag).unwrap();
1174 tag[0] ^= 1;
1175 assert_eq!(mac.verify(&key, msg, &tag), Err(CryptoError::InvalidTag));
1176 }
1177
1178 #[test]
1181 fn cmac_aes256_round_trip() {
1182 let key = [0x42_u8; 32];
1183 let msg = b"hello cmac aes256";
1184 let mac = CmacAes256;
1185 let mut tag = [0u8; 16];
1186 mac.mac(&key, msg, &mut tag).unwrap();
1187 mac.verify(&key, msg, &tag)
1188 .expect("CMAC-AES-256 verify must succeed");
1189 }
1190
1191 #[test]
1204 fn kmac128_nist_sp800_185_sample1() {
1205 let key = hex_decode(
1206 "404142434445464748494a4b4c4d4e4f\
1207 505152535455565758595a5b5c5d5e5f",
1208 );
1209 let data = hex_decode("00010203");
1210 let expected = hex_decode(
1211 "e5780b0d3ea6f7d3a429c5706aa43a00\
1212 fadbd7d49628839e3187243f456ee14e",
1213 );
1214
1215 let kmac = Kmac128::new(b"", 32).unwrap();
1216 let mut out = [0u8; 32];
1217 kmac.mac(&key, &data, &mut out).unwrap();
1218 assert_eq!(
1219 &out[..],
1220 expected.as_slice(),
1221 "KMAC128 SP 800-185 Sample #1"
1222 );
1223 }
1224
1225 #[test]
1226 fn kmac128_round_trip() {
1227 let kmac = Kmac128::new(b"test-domain", 32).unwrap();
1228 let key = [0xaa_u8; 16];
1229 let msg = b"hello kmac128";
1230 let mut tag = [0u8; 32];
1231 kmac.mac(&key, msg, &mut tag).unwrap();
1232 kmac.verify(&key, msg, &tag)
1233 .expect("KMAC128 verify must succeed");
1234 }
1235
1236 #[test]
1237 fn kmac128_verify_fail() {
1238 let kmac = Kmac128::new(b"", 32).unwrap();
1239 let key = [0u8; 16];
1240 let msg = b"test";
1241 let mut tag = [0u8; 32];
1242 kmac.mac(&key, msg, &mut tag).unwrap();
1243 tag[0] ^= 1;
1244 assert_eq!(kmac.verify(&key, msg, &tag), Err(CryptoError::InvalidTag));
1245 }
1246
1247 #[test]
1248 fn kmac128_zero_output_len_rejected() {
1249 assert_eq!(
1250 Kmac128::new(b"", 0).unwrap_err(),
1251 CryptoError::BadInput,
1252 "KMAC128 with output_len=0 must be rejected"
1253 );
1254 }
1255
1256 #[test]
1271 fn kmac256_nist_sp800_185_sample4() {
1272 let key = hex_decode(
1273 "404142434445464748494a4b4c4d4e4f\
1274 505152535455565758595a5b5c5d5e5f",
1275 );
1276 let data: alloc::vec::Vec<u8> = (0x00_u8..=0xc7_u8).collect();
1278 let expected = hex_decode(
1279 "75358cf39e41494e949707927cee0af2\
1280 0a3ff553904c86b08f21cc414bcfd691\
1281 589d27cf5e15369cbbff8b9a4c2eb178\
1282 00855d0235ff635da82533ec6b759b69",
1283 );
1284
1285 let kmac = Kmac256::new(b"", 64).unwrap();
1286 let mut out = [0u8; 64];
1287 kmac.mac(&key, &data, &mut out).unwrap();
1288 assert_eq!(
1289 &out[..],
1290 expected.as_slice(),
1291 "KMAC256 SP 800-185 §A.2 Sample #2 (200-byte data, empty S)"
1292 );
1293 }
1294
1295 #[test]
1296 fn kmac256_round_trip() {
1297 let kmac = Kmac256::new(b"domain", 64).unwrap();
1298 let key = [0xbb_u8; 32];
1299 let msg = b"hello kmac256";
1300 let mut tag = [0u8; 64];
1301 kmac.mac(&key, msg, &mut tag).unwrap();
1302 kmac.verify(&key, msg, &tag)
1303 .expect("KMAC256 verify must succeed");
1304 }
1305
1306 #[test]
1307 fn kmac256_zero_output_len_rejected() {
1308 assert_eq!(
1309 Kmac256::new(b"", 0).unwrap_err(),
1310 CryptoError::BadInput,
1311 "KMAC256 with output_len=0 must be rejected"
1312 );
1313 }
1314
1315 #[test]
1319 fn hmac_sha256_truncated_is_prefix() {
1320 let key = b"trunc-key";
1321 let msg = b"truncated message";
1322
1323 let mac = HmacSha256;
1324 let mut full = [0u8; 32];
1325 mac.mac(key, msg, &mut full).unwrap();
1326
1327 let mut trunc = [0u8; 20];
1328 mac.mac_truncated(key, msg, &mut trunc).unwrap();
1329
1330 assert_eq!(
1331 &trunc[..],
1332 &full[..20],
1333 "truncated tag must be prefix of full tag"
1334 );
1335 }
1336
1337 #[test]
1338 fn hmac_sha256_truncated_verify_ok() {
1339 let key = b"k";
1340 let msg = b"m";
1341 let mac = HmacSha256;
1342
1343 let mut trunc = [0u8; 20];
1344 mac.mac_truncated(key, msg, &mut trunc).unwrap();
1345 mac.verify_truncated(key, msg, &trunc)
1346 .expect("truncated verify must succeed");
1347 }
1348
1349 #[test]
1350 fn hmac_sha256_truncated_too_short_rejected() {
1351 let mac = HmacSha256;
1352 let mut buf = [0u8; 15];
1353 assert_eq!(
1354 mac.mac_truncated(b"k", b"m", &mut buf),
1355 Err(CryptoError::BadInput),
1356 "truncation below 16 bytes must be rejected"
1357 );
1358 assert_eq!(
1359 mac.verify_truncated(b"k", b"m", &buf),
1360 Err(CryptoError::BadInput),
1361 "verify with tag < 16 bytes must be rejected"
1362 );
1363 }
1364
1365 #[test]
1366 fn hmac_sha512_truncated_is_prefix() {
1367 let key = b"key512";
1368 let msg = b"msg512";
1369
1370 let mac = HmacSha512;
1371 let mut full = [0u8; 64];
1372 mac.mac(key, msg, &mut full).unwrap();
1373
1374 let mut trunc = [0u8; 32];
1375 mac.mac_truncated(key, msg, &mut trunc).unwrap();
1376
1377 assert_eq!(&trunc[..], &full[..32]);
1378 }
1379
1380 #[test]
1381 fn hmac_sha384_truncated_is_prefix() {
1382 let key = b"key384";
1383 let msg = b"msg384";
1384
1385 let mac = HmacSha384;
1386 let mut full = [0u8; 48];
1387 mac.mac(key, msg, &mut full).unwrap();
1388
1389 let mut trunc = [0u8; 24];
1390 mac.mac_truncated(key, msg, &mut trunc).unwrap();
1391
1392 assert_eq!(&trunc[..], &full[..24]);
1393 }
1394
1395 #[test]
1400 fn kmac128_xof_matches_trait_impl() {
1401 let key = hex_decode(
1402 "404142434445464748494a4b4c4d4e4f\
1403 505152535455565758595a5b5c5d5e5f",
1404 );
1405 let data = hex_decode("00010203");
1406 let expected = hex_decode(
1408 "e5780b0d3ea6f7d3a429c5706aa43a00\
1409 fadbd7d49628839e3187243f456ee14e",
1410 );
1411
1412 let got = kmac128_xof(&key, b"", &data, 32).expect("kmac128_xof must not fail");
1413 assert_eq!(got, expected, "kmac128_xof NIST SP 800-185 Sample #1");
1414 }
1415
1416 #[test]
1417 fn kmac128_xof_variable_lengths() {
1418 let key = [0xaau8; 16];
1419 let msg = b"variable-length output test";
1420
1421 let out16 = kmac128_xof(&key, b"domain", msg, 16).unwrap();
1422 let out64 = kmac128_xof(&key, b"domain", msg, 64).unwrap();
1423
1424 assert_eq!(
1428 out16.len(),
1429 16,
1430 "kmac128_xof must produce exactly output_len bytes"
1431 );
1432 assert_eq!(
1433 out64.len(),
1434 64,
1435 "kmac128_xof must produce exactly output_len bytes"
1436 );
1437 assert!(out16.iter().any(|&b| b != 0), "output must be non-zero");
1438 assert!(out64.iter().any(|&b| b != 0), "output must be non-zero");
1439 assert_ne!(
1441 &out64[..16],
1442 out16.as_slice(),
1443 "KMAC: different output_len must differ"
1444 );
1445 }
1446
1447 #[test]
1448 fn kmac128_xof_zero_len_rejected() {
1449 assert_eq!(
1450 kmac128_xof(b"key", b"", b"msg", 0).unwrap_err(),
1451 CryptoError::BadInput,
1452 );
1453 }
1454
1455 #[test]
1456 fn kmac256_xof_matches_trait_impl() {
1457 let key = hex_decode(
1458 "404142434445464748494a4b4c4d4e4f\
1459 505152535455565758595a5b5c5d5e5f",
1460 );
1461 let data: alloc::vec::Vec<u8> = (0x00_u8..=0xc7_u8).collect();
1462 let expected = hex_decode(
1463 "75358cf39e41494e949707927cee0af2\
1464 0a3ff553904c86b08f21cc414bcfd691\
1465 589d27cf5e15369cbbff8b9a4c2eb178\
1466 00855d0235ff635da82533ec6b759b69",
1467 );
1468
1469 let got = kmac256_xof(&key, b"", &data, 64).expect("kmac256_xof must not fail");
1470 assert_eq!(got, expected, "kmac256_xof NIST SP 800-185 §A.2 Sample #2");
1471 }
1472
1473 #[test]
1474 fn kmac256_xof_zero_len_rejected() {
1475 assert_eq!(
1476 kmac256_xof(b"key", b"", b"msg", 0).unwrap_err(),
1477 CryptoError::BadInput,
1478 );
1479 }
1480
1481 #[test]
1485 fn blake3_keyed_mac_deterministic() {
1486 let key = [0x42u8; 32];
1487 let msg = b"hello blake3 keyed mac";
1488 let t1 = blake3_keyed_mac(&key, msg);
1489 let t2 = blake3_keyed_mac(&key, msg);
1490 assert_eq!(t1, t2, "BLAKE3 keyed mac must be deterministic");
1491 }
1492
1493 #[test]
1495 fn blake3_keyed_mac_key_dependent() {
1496 let k1 = [0x01u8; 32];
1497 let k2 = [0x02u8; 32];
1498 let msg = b"same msg";
1499 assert_ne!(
1500 blake3_keyed_mac(&k1, msg),
1501 blake3_keyed_mac(&k2, msg),
1502 "Different keys must produce different BLAKE3 MACs"
1503 );
1504 }
1505
1506 #[test]
1508 fn blake3_keyed_mac_verify_ok() {
1509 let key = [0xabu8; 32];
1510 let msg = b"verify me";
1511 let tag = blake3_keyed_mac(&key, msg);
1512 blake3_keyed_mac_verify(&key, msg, &tag).expect("BLAKE3 keyed verify must succeed");
1513 }
1514
1515 #[test]
1517 fn blake3_keyed_mac_verify_fail() {
1518 let key = [0xcd_u8; 32];
1519 let msg = b"corrupt me";
1520 let mut tag = blake3_keyed_mac(&key, msg);
1521 tag[0] ^= 0xff;
1522 assert_eq!(
1523 blake3_keyed_mac_verify(&key, msg, &tag),
1524 Err(CryptoError::InvalidTag),
1525 "corrupted BLAKE3 MAC must be rejected"
1526 );
1527 }
1528
1529 #[test]
1532 fn free_fn_verify_truncated_ok() {
1533 let key = b"verify-trunc-key";
1534 let msg = b"verify-trunc-msg";
1535 let mut full = [0u8; 32];
1536 HmacSha256.mac(key, msg, &mut full).unwrap();
1537 hmac_sha256_verify_truncated(key, msg, &full[..16])
1538 .expect("free-fn verify_truncated must accept valid 16-byte tag");
1539 }
1540
1541 #[test]
1542 fn free_fn_verify_truncated_empty_rejected() {
1543 assert_eq!(
1544 hmac_sha256_verify_truncated(b"k", b"m", &[]),
1545 Err(CryptoError::BadInput),
1546 );
1547 }
1548
1549 #[test]
1550 fn free_fn_verify_truncated_too_long_rejected() {
1551 assert_eq!(
1552 hmac_sha256_verify_truncated(b"k", b"m", &[0u8; 33]),
1553 Err(CryptoError::BadInput),
1554 );
1555 }
1556
1557 #[test]
1558 fn free_fn_verify_truncated_mismatch() {
1559 let key = b"k";
1560 let msg = b"m";
1561 let mut full = [0u8; 32];
1562 HmacSha256.mac(key, msg, &mut full).unwrap();
1563 let mut bad = [0u8; 16];
1564 bad.copy_from_slice(&full[..16]);
1565 bad[0] ^= 0x01;
1566 assert_eq!(
1567 hmac_sha256_verify_truncated(key, msg, &bad),
1568 Err(CryptoError::InvalidTag),
1569 );
1570 }
1571}