1use aes::cipher::{BlockDecrypt, BlockEncrypt, KeyInit};
2use aes::{Aes128, Block};
3use std::net::IpAddr;
4
5use crate::common::{bytes_to_ip, ip_to_bytes};
6
7pub struct IpcryptNdx {
12 cipher1: Aes128, cipher2: Aes128, }
15
16impl IpcryptNdx {
17 pub const KEY_BYTES: usize = 32;
19 pub const TWEAK_BYTES: usize = 16;
21 pub const NDIP_BYTES: usize = 32;
23
24 #[cfg(feature = "random")]
26 pub fn generate_key() -> [u8; Self::KEY_BYTES] {
27 rand::random()
28 }
29
30 pub fn new(key: [u8; Self::KEY_BYTES]) -> Self {
36 let (key1, key2) = key.split_at(Self::KEY_BYTES / 2);
37 let cipher1 = Aes128::new_from_slice(key1).expect("key1 length is correct");
38 let cipher2 = Aes128::new_from_slice(key2).expect("key2 length is correct");
39 Self { cipher1, cipher2 }
40 }
41
42 #[cfg(feature = "random")]
44 pub fn new_random() -> Self {
45 Self::new(Self::generate_key())
46 }
47
48 #[cfg(feature = "random")]
50 pub fn generate_tweak() -> [u8; Self::TWEAK_BYTES] {
51 rand::random()
52 }
53
54 fn encrypt_ip16(&self, ip: &mut [u8; 16], tweak: &[u8; Self::TWEAK_BYTES]) {
61 let mut encrypted_tweak = Block::from(*tweak);
63 self.cipher2.encrypt_block(&mut encrypted_tweak);
64
65 let mut block = Block::from(*ip);
67 for (b, t) in block.iter_mut().zip(encrypted_tweak.iter()) {
68 *b ^= t;
69 }
70
71 self.cipher1.encrypt_block(&mut block);
73
74 for (b, t) in block.iter_mut().zip(encrypted_tweak.iter()) {
76 *b ^= t;
77 }
78
79 *ip = block.into();
80 }
81
82 fn decrypt_ip16(&self, ip: &mut [u8; 16], tweak: &[u8; Self::TWEAK_BYTES]) {
89 let mut encrypted_tweak = Block::from(*tweak);
91 self.cipher2.encrypt_block(&mut encrypted_tweak);
92
93 let mut block = Block::from(*ip);
95 for (b, t) in block.iter_mut().zip(encrypted_tweak.iter()) {
96 *b ^= t;
97 }
98
99 self.cipher1.decrypt_block(&mut block);
101
102 for (b, t) in block.iter_mut().zip(encrypted_tweak.iter()) {
104 *b ^= t;
105 }
106
107 *ip = block.into();
108 }
109
110 pub fn encrypt_ipaddr(
120 &self,
121 ip: IpAddr,
122 tweak: Option<[u8; Self::TWEAK_BYTES]>,
123 ) -> [u8; Self::NDIP_BYTES] {
124 let mut out: [u8; Self::NDIP_BYTES] = [0; Self::NDIP_BYTES];
125 #[cfg(feature = "random")]
126 let tweak = tweak.unwrap_or_else(Self::generate_tweak);
127 #[cfg(not(feature = "random"))]
128 let tweak = tweak.expect("tweak must be provided when random feature is disabled");
129 let mut bytes = ip_to_bytes(ip);
130 self.encrypt_ip16(&mut bytes, &tweak);
131 out[0..16].copy_from_slice(&tweak);
132 out[16..].copy_from_slice(&bytes);
133 out
134 }
135
136 pub fn decrypt_ipaddr(&self, encrypted: &[u8; Self::NDIP_BYTES]) -> IpAddr {
146 let mut tweak = [0u8; Self::TWEAK_BYTES];
147 tweak.copy_from_slice(&encrypted[0..16]);
148 let mut bytes = [0u8; 16];
149 bytes.copy_from_slice(&encrypted[16..]);
150 self.decrypt_ip16(&mut bytes, &tweak);
151 bytes_to_ip(bytes)
152 }
153}
154
155#[cfg(test)]
156mod tests {
157 use super::*;
158 use ct_codecs::{Decoder as _, Encoder as _, Hex};
159 use std::str::FromStr;
160
161 #[test]
162 fn test_ndx_vectors() {
163 let test_vectors = vec![
164 (
165 "0123456789abcdeffedcba98765432101032547698badcfeefcdab8967452301",
167 "0.0.0.0",
168 "21bd1834bc088cd2b4ecbe30b70898d7",
169 "21bd1834bc088cd2b4ecbe30b70898d782db0d4125fdace61db35b8339f20ee5",
170 ),
171 (
172 "1032547698badcfeefcdab89674523010123456789abcdeffedcba9876543210",
174 "192.0.2.1",
175 "08e0c289bff23b7cb4ecbe30b70898d7",
176 "08e0c289bff23b7cb4ecbe30b70898d7766a533392a69edf1ad0d3ce362ba98a",
177 ),
178 (
179 "2b7e151628aed2a6abf7158809cf4f3c3c4fcf098815f7aba6d2ae2816157e2b",
181 "2001:db8::1",
182 "21bd1834bc088cd2b4ecbe30b70898d7",
183 "21bd1834bc088cd2b4ecbe30b70898d76089c7e05ae30c2d10ca149870a263e4",
184 ),
185 ];
186
187 for (key_hex, input_ip, tweak_hex, expected_output) in test_vectors {
188 let key_vec = Hex::decode_to_vec(key_hex.as_bytes(), None).unwrap();
190 let mut key = [0u8; IpcryptNdx::KEY_BYTES];
191 key.copy_from_slice(&key_vec);
192
193 let tweak_vec = Hex::decode_to_vec(tweak_hex.as_bytes(), None).unwrap();
195 let mut tweak = [0u8; IpcryptNdx::TWEAK_BYTES];
196 tweak.copy_from_slice(&tweak_vec);
197
198 let ipcrypt = IpcryptNdx::new(key);
200
201 let ip = IpAddr::from_str(input_ip).unwrap();
203
204 let encrypted = ipcrypt.encrypt_ipaddr(ip, Some(tweak));
206
207 let encrypted_hex = Hex::encode_to_string(encrypted).unwrap();
209 assert_eq!(encrypted_hex, expected_output);
210
211 let decrypted = ipcrypt.decrypt_ipaddr(&encrypted);
213 assert_eq!(decrypted, ip);
214 }
215 }
216}