1use aes::cipher::{BlockEncrypt, KeyInit};
2use aes::Aes128;
3use aes::Block;
4use std::net::IpAddr;
5
6use crate::common::{bytes_to_ip, ip_to_bytes};
7
8pub struct IpcryptPfx {
10 cipher1: Aes128,
11 cipher2: Aes128,
12}
13
14impl IpcryptPfx {
15 pub const KEY_BYTES: usize = 32;
17
18 #[cfg(feature = "random")]
20 pub fn generate_key() -> [u8; Self::KEY_BYTES] {
21 rand::random()
22 }
23
24 pub fn new(key: [u8; Self::KEY_BYTES]) -> Self {
35 let (k1, k2) = key.split_at(16);
37
38 assert_ne!(k1, k2, "The two halves of the key must be different");
40
41 let cipher1 = Aes128::new_from_slice(k1).expect("key length is guaranteed to be correct");
42 let cipher2 = Aes128::new_from_slice(k2).expect("key length is guaranteed to be correct");
43
44 Self { cipher1, cipher2 }
45 }
46
47 #[cfg(feature = "random")]
49 pub fn new_random() -> Self {
50 loop {
51 let key = Self::generate_key();
52 let (k1, k2) = key.split_at(16);
53 if k1 != k2 {
54 return Self::new(key);
55 }
56 }
57 }
58
59 pub fn encrypt_ipaddr(&self, ip: IpAddr) -> IpAddr {
69 let bytes = ip_to_bytes(ip);
70 let encrypted = self.encrypt_bytes(&bytes, ip);
71 bytes_to_ip(encrypted)
72 }
73
74 pub fn decrypt_ipaddr(&self, encrypted: IpAddr) -> IpAddr {
84 let encrypted_bytes = ip_to_bytes(encrypted);
85 let decrypted = self.decrypt_bytes(&encrypted_bytes, encrypted);
86 bytes_to_ip(decrypted)
87 }
88
89 fn encrypt_bytes(&self, bytes: &[u8; 16], ip: IpAddr) -> [u8; 16] {
91 let mut encrypted = [0u8; 16];
92
93 let prefix_start = if ip.is_ipv4() { 96 } else { 0 };
95
96 if ip.is_ipv4() {
98 encrypted[..12].copy_from_slice(&bytes[..12]);
99 }
100
101 let mut padded_prefix = if prefix_start == 0 {
103 Self::pad_prefix_0()
104 } else {
105 Self::pad_prefix_96()
106 };
107
108 for prefix_len_bits in prefix_start..128 {
110 let mut block1 = Block::from(padded_prefix);
112 let mut block2 = Block::from(padded_prefix);
113
114 self.cipher1.encrypt_block(&mut block1);
115 self.cipher2.encrypt_block(&mut block2);
116
117 let e1: [u8; 16] = block1.into();
119 let e2: [u8; 16] = block2.into();
120 let mut e = [0u8; 16];
121 for i in 0..16 {
122 e[i] = e1[i] ^ e2[i];
123 }
124
125 let cipher_bit = e[15] & 1;
127
128 let bit_pos = 127 - prefix_len_bits;
130 let original_bit = Self::get_bit(bytes, bit_pos);
131
132 Self::set_bit(&mut encrypted, bit_pos, cipher_bit ^ original_bit);
134
135 padded_prefix = Self::shift_left_one_bit(&padded_prefix);
137 Self::set_bit(&mut padded_prefix, 0, original_bit);
138 }
139
140 encrypted
141 }
142
143 fn decrypt_bytes(&self, encrypted_bytes: &[u8; 16], encrypted_ip: IpAddr) -> [u8; 16] {
145 let mut decrypted = [0u8; 16];
146
147 let prefix_start = if encrypted_ip.is_ipv4() { 96 } else { 0 };
149
150 if prefix_start == 96 {
152 decrypted[10..12].copy_from_slice(&[0xFF; 2]);
153 }
154
155 let mut padded_prefix = if prefix_start == 0 {
157 Self::pad_prefix_0()
158 } else {
159 Self::pad_prefix_96()
160 };
161
162 for prefix_len_bits in prefix_start..128 {
164 let mut block1 = Block::from(padded_prefix);
166 let mut block2 = Block::from(padded_prefix);
167
168 self.cipher1.encrypt_block(&mut block1);
169 self.cipher2.encrypt_block(&mut block2);
170
171 let e1: [u8; 16] = block1.into();
173 let e2: [u8; 16] = block2.into();
174 let mut e = [0u8; 16];
175 for i in 0..16 {
176 e[i] = e1[i] ^ e2[i];
177 }
178
179 let cipher_bit = e[15] & 1;
181
182 let bit_pos = 127 - prefix_len_bits;
184 let encrypted_bit = Self::get_bit(encrypted_bytes, bit_pos);
185 let original_bit = cipher_bit ^ encrypted_bit;
186
187 Self::set_bit(&mut decrypted, bit_pos, original_bit);
189
190 padded_prefix = Self::shift_left_one_bit(&padded_prefix);
192 Self::set_bit(&mut padded_prefix, 0, original_bit);
193 }
194
195 decrypted
196 }
197
198 fn get_bit(data: &[u8; 16], position: usize) -> u8 {
201 let byte_index = 15 - (position / 8);
202 let bit_index = position % 8;
203 (data[byte_index] >> bit_index) & 1
204 }
205
206 fn set_bit(data: &mut [u8; 16], position: usize, value: u8) {
209 let byte_index = 15 - (position / 8);
210 let bit_index = position % 8;
211 if value != 0 {
212 data[byte_index] |= 1 << bit_index;
213 } else {
214 data[byte_index] &= !(1 << bit_index);
215 }
216 }
217
218 fn shift_left_one_bit(data: &[u8; 16]) -> [u8; 16] {
221 let mut result = [0u8; 16];
222 let mut carry = 0;
223
224 for i in (0..16).rev() {
226 result[i] = (data[i] << 1) | carry;
228 carry = (data[i] >> 7) & 1;
230 }
231
232 result
233 }
234
235 fn pad_prefix_0() -> [u8; 16] {
238 let mut padded = [0u8; 16];
239 padded[15] = 0x01; padded
241 }
242
243 fn pad_prefix_96() -> [u8; 16] {
247 let mut padded = [0u8; 16];
248 padded[3] = 0x01; padded[14] = 0xFF;
250 padded[15] = 0xFF;
251 padded
252 }
253}
254
255#[cfg(test)]
256mod tests {
257 use super::*;
258 use ct_codecs::{Decoder as _, Hex};
259 use std::str::FromStr;
260
261 #[test]
262 fn test_pfx_basic_vectors() {
263 let test_vectors = vec![
264 (
266 "0123456789abcdeffedcba98765432101032547698badcfeefcdab8967452301",
267 "0.0.0.0",
268 "151.82.155.134",
269 ),
270 (
272 "0123456789abcdeffedcba98765432101032547698badcfeefcdab8967452301",
273 "255.255.255.255",
274 "94.185.169.89",
275 ),
276 (
278 "0123456789abcdeffedcba98765432101032547698badcfeefcdab8967452301",
279 "192.0.2.1",
280 "100.115.72.131",
281 ),
282 (
284 "0123456789abcdeffedcba98765432101032547698badcfeefcdab8967452301",
285 "2001:db8::1",
286 "c180:5dd4:2587:3524:30ab:fa65:6ab6:f88",
287 ),
288 ];
289
290 for (key_hex, input_ip, expected_output) in test_vectors {
291 let key_vec = Hex::decode_to_vec(key_hex.as_bytes(), None).unwrap();
293 let mut key = [0u8; IpcryptPfx::KEY_BYTES];
294 key.copy_from_slice(&key_vec);
295
296 let ipcrypt = IpcryptPfx::new(key);
298
299 let ip = IpAddr::from_str(input_ip).unwrap();
301
302 let encrypted = ipcrypt.encrypt_ipaddr(ip);
304 assert_eq!(encrypted.to_string(), expected_output);
305
306 let decrypted = ipcrypt.decrypt_ipaddr(encrypted);
308 assert_eq!(decrypted, ip);
309 }
310 }
311
312 #[test]
313 fn test_pfx_prefix_preserving_ipv4_24() {
314 let key_hex = "2b7e151628aed2a6abf7158809cf4f3ca9f5ba40db214c3798f2e1c23456789a";
315 let key_vec = Hex::decode_to_vec(key_hex.as_bytes(), None).unwrap();
316 let mut key = [0u8; IpcryptPfx::KEY_BYTES];
317 key.copy_from_slice(&key_vec);
318 let ipcrypt = IpcryptPfx::new(key);
319
320 let test_cases = vec![
322 ("10.0.0.47", "19.214.210.244"),
323 ("10.0.0.129", "19.214.210.80"),
324 ("10.0.0.234", "19.214.210.30"),
325 ];
326
327 for (input_ip, expected_output) in test_cases {
328 let ip = IpAddr::from_str(input_ip).unwrap();
329 let encrypted = ipcrypt.encrypt_ipaddr(ip);
330 assert_eq!(encrypted.to_string(), expected_output);
331
332 let decrypted = ipcrypt.decrypt_ipaddr(encrypted);
333 assert_eq!(decrypted, ip);
334 }
335
336 let ip1 = IpAddr::from_str("10.0.0.47").unwrap();
338 let ip2 = IpAddr::from_str("10.0.0.129").unwrap();
339 let ip3 = IpAddr::from_str("10.0.0.234").unwrap();
340
341 let enc1 = ipcrypt.encrypt_ipaddr(ip1);
342 let enc2 = ipcrypt.encrypt_ipaddr(ip2);
343 let enc3 = ipcrypt.encrypt_ipaddr(ip3);
344
345 assert!(enc1.is_ipv4());
347 assert!(enc2.is_ipv4());
348 assert!(enc3.is_ipv4());
349
350 let enc1_bytes = match enc1 {
352 IpAddr::V4(ip) => ip.octets(),
353 _ => panic!("Expected IPv4"),
354 };
355 let enc2_bytes = match enc2 {
356 IpAddr::V4(ip) => ip.octets(),
357 _ => panic!("Expected IPv4"),
358 };
359 let enc3_bytes = match enc3 {
360 IpAddr::V4(ip) => ip.octets(),
361 _ => panic!("Expected IPv4"),
362 };
363
364 assert_eq!(enc1_bytes[0], enc2_bytes[0]);
366 assert_eq!(enc1_bytes[0], enc3_bytes[0]);
367 assert_eq!(enc1_bytes[1], enc2_bytes[1]);
368 assert_eq!(enc1_bytes[1], enc3_bytes[1]);
369 assert_eq!(enc1_bytes[2], enc2_bytes[2]);
370 assert_eq!(enc1_bytes[2], enc3_bytes[2]);
371 }
372
373 #[test]
374 fn test_pfx_prefix_preserving_ipv4_16() {
375 let key_hex = "2b7e151628aed2a6abf7158809cf4f3ca9f5ba40db214c3798f2e1c23456789a";
376 let key_vec = Hex::decode_to_vec(key_hex.as_bytes(), None).unwrap();
377 let mut key = [0u8; IpcryptPfx::KEY_BYTES];
378 key.copy_from_slice(&key_vec);
379 let ipcrypt = IpcryptPfx::new(key);
380
381 let test_cases = vec![
383 ("172.16.5.193", "210.78.229.136"),
384 ("172.16.97.42", "210.78.179.241"),
385 ("172.16.248.177", "210.78.121.215"),
386 ];
387
388 for (input_ip, expected_output) in test_cases {
389 let ip = IpAddr::from_str(input_ip).unwrap();
390 let encrypted = ipcrypt.encrypt_ipaddr(ip);
391 assert_eq!(encrypted.to_string(), expected_output);
392
393 let decrypted = ipcrypt.decrypt_ipaddr(encrypted);
394 assert_eq!(decrypted, ip);
395 }
396 }
397
398 #[test]
399 fn test_pfx_prefix_preserving_ipv6_64() {
400 let key_hex = "2b7e151628aed2a6abf7158809cf4f3ca9f5ba40db214c3798f2e1c23456789a";
401 let key_vec = Hex::decode_to_vec(key_hex.as_bytes(), None).unwrap();
402 let mut key = [0u8; IpcryptPfx::KEY_BYTES];
403 key.copy_from_slice(&key_vec);
404 let ipcrypt = IpcryptPfx::new(key);
405
406 let test_cases = vec![
408 (
409 "2001:db8::a5c9:4e2f:bb91:5a7d",
410 "7cec:702c:1243:f70:1956:125:b9bd:1aba",
411 ),
412 (
413 "2001:db8::7234:d8f1:3c6e:9a52",
414 "7cec:702c:1243:f70:a3ef:c8e:95c1:cd0d",
415 ),
416 (
417 "2001:db8::f1e0:937b:26d4:8c1a",
418 "7cec:702c:1243:f70:443c:c8e:6a62:b64d",
419 ),
420 ];
421
422 for (input_ip, expected_output) in test_cases {
423 let ip = IpAddr::from_str(input_ip).unwrap();
424 let encrypted = ipcrypt.encrypt_ipaddr(ip);
425 assert_eq!(encrypted.to_string(), expected_output);
426
427 let decrypted = ipcrypt.decrypt_ipaddr(encrypted);
428 assert_eq!(decrypted, ip);
429 }
430 }
431
432 #[test]
433 fn test_pfx_prefix_preserving_ipv6_32() {
434 let key_hex = "2b7e151628aed2a6abf7158809cf4f3ca9f5ba40db214c3798f2e1c23456789a";
435 let key_vec = Hex::decode_to_vec(key_hex.as_bytes(), None).unwrap();
436 let mut key = [0u8; IpcryptPfx::KEY_BYTES];
437 key.copy_from_slice(&key_vec);
438 let ipcrypt = IpcryptPfx::new(key);
439
440 let test_cases = vec![
442 (
443 "2001:db8:3a5c::e7d1:4b9f:2c8a:f673",
444 "7cec:702c:3503:bef:e616:96bd:be33:a9b9",
445 ),
446 (
447 "2001:db8:9f27::b4e2:7a3d:5f91:c8e6",
448 "7cec:702c:a504:b74e:194a:3d90:b047:2d1a",
449 ),
450 (
451 "2001:db8:d8b4::193c:a5e7:8b2f:46d1",
452 "7cec:702c:f840:aa67:1b8:e84f:ac9d:77fb",
453 ),
454 ];
455
456 for (input_ip, expected_output) in test_cases {
457 let ip = IpAddr::from_str(input_ip).unwrap();
458 let encrypted = ipcrypt.encrypt_ipaddr(ip);
459 assert_eq!(encrypted.to_string(), expected_output);
460
461 let decrypted = ipcrypt.decrypt_ipaddr(encrypted);
462 assert_eq!(decrypted, ip);
463 }
464 }
465
466 #[test]
467 #[cfg(feature = "random")]
468 fn test_random_key() {
469 let ipcrypt = IpcryptPfx::new_random();
470 let ip = IpAddr::from_str("192.0.2.1").unwrap();
471 let encrypted = ipcrypt.encrypt_ipaddr(ip);
472 let decrypted = ipcrypt.decrypt_ipaddr(encrypted);
473 assert_eq!(ip, decrypted);
474 }
475
476 #[test]
477 #[should_panic(expected = "The two halves of the key must be different")]
478 fn test_identical_key_halves() {
479 let mut key = [0u8; 32];
480 key[0..16].copy_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
482 key[16..32].copy_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
483 IpcryptPfx::new(key);
484 }
485
486 #[test]
487 fn test_bit_operations() {
488 let mut data = [0u8; 16];
489
490 for pos in 0..128 {
492 IpcryptPfx::set_bit(&mut data, pos, 1);
493 assert_eq!(IpcryptPfx::get_bit(&data, pos), 1);
494 IpcryptPfx::set_bit(&mut data, pos, 0);
495 assert_eq!(IpcryptPfx::get_bit(&data, pos), 0);
496 }
497 }
498
499 #[test]
500 fn test_shift_left() {
501 let data = [
502 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
503 0x00, 0x01,
504 ];
505 let result = IpcryptPfx::shift_left_one_bit(&data);
506
507 assert_eq!(result[0], 0x00); assert_eq!(result[15], 0x02); }
511
512 #[test]
513 fn test_pad_prefix() {
514 let padded0 = IpcryptPfx::pad_prefix_0();
515 assert_eq!(padded0[15], 0x01);
516 assert_eq!(padded0[0..15], [0u8; 15]);
517
518 let padded96 = IpcryptPfx::pad_prefix_96();
519 assert_eq!(padded96[3], 0x01);
520 assert_eq!(padded96[14], 0xFF);
521 assert_eq!(padded96[15], 0xFF);
522 assert_eq!(padded96[0..3], [0u8; 3]);
523 assert_eq!(padded96[4..14], [0u8; 10]);
524 }
525}