1use aes::Aes128;
18use aes::cipher::generic_array::GenericArray;
19use aes::cipher::{BlockDecrypt, BlockEncrypt, KeyInit};
20use zeroize::{Zeroize, ZeroizeOnDrop};
21
22pub type Block = [u8; 16];
24
25#[inline]
27pub fn aes128_encrypt(key: &[u8; 16], block: &Block) -> Block {
28 let cipher = Aes128::new(GenericArray::from_slice(key));
29 let mut buf = *GenericArray::from_slice(block);
30 cipher.encrypt_block(&mut buf);
31 let mut out = [0u8; 16];
32 out.copy_from_slice(&buf);
33 out
34}
35
36#[inline]
38pub fn aes128_decrypt(key: &[u8; 16], block: &Block) -> Block {
39 let cipher = Aes128::new(GenericArray::from_slice(key));
40 let mut buf = *GenericArray::from_slice(block);
41 cipher.decrypt_block(&mut buf);
42 let mut out = [0u8; 16];
43 out.copy_from_slice(&buf);
44 out
45}
46
47fn key_template(tag1: u8, tag2: u8, rnd_a: &[u8; 8]) -> Block {
49 let mut t = [0u8; 16];
50 t[0] = tag1;
51 t[1] = tag2;
52 t[2..8].copy_from_slice(&rnd_a[0..6]);
53 t
54}
55
56#[derive(Debug, Clone, PartialEq, Eq, Default, Zeroize, ZeroizeOnDrop)]
61pub struct SessionKeys {
62 pub s_enc: [u8; 16],
64 pub s_mac1: [u8; 16],
66 pub s_mac2: [u8; 16],
68}
69
70impl SessionKeys {
71 pub fn derive(scbk: &[u8; 16], rnd_a: &[u8; 8]) -> Self {
73 Self {
74 s_enc: aes128_encrypt(scbk, &key_template(0x01, 0x82, rnd_a)),
75 s_mac1: aes128_encrypt(scbk, &key_template(0x01, 0x01, rnd_a)),
76 s_mac2: aes128_encrypt(scbk, &key_template(0x01, 0x02, rnd_a)),
77 }
78 }
79}
80
81pub fn client_cryptogram(s_enc: &[u8; 16], rnd_a: &[u8; 8], rnd_b: &[u8; 8]) -> Block {
83 let mut block = [0u8; 16];
84 block[..8].copy_from_slice(rnd_a);
85 block[8..].copy_from_slice(rnd_b);
86 aes128_encrypt(s_enc, &block)
87}
88
89pub fn server_cryptogram(s_enc: &[u8; 16], rnd_a: &[u8; 8], rnd_b: &[u8; 8]) -> Block {
91 let mut block = [0u8; 16];
92 block[..8].copy_from_slice(rnd_b);
93 block[8..].copy_from_slice(rnd_a);
94 aes128_encrypt(s_enc, &block)
95}
96
97pub fn initial_rmac(s_mac1: &[u8; 16], s_mac2: &[u8; 16], server_cryptogram: &Block) -> Block {
101 let first = aes128_encrypt(s_mac1, server_cryptogram);
102 aes128_encrypt(s_mac2, &first)
103}
104
105pub fn diversify_scbk_legacy(mk: &[u8; 16], cuid: &[u8; 8]) -> [u8; 16] {
109 let mut block = [0u8; 16];
110 block[..8].copy_from_slice(cuid);
111 for (i, &b) in cuid.iter().enumerate() {
112 block[8 + i] = !b;
113 }
114 aes128_encrypt(mk, &block)
115}
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120
121 #[test]
123 fn enc_then_dec_identity() {
124 let key = [0u8; 16];
125 let plain = [0xABu8; 16];
126 let ct = aes128_encrypt(&key, &plain);
127 let pt = aes128_decrypt(&key, &ct);
128 assert_eq!(pt, plain);
129 }
130
131 #[test]
133 fn fips_known_answer() {
134 let key = [0u8; 16];
135 let plain = [0u8; 16];
136 let ct = aes128_encrypt(&key, &plain);
137 let expected = [
138 0x66, 0xE9, 0x4B, 0xD4, 0xEF, 0x8A, 0x2C, 0x3B, 0x88, 0x4C, 0xFA, 0x59, 0xCA, 0x34,
139 0x2B, 0x2E,
140 ];
141 assert_eq!(ct, expected);
142 }
143
144 #[test]
145 fn keys_differ() {
146 let scbk = [0xAA; 16];
147 let rnd_a = [0x55u8; 8];
148 let k = SessionKeys::derive(&scbk, &rnd_a);
149 assert_ne!(k.s_enc, k.s_mac1);
150 assert_ne!(k.s_mac1, k.s_mac2);
151 assert_ne!(k.s_enc, k.s_mac2);
152 }
153
154 #[test]
155 fn cryptograms_distinct() {
156 let s_enc = [0; 16];
157 let rnd_a = [1u8; 8];
158 let rnd_b = [2u8; 8];
159 let c = client_cryptogram(&s_enc, &rnd_a, &rnd_b);
160 let s = server_cryptogram(&s_enc, &rnd_a, &rnd_b);
161 assert_ne!(c, s);
162 }
163}