1use crate::ZUC;
2
3#[derive(Debug)]
4pub struct EIA {
5 zuc: ZUC,
6}
7
8impl EIA {
9 pub fn new(ik: &[u8], count: u32, bearer: u32, direction: u32) -> EIA {
10 let mut iv = [0u8; 16];
11 iv[0] = (count >> 24) as u8;
12 iv[1] = (count >> 16) as u8;
13 iv[2] = (count >> 8) as u8;
14 iv[3] = count as u8;
15 iv[4] = (bearer << 3) as u8;
16
17 iv[8] = iv[0] ^ ((direction << 7) as u8);
18 iv[9] = iv[1];
19 iv[10] = iv[2];
20 iv[11] = iv[3];
21 iv[12] = iv[4];
22 iv[14] = iv[6] ^ ((direction << 7) as u8);
23 EIA {
24 zuc: ZUC::new(ik, &iv),
25 }
26 }
27
28 pub fn gen_mac(&mut self, m: &[u32], ilen: u32) -> u32 {
30 let keylength = (ilen + 31) / 32 + 2;
31 let keys = self.zuc.generate_keystream(keylength as usize);
32 let keys = keys.as_slice();
33 let mut t = 0_u32;
34 for i in 0..ilen as usize {
35 if m[i >> 5] & (0x1 << (31 - (i & 0x1f))) > 0 {
36 t ^= find_word(keys, i);
37 }
38 }
39
40 t ^= find_word(keys, ilen as usize);
41 t ^ find_word(keys, 32 * (keylength - 1) as usize)
42 }
43}
44
45fn find_word(keys: &[u32], i: usize) -> u32 {
50 let j = i >> 5;
51 let m = i & 0x1f;
52 if m == 0 {
53 keys[j]
54 } else {
55 (keys[j] << m) | (keys[j + 1] >> (32 - m))
56 }
57}
58
59#[cfg(test)]
60mod eia_test {
61 use crate::eia::EIA;
62
63 #[test]
64 pub fn test_eia() {
65 let ik: [u8; 16] = [
66 0xc9, 0xe6, 0xce, 0xc4, 0x60, 0x7c, 0x72, 0xdb, 0x00, 0x0a, 0xef, 0xa8, 0x83, 0x85,
67 0xab, 0x0a,
68 ];
69
70 let count = 0xa94059da_u32;
71 let bearer = 0x0a_u32;
72 let direction = 0x01_u32;
73 let length = 0x0241_u32;
74
75 let m: [u32; 19] = [
76 0x983b41d4, 0x7d780c9e, 0x1ad11d7e, 0xb70391b1, 0xde0b35da, 0x2dc62f83, 0xe7b78d63,
77 0x06ca0ea0, 0x7e941b7b, 0xe91348f9, 0xfcb170e2, 0x217fecd9, 0x7f9f68ad, 0xb16e5d7d,
78 0x21e569d2, 0x80ed775c, 0xebde3f40, 0x93c53881, 0x00000000,
79 ];
80
81 let mac = 0xfae8ff0b_u32;
82
83 let mut eia = EIA::new(&ik, count, bearer, direction);
84 let rs = eia.gen_mac(&m, length);
85 assert_eq!(mac, rs)
86 }
87}