1use crate::aws_lc::{
95 CMAC_CTX_copy, CMAC_CTX_new, CMAC_Final, CMAC_Init, CMAC_Update, EVP_aes_128_cbc,
96 EVP_aes_192_cbc, EVP_aes_256_cbc, EVP_des_ede3_cbc, CMAC_CTX, EVP_CIPHER,
97};
98use crate::error::Unspecified;
99use crate::fips::indicator_check;
100use crate::ptr::{ConstPointer, LcPtr};
101use crate::{constant_time, rand};
102use core::mem::MaybeUninit;
103use core::ptr::null_mut;
104
105#[derive(Clone, Copy, PartialEq, Eq, Debug)]
106enum AlgorithmId {
107 Aes128,
108 Aes192,
109 Aes256,
110 Tdes,
111}
112
113#[derive(Clone, Copy, PartialEq, Eq, Debug)]
115pub struct Algorithm {
116 id: AlgorithmId,
117 key_len: usize,
118 tag_len: usize,
119}
120
121impl Algorithm {
122 #[inline]
124 #[must_use]
125 pub fn key_len(&self) -> usize {
126 self.key_len
127 }
128
129 #[inline]
131 #[must_use]
132 pub fn tag_len(&self) -> usize {
133 self.tag_len
134 }
135}
136
137impl AlgorithmId {
138 fn evp_cipher(&self) -> ConstPointer<'_, EVP_CIPHER> {
139 unsafe {
140 ConstPointer::new_static(match self {
141 AlgorithmId::Aes128 => EVP_aes_128_cbc(),
142 AlgorithmId::Aes192 => EVP_aes_192_cbc(),
143 AlgorithmId::Aes256 => EVP_aes_256_cbc(),
144 AlgorithmId::Tdes => EVP_des_ede3_cbc(),
145 })
146 .unwrap()
147 }
148 }
149}
150
151pub const AES_128: Algorithm = Algorithm {
153 id: AlgorithmId::Aes128,
154 key_len: 16,
155 tag_len: 16,
156};
157
158pub const AES_192: Algorithm = Algorithm {
160 id: AlgorithmId::Aes192,
161 key_len: 24,
162 tag_len: 16,
163};
164
165pub const AES_256: Algorithm = Algorithm {
167 id: AlgorithmId::Aes256,
168 key_len: 32,
169 tag_len: 16,
170};
171
172pub const TDES_FOR_LEGACY_USE_ONLY: Algorithm = Algorithm {
174 id: AlgorithmId::Tdes,
175 key_len: 24,
176 tag_len: 8,
177};
178
179const MAX_CMAC_TAG_LEN: usize = 16;
181
182#[derive(Clone, Copy, Debug)]
186pub struct Tag {
187 bytes: [u8; MAX_CMAC_TAG_LEN],
188 len: usize,
189}
190
191impl AsRef<[u8]> for Tag {
192 #[inline]
193 fn as_ref(&self) -> &[u8] {
194 &self.bytes[..self.len]
195 }
196}
197
198#[derive(Clone)]
205pub struct Key {
206 algorithm: Algorithm,
207 ctx: LcPtr<CMAC_CTX>,
208}
209
210impl Clone for LcPtr<CMAC_CTX> {
211 fn clone(&self) -> Self {
212 let mut new_ctx = LcPtr::new(unsafe { CMAC_CTX_new() }).expect("CMAC_CTX_new failed");
213 unsafe {
214 assert!(
215 1 == CMAC_CTX_copy(new_ctx.as_mut_ptr(), self.as_const_ptr()),
216 "CMAC_CTX_copy failed"
217 );
218 }
219 new_ctx
220 }
221}
222
223unsafe impl Send for Key {}
224unsafe impl Sync for Key {}
226
227#[allow(clippy::missing_fields_in_debug)]
228impl core::fmt::Debug for Key {
229 fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
230 f.debug_struct("Key")
231 .field("algorithm", &self.algorithm)
232 .finish()
233 }
234}
235
236impl Key {
237 pub fn generate(algorithm: Algorithm) -> Result<Self, Unspecified> {
249 let mut key_bytes = vec![0u8; algorithm.key_len()];
250 rand::fill(&mut key_bytes)?;
251 Self::new(algorithm, &key_bytes)
252 }
253
254 pub fn new(algorithm: Algorithm, key_value: &[u8]) -> Result<Self, Unspecified> {
263 if key_value.len() != algorithm.key_len() {
264 return Err(Unspecified);
265 }
266
267 let mut ctx = LcPtr::new(unsafe { CMAC_CTX_new() })?;
268
269 unsafe {
270 let cipher = algorithm.id.evp_cipher();
271 if 1 != CMAC_Init(
272 ctx.as_mut_ptr(),
273 key_value.as_ptr().cast(),
274 key_value.len(),
275 cipher.as_const_ptr(),
276 null_mut(),
277 ) {
278 return Err(Unspecified);
279 }
280 }
281
282 Ok(Self { algorithm, ctx })
283 }
284
285 #[inline]
287 #[must_use]
288 pub fn algorithm(&self) -> Algorithm {
289 self.algorithm
290 }
291}
292
293pub struct Context {
297 key: Key,
298}
299
300impl Clone for Context {
301 fn clone(&self) -> Self {
302 Self {
303 key: self.key.clone(),
304 }
305 }
306}
307
308unsafe impl Send for Context {}
309
310impl core::fmt::Debug for Context {
311 fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
312 f.debug_struct("Context")
313 .field("algorithm", &self.key.algorithm)
314 .finish()
315 }
316}
317
318impl Context {
319 #[inline]
321 #[must_use]
322 pub fn with_key(key: &Key) -> Self {
323 Self { key: key.clone() }
324 }
325
326 pub fn update(&mut self, data: &[u8]) -> Result<(), Unspecified> {
332 unsafe {
333 if 1 != CMAC_Update(self.key.ctx.as_mut_ptr(), data.as_ptr(), data.len()) {
334 return Err(Unspecified);
335 }
336 }
337 Ok(())
338 }
339
340 pub fn sign(mut self) -> Result<Tag, Unspecified> {
360 let mut output = [0u8; MAX_CMAC_TAG_LEN];
361 let output_len = {
362 let result = internal_sign(&mut self, &mut output)?;
363 result.len()
364 };
365
366 Ok(Tag {
367 bytes: output,
368 len: output_len,
369 })
370 }
371
372 #[inline]
388 pub fn verify(mut self, tag: &[u8]) -> Result<(), Unspecified> {
389 let mut output = [0u8; MAX_CMAC_TAG_LEN];
390 let output_len = {
391 let result = internal_sign(&mut self, &mut output)?;
392 result.len()
393 };
394
395 constant_time::verify_slices_are_equal(&output[0..output_len], tag)
396 }
397}
398
399pub(crate) fn internal_sign<'in_out>(
400 ctx: &mut Context,
401 output: &'in_out mut [u8],
402) -> Result<&'in_out mut [u8], Unspecified> {
403 let mut out_len = MaybeUninit::<usize>::uninit();
404
405 if 1 != indicator_check!(unsafe {
406 CMAC_Final(
407 ctx.key.ctx.as_mut_ptr(),
408 output.as_mut_ptr(),
409 out_len.as_mut_ptr(),
410 )
411 }) {
412 return Err(Unspecified);
413 }
414 let actual_len = unsafe { out_len.assume_init() };
415
416 debug_assert!(
418 actual_len <= MAX_CMAC_TAG_LEN,
419 "CMAC tag length {actual_len} exceeds maximum {MAX_CMAC_TAG_LEN}"
420 );
421 if actual_len != ctx.key.algorithm.tag_len() {
422 return Err(Unspecified);
423 }
424
425 Ok(&mut output[0..actual_len])
426}
427
428#[inline]
443pub fn sign(key: &Key, data: &[u8]) -> Result<Tag, Unspecified> {
444 let mut ctx = Context::with_key(key);
445 ctx.update(data)?;
446 ctx.sign()
447}
448
449#[inline]
469pub fn sign_to_buffer<'out>(
470 key: &Key,
471 data: &[u8],
472 output: &'out mut [u8],
473) -> Result<&'out mut [u8], Unspecified> {
474 if output.len() < key.algorithm().tag_len() {
475 return Err(Unspecified);
476 }
477
478 let mut ctx = Context::with_key(key);
479 ctx.update(data)?;
480
481 internal_sign(&mut ctx, output)
482}
483
484#[inline]
497pub fn verify(key: &Key, data: &[u8], tag: &[u8]) -> Result<(), Unspecified> {
498 let mut output = [0u8; MAX_CMAC_TAG_LEN];
499 let output_len = {
500 let result = sign_to_buffer(key, data, &mut output)?;
501 result.len()
502 };
503
504 constant_time::verify_slices_are_equal(&output[0..output_len], tag)
505}
506
507#[cfg(test)]
508mod tests {
509 use super::*;
510
511 #[cfg(feature = "fips")]
512 mod fips;
513
514 #[test]
515 fn cmac_basic_test() {
516 for &algorithm in &[AES_128, AES_192, AES_256, TDES_FOR_LEGACY_USE_ONLY] {
517 let key = Key::generate(algorithm).unwrap();
518 let data = b"hello, world";
519
520 let tag = sign(&key, data).unwrap();
521 assert!(verify(&key, data, tag.as_ref()).is_ok());
522 assert!(verify(&key, b"hello, worle", tag.as_ref()).is_err());
523 }
524 }
525
526 #[test]
528 pub fn cmac_signing_key_coverage() {
529 const HELLO_WORLD_GOOD: &[u8] = b"hello, world";
530 const HELLO_WORLD_BAD: &[u8] = b"hello, worle";
531
532 for algorithm in &[AES_128, AES_192, AES_256, TDES_FOR_LEGACY_USE_ONLY] {
533 let key = Key::generate(*algorithm).unwrap();
534 let tag = sign(&key, HELLO_WORLD_GOOD).unwrap();
535 println!("{key:?}");
536 assert!(verify(&key, HELLO_WORLD_GOOD, tag.as_ref()).is_ok());
537 assert!(verify(&key, HELLO_WORLD_BAD, tag.as_ref()).is_err());
538 }
539 }
540
541 #[test]
542 fn cmac_coverage() {
543 assert_ne!(AES_128, AES_256);
546 assert_ne!(AES_192, AES_256);
547
548 for &alg in &[AES_128, AES_192, AES_256, TDES_FOR_LEGACY_USE_ONLY] {
549 let key_bytes = vec![0u8; alg.key_len()];
551 let key = Key::new(alg, &key_bytes).unwrap();
552 let mut ctx = Context::with_key(&key);
553 ctx.update(b"hello, world").unwrap();
554 let ctx_clone = ctx.clone();
555
556 let orig_tag = ctx.sign().unwrap();
557 let clone_tag = ctx_clone.sign().unwrap();
558 assert_eq!(orig_tag.as_ref(), clone_tag.as_ref());
559 assert_eq!(orig_tag.clone().as_ref(), clone_tag.as_ref());
560 }
561 }
562
563 #[test]
564 fn cmac_context_test() {
565 let key = Key::generate(AES_192).unwrap();
566
567 let mut ctx = Context::with_key(&key);
568 ctx.update(b"hello").unwrap();
569 ctx.update(b", ").unwrap();
570 ctx.update(b"world").unwrap();
571 let tag1 = ctx.sign().unwrap();
572
573 let tag2 = sign(&key, b"hello, world").unwrap();
574 assert_eq!(tag1.as_ref(), tag2.as_ref());
575 }
576
577 #[test]
578 fn cmac_multi_part_test() {
579 let parts = ["hello", ", ", "world"];
580
581 for &algorithm in &[AES_128, AES_256] {
582 let key = Key::generate(algorithm).unwrap();
583
584 let mut ctx = Context::with_key(&key);
586 for part in &parts {
587 ctx.update(part.as_bytes()).unwrap();
588 }
589 let tag = ctx.sign().unwrap();
590
591 let mut msg = Vec::<u8>::new();
593 for part in &parts {
594 msg.extend(part.as_bytes());
595 }
596 assert!(verify(&key, &msg, tag.as_ref()).is_ok());
597 }
598 }
599
600 #[test]
601 fn cmac_key_new_test() {
602 let key_128 = [0u8; 16];
604 let key_192 = [0u8; 24];
605 let key_256 = [0u8; 32];
606 let key_3des = [0u8; 24];
607
608 let k1 = Key::new(AES_128, &key_128).unwrap();
609 let k2 = Key::new(AES_192, &key_192).unwrap();
610 let k3 = Key::new(AES_256, &key_256).unwrap();
611 let k4 = Key::new(TDES_FOR_LEGACY_USE_ONLY, &key_3des).unwrap();
612
613 let data = b"test message";
614
615 let _ = sign(&k1, data).unwrap();
617 let _ = sign(&k2, data).unwrap();
618 let _ = sign(&k3, data).unwrap();
619 let _ = sign(&k4, data).unwrap();
620 }
621
622 #[test]
623 fn cmac_key_new_wrong_length_test() {
624 let key_256 = [0u8; 32];
625 assert!(Key::new(AES_128, &key_256).is_err());
627 }
628
629 #[test]
630 fn cmac_algorithm_properties() {
631 assert_eq!(AES_128.key_len(), 16);
632 assert_eq!(AES_128.tag_len(), 16);
633
634 assert_eq!(AES_192.key_len(), 24);
635 assert_eq!(AES_192.tag_len(), 16);
636
637 assert_eq!(AES_256.key_len(), 32);
638 assert_eq!(AES_256.tag_len(), 16);
639
640 assert_eq!(TDES_FOR_LEGACY_USE_ONLY.key_len(), 24);
641 assert_eq!(TDES_FOR_LEGACY_USE_ONLY.tag_len(), 8);
642 }
643
644 #[test]
645 fn cmac_empty_data() {
646 let key = Key::generate(AES_128).unwrap();
647
648 let tag = sign(&key, b"").unwrap();
650 assert!(verify(&key, b"", tag.as_ref()).is_ok());
651
652 let ctx = Context::with_key(&key);
654 let tag2 = ctx.sign().unwrap();
655 assert_eq!(tag.as_ref(), tag2.as_ref());
656 }
657
658 #[test]
659 fn des_ede3_cmac_test() {
660 let key = Key::generate(TDES_FOR_LEGACY_USE_ONLY).unwrap();
661 let data = b"test data for 3DES CMAC";
662
663 let tag = sign(&key, data).unwrap();
664 assert_eq!(tag.as_ref().len(), 8); assert!(verify(&key, data, tag.as_ref()).is_ok());
666 }
667
668 #[test]
669 fn cmac_sign_to_buffer_test() {
670 for &algorithm in &[AES_128, AES_192, AES_256, TDES_FOR_LEGACY_USE_ONLY] {
671 let key = Key::generate(algorithm).unwrap();
672 let data = b"hello, world";
673
674 let mut output = vec![0u8; algorithm.tag_len()];
676 let result = sign_to_buffer(&key, data, &mut output).unwrap();
677 assert_eq!(result.len(), algorithm.tag_len());
678
679 let tag = sign(&key, data).unwrap();
681 assert_eq!(result, tag.as_ref());
682
683 let mut large_output = vec![0u8; algorithm.tag_len() + 10];
685 let result2 = sign_to_buffer(&key, data, &mut large_output).unwrap();
686 assert_eq!(result2.len(), algorithm.tag_len());
687 assert_eq!(result2, tag.as_ref());
688 }
689 }
690
691 #[test]
692 fn cmac_sign_to_buffer_too_small_test() {
693 let key = Key::generate(AES_128).unwrap();
694 let data = b"hello";
695
696 let mut small_buffer = vec![0u8; AES_128.tag_len() - 1];
698 assert!(sign_to_buffer(&key, data, &mut small_buffer).is_err());
699
700 let mut empty_buffer = vec![];
702 assert!(sign_to_buffer(&key, data, &mut empty_buffer).is_err());
703 }
704
705 #[test]
706 fn cmac_context_verify_test() {
707 for &algorithm in &[AES_128, AES_192, AES_256, TDES_FOR_LEGACY_USE_ONLY] {
708 let key = Key::generate(algorithm).unwrap();
709 let data = b"hello, world";
710
711 let tag = sign(&key, data).unwrap();
713
714 let mut ctx = Context::with_key(&key);
716 ctx.update(data).unwrap();
717 assert!(ctx.verify(tag.as_ref()).is_ok());
718
719 let mut ctx2 = Context::with_key(&key);
721 ctx2.update(data).unwrap();
722 let wrong_tag = vec![0u8; algorithm.tag_len()];
723 assert!(ctx2.verify(&wrong_tag).is_err());
724
725 let mut ctx3 = Context::with_key(&key);
727 ctx3.update(b"wrong data").unwrap();
728 assert!(ctx3.verify(tag.as_ref()).is_err());
729 }
730 }
731
732 #[test]
733 fn cmac_context_verify_multipart_test() {
734 let key = Key::generate(AES_256).unwrap();
735 let parts = ["hello", ", ", "world"];
736
737 let mut full_msg = Vec::new();
739 for part in &parts {
740 full_msg.extend_from_slice(part.as_bytes());
741 }
742 let tag = sign(&key, &full_msg).unwrap();
743
744 let mut ctx = Context::with_key(&key);
746 for part in &parts {
747 ctx.update(part.as_bytes()).unwrap();
748 }
749 assert!(ctx.verify(tag.as_ref()).is_ok());
750
751 let mut ctx2 = Context::with_key(&key);
753 ctx2.update(parts[0].as_bytes()).unwrap();
754 ctx2.update(parts[1].as_bytes()).unwrap();
755 assert!(ctx2.verify(tag.as_ref()).is_err());
757 }
758}