1use aes::hazmat;
2use aes::Block;
3use std::net::IpAddr;
4
5use crate::aes::*;
6use crate::common::{bytes_to_ip, ip_to_bytes};
7
8pub struct IpcryptNd {
13 round_keys: Vec<Block>,
14}
15
16impl Drop for IpcryptNd {
17 fn drop(&mut self) {
18 self.round_keys.clear();
19 }
20}
21
22impl IpcryptNd {
23 pub const KEY_BYTES: usize = 16;
25 pub const TWEAK_BYTES: usize = 8;
27 pub const NDIP_BYTES: usize = Self::TWEAK_BYTES + 16;
29
30 pub fn generate_key() -> [u8; Self::KEY_BYTES] {
32 rand::random()
33 }
34
35 pub fn new(key: [u8; Self::KEY_BYTES]) -> Self {
41 let round_keys = Self::expand_key(&key);
42 Self { round_keys }
43 }
44
45 pub fn new_random() -> Self {
47 Self::new(Self::generate_key())
48 }
49
50 pub fn generate_tweak() -> [u8; Self::TWEAK_BYTES] {
52 rand::random()
53 }
54
55 fn pad_tweak(tweak: &[u8; Self::TWEAK_BYTES]) -> Block {
58 let mut padded = Block::default();
59 for i in (0..8).step_by(2) {
60 padded[i * 2] = tweak[i];
61 padded[i * 2 + 1] = tweak[i + 1];
62 }
63 padded
64 }
65
66 fn encrypt_ip16(&self, ip: &mut [u8; 16], tweak: &[u8; Self::TWEAK_BYTES]) {
71 let padded_tweak = Self::pad_tweak(tweak);
72 let mut block = Block::from(*ip);
73
74 for i in 0..16 {
76 block[i] ^= self.round_keys[0][i] ^ padded_tweak[i];
77 }
78
79 for round in 1..10 {
81 let mut tweaked_key = self.round_keys[round];
83 for i in 0..16 {
84 tweaked_key[i] ^= padded_tweak[i];
85 }
86 hazmat::cipher_round(&mut block, &tweaked_key);
87 }
88
89 for i in 0..16 {
92 block[i] = SBOX[block[i] as usize];
93 }
94
95 shift_rows(&mut block);
97
98 for i in 0..16 {
100 block[i] ^= self.round_keys[10][i] ^ padded_tweak[i];
101 }
102
103 *ip = block.into();
104 }
105
106 fn decrypt_ip16(&self, ip: &mut [u8; 16], tweak: &[u8; Self::TWEAK_BYTES]) {
111 let padded_tweak = Self::pad_tweak(tweak);
112 let mut block = Block::from(*ip);
113
114 for i in 0..16 {
116 block[i] ^= self.round_keys[10][i] ^ padded_tweak[i];
117 }
118
119 inv_shift_rows(&mut block);
121
122 for i in 0..16 {
124 block[i] = INV_SBOX[block[i] as usize];
125 }
126
127 for round in (1..10).rev() {
129 for i in 0..16 {
131 block[i] ^= self.round_keys[round][i] ^ padded_tweak[i];
132 }
133
134 inv_mix_columns(&mut block);
136
137 inv_shift_rows(&mut block);
139
140 for i in 0..16 {
142 block[i] = INV_SBOX[block[i] as usize];
143 }
144 }
145
146 for i in 0..16 {
148 block[i] ^= self.round_keys[0][i] ^ padded_tweak[i];
149 }
150
151 *ip = block.into();
152 }
153
154 pub fn encrypt_ipaddr(
164 &self,
165 ip: IpAddr,
166 tweak: Option<[u8; Self::TWEAK_BYTES]>,
167 ) -> [u8; Self::NDIP_BYTES] {
168 let mut out = [0u8; Self::NDIP_BYTES];
169 let tweak = tweak.unwrap_or_else(Self::generate_tweak);
170 let mut bytes = ip_to_bytes(ip);
171 self.encrypt_ip16(&mut bytes, &tweak);
172 out[0..Self::TWEAK_BYTES].copy_from_slice(&tweak);
173 out[Self::TWEAK_BYTES..].copy_from_slice(&bytes);
174 out
175 }
176
177 pub fn decrypt_ipaddr(&self, encrypted: &[u8; Self::NDIP_BYTES]) -> IpAddr {
186 let mut tweak = [0u8; Self::TWEAK_BYTES];
187 tweak.copy_from_slice(&encrypted[0..Self::TWEAK_BYTES]);
188 let mut bytes = [0u8; 16];
189 bytes.copy_from_slice(&encrypted[Self::TWEAK_BYTES..]);
190 self.decrypt_ip16(&mut bytes, &tweak);
191 bytes_to_ip(bytes)
192 }
193
194 fn expand_key(key: &[u8; Self::KEY_BYTES]) -> Vec<Block> {
199 let mut round_keys = Vec::with_capacity(11);
200
201 let current_key = Block::from(*key);
203 round_keys.push(current_key);
204
205 for i in 1..11 {
207 let prev_key = round_keys[i - 1];
208 let mut next_key = Block::default();
209
210 let t0 = prev_key[13];
213 let t1 = prev_key[14];
214 let t2 = prev_key[15];
215 let t3 = prev_key[12];
216 let s0 = SBOX[t0 as usize];
217 let s1 = SBOX[t1 as usize];
218 let s2 = SBOX[t2 as usize];
219 let s3 = SBOX[t3 as usize];
220
221 next_key[0] = prev_key[0] ^ s0 ^ RCON[i - 1];
223 next_key[1] = prev_key[1] ^ s1;
224 next_key[2] = prev_key[2] ^ s2;
225 next_key[3] = prev_key[3] ^ s3;
226
227 next_key[4] = next_key[0] ^ prev_key[4];
229 next_key[5] = next_key[1] ^ prev_key[5];
230 next_key[6] = next_key[2] ^ prev_key[6];
231 next_key[7] = next_key[3] ^ prev_key[7];
232
233 next_key[8] = next_key[4] ^ prev_key[8];
234 next_key[9] = next_key[5] ^ prev_key[9];
235 next_key[10] = next_key[6] ^ prev_key[10];
236 next_key[11] = next_key[7] ^ prev_key[11];
237
238 next_key[12] = next_key[8] ^ prev_key[12];
239 next_key[13] = next_key[9] ^ prev_key[13];
240 next_key[14] = next_key[10] ^ prev_key[14];
241 next_key[15] = next_key[11] ^ prev_key[15];
242
243 round_keys.push(next_key);
244 }
245
246 round_keys
247 }
248}
249
250#[cfg(test)]
251mod tests {
252 use super::*;
253 use ct_codecs::{Decoder as _, Encoder as _, Hex};
254 use std::str::FromStr;
255
256 #[test]
257 fn test_nd_vectors() {
258 let test_vectors = vec![
259 (
260 "0123456789abcdeffedcba9876543210",
262 "0.0.0.0",
263 "08e0c289bff23b7c",
264 "08e0c289bff23b7cb349aadfe3bcef56221c384c7c217b16",
265 ),
266 (
267 "1032547698badcfeefcdab8967452301",
269 "192.0.2.1",
270 "21bd1834bc088cd2",
271 "21bd1834bc088cd2e5e1fe55f95876e639faae2594a0caad",
272 ),
273 (
274 "2b7e151628aed2a6abf7158809cf4f3c",
276 "2001:db8::1",
277 "b4ecbe30b70898d7",
278 "b4ecbe30b70898d7553ac8974d1b4250eafc4b0aa1f80c96",
279 ),
280 ];
281
282 for (key_hex, input_ip, tweak_hex, expected_output) in test_vectors {
283 let key_vec = Hex::decode_to_vec(key_hex.as_bytes(), None).unwrap();
285 let mut key = [0u8; IpcryptNd::KEY_BYTES];
286 key.copy_from_slice(&key_vec);
287
288 let tweak_vec = Hex::decode_to_vec(tweak_hex.as_bytes(), None).unwrap();
290 let mut tweak = [0u8; IpcryptNd::TWEAK_BYTES];
291 tweak.copy_from_slice(&tweak_vec);
292
293 let ipcrypt = IpcryptNd::new(key);
295
296 let ip = IpAddr::from_str(input_ip).unwrap();
298
299 let encrypted = ipcrypt.encrypt_ipaddr(ip, Some(tweak));
301
302 let encrypted_hex = Hex::encode_to_string(encrypted).unwrap();
304 assert_eq!(encrypted_hex, expected_output);
305
306 let decrypted = ipcrypt.decrypt_ipaddr(&encrypted);
308 assert_eq!(decrypted, ip);
309 }
310 }
311}