1#![forbid(unsafe_code)]
2
3extern crate alloc;
63
64pub mod hmac_streaming_hash;
65pub use hmac_streaming_hash::{
66 hmac_with_streaming_hash, StreamingHashHmac, StreamingHashHmacSession,
67};
68
69use digest::KeyInit;
70use hmac::Mac as HmacMac;
71use oxicrypto_core::{CryptoError, Mac, StreamingMac};
72use subtle::ConstantTimeEq;
73
74#[derive(Debug, Default, Clone, Copy)]
78pub struct HmacSha256;
79
80impl Mac for HmacSha256 {
81 fn name(&self) -> &'static str {
82 "HMAC-SHA-256"
83 }
84 fn key_len(&self) -> usize {
85 32
86 }
87 fn output_len(&self) -> usize {
88 32
89 }
90 fn min_key_len(&self) -> usize {
91 32
92 }
93 fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
94 if out.len() < 32 {
95 return Err(CryptoError::BufferTooSmall);
96 }
97 let mut mac =
98 hmac::Hmac::<sha2::Sha256>::new_from_slice(key).map_err(|_| CryptoError::InvalidKey)?;
99 mac.update(msg);
100 let result = mac.finalize().into_bytes();
101 out[..32].copy_from_slice(&result);
102 Ok(())
103 }
104 fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
105 if tag.len() != 32 {
106 return Err(CryptoError::InvalidTag);
107 }
108 let mut expected = [0u8; 32];
109 self.mac(key, msg, &mut expected)?;
110 if expected.ct_eq(tag).into() {
111 Ok(())
112 } else {
113 Err(CryptoError::InvalidTag)
114 }
115 }
116}
117
118impl HmacSha256 {
119 pub const OUTPUT_LEN: usize = 32;
121
122 pub fn new_keyed(key: &[u8]) -> Result<HmacSha256Keyed, CryptoError> {
124 HmacSha256Keyed::new(key)
125 }
126
127 pub fn mac_truncated(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
133 let n = out.len();
134 if n < 16 {
135 return Err(CryptoError::BadInput);
136 }
137 let mut full = [0u8; 32];
138 self.mac(key, msg, &mut full)?;
139 out.copy_from_slice(&full[..n]);
140 Ok(())
141 }
142
143 pub fn verify_truncated(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
148 let n = tag.len();
149 if n < 16 {
150 return Err(CryptoError::BadInput);
151 }
152 let mut buf = [0u8; 32];
153 self.mac(key, msg, &mut buf)?;
154 if buf[..n].ct_eq(tag).into() {
155 Ok(())
156 } else {
157 Err(CryptoError::InvalidTag)
158 }
159 }
160}
161
162#[derive(Debug, Default, Clone, Copy)]
166pub struct HmacSha512;
167
168impl Mac for HmacSha512 {
169 fn name(&self) -> &'static str {
170 "HMAC-SHA-512"
171 }
172 fn key_len(&self) -> usize {
173 64
174 }
175 fn output_len(&self) -> usize {
176 64
177 }
178 fn min_key_len(&self) -> usize {
179 64
180 }
181 fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
182 if out.len() < 64 {
183 return Err(CryptoError::BufferTooSmall);
184 }
185 let mut mac =
186 hmac::Hmac::<sha2::Sha512>::new_from_slice(key).map_err(|_| CryptoError::InvalidKey)?;
187 mac.update(msg);
188 let result = mac.finalize().into_bytes();
189 out[..64].copy_from_slice(&result);
190 Ok(())
191 }
192 fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
193 if tag.len() != 64 {
194 return Err(CryptoError::InvalidTag);
195 }
196 let mut expected = [0u8; 64];
197 self.mac(key, msg, &mut expected)?;
198 if expected.ct_eq(tag).into() {
199 Ok(())
200 } else {
201 Err(CryptoError::InvalidTag)
202 }
203 }
204}
205
206impl HmacSha512 {
207 pub const OUTPUT_LEN: usize = 64;
209
210 pub fn new_keyed(key: &[u8]) -> Result<HmacSha512Keyed, CryptoError> {
212 HmacSha512Keyed::new(key)
213 }
214
215 pub fn mac_truncated(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
220 let n = out.len();
221 if n < 16 {
222 return Err(CryptoError::BadInput);
223 }
224 let mut full = [0u8; 64];
225 self.mac(key, msg, &mut full)?;
226 out.copy_from_slice(&full[..n]);
227 Ok(())
228 }
229
230 pub fn verify_truncated(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
235 let n = tag.len();
236 if n < 16 {
237 return Err(CryptoError::BadInput);
238 }
239 let mut buf = [0u8; 64];
240 self.mac(key, msg, &mut buf)?;
241 if buf[..n].ct_eq(tag).into() {
242 Ok(())
243 } else {
244 Err(CryptoError::InvalidTag)
245 }
246 }
247}
248
249#[derive(Debug, Default, Clone, Copy)]
253pub struct HmacSha384;
254
255impl Mac for HmacSha384 {
256 fn name(&self) -> &'static str {
257 "HMAC-SHA-384"
258 }
259 fn key_len(&self) -> usize {
260 48
261 }
262 fn output_len(&self) -> usize {
263 48
264 }
265 fn min_key_len(&self) -> usize {
266 48
267 }
268 fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
269 if out.len() < 48 {
270 return Err(CryptoError::BufferTooSmall);
271 }
272 let mut mac =
273 hmac::Hmac::<sha2::Sha384>::new_from_slice(key).map_err(|_| CryptoError::InvalidKey)?;
274 mac.update(msg);
275 let result = mac.finalize().into_bytes();
276 out[..48].copy_from_slice(&result);
277 Ok(())
278 }
279 fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
280 if tag.len() != 48 {
281 return Err(CryptoError::InvalidTag);
282 }
283 let mut expected = [0u8; 48];
284 self.mac(key, msg, &mut expected)?;
285 if expected.ct_eq(tag).into() {
286 Ok(())
287 } else {
288 Err(CryptoError::InvalidTag)
289 }
290 }
291}
292
293impl HmacSha384 {
294 pub const OUTPUT_LEN: usize = 48;
296
297 pub fn new_keyed(key: &[u8]) -> Result<HmacSha384Keyed, CryptoError> {
299 HmacSha384Keyed::new(key)
300 }
301
302 pub fn mac_truncated(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
307 let n = out.len();
308 if n < 16 {
309 return Err(CryptoError::BadInput);
310 }
311 let mut full = [0u8; 48];
312 self.mac(key, msg, &mut full)?;
313 out.copy_from_slice(&full[..n]);
314 Ok(())
315 }
316
317 pub fn verify_truncated(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
322 let n = tag.len();
323 if n < 16 {
324 return Err(CryptoError::BadInput);
325 }
326 let mut buf = [0u8; 48];
327 self.mac(key, msg, &mut buf)?;
328 if buf[..n].ct_eq(tag).into() {
329 Ok(())
330 } else {
331 Err(CryptoError::InvalidTag)
332 }
333 }
334}
335
336pub struct HmacStreamingAdapter<D: hmac::digest::block_api::EagerHash>
343where
344 hmac::Hmac<D>: HmacMac + KeyInit,
345{
346 inner: hmac::Hmac<D>,
347}
348
349impl<D: hmac::digest::block_api::EagerHash> HmacStreamingAdapter<D>
350where
351 hmac::Hmac<D>: HmacMac + KeyInit,
352{
353 pub fn new(key: &[u8]) -> Result<Self, CryptoError> {
357 let inner = hmac::Hmac::<D>::new_from_slice(key).map_err(|_| CryptoError::InvalidKey)?;
358 Ok(Self { inner })
359 }
360}
361
362impl<D: hmac::digest::block_api::EagerHash + Send> StreamingMac for HmacStreamingAdapter<D>
363where
364 hmac::Hmac<D>: HmacMac + KeyInit + Send,
365{
366 fn update(&mut self, data: &[u8]) {
367 self.inner.update(data);
368 }
369
370 fn finalize(self, out: &mut [u8]) -> Result<(), CryptoError> {
371 let tag = self.inner.finalize().into_bytes();
372 if out.len() < tag.len() {
373 return Err(CryptoError::BufferTooSmall);
374 }
375 out[..tag.len()].copy_from_slice(&tag);
376 Ok(())
377 }
378
379 fn verify(self, expected: &[u8]) -> Result<(), CryptoError> {
380 let tag = self.inner.finalize().into_bytes();
381 if tag.len() != expected.len() {
382 return Err(CryptoError::InvalidTag);
383 }
384 if tag.as_slice().ct_eq(expected).into() {
385 Ok(())
386 } else {
387 Err(CryptoError::InvalidTag)
388 }
389 }
390}
391
392pub type HmacSha256Streaming = HmacStreamingAdapter<sha2::Sha256>;
394pub type HmacSha384Streaming = HmacStreamingAdapter<sha2::Sha384>;
396pub type HmacSha512Streaming = HmacStreamingAdapter<sha2::Sha512>;
398
399pub struct HmacSha256Keyed(hmac::Hmac<sha2::Sha256>);
407
408impl HmacSha256Keyed {
409 pub fn new(key: &[u8]) -> Result<Self, CryptoError> {
411 hmac::Hmac::<sha2::Sha256>::new_from_slice(key)
412 .map(Self)
413 .map_err(|_| CryptoError::InvalidKey)
414 }
415}
416
417impl StreamingMac for HmacSha256Keyed {
418 fn update(&mut self, data: &[u8]) {
419 HmacMac::update(&mut self.0, data);
420 }
421 fn finalize(self, out: &mut [u8]) -> Result<(), CryptoError> {
422 let result = HmacMac::finalize(self.0).into_bytes();
423 if out.len() < result.len() {
424 return Err(CryptoError::BufferTooSmall);
425 }
426 out[..result.len()].copy_from_slice(&result);
427 Ok(())
428 }
429 fn verify(self, expected: &[u8]) -> Result<(), CryptoError> {
430 let tag = HmacMac::finalize(self.0).into_bytes();
431 if tag.len() != expected.len() {
432 return Err(CryptoError::InvalidTag);
433 }
434 if tag.as_slice().ct_eq(expected).into() {
435 Ok(())
436 } else {
437 Err(CryptoError::InvalidTag)
438 }
439 }
440}
441
442pub struct HmacSha512Keyed(hmac::Hmac<sha2::Sha512>);
448
449impl HmacSha512Keyed {
450 pub fn new(key: &[u8]) -> Result<Self, CryptoError> {
452 hmac::Hmac::<sha2::Sha512>::new_from_slice(key)
453 .map(Self)
454 .map_err(|_| CryptoError::InvalidKey)
455 }
456}
457
458impl StreamingMac for HmacSha512Keyed {
459 fn update(&mut self, data: &[u8]) {
460 HmacMac::update(&mut self.0, data);
461 }
462 fn finalize(self, out: &mut [u8]) -> Result<(), CryptoError> {
463 let result = HmacMac::finalize(self.0).into_bytes();
464 if out.len() < result.len() {
465 return Err(CryptoError::BufferTooSmall);
466 }
467 out[..result.len()].copy_from_slice(&result);
468 Ok(())
469 }
470 fn verify(self, expected: &[u8]) -> Result<(), CryptoError> {
471 let tag = HmacMac::finalize(self.0).into_bytes();
472 if tag.len() != expected.len() {
473 return Err(CryptoError::InvalidTag);
474 }
475 if tag.as_slice().ct_eq(expected).into() {
476 Ok(())
477 } else {
478 Err(CryptoError::InvalidTag)
479 }
480 }
481}
482
483pub struct HmacSha384Keyed(hmac::Hmac<sha2::Sha384>);
489
490impl HmacSha384Keyed {
491 pub fn new(key: &[u8]) -> Result<Self, CryptoError> {
493 hmac::Hmac::<sha2::Sha384>::new_from_slice(key)
494 .map(Self)
495 .map_err(|_| CryptoError::InvalidKey)
496 }
497}
498
499impl StreamingMac for HmacSha384Keyed {
500 fn update(&mut self, data: &[u8]) {
501 HmacMac::update(&mut self.0, data);
502 }
503 fn finalize(self, out: &mut [u8]) -> Result<(), CryptoError> {
504 let result = HmacMac::finalize(self.0).into_bytes();
505 if out.len() < result.len() {
506 return Err(CryptoError::BufferTooSmall);
507 }
508 out[..result.len()].copy_from_slice(&result);
509 Ok(())
510 }
511 fn verify(self, expected: &[u8]) -> Result<(), CryptoError> {
512 let tag = HmacMac::finalize(self.0).into_bytes();
513 if tag.len() != expected.len() {
514 return Err(CryptoError::InvalidTag);
515 }
516 if tag.as_slice().ct_eq(expected).into() {
517 Ok(())
518 } else {
519 Err(CryptoError::InvalidTag)
520 }
521 }
522}
523
524#[derive(Debug, Default, Clone, Copy)]
531pub struct HmacSha3_256;
532
533impl Mac for HmacSha3_256 {
534 fn name(&self) -> &'static str {
535 "HMAC-SHA3-256"
536 }
537 fn key_len(&self) -> usize {
538 32
539 }
540 fn output_len(&self) -> usize {
541 32
542 }
543 fn min_key_len(&self) -> usize {
544 32
545 }
546 fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
547 use digest::KeyInit as _;
548
549 if out.len() < 32 {
550 return Err(CryptoError::BufferTooSmall);
551 }
552 let mut mac = hmac::SimpleHmac::<sha3::Sha3_256>::new_from_slice(key)
553 .map_err(|_| CryptoError::InvalidKey)?;
554 HmacMac::update(&mut mac, msg);
555 let result = HmacMac::finalize(mac).into_bytes();
556 out[..32].copy_from_slice(&result);
557 Ok(())
558 }
559 fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
560 if tag.len() != 32 {
561 return Err(CryptoError::InvalidTag);
562 }
563 let mut expected = [0u8; 32];
564 self.mac(key, msg, &mut expected)?;
565 if expected.ct_eq(tag).into() {
566 Ok(())
567 } else {
568 Err(CryptoError::InvalidTag)
569 }
570 }
571}
572
573impl HmacSha3_256 {
574 pub const OUTPUT_LEN: usize = 32;
576}
577
578#[derive(Debug, Default, Clone, Copy)]
585pub struct HmacSha3_512;
586
587impl Mac for HmacSha3_512 {
588 fn name(&self) -> &'static str {
589 "HMAC-SHA3-512"
590 }
591 fn key_len(&self) -> usize {
592 64
593 }
594 fn output_len(&self) -> usize {
595 64
596 }
597 fn min_key_len(&self) -> usize {
598 64
599 }
600 fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
601 use digest::KeyInit as _;
602
603 if out.len() < 64 {
604 return Err(CryptoError::BufferTooSmall);
605 }
606 let mut mac = hmac::SimpleHmac::<sha3::Sha3_512>::new_from_slice(key)
607 .map_err(|_| CryptoError::InvalidKey)?;
608 HmacMac::update(&mut mac, msg);
609 let result = HmacMac::finalize(mac).into_bytes();
610 out[..64].copy_from_slice(&result);
611 Ok(())
612 }
613 fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
614 if tag.len() != 64 {
615 return Err(CryptoError::InvalidTag);
616 }
617 let mut expected = [0u8; 64];
618 self.mac(key, msg, &mut expected)?;
619 if expected.ct_eq(tag).into() {
620 Ok(())
621 } else {
622 Err(CryptoError::InvalidTag)
623 }
624 }
625}
626
627impl HmacSha3_512 {
628 pub const OUTPUT_LEN: usize = 64;
630}
631
632#[derive(Debug, Default, Clone, Copy)]
643pub struct Poly1305Mac;
644
645impl Mac for Poly1305Mac {
646 fn name(&self) -> &'static str {
647 "Poly1305"
648 }
649 fn key_len(&self) -> usize {
650 32
651 }
652 fn output_len(&self) -> usize {
653 16
654 }
655 fn min_key_len(&self) -> usize {
656 32
657 }
658 fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
659 use poly1305::universal_hash::KeyInit as _;
660
661 if key.len() != 32 {
662 return Err(CryptoError::InvalidKey);
663 }
664 if out.len() < 16 {
665 return Err(CryptoError::BufferTooSmall);
666 }
667 let key_arr = poly1305::Key::try_from(key).map_err(|_| CryptoError::InvalidKey)?;
668 let mac = poly1305::Poly1305::new(&key_arr);
669 let tag = mac.compute_unpadded(msg);
673 out[..16].copy_from_slice(tag.as_slice());
674 Ok(())
675 }
676 fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
677 if tag.len() != 16 {
678 return Err(CryptoError::InvalidTag);
679 }
680 let mut computed = [0u8; 16];
681 self.mac(key, msg, &mut computed)?;
682 if computed.ct_eq(tag).into() {
683 Ok(())
684 } else {
685 Err(CryptoError::InvalidTag)
686 }
687 }
688}
689
690impl Poly1305Mac {
691 pub const OUTPUT_LEN: usize = 16;
693}
694
695#[derive(Debug, Default, Clone, Copy)]
701pub struct CmacAes128;
702
703impl Mac for CmacAes128 {
704 fn name(&self) -> &'static str {
705 "CMAC-AES-128"
706 }
707 fn key_len(&self) -> usize {
708 16
709 }
710 fn output_len(&self) -> usize {
711 16
712 }
713 fn min_key_len(&self) -> usize {
714 16
715 }
716 fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
717 use cmac::Mac as _;
718 use digest::KeyInit as _;
719
720 if out.len() < 16 {
721 return Err(CryptoError::BufferTooSmall);
722 }
723 let mut mac = cmac::Cmac::<aes_cipher05::Aes128>::new_from_slice(key)
724 .map_err(|_| CryptoError::InvalidKey)?;
725 mac.update(msg);
726 let result = mac.finalize().into_bytes();
727 out[..16].copy_from_slice(&result);
728 Ok(())
729 }
730 fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
731 if tag.len() != 16 {
732 return Err(CryptoError::InvalidTag);
733 }
734 let mut expected = [0u8; 16];
735 self.mac(key, msg, &mut expected)?;
736 if expected.ct_eq(tag).into() {
737 Ok(())
738 } else {
739 Err(CryptoError::InvalidTag)
740 }
741 }
742}
743
744impl CmacAes128 {
745 pub const OUTPUT_LEN: usize = 16;
747}
748
749#[derive(Debug, Default, Clone, Copy)]
755pub struct CmacAes256;
756
757impl Mac for CmacAes256 {
758 fn name(&self) -> &'static str {
759 "CMAC-AES-256"
760 }
761 fn key_len(&self) -> usize {
762 32
763 }
764 fn output_len(&self) -> usize {
765 16
766 }
767 fn min_key_len(&self) -> usize {
768 32
769 }
770 fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
771 use cmac::Mac as _;
772 use digest::KeyInit as _;
773
774 if out.len() < 16 {
775 return Err(CryptoError::BufferTooSmall);
776 }
777 let mut mac = cmac::Cmac::<aes_cipher05::Aes256>::new_from_slice(key)
778 .map_err(|_| CryptoError::InvalidKey)?;
779 mac.update(msg);
780 let result = mac.finalize().into_bytes();
781 out[..16].copy_from_slice(&result);
782 Ok(())
783 }
784 fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
785 if tag.len() != 16 {
786 return Err(CryptoError::InvalidTag);
787 }
788 let mut expected = [0u8; 16];
789 self.mac(key, msg, &mut expected)?;
790 if expected.ct_eq(tag).into() {
791 Ok(())
792 } else {
793 Err(CryptoError::InvalidTag)
794 }
795 }
796}
797
798impl CmacAes256 {
799 pub const OUTPUT_LEN: usize = 16;
801}
802
803pub struct Kmac128 {
810 custom: alloc::vec::Vec<u8>,
812 output_len: usize,
814}
815
816impl Kmac128 {
817 pub fn new(custom: &[u8], output_len: usize) -> Result<Self, CryptoError> {
821 if output_len == 0 {
822 return Err(CryptoError::BadInput);
823 }
824 Ok(Self {
825 custom: custom.to_vec(),
826 output_len,
827 })
828 }
829}
830
831impl core::fmt::Debug for Kmac128 {
832 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
833 f.debug_struct("Kmac128")
834 .field("output_len", &self.output_len)
835 .finish()
836 }
837}
838
839impl Mac for Kmac128 {
840 fn name(&self) -> &'static str {
841 "KMAC128"
842 }
843 fn key_len(&self) -> usize {
844 16
846 }
847 fn output_len(&self) -> usize {
848 self.output_len
849 }
850 fn min_key_len(&self) -> usize {
851 16
852 }
853 fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
854 use tiny_keccak::Hasher as _;
855 if out.len() < self.output_len {
856 return Err(CryptoError::BufferTooSmall);
857 }
858 let mut kmac = tiny_keccak::Kmac::v128(key, &self.custom);
859 kmac.update(msg);
860 kmac.finalize(&mut out[..self.output_len]);
861 Ok(())
862 }
863 fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
864 if tag.len() != self.output_len {
865 return Err(CryptoError::InvalidTag);
866 }
867 let mut computed = alloc::vec![0u8; self.output_len];
868 self.mac(key, msg, &mut computed)?;
869 if computed.ct_eq(tag).into() {
870 Ok(())
871 } else {
872 Err(CryptoError::InvalidTag)
873 }
874 }
875}
876
877pub struct Kmac256 {
884 custom: alloc::vec::Vec<u8>,
886 output_len: usize,
888}
889
890impl Kmac256 {
891 pub fn new(custom: &[u8], output_len: usize) -> Result<Self, CryptoError> {
895 if output_len == 0 {
896 return Err(CryptoError::BadInput);
897 }
898 Ok(Self {
899 custom: custom.to_vec(),
900 output_len,
901 })
902 }
903}
904
905impl core::fmt::Debug for Kmac256 {
906 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
907 f.debug_struct("Kmac256")
908 .field("output_len", &self.output_len)
909 .finish()
910 }
911}
912
913impl Mac for Kmac256 {
914 fn name(&self) -> &'static str {
915 "KMAC256"
916 }
917 fn key_len(&self) -> usize {
918 32
919 }
920 fn output_len(&self) -> usize {
921 self.output_len
922 }
923 fn min_key_len(&self) -> usize {
924 16
925 }
926 fn mac(&self, key: &[u8], msg: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
927 use tiny_keccak::Hasher as _;
928 if out.len() < self.output_len {
929 return Err(CryptoError::BufferTooSmall);
930 }
931 let mut kmac = tiny_keccak::Kmac::v256(key, &self.custom);
932 kmac.update(msg);
933 kmac.finalize(&mut out[..self.output_len]);
934 Ok(())
935 }
936 fn verify(&self, key: &[u8], msg: &[u8], tag: &[u8]) -> Result<(), CryptoError> {
937 if tag.len() != self.output_len {
938 return Err(CryptoError::InvalidTag);
939 }
940 let mut computed = alloc::vec![0u8; self.output_len];
941 self.mac(key, msg, &mut computed)?;
942 if computed.ct_eq(tag).into() {
943 Ok(())
944 } else {
945 Err(CryptoError::InvalidTag)
946 }
947 }
948}
949
950pub fn kmac128_xof(
965 key: &[u8],
966 custom: &[u8],
967 msg: &[u8],
968 output_len: usize,
969) -> Result<alloc::vec::Vec<u8>, CryptoError> {
970 use tiny_keccak::Hasher as _;
971 if output_len == 0 {
972 return Err(CryptoError::BadInput);
973 }
974 let mut k = tiny_keccak::Kmac::v128(key, custom);
975 k.update(msg);
976 let mut out = alloc::vec![0u8; output_len];
977 k.finalize(&mut out);
978 Ok(out)
979}
980
981pub fn kmac256_xof(
994 key: &[u8],
995 custom: &[u8],
996 msg: &[u8],
997 output_len: usize,
998) -> Result<alloc::vec::Vec<u8>, CryptoError> {
999 use tiny_keccak::Hasher as _;
1000 if output_len == 0 {
1001 return Err(CryptoError::BadInput);
1002 }
1003 let mut k = tiny_keccak::Kmac::v256(key, custom);
1004 k.update(msg);
1005 let mut out = alloc::vec![0u8; output_len];
1006 k.finalize(&mut out);
1007 Ok(out)
1008}
1009
1010pub fn blake3_keyed_mac(key: &[u8; 32], msg: &[u8]) -> [u8; 32] {
1023 *blake3::Hasher::new_keyed(key)
1024 .update(msg)
1025 .finalize()
1026 .as_bytes()
1027}
1028
1029pub fn blake3_keyed_mac_verify(
1034 key: &[u8; 32],
1035 msg: &[u8],
1036 expected: &[u8; 32],
1037) -> Result<(), CryptoError> {
1038 let actual = blake3_keyed_mac(key, msg);
1039 if actual.ct_eq(expected).into() {
1040 Ok(())
1041 } else {
1042 Err(CryptoError::InvalidTag)
1043 }
1044}
1045
1046pub fn hmac_sha256_verify_truncated(
1061 key: &[u8],
1062 msg: &[u8],
1063 truncated_tag: &[u8],
1064) -> Result<(), CryptoError> {
1065 if truncated_tag.is_empty() || truncated_tag.len() > 32 {
1066 return Err(CryptoError::BadInput);
1067 }
1068 let mut buf = [0u8; 32];
1069 HmacSha256.mac(key, msg, &mut buf)?;
1070 if buf[..truncated_tag.len()].ct_eq(truncated_tag).into() {
1071 Ok(())
1072 } else {
1073 Err(CryptoError::InvalidTag)
1074 }
1075}
1076
1077pub mod tls;
1083pub use tls::{mac_name_for_suite, negotiate_mac, TlsCipherSuite};
1084
1085#[must_use = "MAC result must be used or verified"]
1096pub fn hmac_sha256_to_vec(key: &[u8], msg: &[u8]) -> Result<alloc::vec::Vec<u8>, CryptoError> {
1097 let mut out = alloc::vec![0u8; 32];
1098 HmacSha256.mac(key, msg, &mut out)?;
1099 Ok(out)
1100}
1101
1102#[must_use = "MAC result must be used or verified"]
1111pub fn hmac_sha384_to_vec(key: &[u8], msg: &[u8]) -> Result<alloc::vec::Vec<u8>, CryptoError> {
1112 let mut out = alloc::vec![0u8; 48];
1113 HmacSha384.mac(key, msg, &mut out)?;
1114 Ok(out)
1115}
1116
1117#[must_use = "MAC result must be used or verified"]
1126pub fn hmac_sha512_to_vec(key: &[u8], msg: &[u8]) -> Result<alloc::vec::Vec<u8>, CryptoError> {
1127 let mut out = alloc::vec![0u8; 64];
1128 HmacSha512.mac(key, msg, &mut out)?;
1129 Ok(out)
1130}
1131
1132#[cfg(test)]
1135mod tests {
1136 include!("tests_inline.rs");
1137}