1use crate::secure::crypto::aes128_encrypt;
14use crate::secure::pad::pad_mac;
15use alloc::vec::Vec;
16
17#[inline]
19fn xor_in_place(dst: &mut [u8; 16], src: &[u8]) {
20 for (d, s) in dst.iter_mut().zip(src.iter()) {
21 *d ^= *s;
22 }
23}
24
25pub fn cbc_mac(input: &[u8], icv: &[u8; 16], s_mac1: &[u8; 16], s_mac2: &[u8; 16]) -> [u8; 16] {
33 let mut padded = Vec::with_capacity(input.len() + 16);
34 padded.extend_from_slice(input);
35 pad_mac(&mut padded);
36 debug_assert_eq!(padded.len() % 16, 0);
37 debug_assert!(!padded.is_empty());
38
39 let mut state = *icv;
40 let blocks = padded.len() / 16;
41 for (i, chunk) in padded.chunks_exact(16).enumerate() {
42 xor_in_place(&mut state, chunk);
43 let key = if i + 1 == blocks { s_mac2 } else { s_mac1 };
44 state = aes128_encrypt(key, &state);
45 }
46 state
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52
53 #[test]
55 fn deterministic() {
56 let icv = [0u8; 16];
57 let s1 = [1u8; 16];
58 let s2 = [2u8; 16];
59 let m1 = cbc_mac(&[1, 2, 3], &icv, &s1, &s2);
60 let m2 = cbc_mac(&[1, 2, 3], &icv, &s1, &s2);
61 assert_eq!(m1, m2);
62 }
63
64 #[test]
66 fn distinct_inputs_distinct_macs() {
67 let icv = [0u8; 16];
68 let s1 = [1u8; 16];
69 let s2 = [2u8; 16];
70 let m1 = cbc_mac(&[1], &icv, &s1, &s2);
71 let m2 = cbc_mac(&[2], &icv, &s1, &s2);
72 assert_ne!(m1, m2);
73 }
74
75 #[test]
77 fn icv_matters() {
78 let s1 = [1u8; 16];
79 let s2 = [2u8; 16];
80 let m1 = cbc_mac(&[7, 8, 9], &[0u8; 16], &s1, &s2);
81 let m2 = cbc_mac(&[7, 8, 9], &[1u8; 16], &s1, &s2);
82 assert_ne!(m1, m2);
83 }
84
85 #[test]
87 fn key_swap_observable() {
88 let icv = [0u8; 16];
89 let s1 = [1u8; 16];
90 let s2_a = [2u8; 16];
91 let s2_b = [3u8; 16];
92 let input = [0u8; 32];
93 let m1 = cbc_mac(&input, &icv, &s1, &s2_a);
94 let m2 = cbc_mac(&input, &icv, &s1, &s2_b);
95 assert_ne!(m1, m2);
96 }
97}