1use tink_core::{utils::wrap_err, Prf, TinkError};
20
21const MIN_CMAC_KEY_SIZE_IN_BYTES: usize = 16;
22const RECOMMENDED_CMAC_KEY_SIZE_IN_BYTES: usize = 32;
23const MIN_TAG_LENGTH_IN_BYTES: usize = 10;
24const MAX_TAG_LENGTH_IN_BYTES: usize = 16;
25
26#[derive(Clone)]
28pub struct AesCmac {
29 prf: tink_prf::subtle::AesCmacPrf,
30 tag_size: usize,
31}
32
33impl AesCmac {
34 pub fn new(key: &[u8], tag_size: usize) -> Result<AesCmac, TinkError> {
36 if key.len() < MIN_CMAC_KEY_SIZE_IN_BYTES {
37 return Err("AesCmac: Only 256 bit keys are allowed".into());
38 }
39 if tag_size < MIN_TAG_LENGTH_IN_BYTES {
40 return Err(format!(
41 "AesCmac: tag length {tag_size} is shorter than minimum tag length {MIN_TAG_LENGTH_IN_BYTES}",
42 )
43 .into());
44 }
45 if tag_size > MAX_TAG_LENGTH_IN_BYTES {
46 return Err(format!(
47 "AesCmac: tag length {tag_size} is longer than maximum tag length {MAX_TAG_LENGTH_IN_BYTES}",
48 )
49 .into());
50 }
51 let prf = tink_prf::subtle::AesCmacPrf::new(key)
52 .map_err(|e| wrap_err("AesCmac: could not create AES-CMAC prf", e))?;
53 Ok(AesCmac { prf, tag_size })
54 }
55}
56
57impl tink_core::Mac for AesCmac {
58 fn compute_mac(&self, data: &[u8]) -> Result<Vec<u8>, TinkError> {
59 self.prf.compute_prf(data, self.tag_size)
60 }
61}
62
63pub fn validate_cmac_params(key_size: usize, tag_size: usize) -> Result<(), TinkError> {
65 if key_size != RECOMMENDED_CMAC_KEY_SIZE_IN_BYTES {
66 return Err(format!(
67 "Only {RECOMMENDED_CMAC_KEY_SIZE_IN_BYTES} sized keys are allowed with Tink's AES-CMAC",
68 )
69 .into());
70 }
71 if tag_size < MIN_TAG_LENGTH_IN_BYTES {
72 return Err("Tag size too short".into());
73 }
74 if tag_size > MAX_TAG_LENGTH_IN_BYTES {
75 return Err("Tag size too long".into());
76 }
77 Ok(())
78}