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 #[cfg(feature = "random")]
32 pub fn generate_key() -> [u8; Self::KEY_BYTES] {
33 rand::random()
34 }
35
36 pub fn new(key: [u8; Self::KEY_BYTES]) -> Self {
42 let round_keys = Self::expand_key(&key);
43 Self { round_keys }
44 }
45
46 #[cfg(feature = "random")]
48 pub fn new_random() -> Self {
49 Self::new(Self::generate_key())
50 }
51
52 #[cfg(feature = "random")]
54 pub fn generate_tweak() -> [u8; Self::TWEAK_BYTES] {
55 rand::random()
56 }
57
58 fn pad_tweak(tweak: &[u8; Self::TWEAK_BYTES]) -> Block {
61 let mut padded = Block::default();
62 for i in (0..8).step_by(2) {
63 padded[i * 2] = tweak[i];
64 padded[i * 2 + 1] = tweak[i + 1];
65 }
66 padded
67 }
68
69 fn encrypt_ip16(&self, ip: &mut [u8; 16], tweak: &[u8; Self::TWEAK_BYTES]) {
74 let padded_tweak = Self::pad_tweak(tweak);
75 let mut block = Block::from(*ip);
76
77 for i in 0..16 {
79 block[i] ^= self.round_keys[0][i] ^ padded_tweak[i];
80 }
81
82 for round in 1..10 {
84 let mut tweaked_key = self.round_keys[round];
86 for i in 0..16 {
87 tweaked_key[i] ^= padded_tweak[i];
88 }
89 hazmat::cipher_round(&mut block, &tweaked_key);
90 }
91
92 for i in 0..16 {
95 block[i] = SBOX[block[i] as usize];
96 }
97
98 shift_rows(&mut block);
100
101 for i in 0..16 {
103 block[i] ^= self.round_keys[10][i] ^ padded_tweak[i];
104 }
105
106 *ip = block.into();
107 }
108
109 fn decrypt_ip16(&self, ip: &mut [u8; 16], tweak: &[u8; Self::TWEAK_BYTES]) {
114 let padded_tweak = Self::pad_tweak(tweak);
115 let mut block = Block::from(*ip);
116
117 for i in 0..16 {
119 block[i] ^= self.round_keys[10][i] ^ padded_tweak[i];
120 }
121
122 inv_shift_rows(&mut block);
124
125 for i in 0..16 {
127 block[i] = INV_SBOX[block[i] as usize];
128 }
129
130 for round in (1..10).rev() {
132 for i in 0..16 {
134 block[i] ^= self.round_keys[round][i] ^ padded_tweak[i];
135 }
136
137 inv_mix_columns(&mut block);
139
140 inv_shift_rows(&mut block);
142
143 for i in 0..16 {
145 block[i] = INV_SBOX[block[i] as usize];
146 }
147 }
148
149 for i in 0..16 {
151 block[i] ^= self.round_keys[0][i] ^ padded_tweak[i];
152 }
153
154 *ip = block.into();
155 }
156
157 pub fn encrypt_ipaddr(
167 &self,
168 ip: IpAddr,
169 tweak: Option<[u8; Self::TWEAK_BYTES]>,
170 ) -> [u8; Self::NDIP_BYTES] {
171 let mut out = [0u8; Self::NDIP_BYTES];
172 #[cfg(feature = "random")]
173 let tweak = tweak.unwrap_or_else(Self::generate_tweak);
174 #[cfg(not(feature = "random"))]
175 let tweak = tweak.expect("tweak must be provided when random feature is disabled");
176 let mut bytes = ip_to_bytes(ip);
177 self.encrypt_ip16(&mut bytes, &tweak);
178 out[0..Self::TWEAK_BYTES].copy_from_slice(&tweak);
179 out[Self::TWEAK_BYTES..].copy_from_slice(&bytes);
180 out
181 }
182
183 pub fn decrypt_ipaddr(&self, encrypted: &[u8; Self::NDIP_BYTES]) -> IpAddr {
192 let mut tweak = [0u8; Self::TWEAK_BYTES];
193 tweak.copy_from_slice(&encrypted[0..Self::TWEAK_BYTES]);
194 let mut bytes = [0u8; 16];
195 bytes.copy_from_slice(&encrypted[Self::TWEAK_BYTES..]);
196 self.decrypt_ip16(&mut bytes, &tweak);
197 bytes_to_ip(bytes)
198 }
199
200 fn expand_key(key: &[u8; Self::KEY_BYTES]) -> Vec<Block> {
205 let mut round_keys = Vec::with_capacity(11);
206
207 let current_key = Block::from(*key);
209 round_keys.push(current_key);
210
211 for i in 1..11 {
213 let prev_key = round_keys[i - 1];
214 let mut next_key = Block::default();
215
216 let t0 = prev_key[13];
219 let t1 = prev_key[14];
220 let t2 = prev_key[15];
221 let t3 = prev_key[12];
222 let s0 = SBOX[t0 as usize];
223 let s1 = SBOX[t1 as usize];
224 let s2 = SBOX[t2 as usize];
225 let s3 = SBOX[t3 as usize];
226
227 next_key[0] = prev_key[0] ^ s0 ^ RCON[i - 1];
229 next_key[1] = prev_key[1] ^ s1;
230 next_key[2] = prev_key[2] ^ s2;
231 next_key[3] = prev_key[3] ^ s3;
232
233 next_key[4] = next_key[0] ^ prev_key[4];
235 next_key[5] = next_key[1] ^ prev_key[5];
236 next_key[6] = next_key[2] ^ prev_key[6];
237 next_key[7] = next_key[3] ^ prev_key[7];
238
239 next_key[8] = next_key[4] ^ prev_key[8];
240 next_key[9] = next_key[5] ^ prev_key[9];
241 next_key[10] = next_key[6] ^ prev_key[10];
242 next_key[11] = next_key[7] ^ prev_key[11];
243
244 next_key[12] = next_key[8] ^ prev_key[12];
245 next_key[13] = next_key[9] ^ prev_key[13];
246 next_key[14] = next_key[10] ^ prev_key[14];
247 next_key[15] = next_key[11] ^ prev_key[15];
248
249 round_keys.push(next_key);
250 }
251
252 round_keys
253 }
254}
255
256#[cfg(test)]
257mod tests {
258 use super::*;
259 use ct_codecs::{Decoder as _, Encoder as _, Hex};
260 use std::str::FromStr;
261
262 #[test]
263 fn test_nd_vectors() {
264 let test_vectors = vec![
265 (
266 "0123456789abcdeffedcba9876543210",
268 "0.0.0.0",
269 "08e0c289bff23b7c",
270 "08e0c289bff23b7cb349aadfe3bcef56221c384c7c217b16",
271 ),
272 (
273 "1032547698badcfeefcdab8967452301",
275 "192.0.2.1",
276 "21bd1834bc088cd2",
277 "21bd1834bc088cd2e5e1fe55f95876e639faae2594a0caad",
278 ),
279 (
280 "2b7e151628aed2a6abf7158809cf4f3c",
282 "2001:db8::1",
283 "b4ecbe30b70898d7",
284 "b4ecbe30b70898d7553ac8974d1b4250eafc4b0aa1f80c96",
285 ),
286 ];
287
288 for (key_hex, input_ip, tweak_hex, expected_output) in test_vectors {
289 let key_vec = Hex::decode_to_vec(key_hex.as_bytes(), None).unwrap();
291 let mut key = [0u8; IpcryptNd::KEY_BYTES];
292 key.copy_from_slice(&key_vec);
293
294 let tweak_vec = Hex::decode_to_vec(tweak_hex.as_bytes(), None).unwrap();
296 let mut tweak = [0u8; IpcryptNd::TWEAK_BYTES];
297 tweak.copy_from_slice(&tweak_vec);
298
299 let ipcrypt = IpcryptNd::new(key);
301
302 let ip = IpAddr::from_str(input_ip).unwrap();
304
305 let encrypted = ipcrypt.encrypt_ipaddr(ip, Some(tweak));
307
308 let encrypted_hex = Hex::encode_to_string(encrypted).unwrap();
310 assert_eq!(encrypted_hex, expected_output);
311
312 let decrypted = ipcrypt.decrypt_ipaddr(&encrypted);
314 assert_eq!(decrypted, ip);
315 }
316 }
317}