/src/pdns/pdns/dnsdistdist/ext/ipcrypt2/ipcrypt2.c
Line | Count | Source |
1 | | /** |
2 | | * IPCrypt2: Lightweight IP Address Encryption Library |
3 | | * |
4 | | * IPCrypt2 provides simple and efficient encryption and decryption of IP addresses (IPv4 & IPv6). |
5 | | * Designed for privacy-preserving network applications, it supports four encryption modes: |
6 | | * |
7 | | * 1. **Format-Preserving AES Encryption** |
8 | | * - Transforms an IP address into another valid IP address of the same size. |
9 | | * - Useful for logs or systems that expect syntactically correct IPs. |
10 | | * |
11 | | * 2. **Prefix-Preserving AES Encryption (PFX)** |
12 | | * - IP addresses with the same prefix produce encrypted IP addresses with the same prefix. |
13 | | * - The prefix can be of any length. |
14 | | * - Useful for maintaining network structure while anonymizing individual hosts. |
15 | | * - Format-preserving: output remains a valid IP address. |
16 | | * |
17 | | * 3. **Non-Deterministic AES Encryption (KIASU-BC)** |
18 | | * - Introduces a 64-bit tweak, producing different ciphertexts for the same IP. |
19 | | * - Useful when repeated IPs must remain unlinkable. This mode is not format-preserving. |
20 | | * |
21 | | * 4. **NDX Mode: Non-Deterministic AES Encryption with Extended Tweaks (AES-XTX)** |
22 | | * - Introduces a 128-bit tweak, producing different ciphertexts for the same IP. |
23 | | * - Useful when repeated IPs must remain unlinkable. This mode is not format-preserving. |
24 | | * - Higher usage limits than KIASU-BC, but half the performance and larger ciphertexts. |
25 | | * |
26 | | * Additional Features: |
27 | | * - Built-in string/binary IP conversion helpers. |
28 | | * - Optimized for x86_64 and ARM (aarch64) with AES hardware acceleration. |
29 | | * - Minimal external dependencies; just compile and link. |
30 | | * |
31 | | * Limitations: |
32 | | * - Not intended for general-purpose encryption — IP address only. |
33 | | * - Ensure keys are secret and tweak values are random or unique per encryption. |
34 | | */ |
35 | | |
36 | | #include <stdint.h> |
37 | | #include <string.h> |
38 | | |
39 | | #include <sys/types.h> |
40 | | #ifdef _WIN32 |
41 | | # include <ws2tcpip.h> |
42 | | #else |
43 | | # include <arpa/inet.h> |
44 | | # include <netinet/in.h> |
45 | | # include <sys/socket.h> |
46 | | #endif |
47 | | |
48 | | #include "include/ipcrypt2.h" |
49 | | |
50 | | /** Number of AES rounds. For AES-128, this is 10. */ |
51 | 0 | #define ROUNDS 10 |
52 | | |
53 | 0 | #define COMPILER_ASSERT(X) (void) sizeof(char[(X) ? 1 : -1]) |
54 | | |
55 | | #if !defined(_MSC_VER) || _MSC_VER < 1800 |
56 | | # define __vectorcall |
57 | | #endif |
58 | | |
59 | | #ifndef HAVE_EXPLICIT_BZERO |
60 | | # if (defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ |
61 | | defined(__DragonFly__)) || \ |
62 | | (defined(__sun) && defined(__illumos__)) |
63 | | # define HAVE_EXPLICIT_BZERO 1 |
64 | | # elif defined(__GLIBC__) && defined(__GLIBC_PREREQ) && defined(_GNU_SOURCE) |
65 | | # if __GLIBC_PREREQ(2, 25) |
66 | | # define HAVE_EXPLICIT_BZERO 1 |
67 | | # endif |
68 | | # endif |
69 | | #endif |
70 | | |
71 | | #ifdef __aarch64__ |
72 | | # ifndef __ARM_FEATURE_CRYPTO |
73 | | # define __ARM_FEATURE_CRYPTO 1 |
74 | | # endif |
75 | | # ifndef __ARM_FEATURE_AES |
76 | | # define __ARM_FEATURE_AES 1 |
77 | | # endif |
78 | | |
79 | | # if defined(_MSC_VER) && defined(_M_ARM64) |
80 | | # include <arm64_neon.h> |
81 | | # else |
82 | | # include <arm_neon.h> |
83 | | # endif |
84 | | |
85 | | # ifdef __clang__ |
86 | | /** |
87 | | * Enable AES instructions when compiling with Clang. |
88 | | */ |
89 | | # pragma clang attribute push(__attribute__((target("neon,crypto,aes"))), \ |
90 | | apply_to = function) |
91 | | # elif defined(__GNUC__) |
92 | | /** |
93 | | * Enable AES and crypto instructions when compiling with GCC. |
94 | | */ |
95 | | # pragma GCC target("+simd+crypto") |
96 | | # endif |
97 | | |
98 | | /** |
99 | | * For AArch64, we represent AES blocks using a 128-bit NEON register (uint64x2_t). |
100 | | */ |
101 | | typedef uint64x2_t BlockVec; |
102 | | |
103 | | /** |
104 | | * Load 16 bytes from memory into a NEON register. |
105 | | */ |
106 | | # define LOAD128(a) vld1q_u64((const uint64_t *) (const void *) (a)) |
107 | | /** |
108 | | * Store 16 bytes from a NEON register into memory. |
109 | | */ |
110 | | # define STORE128(a, b) vst1q_u64((uint64_t *) (void *) (a), (b)) |
111 | | /** |
112 | | * Perform one round of AES encryption (no final round) on block_vec with rkey. |
113 | | */ |
114 | | # define AES_XENCRYPT(block_vec, rkey) \ |
115 | | vreinterpretq_u64_u8(vaesmcq_u8(vaeseq_u8(rkey, vreinterpretq_u8_u64(block_vec)))) |
116 | | /** |
117 | | * Perform the final AES encryption round on block_vec with rkey. |
118 | | * The final round excludes the MixColumns step. |
119 | | */ |
120 | | # define AES_XENCRYPTLAST(block_vec, rkey) \ |
121 | | vreinterpretq_u64_u8(vaeseq_u8(rkey, vreinterpretq_u8_u64(block_vec))) |
122 | | /** |
123 | | * Perform one round of AES decryption (no final round) on block_vec with rkey. |
124 | | */ |
125 | | # define AES_XDECRYPT(block_vec, rkey) \ |
126 | | vreinterpretq_u64_u8(vaesimcq_u8(vaesdq_u8(rkey, vreinterpretq_u8_u64(block_vec)))) |
127 | | /** |
128 | | * Perform the final AES decryption round on block_vec with rkey. |
129 | | * The final round excludes the InverseMixColumns step. |
130 | | */ |
131 | | # define AES_XDECRYPTLAST(block_vec, rkey) \ |
132 | | vreinterpretq_u64_u8(vaesdq_u8(rkey, vreinterpretq_u8_u64(block_vec))) |
133 | | /** |
134 | | * XOR two 128-bit blocks. |
135 | | */ |
136 | | # define XOR128(a, b) veorq_u64((a), (b)) |
137 | | /** |
138 | | * XOR three 128-bit blocks. |
139 | | */ |
140 | | # define XOR128_3(a, b, c) veorq_u64(veorq_u64((a), (b)), c) |
141 | | /** |
142 | | * Create a 128-bit register by combining two 64-bit values. |
143 | | */ |
144 | | # define SET64x2(a, b) vsetq_lane_u64((uint64_t) (a), vmovq_n_u64((uint64_t) (b)), 1) |
145 | | /** |
146 | | * Shift left a 128-bit register by b bytes (zero-filling from the right). |
147 | | */ |
148 | | # define BYTESHL128(a, b) vreinterpretq_u64_u8(vextq_u8(vdupq_n_u8(0), vreinterpretq_u8_u64(a), 16 - (b))) |
149 | | /** |
150 | | * Broadcast 32-bit lane 3 across the 128-bit register. |
151 | | */ |
152 | | # define SHUFFLE32x4_3333(x) vreinterpretq_u64_u32(vdupq_laneq_u32(vreinterpretq_u32_u64(x), 3)) |
153 | | /** |
154 | | * Invert an AES round key for decryption. |
155 | | */ |
156 | | # define RKINVERT(rkey) vaesimcq_u8(rkey) |
157 | | /** |
158 | | * Expand the 8-byte tweak into a 128-bit NEON register. |
159 | | */ |
160 | | # define TWEAK_EXPAND(tweak) \ |
161 | | vreinterpretq_u8_u32(vmovl_u16(vld1_u16((const uint16_t *) (tweak)))); |
162 | | |
163 | | /** |
164 | | * Shift an entire 128-bit block left by 1 bit. |
165 | | */ |
166 | | static inline BlockVec |
167 | | SHL1_128(const BlockVec a) |
168 | | { |
169 | | const uint8x16_t shl = vshlq_n_u8(vreinterpretq_u8_u64(a), 1); |
170 | | const uint8x16_t msb = vshrq_n_u8(vreinterpretq_u8_u64(a), 7); |
171 | | const uint8x16_t zero = vdupq_n_u8(0); |
172 | | const uint8x16_t carries = vextq_u8(msb, zero, 1); |
173 | | return vreinterpretq_u64_u8(vorrq_u8(shl, carries)); |
174 | | } |
175 | | |
176 | | /** |
177 | | * Internal function for deriving a subkey using AES key generation instructions. |
178 | | * block_vec: the current AES round key block. |
179 | | * rc: the round constant. |
180 | | */ |
181 | | static inline BlockVec |
182 | | AES_KEYGEN(BlockVec block_vec, const int rc) |
183 | | { |
184 | | // Perform an AES single round encryption on block_vec with a zero key. |
185 | | // This extracts the needed transformation for generating a new round key. |
186 | | uint8x16_t a = vaeseq_u8(vreinterpretq_u8_u64(block_vec), vmovq_n_u8(0)); |
187 | | // Shuffle for the key expansion rotation. |
188 | | static const uint8_t aes_keygen_shuffle[16] = { |
189 | | 4, 1, 14, 11, 1, 14, 11, 4, 12, 9, 6, 3, 9, 6, 3, 12, |
190 | | }; |
191 | | const BlockVec b = vreinterpretq_u64_u8(vqtbl1q_u8(a, vld1q_u8(aes_keygen_shuffle))); |
192 | | // Combine with round constant. |
193 | | const uint64x2_t c = SET64x2((uint64_t) rc << 32, (uint64_t) rc << 32); |
194 | | return XOR128(b, c); |
195 | | } |
196 | | |
197 | | #else |
198 | | |
199 | | # if defined(__x86_64__) || defined(__i386__) || defined(_M_X64) || defined(_M_IX86) |
200 | | |
201 | | # ifdef __clang__ |
202 | | /** |
203 | | * Enable AES/SSE4.1 instructions when compiling with Clang. |
204 | | */ |
205 | | # pragma clang attribute push(__attribute__((target("aes,sse4.1"))), apply_to = function) |
206 | | # elif defined(__GNUC__) |
207 | | /** |
208 | | * Enable AES/SSE4.1 instructions when compiling with GCC. |
209 | | */ |
210 | | # pragma GCC target("aes,sse4.1") |
211 | | # elif defined(_MSC_VER) |
212 | | # include <intrin.h> |
213 | | # pragma intrinsic(_mm_aesenc_si128) |
214 | | # pragma intrinsic(_mm_aesenclast_si128) |
215 | | # pragma intrinsic(_mm_aesdec_si128) |
216 | | # pragma intrinsic(_mm_aesdeclast_si128) |
217 | | # pragma intrinsic(_mm_aesimc_si128) |
218 | | # pragma intrinsic(_mm_aeskeygenassist_si128) |
219 | | # endif |
220 | | |
221 | | # include <smmintrin.h> |
222 | | # include <tmmintrin.h> |
223 | | # include <wmmintrin.h> |
224 | | |
225 | | # else |
226 | | # ifdef __clang__ |
227 | | # pragma clang attribute push(__attribute__((target(""))), apply_to = function) |
228 | | # elif defined(__GNUC__) |
229 | | # pragma GCC target("") |
230 | | # endif |
231 | | # include "softaes/untrinsics.h" |
232 | | # endif |
233 | | |
234 | | /** |
235 | | * On x86_64, we represent AES blocks using __m128i. |
236 | | */ |
237 | | typedef __m128i BlockVec; |
238 | | |
239 | | /** |
240 | | * Load 16 bytes from memory into an __m128i. |
241 | | */ |
242 | 0 | # define LOAD128(a) _mm_loadu_si128((const BlockVec *) (a)) |
243 | | /** |
244 | | * Store 16 bytes from an __m128i into memory. |
245 | | */ |
246 | 0 | # define STORE128(a, b) _mm_storeu_si128((BlockVec *) (a), (b)) |
247 | | /** |
248 | | * Perform a standard AES round (no final) on block_vec with rkey. |
249 | | */ |
250 | 0 | # define AES_ENCRYPT(block_vec, rkey) _mm_aesenc_si128((block_vec), (rkey)) |
251 | | /** |
252 | | * Perform the final AES round (excludes MixColumns) on block_vec with rkey. |
253 | | */ |
254 | 0 | # define AES_ENCRYPTLAST(block_vec, rkey) _mm_aesenclast_si128((block_vec), (rkey)) |
255 | | /** |
256 | | * Perform a standard AES decryption round on block_vec with rkey. |
257 | | */ |
258 | 0 | # define AES_DECRYPT(block_vec, rkey) _mm_aesdec_si128((block_vec), (rkey)) |
259 | | /** |
260 | | * Perform the final AES decryption round (excludes InverseMixColumns) on block_vec with rkey. |
261 | | */ |
262 | 0 | # define AES_DECRYPTLAST(block_vec, rkey) _mm_aesdeclast_si128((block_vec), (rkey)) |
263 | | /** |
264 | | * Generate an AES subkey for key expansion. |
265 | | */ |
266 | 0 | # define AES_KEYGEN(block_vec, rc) _mm_aeskeygenassist_si128((block_vec), (rc)) |
267 | | /** |
268 | | * XOR two 128-bit blocks. |
269 | | */ |
270 | 0 | # define XOR128(a, b) _mm_xor_si128((a), (b)) |
271 | | /** |
272 | | * XOR three 128-bit blocks. |
273 | | */ |
274 | 0 | # define XOR128_3(a, b, c) _mm_xor_si128(_mm_xor_si128((a), (b)), (c)) |
275 | | /** |
276 | | * Construct a 128-bit block from two 64-bit values. |
277 | | */ |
278 | | # define SET64x2(a, b) _mm_set_epi64x((uint64_t) (a), (uint64_t) (b)) |
279 | | /** |
280 | | * Shift a 128-bit block left by b bytes. |
281 | | */ |
282 | | # define BYTESHL128(a, b) _mm_slli_si128(a, b) |
283 | | /** |
284 | | * Reorder 32-bit lanes in a 128-bit block. |
285 | | */ |
286 | | # define SHUFFLE32x4_3333(x) _mm_shuffle_epi32((x), _MM_SHUFFLE(3, 3, 3, 3)) |
287 | | /** |
288 | | * Invert an AES round key for decryption. |
289 | | */ |
290 | 0 | # define RKINVERT(rkey) _mm_aesimc_si128(rkey) |
291 | | /** |
292 | | * Expand an 8-byte tweak into a 128-bit register. |
293 | | */ |
294 | | # define TWEAK_EXPAND(tweak) \ |
295 | 0 | _mm_shuffle_epi8(_mm_loadu_si64((const void *) tweak), \ |
296 | 0 | _mm_setr_epi8(0x00, 0x01, 0x80, 0x80, 0x02, 0x03, 0x80, 0x80, 0x04, 0x05, \ |
297 | 0 | 0x80, 0x80, 0x06, 0x07, 0x80, 0x80)) |
298 | | |
299 | | /** |
300 | | * Shift an entire 128-bit block left by 1 bit. |
301 | | */ |
302 | | static inline BlockVec |
303 | | SHL1_128(const BlockVec a) |
304 | 0 | { |
305 | 0 | const BlockVec shl = _mm_add_epi8(a, a); |
306 | 0 | const BlockVec msb = _mm_and_si128(_mm_srli_epi16(a, 7), _mm_set1_epi8(0x01)); |
307 | 0 | const BlockVec carries = _mm_srli_si128(msb, 1); |
308 | 0 | return _mm_or_si128(shl, carries); |
309 | 0 | } |
310 | | #endif |
311 | | |
312 | | /** |
313 | | * KeySchedule is an array of 1 + ROUNDS 128-bit blocks. |
314 | | * The first block is the initial round key, followed by ROUNDS subkeys. |
315 | | */ |
316 | | typedef BlockVec KeySchedule[1 + ROUNDS]; |
317 | | |
318 | | /** |
319 | | * Inverse key schedule for decryption. |
320 | | */ |
321 | | typedef BlockVec InvKeySchedule[ROUNDS - 1]; |
322 | | |
323 | | /** |
324 | | * AesState holds the expanded round keys for encryption/decryption. |
325 | | */ |
326 | | typedef struct AesState { |
327 | | KeySchedule rkeys; |
328 | | } AesState; |
329 | | |
330 | | /** |
331 | | * NDXState holds the expanded tweak round keys and encryption round keys for encryption/decryption. |
332 | | */ |
333 | | typedef struct NDXState { |
334 | | KeySchedule tkeys; |
335 | | KeySchedule rkeys; |
336 | | } NDXState; |
337 | | |
338 | | /** |
339 | | * PFXState holds the expanded tweak round keys and encryption round keys for encryption/decryption. |
340 | | */ |
341 | | typedef struct PFXState { |
342 | | KeySchedule k1keys; |
343 | | KeySchedule k2keys; |
344 | | } PFXState; |
345 | | |
346 | | /** |
347 | | * expand_key expands a 16-byte AES key into a full set of round keys. |
348 | | * st: the AesState structure to be populated. |
349 | | * key: a 16-byte AES key. |
350 | | */ |
351 | | static void __vectorcall |
352 | | expand_key(KeySchedule rkeys, const unsigned char key[IPCRYPT_KEYBYTES]) |
353 | 0 | { |
354 | 0 | BlockVec t, s; |
355 | 0 | size_t i = 0; |
356 | |
|
357 | 0 | #define EXPAND_KEY(RC) \ |
358 | 0 | rkeys[i++] = t; \ |
359 | 0 | s = AES_KEYGEN(t, RC); \ |
360 | 0 | t = XOR128(t, BYTESHL128(t, 4)); \ |
361 | 0 | t = XOR128(t, BYTESHL128(t, 8)); \ |
362 | 0 | t = XOR128(t, SHUFFLE32x4_3333(s)); |
363 | | |
364 | | // Load the initial 128-bit key from memory. |
365 | 0 | t = LOAD128(key); |
366 | | // Repeatedly generate the next round key. |
367 | 0 | EXPAND_KEY(0x01); |
368 | 0 | EXPAND_KEY(0x02); |
369 | 0 | EXPAND_KEY(0x04); |
370 | 0 | EXPAND_KEY(0x08); |
371 | 0 | EXPAND_KEY(0x10); |
372 | 0 | EXPAND_KEY(0x20); |
373 | 0 | EXPAND_KEY(0x40); |
374 | 0 | EXPAND_KEY(0x80); |
375 | 0 | EXPAND_KEY(0x1b); |
376 | 0 | EXPAND_KEY(0x36); |
377 | | // Store the final key. |
378 | 0 | rkeys[i++] = t; |
379 | 0 | } |
380 | | |
381 | | /** |
382 | | * aes_encrypt encrypts a 16-byte block x in-place using the expanded keys in st. |
383 | | */ |
384 | | static void |
385 | | aes_encrypt(uint8_t x[16], const AesState *st) |
386 | 0 | { |
387 | 0 | const BlockVec *rkeys = st->rkeys; |
388 | 0 | BlockVec t; |
389 | 0 | size_t i; |
390 | |
|
391 | | #ifdef AES_XENCRYPT |
392 | | // For AArch64 with AES_XENCRYPT macros. |
393 | | t = AES_XENCRYPT(LOAD128(x), rkeys[0]); |
394 | | for (i = 1; i < ROUNDS - 1; i++) { |
395 | | t = AES_XENCRYPT(t, rkeys[i]); |
396 | | } |
397 | | t = AES_XENCRYPTLAST(t, rkeys[i]); |
398 | | t = XOR128(t, rkeys[ROUNDS]); |
399 | | #else |
400 | | // For x86_64 or a fallback. |
401 | 0 | t = XOR128(LOAD128(x), rkeys[0]); |
402 | 0 | for (i = 1; i < ROUNDS; i++) { |
403 | 0 | t = AES_ENCRYPT(t, rkeys[i]); |
404 | 0 | } |
405 | 0 | t = AES_ENCRYPTLAST(t, rkeys[ROUNDS]); |
406 | 0 | #endif |
407 | 0 | STORE128(x, t); |
408 | 0 | } |
409 | | |
410 | | /** |
411 | | * aes_decrypt decrypts a 16-byte block x in-place using the expanded keys in st. |
412 | | */ |
413 | | static void |
414 | | aes_decrypt(uint8_t x[16], const AesState *st) |
415 | 0 | { |
416 | 0 | const BlockVec *rkeys = st->rkeys; |
417 | 0 | InvKeySchedule rkeys_inv; |
418 | 0 | BlockVec t; |
419 | 0 | size_t i; |
420 | | |
421 | | // Given the purpose of this library, we assume that decryption is not a frequent operation. |
422 | 0 | for (i = 0; i < ROUNDS - 1; i++) { |
423 | 0 | rkeys_inv[i] = RKINVERT(rkeys[ROUNDS - 1 - i]); |
424 | 0 | } |
425 | | #ifdef AES_XENCRYPT |
426 | | // AArch64 path with AES_XDECRYPT. |
427 | | t = AES_XDECRYPT(LOAD128(x), rkeys[ROUNDS]); |
428 | | for (i = 0; i < ROUNDS - 2; i++) { |
429 | | t = AES_XDECRYPT(t, rkeys_inv[i]); |
430 | | } |
431 | | t = AES_XDECRYPTLAST(t, rkeys_inv[i]); |
432 | | t = XOR128(t, rkeys[0]); |
433 | | #else |
434 | | // x86_64 path using AES_DECRYPT. |
435 | 0 | t = XOR128(LOAD128(x), rkeys[ROUNDS]); |
436 | 0 | for (i = 0; i < ROUNDS - 1; i++) { |
437 | 0 | t = AES_DECRYPT(t, rkeys_inv[i]); |
438 | 0 | } |
439 | 0 | t = AES_DECRYPTLAST(t, rkeys[0]); |
440 | 0 | #endif |
441 | 0 | STORE128(x, t); |
442 | 0 | } |
443 | | |
444 | | /** |
445 | | * aes_encrypt_with_tweak encrypts a 16-byte block x with an additional 8-byte tweak. |
446 | | * The tweak is XORed with each round key. |
447 | | */ |
448 | | static void |
449 | | aes_encrypt_with_tweak(uint8_t x[16], const AesState *st, const uint8_t tweak[IPCRYPT_TWEAKBYTES]) |
450 | 0 | { |
451 | 0 | const BlockVec *rkeys = st->rkeys; |
452 | 0 | const BlockVec tweak_block = TWEAK_EXPAND(tweak); |
453 | 0 | BlockVec t; |
454 | 0 | size_t i; |
455 | |
|
456 | | #ifdef AES_XENCRYPT |
457 | | // AArch64 path. |
458 | | t = AES_XENCRYPT(LOAD128(x), XOR128(tweak_block, rkeys[0])); |
459 | | for (i = 1; i < ROUNDS - 1; i++) { |
460 | | t = AES_XENCRYPT(t, XOR128(tweak_block, rkeys[i])); |
461 | | } |
462 | | t = AES_XENCRYPTLAST(t, XOR128(tweak_block, rkeys[i])); |
463 | | t = XOR128(t, XOR128(tweak_block, rkeys[ROUNDS])); |
464 | | #else |
465 | | // x86_64 path. |
466 | 0 | t = XOR128_3(LOAD128(x), tweak_block, rkeys[0]); |
467 | 0 | for (i = 1; i < ROUNDS; i++) { |
468 | 0 | t = AES_ENCRYPT(t, XOR128(tweak_block, rkeys[i])); |
469 | 0 | } |
470 | 0 | t = AES_ENCRYPTLAST(t, XOR128(tweak_block, rkeys[ROUNDS])); |
471 | 0 | #endif |
472 | 0 | STORE128(x, t); |
473 | 0 | } |
474 | | |
475 | | /** |
476 | | * aes_decrypt_with_tweak decrypts a 16-byte block x with an additional 8-byte tweak. |
477 | | * The same tweak used during encryption must be provided. |
478 | | */ |
479 | | static void |
480 | | aes_decrypt_with_tweak(uint8_t x[16], const AesState *st, const uint8_t tweak[IPCRYPT_TWEAKBYTES]) |
481 | 0 | { |
482 | 0 | const BlockVec *rkeys = st->rkeys; |
483 | 0 | InvKeySchedule rkeys_inv; |
484 | 0 | const BlockVec tweak_block = TWEAK_EXPAND(tweak); |
485 | 0 | const BlockVec tweak_block_inv = RKINVERT(tweak_block); |
486 | 0 | BlockVec t; |
487 | 0 | size_t i; |
488 | | |
489 | | // Given the purpose of this library, we assume that decryption is not a frequent operation. |
490 | 0 | for (i = 0; i < ROUNDS - 1; i++) { |
491 | 0 | rkeys_inv[i] = RKINVERT(rkeys[ROUNDS - 1 - i]); |
492 | 0 | } |
493 | | #ifdef AES_XENCRYPT |
494 | | t = AES_XDECRYPT(LOAD128(x), XOR128(tweak_block, rkeys[ROUNDS])); |
495 | | for (i = 0; i < ROUNDS - 2; i++) { |
496 | | t = AES_XDECRYPT(t, XOR128(tweak_block_inv, rkeys_inv[i])); |
497 | | } |
498 | | t = AES_XDECRYPTLAST(t, XOR128(tweak_block_inv, rkeys_inv[i])); |
499 | | t = XOR128(t, XOR128(tweak_block, rkeys[0])); |
500 | | #else |
501 | 0 | t = XOR128_3(LOAD128(x), tweak_block, rkeys[ROUNDS]); |
502 | 0 | for (i = 0; i < ROUNDS - 1; i++) { |
503 | 0 | t = AES_DECRYPT(t, XOR128(tweak_block_inv, rkeys_inv[i])); |
504 | 0 | } |
505 | 0 | t = AES_DECRYPTLAST(t, XOR128(tweak_block, rkeys[0])); |
506 | 0 | #endif |
507 | 0 | STORE128(x, t); |
508 | 0 | } |
509 | | |
510 | | static BlockVec |
511 | | aes_xex_tweak(const NDXState *st, const uint8_t tweak[IPCRYPT_NDX_TWEAKBYTES]) |
512 | 0 | { |
513 | 0 | const BlockVec *tkeys = st->tkeys; |
514 | 0 | BlockVec tt; |
515 | 0 | size_t i; |
516 | |
|
517 | 0 | COMPILER_ASSERT(IPCRYPT_NDX_TWEAKBYTES == 16); |
518 | |
|
519 | | #ifdef AES_XENCRYPT |
520 | | // AArch64 path. |
521 | | tt = AES_XENCRYPT(LOAD128(tweak), tkeys[0]); |
522 | | for (i = 1; i < ROUNDS - 1; i++) { |
523 | | tt = AES_XENCRYPT(tt, tkeys[i]); |
524 | | } |
525 | | tt = AES_XENCRYPTLAST(tt, tkeys[i]); |
526 | | tt = XOR128(tt, tkeys[ROUNDS]); |
527 | | #else |
528 | | // x86_64 path. |
529 | 0 | tt = XOR128(LOAD128(tweak), tkeys[0]); |
530 | 0 | for (i = 1; i < ROUNDS; i++) { |
531 | 0 | tt = AES_ENCRYPT(tt, tkeys[i]); |
532 | 0 | } |
533 | 0 | tt = AES_ENCRYPTLAST(tt, tkeys[ROUNDS]); |
534 | 0 | #endif |
535 | 0 | return tt; |
536 | 0 | } |
537 | | |
538 | | static void |
539 | | aes_xex_encrypt(uint8_t x[16], const NDXState *st, const uint8_t tweak[IPCRYPT_NDX_TWEAKBYTES]) |
540 | 0 | { |
541 | 0 | const BlockVec tt = aes_xex_tweak(st, tweak); |
542 | 0 | const BlockVec *rkeys = st->rkeys; |
543 | 0 | BlockVec t; |
544 | 0 | size_t i; |
545 | |
|
546 | 0 | COMPILER_ASSERT(IPCRYPT_NDX_TWEAKBYTES == 16); |
547 | |
|
548 | | #ifdef AES_XENCRYPT |
549 | | // For AArch64 with AES_XENCRYPT macros. |
550 | | t = AES_XENCRYPT(XOR128(LOAD128(x), tt), rkeys[0]); |
551 | | for (i = 1; i < ROUNDS - 1; i++) { |
552 | | t = AES_XENCRYPT(t, rkeys[i]); |
553 | | } |
554 | | t = AES_XENCRYPTLAST(t, rkeys[i]); |
555 | | t = XOR128_3(t, rkeys[ROUNDS], tt); |
556 | | #else |
557 | | // For x86_64 or a fallback. |
558 | 0 | t = XOR128(XOR128(LOAD128(x), tt), rkeys[0]); |
559 | 0 | for (i = 1; i < ROUNDS; i++) { |
560 | 0 | t = AES_ENCRYPT(t, rkeys[i]); |
561 | 0 | } |
562 | 0 | t = AES_ENCRYPTLAST(t, XOR128(rkeys[ROUNDS], tt)); |
563 | 0 | #endif |
564 | 0 | STORE128(x, t); |
565 | 0 | } |
566 | | |
567 | | static void |
568 | | aes_ndx_decrypt(uint8_t x[16], const NDXState *st, const uint8_t tweak[IPCRYPT_NDX_TWEAKBYTES]) |
569 | 0 | { |
570 | |
|
571 | 0 | const BlockVec tt = aes_xex_tweak(st, tweak); |
572 | 0 | const BlockVec *rkeys = st->rkeys; |
573 | 0 | BlockVec t; |
574 | 0 | size_t i; |
575 | |
|
576 | | #ifdef AES_XENCRYPT |
577 | | // AArch64 path with AES_XDECRYPT. |
578 | | t = AES_XDECRYPT(XOR128(LOAD128(x), tt), rkeys[ROUNDS]); |
579 | | for (i = ROUNDS - 1; i > 1; i--) { |
580 | | t = AES_XDECRYPT(t, RKINVERT(rkeys[i])); |
581 | | } |
582 | | t = AES_XDECRYPTLAST(t, RKINVERT(rkeys[1])); |
583 | | t = XOR128_3(t, rkeys[0], tt); |
584 | | #else |
585 | | // x86_64 path using AES_DECRYPT. |
586 | 0 | t = XOR128(XOR128(LOAD128(x), tt), rkeys[ROUNDS]); |
587 | 0 | for (i = ROUNDS - 1; i > 0; i--) { |
588 | 0 | t = AES_DECRYPT(t, RKINVERT(rkeys[i])); |
589 | 0 | } |
590 | 0 | t = AES_DECRYPTLAST(t, XOR128(rkeys[0], tt)); |
591 | 0 | #endif |
592 | 0 | STORE128(x, t); |
593 | 0 | } |
594 | | |
595 | | /** |
596 | | * bin2hex converts a binary buffer into a lowercase hex string. |
597 | | * hex: the destination buffer. |
598 | | * hex_maxlen: maximum capacity of hex. |
599 | | * bin: source buffer. |
600 | | * bin_len: length of bin. |
601 | | * Returns NULL on error, or hex on success. |
602 | | */ |
603 | | static char * |
604 | | bin2hex(char *hex, size_t hex_maxlen, const uint8_t *bin, size_t bin_len) |
605 | 0 | { |
606 | 0 | size_t i = (size_t) 0U; |
607 | 0 | unsigned int x; |
608 | 0 | int b; |
609 | 0 | int c; |
610 | | |
611 | | // Check buffer limits. |
612 | 0 | if (bin_len >= SIZE_MAX / 2 || hex_maxlen <= bin_len * 2U) { |
613 | 0 | return NULL; |
614 | 0 | } |
615 | | // Convert each byte to two hex characters. |
616 | 0 | while (i < bin_len) { |
617 | 0 | c = bin[i] & 0xf; |
618 | 0 | b = bin[i] >> 4; |
619 | 0 | x = (unsigned char) (87U + c + (((c - 10U) >> 8) & ~38U)) << 8 | |
620 | 0 | (unsigned char) (87U + b + (((b - 10U) >> 8) & ~38U)); |
621 | 0 | hex[i * 2U] = (char) x; |
622 | 0 | x >>= 8; |
623 | 0 | hex[i * 2U + 1U] = (char) x; |
624 | 0 | i++; |
625 | 0 | } |
626 | | // Null-terminate the string. |
627 | 0 | hex[i * 2U] = 0U; |
628 | |
|
629 | 0 | return hex; |
630 | 0 | } |
631 | | |
632 | | /** |
633 | | * hex2bin converts a hex string into a binary buffer. |
634 | | * bin: destination buffer. |
635 | | * bin_maxlen: capacity of bin. |
636 | | * hex: source string. |
637 | | * hex_len: length of the hex string. |
638 | | * Returns the number of bytes written on success, or 0 on error. |
639 | | */ |
640 | | static size_t |
641 | | hex2bin(uint8_t *bin, size_t bin_maxlen, const char *hex, size_t hex_len) |
642 | 0 | { |
643 | 0 | const size_t bin_len = hex_len / 2U; |
644 | 0 | size_t i; |
645 | | |
646 | | // Must have an even length and fit the destination. |
647 | 0 | if (hex_len % 2U != 0 || bin_len > bin_maxlen) { |
648 | 0 | return 0U; |
649 | 0 | } |
650 | 0 | for (i = 0; i < bin_len; i++) { |
651 | 0 | unsigned char c = (unsigned char) hex[i * 2U]; |
652 | 0 | unsigned char b = (unsigned char) hex[i * 2U + 1U]; |
653 | | // Convert from ASCII to nibble. |
654 | 0 | if (c >= '0' && c <= '9') { |
655 | 0 | c -= '0'; |
656 | 0 | } else if (c >= 'a' && c <= 'f') { |
657 | 0 | c -= 'a' - 10; |
658 | 0 | } else { |
659 | 0 | return 0U; |
660 | 0 | } |
661 | 0 | if (b >= '0' && b <= '9') { |
662 | 0 | b -= '0'; |
663 | 0 | } else if (b >= 'a' && b <= 'f') { |
664 | 0 | b -= 'a' - 10; |
665 | 0 | } else { |
666 | 0 | return 0U; |
667 | 0 | } |
668 | 0 | bin[i] = ((uint8_t) c << 4) | b; |
669 | 0 | } |
670 | 0 | return bin_len; |
671 | 0 | } |
672 | | |
673 | | /** |
674 | | * ipcrypt_zeroize securely zeroes a memory region of length len starting at pnt. |
675 | | * This function attempts to prevent the compiler from optimizing away the zeroing. |
676 | | */ |
677 | | static void |
678 | | ipcrypt_zeroize(void *pnt, size_t len) |
679 | 0 | { |
680 | | #ifdef HAVE_EXPLICIT_BZERO |
681 | | explicit_bzero(pnt, len); |
682 | | #elif defined(_MSC_VER) |
683 | | SecureZeroMemory(pnt, len); |
684 | | #elif defined(__STDC_LIB_EXT1__) |
685 | | memset_s(pnt, len, 0, len); |
686 | | #elif defined(__GNUC__) || defined(__clang__) |
687 | | memset(pnt, 0, len); |
688 | | // Compiler barrier to prevent optimizations from removing memset. |
689 | 0 | __asm__ __volatile__("" : : "r"(pnt) : "memory"); |
690 | | #else |
691 | | volatile unsigned char *volatile pnt_ = (volatile unsigned char *volatile) pnt; |
692 | | size_t i = (size_t) 0U; |
693 | | while (i < len) { |
694 | | pnt_[i++] = 0U; |
695 | | } |
696 | | #endif |
697 | 0 | } |
698 | | |
699 | | /** |
700 | | * Convert a hexadecimal string to a secret key. |
701 | | * |
702 | | * The input string must be exactly 32 or 64 characters long (IPCRYPT_KEYBYTES or |
703 | | * IPCRYPT_NDX_KEYBYTES bytes in hex). Returns 0 on success, or -1 if the input string is invalid or |
704 | | * conversion fails. |
705 | | */ |
706 | | int |
707 | | ipcrypt_key_from_hex(uint8_t *key, size_t key_len, const char *hex, size_t hex_len) |
708 | 0 | { |
709 | 0 | if (hex_len != 2 * IPCRYPT_KEYBYTES && hex_len != 2 * IPCRYPT_NDX_KEYBYTES) { |
710 | 0 | return -1; |
711 | 0 | } |
712 | 0 | if (hex2bin(key, key_len, hex, hex_len) != key_len) { |
713 | 0 | return -1; |
714 | 0 | } |
715 | 0 | return 0; |
716 | 0 | } |
717 | | |
718 | | /** |
719 | | * Convert a hexadecimal string to an ipcrypt-nd ciphertext. |
720 | | * |
721 | | * The input string must be exactly 48 characters long (IPCRYPT_NDIP_BYTES bytes in hex). |
722 | | * Returns 0 on success, or -1 if the input string is invalid or conversion fails. |
723 | | */ |
724 | | int |
725 | | ipcrypt_ndip_from_hex(uint8_t ndip[IPCRYPT_NDIP_BYTES], const char *hex, size_t hex_len) |
726 | 0 | { |
727 | 0 | if (hex_len != 2 * IPCRYPT_NDIP_BYTES) { |
728 | 0 | return -1; |
729 | 0 | } |
730 | 0 | if (hex2bin(ndip, IPCRYPT_NDIP_BYTES, hex, hex_len) != IPCRYPT_NDIP_BYTES) { |
731 | 0 | return -1; |
732 | 0 | } |
733 | 0 | return 0; |
734 | 0 | } |
735 | | |
736 | | /** |
737 | | * Convert a hexadecimal string to an ipcrypt-ndx ciphertext. |
738 | | * |
739 | | * The input string must be exactly 64 characters long (IPCRYPT_NDX_NDIP_BYTES bytes in hex). |
740 | | * Returns 0 on success, or -1 if the input string is invalid or conversion fails. |
741 | | */ |
742 | | int |
743 | | ipcrypt_ndx_ndip_from_hex(uint8_t ndip[IPCRYPT_NDX_NDIP_BYTES], const char *hex, size_t hex_len) |
744 | 0 | { |
745 | 0 | if (hex_len != 2 * IPCRYPT_NDX_NDIP_BYTES) { |
746 | 0 | return -1; |
747 | 0 | } |
748 | 0 | if (hex2bin(ndip, IPCRYPT_NDX_NDIP_BYTES, hex, hex_len) != IPCRYPT_NDX_NDIP_BYTES) { |
749 | 0 | return -1; |
750 | 0 | } |
751 | 0 | return 0; |
752 | 0 | } |
753 | | |
754 | | /** |
755 | | * ipcrypt_str_to_ip16 parses an IP address string (IPv4 or IPv6) into a 16-byte buffer ip16. |
756 | | * If it detects an IPv4 address, it is stored as an IPv4-mapped IPv6 address. |
757 | | * Returns 0 on success, or -1 on failure. |
758 | | */ |
759 | | int |
760 | | ipcrypt_str_to_ip16(uint8_t ip16[16], const char *ip_str) |
761 | 0 | { |
762 | 0 | struct in6_addr addr6; |
763 | 0 | struct in_addr addr4; |
764 | | |
765 | | // Try parsing as IPv6. |
766 | 0 | if (inet_pton(AF_INET6, ip_str, &addr6) == 1) { |
767 | 0 | memcpy(ip16, &addr6, 16); |
768 | 0 | return 0; |
769 | 0 | } |
770 | | // Try parsing as IPv4. |
771 | 0 | if (inet_pton(AF_INET, ip_str, &addr4) == 1) { |
772 | 0 | memset(ip16, 0, 16); |
773 | 0 | ip16[10] = 0xff; |
774 | 0 | ip16[11] = 0xff; |
775 | 0 | memcpy(ip16 + 12, &addr4, 4); |
776 | 0 | return 0; |
777 | 0 | } |
778 | 0 | return -1; // Parsing failed. |
779 | 0 | } |
780 | | |
781 | | /** |
782 | | * ipcrypt_ip16_to_str converts a 16-byte buffer ip16 into its string representation (IPv4 or IPv6). |
783 | | * If the buffer holds an IPv4-mapped address, it returns an IPv4 string. |
784 | | * Returns the length of the resulting string on success, or 0 on error. |
785 | | */ |
786 | | size_t |
787 | | ipcrypt_ip16_to_str(char ip_str[IPCRYPT_MAX_IP_STR_BYTES], const uint8_t ip16[16]) |
788 | 0 | { |
789 | 0 | int is_ipv4_mapped = 1; |
790 | 0 | size_t i; |
791 | |
|
792 | 0 | COMPILER_ASSERT(IPCRYPT_MAX_IP_STR_BYTES >= 46U); |
793 | | |
794 | | // Check whether it's an IPv4-mapped IPv6 address (::ffff:x.x.x.x). |
795 | 0 | for (i = 0; i < 10; i++) { |
796 | 0 | if (ip16[i] != 0) { |
797 | 0 | is_ipv4_mapped = 0; |
798 | 0 | break; |
799 | 0 | } |
800 | 0 | } |
801 | 0 | if (is_ipv4_mapped && (ip16[10] != 0xff || ip16[11] != 0xff)) { |
802 | 0 | is_ipv4_mapped = 0; |
803 | 0 | } |
804 | | // If IPv4-mapped, convert to IPv4 string. |
805 | 0 | if (is_ipv4_mapped) { |
806 | 0 | struct in_addr addr4; |
807 | 0 | memcpy(&addr4, ip16 + 12, 4); |
808 | 0 | if (inet_ntop(AF_INET, &addr4, ip_str, INET_ADDRSTRLEN) == NULL) { |
809 | 0 | return 0; |
810 | 0 | } |
811 | 0 | } else { |
812 | | // Otherwise, treat as IPv6. |
813 | 0 | struct in6_addr addr6; |
814 | 0 | memcpy(&addr6, ip16, 16); |
815 | 0 | if (inet_ntop(AF_INET6, &addr6, ip_str, INET6_ADDRSTRLEN) == NULL) { |
816 | 0 | return 0; |
817 | 0 | } |
818 | 0 | } |
819 | 0 | return strlen(ip_str); |
820 | 0 | } |
821 | | |
822 | | /** |
823 | | * Convert a socket address structure to a 16-byte binary IP representation. |
824 | | * |
825 | | * Supports both IPv4 (AF_INET) and IPv6 (AF_INET6) socket addresses. |
826 | | * For IPv4 addresses, they are converted to IPv4-mapped IPv6 format. |
827 | | * |
828 | | * Returns 0 on success, or -1 if the address family is not supported. |
829 | | */ |
830 | | int |
831 | | ipcrypt_sockaddr_to_ip16(uint8_t ip16[16], const struct sockaddr *sa) |
832 | 0 | { |
833 | 0 | if (sa->sa_family == AF_INET) { |
834 | 0 | const struct sockaddr_in *s = (const struct sockaddr_in *) sa; |
835 | 0 | memset(ip16, 0, 10); |
836 | 0 | ip16[10] = 0xff; |
837 | 0 | ip16[11] = 0xff; |
838 | 0 | memcpy(ip16 + 12, &s->sin_addr, 4); |
839 | 0 | return 0; |
840 | 0 | } else if (sa->sa_family == AF_INET6) { |
841 | 0 | const struct sockaddr_in6 *s = (const struct sockaddr_in6 *) sa; |
842 | 0 | memcpy(ip16, &s->sin6_addr, 16); |
843 | 0 | return 0; |
844 | 0 | } |
845 | 0 | return -1; |
846 | 0 | } |
847 | | |
848 | | /** |
849 | | * Convert a 16-byte binary IP address to a socket address structure. |
850 | | * |
851 | | * The socket address structure is populated based on the IP format: |
852 | | * - For IPv4-mapped IPv6 addresses, an IPv4 socket address is created |
853 | | * - For other IPv6 addresses, an IPv6 socket address is created |
854 | | * |
855 | | * The provided sockaddr_storage structure is guaranteed to be large enough |
856 | | * to hold any socket address type. |
857 | | */ |
858 | | void |
859 | | ipcrypt_ip16_to_sockaddr(struct sockaddr_storage *sa, const uint8_t ip16[16]) |
860 | 0 | { |
861 | 0 | const uint8_t ipv4_mapped[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff }; |
862 | |
|
863 | 0 | memset(sa, 0, sizeof *sa); |
864 | 0 | if (memcmp(ip16, ipv4_mapped, sizeof ipv4_mapped) == 0) { |
865 | 0 | struct sockaddr_in *s = (struct sockaddr_in *) sa; |
866 | 0 | s->sin_family = AF_INET; |
867 | 0 | memcpy(&s->sin_addr, ip16 + 12, 4); |
868 | | #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ |
869 | | defined(__DragonFly__) |
870 | | s->sin_len = sizeof *s; |
871 | | #endif |
872 | 0 | } else { |
873 | 0 | struct sockaddr_in6 *s = (struct sockaddr_in6 *) sa; |
874 | 0 | s->sin6_family = AF_INET6; |
875 | 0 | memcpy(&s->sin6_addr, ip16, 16); |
876 | | #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ |
877 | | defined(__DragonFly__) |
878 | | s->sin6_len = sizeof *s; |
879 | | #endif |
880 | 0 | } |
881 | 0 | } |
882 | | |
883 | | /** |
884 | | * ipcrypt_init initializes an IPCrypt context with a 16-byte key. |
885 | | * Expands the key into round keys and stores them in ipcrypt->opaque. |
886 | | */ |
887 | | void |
888 | | ipcrypt_init(IPCrypt *ipcrypt, const uint8_t key[IPCRYPT_KEYBYTES]) |
889 | 0 | { |
890 | 0 | AesState st; |
891 | |
|
892 | 0 | expand_key(st.rkeys, key); |
893 | 0 | COMPILER_ASSERT(sizeof ipcrypt->opaque >= sizeof st); |
894 | 0 | memcpy(ipcrypt->opaque, &st, sizeof st); |
895 | 0 | } |
896 | | |
897 | | /** |
898 | | * ipcrypt_deinit clears the IPCrypt context to wipe sensitive data from memory. |
899 | | */ |
900 | | void |
901 | | ipcrypt_deinit(IPCrypt *ipcrypt) |
902 | 0 | { |
903 | 0 | ipcrypt_zeroize(ipcrypt, sizeof *ipcrypt); |
904 | 0 | } |
905 | | |
906 | | /** |
907 | | * ipcrypt_pfx_init initializes the IPCryptPFX context with a 32-byte secret key. |
908 | | * This prepares the context for prefix-preserving IP address encryption operations. |
909 | | * Returns 0 on success. |
910 | | */ |
911 | | int |
912 | | ipcrypt_pfx_init(IPCryptPFX *ipcrypt, const uint8_t key[IPCRYPT_PFX_KEYBYTES]) |
913 | 0 | { |
914 | 0 | PFXState st; |
915 | 0 | uint8_t diff[16]; |
916 | 0 | size_t i; |
917 | 0 | uint8_t d; |
918 | |
|
919 | 0 | expand_key(st.k1keys, key); |
920 | 0 | expand_key(st.k2keys, key + 16); |
921 | | |
922 | | /** |
923 | | * Ensure the two keys differ in case of misuse. |
924 | | */ |
925 | 0 | STORE128(diff, XOR128(st.k1keys[ROUNDS / 2], st.k2keys[ROUNDS / 2])); |
926 | 0 | d = 0; |
927 | 0 | for (i = 0; i < 16; i++) { |
928 | 0 | d |= diff[i]; |
929 | 0 | } |
930 | 0 | if (d == 0) { |
931 | 0 | for (i = 0; i < 16; i++) { |
932 | 0 | diff[i] = key[i] ^ 0x5a; |
933 | 0 | } |
934 | 0 | expand_key(st.k2keys, diff); |
935 | 0 | } |
936 | |
|
937 | 0 | COMPILER_ASSERT(sizeof ipcrypt->opaque >= sizeof st); |
938 | 0 | memcpy(ipcrypt->opaque, &st, sizeof st); |
939 | |
|
940 | 0 | return -(d == 0); |
941 | 0 | } |
942 | | |
943 | | /** |
944 | | * ipcrypt_pfx_deinit securely clears and deinitializes the IPCryptPFX context. |
945 | | * This ensures that secret key material is wiped from memory. |
946 | | */ |
947 | | void |
948 | | ipcrypt_pfx_deinit(IPCryptPFX *ipcrypt) |
949 | 0 | { |
950 | 0 | ipcrypt_zeroize(ipcrypt, sizeof *ipcrypt); |
951 | 0 | } |
952 | | |
953 | | static int |
954 | | ipcrypt_is_mapped_ipv4(const uint8_t ip16[16]) |
955 | 0 | { |
956 | 0 | static const uint8_t ipv4_mapped[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff }; |
957 | 0 | return memcmp(ip16, ipv4_mapped, sizeof ipv4_mapped) == 0; |
958 | 0 | } |
959 | | |
960 | | static void |
961 | | ipcrypt_pfx_pad_prefix(uint8_t padded_prefix[16], unsigned int prefix_len_bits) |
962 | 0 | { |
963 | 0 | memset(padded_prefix, 0, 16); |
964 | 0 | if (prefix_len_bits == 0) { |
965 | 0 | padded_prefix[15] = 0x01; |
966 | 0 | } else { |
967 | 0 | padded_prefix[3] = 0x01; |
968 | 0 | padded_prefix[14] = 0xff; |
969 | 0 | padded_prefix[15] = 0xff; |
970 | 0 | } |
971 | 0 | } |
972 | | |
973 | | static uint8_t |
974 | | ipcrypt_pfx_get_bit(const uint8_t ip16[16], const unsigned int bit_index) |
975 | 0 | { |
976 | 0 | return (ip16[15 - bit_index / 8] >> (bit_index % 8)) & 1; |
977 | 0 | } |
978 | | |
979 | | static void |
980 | | ipcrypt_pfx_set_bit(uint8_t ip16[16], const unsigned int bit_index, const uint8_t bit_value) |
981 | 0 | { |
982 | 0 | const size_t byte_index = 15 - bit_index / 8; |
983 | 0 | const uint8_t bit_mask = (uint8_t) (1 << (bit_index % 8)); |
984 | 0 | uint8_t mask = (uint8_t) -((bit_value & 1)); |
985 | |
|
986 | 0 | #if defined(__GNUC__) || defined(__clang__) |
987 | 0 | __asm__ __volatile__("" : "+r"(mask) :); |
988 | 0 | #endif |
989 | 0 | ip16[byte_index] = (ip16[byte_index] & ~bit_mask) | (bit_mask & mask); |
990 | 0 | } |
991 | | |
992 | | static void |
993 | | ipcrypt_pfx_shift_left(uint8_t ip16[16]) |
994 | 0 | { |
995 | | #ifdef STANDARD |
996 | | size_t i; |
997 | | |
998 | | for (i = 0; i < 15; i++) { |
999 | | ip16[i] = (ip16[i] << 1) | (ip16[i + 1] >> 7); |
1000 | | } |
1001 | | ip16[15] <<= 1; |
1002 | | #else |
1003 | 0 | BlockVec v = LOAD128(ip16); |
1004 | 0 | v = SHL1_128(v); |
1005 | 0 | STORE128(ip16, v); |
1006 | 0 | #endif |
1007 | 0 | } |
1008 | | |
1009 | | /** |
1010 | | * ipcrypt_pfx_encrypt_ip16 encrypts a 16-byte IP address in-place with prefix preservation. |
1011 | | * IP addresses with the same prefix produce encrypted IP addresses with the same prefix. |
1012 | | * The prefix can be of any length. For IPv4 addresses (stored as IPv4-mapped IPv6), |
1013 | | * this preserves the IPv4 prefix structure. |
1014 | | */ |
1015 | | void |
1016 | | ipcrypt_pfx_encrypt_ip16(const IPCryptPFX *ipcrypt, uint8_t ip16[16]) |
1017 | 0 | { |
1018 | 0 | PFXState st; |
1019 | 0 | BlockVec e1_0, e2_0, e_0, e1_1, e2_1, e_1; |
1020 | 0 | uint8_t encrypted_ip[16]; |
1021 | 0 | uint8_t padded_prefix_0[16], padded_prefix_1[16]; |
1022 | 0 | uint8_t t_0[16], t_1[16]; |
1023 | 0 | size_t i; |
1024 | 0 | unsigned int bit_pos_0, bit_pos_1; |
1025 | 0 | unsigned int prefix_start = 0; |
1026 | 0 | unsigned int prefix_len_bits; |
1027 | 0 | uint8_t cipher_bit_0, cipher_bit_1; |
1028 | 0 | uint8_t original_bit_0, original_bit_1; |
1029 | |
|
1030 | 0 | memcpy(&st, ipcrypt->opaque, sizeof st); |
1031 | 0 | if (ipcrypt_is_mapped_ipv4(ip16)) { |
1032 | 0 | prefix_start = 96; |
1033 | 0 | } |
1034 | |
|
1035 | 0 | ipcrypt_pfx_pad_prefix(padded_prefix_0, prefix_start); |
1036 | |
|
1037 | 0 | memset(encrypted_ip, 0, 16); |
1038 | 0 | if (prefix_start == 96) { |
1039 | 0 | encrypted_ip[10] = 0xff; |
1040 | 0 | encrypted_ip[11] = 0xff; |
1041 | 0 | } |
1042 | | |
1043 | | // Process two bits per iteration for better parallelism |
1044 | 0 | for (prefix_len_bits = prefix_start; prefix_len_bits < 128; prefix_len_bits += 2) { |
1045 | | // Prepare padded_prefix_1 for the second iteration |
1046 | 0 | memcpy(padded_prefix_1, padded_prefix_0, 16); |
1047 | 0 | bit_pos_0 = 127 - prefix_len_bits; |
1048 | 0 | original_bit_0 = ipcrypt_pfx_get_bit(ip16, bit_pos_0); |
1049 | 0 | ipcrypt_pfx_shift_left(padded_prefix_1); |
1050 | 0 | ipcrypt_pfx_set_bit(padded_prefix_1, 0, original_bit_0); |
1051 | |
|
1052 | | #ifdef AES_XENCRYPT |
1053 | | // For AArch64 with AES_XENCRYPT macros - process two encryptions in parallel |
1054 | | e1_0 = AES_XENCRYPT(LOAD128(padded_prefix_0), st.k1keys[0]); |
1055 | | e2_0 = AES_XENCRYPT(LOAD128(padded_prefix_0), st.k2keys[0]); |
1056 | | e1_1 = AES_XENCRYPT(LOAD128(padded_prefix_1), st.k1keys[0]); |
1057 | | e2_1 = AES_XENCRYPT(LOAD128(padded_prefix_1), st.k2keys[0]); |
1058 | | |
1059 | | for (i = 1; i < ROUNDS - 1; i++) { |
1060 | | e1_0 = AES_XENCRYPT(e1_0, st.k1keys[i]); |
1061 | | e2_0 = AES_XENCRYPT(e2_0, st.k2keys[i]); |
1062 | | e1_1 = AES_XENCRYPT(e1_1, st.k1keys[i]); |
1063 | | e2_1 = AES_XENCRYPT(e2_1, st.k2keys[i]); |
1064 | | } |
1065 | | |
1066 | | e1_0 = AES_XENCRYPTLAST(e1_0, st.k1keys[i]); |
1067 | | e2_0 = AES_XENCRYPTLAST(e2_0, st.k2keys[i]); |
1068 | | e1_1 = AES_XENCRYPTLAST(e1_1, st.k1keys[i]); |
1069 | | e2_1 = AES_XENCRYPTLAST(e2_1, st.k2keys[i]); |
1070 | | |
1071 | | e1_0 = XOR128(e1_0, st.k1keys[ROUNDS]); |
1072 | | e2_0 = XOR128(e2_0, st.k2keys[ROUNDS]); |
1073 | | e1_1 = XOR128(e1_1, st.k1keys[ROUNDS]); |
1074 | | e2_1 = XOR128(e2_1, st.k2keys[ROUNDS]); |
1075 | | #else |
1076 | | // For x86_64 or a fallback - process two encryptions in parallel |
1077 | 0 | e1_0 = XOR128(LOAD128(padded_prefix_0), st.k1keys[0]); |
1078 | 0 | e2_0 = XOR128(LOAD128(padded_prefix_0), st.k2keys[0]); |
1079 | 0 | e1_1 = XOR128(LOAD128(padded_prefix_1), st.k1keys[0]); |
1080 | 0 | e2_1 = XOR128(LOAD128(padded_prefix_1), st.k2keys[0]); |
1081 | |
|
1082 | 0 | for (i = 1; i < ROUNDS; i++) { |
1083 | 0 | e1_0 = AES_ENCRYPT(e1_0, st.k1keys[i]); |
1084 | 0 | e2_0 = AES_ENCRYPT(e2_0, st.k2keys[i]); |
1085 | 0 | e1_1 = AES_ENCRYPT(e1_1, st.k1keys[i]); |
1086 | 0 | e2_1 = AES_ENCRYPT(e2_1, st.k2keys[i]); |
1087 | 0 | } |
1088 | |
|
1089 | 0 | e1_0 = AES_ENCRYPTLAST(e1_0, st.k1keys[ROUNDS]); |
1090 | 0 | e2_0 = AES_ENCRYPTLAST(e2_0, st.k2keys[ROUNDS]); |
1091 | 0 | e1_1 = AES_ENCRYPTLAST(e1_1, st.k1keys[ROUNDS]); |
1092 | 0 | e2_1 = AES_ENCRYPTLAST(e2_1, st.k2keys[ROUNDS]); |
1093 | 0 | #endif |
1094 | | |
1095 | | // Process results for first bit |
1096 | 0 | e_0 = XOR128(e1_0, e2_0); |
1097 | 0 | STORE128(t_0, e_0); |
1098 | 0 | cipher_bit_0 = t_0[15] & 1; |
1099 | | |
1100 | | // Process results for second bit |
1101 | 0 | e_1 = XOR128(e1_1, e2_1); |
1102 | 0 | STORE128(t_1, e_1); |
1103 | 0 | cipher_bit_1 = t_1[15] & 1; |
1104 | 0 | bit_pos_1 = bit_pos_0 - 1; |
1105 | 0 | original_bit_1 = ipcrypt_pfx_get_bit(ip16, bit_pos_1); |
1106 | |
|
1107 | 0 | ipcrypt_pfx_set_bit(encrypted_ip, bit_pos_0, original_bit_0 ^ cipher_bit_0); |
1108 | 0 | ipcrypt_pfx_set_bit(encrypted_ip, bit_pos_1, original_bit_1 ^ cipher_bit_1); |
1109 | | |
1110 | | // Update padded_prefix_0 for next iteration |
1111 | 0 | ipcrypt_pfx_shift_left(padded_prefix_1); |
1112 | 0 | ipcrypt_pfx_set_bit(padded_prefix_1, 0, original_bit_1); |
1113 | 0 | memcpy(padded_prefix_0, padded_prefix_1, 16); |
1114 | 0 | } |
1115 | 0 | memcpy(ip16, encrypted_ip, 16); |
1116 | 0 | } |
1117 | | |
1118 | | /** |
1119 | | * ipcrypt_pfx_decrypt_ip16 decrypts a 16-byte IP address in-place with prefix preservation. |
1120 | | * This reverses the encryption performed by ipcrypt_pfx_encrypt_ip16, recovering the original IP |
1121 | | * address. |
1122 | | */ |
1123 | | void |
1124 | | ipcrypt_pfx_decrypt_ip16(const IPCryptPFX *ipcrypt, uint8_t ip16[16]) |
1125 | 0 | { |
1126 | 0 | PFXState st; |
1127 | 0 | BlockVec e1, e2, e; |
1128 | 0 | uint8_t original_ip[16]; |
1129 | 0 | uint8_t padded_prefix[16]; |
1130 | 0 | uint8_t t[16]; |
1131 | 0 | size_t i; |
1132 | 0 | unsigned int bit_pos; |
1133 | 0 | unsigned int prefix_start = 0; |
1134 | 0 | unsigned int prefix_len_bits; |
1135 | 0 | uint8_t cipher_bit; |
1136 | 0 | uint8_t encrypted_bit; |
1137 | 0 | uint8_t original_bit; |
1138 | |
|
1139 | 0 | memcpy(&st, ipcrypt->opaque, sizeof st); |
1140 | 0 | if (ipcrypt_is_mapped_ipv4(ip16)) { |
1141 | 0 | prefix_start = 96; |
1142 | 0 | } |
1143 | |
|
1144 | 0 | ipcrypt_pfx_pad_prefix(padded_prefix, prefix_start); |
1145 | |
|
1146 | 0 | memset(original_ip, 0, 16); |
1147 | 0 | if (prefix_start == 96) { |
1148 | 0 | original_ip[10] = 0xff; |
1149 | 0 | original_ip[11] = 0xff; |
1150 | 0 | } |
1151 | |
|
1152 | 0 | for (prefix_len_bits = prefix_start; prefix_len_bits < 128; prefix_len_bits++) { |
1153 | | #ifdef AES_XENCRYPT |
1154 | | // For AArch64 with AES_XENCRYPT macros. |
1155 | | e1 = AES_XENCRYPT(LOAD128(padded_prefix), st.k1keys[0]); |
1156 | | e2 = AES_XENCRYPT(LOAD128(padded_prefix), st.k2keys[0]); |
1157 | | for (i = 1; i < ROUNDS - 1; i++) { |
1158 | | e1 = AES_XENCRYPT(e1, st.k1keys[i]); |
1159 | | e2 = AES_XENCRYPT(e2, st.k2keys[i]); |
1160 | | } |
1161 | | e1 = AES_XENCRYPTLAST(e1, st.k1keys[i]); |
1162 | | e2 = AES_XENCRYPTLAST(e2, st.k2keys[i]); |
1163 | | e1 = XOR128(e1, st.k1keys[ROUNDS]); |
1164 | | e2 = XOR128(e2, st.k2keys[ROUNDS]); |
1165 | | #else |
1166 | | // For x86_64 or a fallback. |
1167 | 0 | e1 = XOR128(LOAD128(padded_prefix), st.k1keys[0]); |
1168 | 0 | e2 = XOR128(LOAD128(padded_prefix), st.k2keys[0]); |
1169 | 0 | for (i = 1; i < ROUNDS; i++) { |
1170 | 0 | e1 = AES_ENCRYPT(e1, st.k1keys[i]); |
1171 | 0 | e2 = AES_ENCRYPT(e2, st.k2keys[i]); |
1172 | 0 | } |
1173 | 0 | e1 = AES_ENCRYPTLAST(e1, st.k1keys[ROUNDS]); |
1174 | 0 | e2 = AES_ENCRYPTLAST(e2, st.k2keys[ROUNDS]); |
1175 | 0 | #endif |
1176 | 0 | e = XOR128(e1, e2); |
1177 | 0 | STORE128(t, e); |
1178 | 0 | cipher_bit = t[15] & 1; |
1179 | 0 | bit_pos = 127 - prefix_len_bits; |
1180 | 0 | encrypted_bit = ipcrypt_pfx_get_bit(ip16, bit_pos); |
1181 | 0 | original_bit = encrypted_bit ^ cipher_bit; |
1182 | 0 | ipcrypt_pfx_set_bit(original_ip, bit_pos, original_bit); |
1183 | 0 | ipcrypt_pfx_shift_left(padded_prefix); |
1184 | 0 | ipcrypt_pfx_set_bit(padded_prefix, 0, original_bit); |
1185 | 0 | } |
1186 | 0 | memcpy(ip16, original_ip, 16); |
1187 | 0 | } |
1188 | | |
1189 | | /** |
1190 | | * ipcrypt_pfx_encrypt_ip_str encrypts an IP address string (IPv4 or IPv6) with prefix preservation. |
1191 | | * The result is another valid IP address string. |
1192 | | * Returns the length of the encrypted string or 0 on error. |
1193 | | */ |
1194 | | size_t |
1195 | | ipcrypt_pfx_encrypt_ip_str(const IPCryptPFX *ipcrypt, |
1196 | | char encrypted_ip_str[IPCRYPT_MAX_IP_STR_BYTES], |
1197 | | const char *ip_str) |
1198 | 0 | { |
1199 | 0 | uint8_t ip16[16]; |
1200 | |
|
1201 | 0 | if (ipcrypt_str_to_ip16(ip16, ip_str) != 0) { |
1202 | 0 | return 0; |
1203 | 0 | } |
1204 | 0 | ipcrypt_pfx_encrypt_ip16(ipcrypt, ip16); |
1205 | 0 | return ipcrypt_ip16_to_str(encrypted_ip_str, ip16); |
1206 | 0 | } |
1207 | | |
1208 | | /** |
1209 | | * ipcrypt_pfx_decrypt_ip_str decrypts an encrypted IP address string with prefix preservation. |
1210 | | * Returns the length of the decrypted string or 0 on error. |
1211 | | */ |
1212 | | size_t |
1213 | | ipcrypt_pfx_decrypt_ip_str(const IPCryptPFX *ipcrypt, |
1214 | | char ip_str[IPCRYPT_MAX_IP_STR_BYTES], |
1215 | | const char *encrypted_ip_str) |
1216 | 0 | { |
1217 | 0 | uint8_t ip16[16]; |
1218 | |
|
1219 | 0 | memset(ip_str, 0, IPCRYPT_MAX_IP_STR_BYTES); |
1220 | 0 | if (ipcrypt_str_to_ip16(ip16, encrypted_ip_str) != 0) { |
1221 | 0 | return 0; |
1222 | 0 | } |
1223 | 0 | ipcrypt_pfx_decrypt_ip16(ipcrypt, ip16); |
1224 | 0 | return ipcrypt_ip16_to_str(ip_str, ip16); |
1225 | 0 | } |
1226 | | |
1227 | | /** |
1228 | | * ipcrypt_init initializes an IPCrypt context with a 16-byte key. |
1229 | | * Expands the key into round keys and stores them in ipcrypt->opaque. |
1230 | | * Returns 0 on success. |
1231 | | */ |
1232 | | int |
1233 | | ipcrypt_ndx_init(IPCryptNDX *ipcrypt, const uint8_t key[IPCRYPT_NDX_KEYBYTES]) |
1234 | 0 | { |
1235 | 0 | NDXState st; |
1236 | 0 | uint8_t diff[16]; |
1237 | 0 | size_t i; |
1238 | 0 | uint8_t d; |
1239 | |
|
1240 | 0 | expand_key(st.tkeys, key + 16); |
1241 | 0 | expand_key(st.rkeys, key); |
1242 | | |
1243 | | /** |
1244 | | * Ensure the two keys differ in case of misuse. |
1245 | | */ |
1246 | 0 | STORE128(diff, XOR128(st.tkeys[ROUNDS / 2], st.rkeys[ROUNDS / 2])); |
1247 | 0 | d = 0; |
1248 | 0 | for (i = 0; i < 16; i++) { |
1249 | 0 | d |= diff[i]; |
1250 | 0 | } |
1251 | 0 | if (d == 0) { |
1252 | 0 | for (i = 0; i < 16; i++) { |
1253 | 0 | diff[i] = key[i] ^ 0x5a; |
1254 | 0 | } |
1255 | 0 | expand_key(st.rkeys, diff); |
1256 | 0 | } |
1257 | |
|
1258 | 0 | COMPILER_ASSERT(sizeof ipcrypt->opaque >= sizeof st); |
1259 | 0 | memcpy(ipcrypt->opaque, &st, sizeof st); |
1260 | |
|
1261 | 0 | return -(d == 0); |
1262 | 0 | } |
1263 | | |
1264 | | /** |
1265 | | * ipcrypt_deinit clears the IPCrypt context to wipe sensitive data from memory. |
1266 | | */ |
1267 | | void |
1268 | | ipcrypt_ndx_deinit(IPCryptNDX *ipcrypt) |
1269 | 0 | { |
1270 | 0 | ipcrypt_zeroize(ipcrypt, sizeof *ipcrypt); |
1271 | 0 | } |
1272 | | |
1273 | | /** |
1274 | | * ipcrypt_encrypt_ip16 performs format-preserving encryption on a 16-byte IP buffer. |
1275 | | * Encrypted data is stored in-place. |
1276 | | */ |
1277 | | void |
1278 | | ipcrypt_encrypt_ip16(const IPCrypt *ipcrypt, uint8_t ip16[16]) |
1279 | 0 | { |
1280 | 0 | AesState st; |
1281 | 0 | memcpy(&st, ipcrypt->opaque, sizeof st); |
1282 | 0 | aes_encrypt(ip16, &st); |
1283 | 0 | } |
1284 | | |
1285 | | /** |
1286 | | * ipcrypt_decrypt_ip16 performs format-preserving decryption on a 16-byte IP buffer. |
1287 | | * Decrypted data is stored in-place. |
1288 | | */ |
1289 | | void |
1290 | | ipcrypt_decrypt_ip16(const IPCrypt *ipcrypt, uint8_t ip16[16]) |
1291 | 0 | { |
1292 | 0 | AesState st; |
1293 | 0 | memcpy(&st, ipcrypt->opaque, sizeof st); |
1294 | 0 | aes_decrypt(ip16, &st); |
1295 | 0 | } |
1296 | | |
1297 | | /** |
1298 | | * ipcrypt_encrypt_ip_str encrypts an IP address string (IPv4 or IPv6) in a format-preserving way. |
1299 | | * The result is another valid IP address string. |
1300 | | * Returns the length of the encrypted string or 0 on error. |
1301 | | */ |
1302 | | size_t |
1303 | | ipcrypt_encrypt_ip_str(const IPCrypt *ipcrypt, char encrypted_ip_str[IPCRYPT_MAX_IP_STR_BYTES], |
1304 | | const char *ip_str) |
1305 | 0 | { |
1306 | 0 | uint8_t ip16[16]; |
1307 | |
|
1308 | 0 | if (ipcrypt_str_to_ip16(ip16, ip_str) != 0) { |
1309 | 0 | return 0; |
1310 | 0 | } |
1311 | 0 | ipcrypt_encrypt_ip16(ipcrypt, ip16); |
1312 | 0 | return ipcrypt_ip16_to_str(encrypted_ip_str, ip16); |
1313 | 0 | } |
1314 | | |
1315 | | /** |
1316 | | * ipcrypt_decrypt_ip_str decrypts an encrypted IP address string and restores the original address. |
1317 | | * Returns the length of the decrypted string or 0 on error. |
1318 | | */ |
1319 | | size_t |
1320 | | ipcrypt_decrypt_ip_str(const IPCrypt *ipcrypt, char ip_str[IPCRYPT_MAX_IP_STR_BYTES], |
1321 | | const char *encrypted_ip_str) |
1322 | 0 | { |
1323 | 0 | uint8_t ip16[16]; |
1324 | |
|
1325 | 0 | memset(ip_str, 0, IPCRYPT_MAX_IP_STR_BYTES); |
1326 | 0 | if (ipcrypt_str_to_ip16(ip16, encrypted_ip_str) != 0) { |
1327 | 0 | return 0; |
1328 | 0 | } |
1329 | 0 | ipcrypt_decrypt_ip16(ipcrypt, ip16); |
1330 | 0 | return ipcrypt_ip16_to_str(ip_str, ip16); |
1331 | 0 | } |
1332 | | |
1333 | | /** |
1334 | | * ipcrypt_nd_encrypt_ip16 performs non-deterministic encryption of a 16-byte IP. |
1335 | | * A random 8-byte tweak (random) must be provided. |
1336 | | * Output is 24 bytes: the tweak + the encrypted IP. |
1337 | | */ |
1338 | | void |
1339 | | ipcrypt_nd_encrypt_ip16(const IPCrypt *ipcrypt, uint8_t ndip[IPCRYPT_NDIP_BYTES], |
1340 | | const uint8_t ip16[16], const uint8_t random[IPCRYPT_TWEAKBYTES]) |
1341 | 0 | { |
1342 | 0 | AesState st; |
1343 | |
|
1344 | 0 | COMPILER_ASSERT(IPCRYPT_NDIP_BYTES == 16 + IPCRYPT_TWEAKBYTES); |
1345 | 0 | memcpy(&st, ipcrypt->opaque, sizeof st); |
1346 | | // Copy the tweak into the first 8 bytes. |
1347 | 0 | memcpy(ndip, random, IPCRYPT_TWEAKBYTES); |
1348 | | // Copy the IP into the next 16 bytes. |
1349 | 0 | memcpy(ndip + IPCRYPT_TWEAKBYTES, ip16, 16); |
1350 | | // Encrypt the IP portion with the tweak. |
1351 | 0 | aes_encrypt_with_tweak(ndip + IPCRYPT_TWEAKBYTES, &st, random); |
1352 | 0 | } |
1353 | | |
1354 | | /** |
1355 | | * ipcrypt_nd_decrypt_ip16 decrypts a 24-byte (tweak + IP) buffer produced by |
1356 | | * ipcrypt_nd_encrypt_ip16. The original IP is restored in ip16. |
1357 | | */ |
1358 | | void |
1359 | | ipcrypt_nd_decrypt_ip16(const IPCrypt *ipcrypt, uint8_t ip16[16], |
1360 | | const uint8_t ndip[IPCRYPT_NDIP_BYTES]) |
1361 | 0 | { |
1362 | 0 | AesState st; |
1363 | |
|
1364 | 0 | COMPILER_ASSERT(IPCRYPT_NDIP_BYTES == 16 + IPCRYPT_TWEAKBYTES); |
1365 | 0 | memcpy(&st, ipcrypt->opaque, sizeof st); |
1366 | | // Copy the IP portion from ndip. |
1367 | 0 | memcpy(ip16, ndip + IPCRYPT_TWEAKBYTES, 16); |
1368 | | // Decrypt using the tweak from the first 8 bytes. |
1369 | 0 | aes_decrypt_with_tweak(ip16, &st, ndip); |
1370 | 0 | } |
1371 | | |
1372 | | /** |
1373 | | * ipcrypt_nd_encrypt_ip_str encrypts an IP address string in non-deterministic mode. |
1374 | | * The output is a hex-encoded string of length IPCRYPT_NDIP_STR_BYTES (48 hex chars + null |
1375 | | * terminator). random must be an 8-byte random value. |
1376 | | */ |
1377 | | size_t |
1378 | | ipcrypt_nd_encrypt_ip_str(const IPCrypt *ipcrypt, char encrypted_ip_str[IPCRYPT_NDIP_STR_BYTES], |
1379 | | const char *ip_str, const uint8_t random[IPCRYPT_TWEAKBYTES]) |
1380 | 0 | { |
1381 | 0 | uint8_t ip16[16]; |
1382 | 0 | uint8_t ndip[IPCRYPT_NDIP_BYTES]; |
1383 | |
|
1384 | 0 | COMPILER_ASSERT(IPCRYPT_NDIP_STR_BYTES == IPCRYPT_NDIP_BYTES * 2 + 1); |
1385 | | // Convert to 16-byte IP. |
1386 | 0 | ipcrypt_str_to_ip16(ip16, ip_str); |
1387 | | // Perform non-deterministic encryption. |
1388 | 0 | ipcrypt_nd_encrypt_ip16(ipcrypt, ndip, ip16, random); |
1389 | | // Convert the 24-byte ndip to a hex string. |
1390 | 0 | bin2hex(encrypted_ip_str, IPCRYPT_NDIP_STR_BYTES, ndip, IPCRYPT_NDIP_BYTES); |
1391 | |
|
1392 | 0 | return IPCRYPT_NDIP_STR_BYTES - 1; |
1393 | 0 | } |
1394 | | |
1395 | | /** |
1396 | | * ipcrypt_nd_decrypt_ip_str decrypts a hex-encoded string produced by ipcrypt_nd_encrypt_ip_str. |
1397 | | * The original IP address string is written to ip_str. |
1398 | | * Returns the length of the resulting IP string on success, or 0 on error. |
1399 | | */ |
1400 | | size_t |
1401 | | ipcrypt_nd_decrypt_ip_str(const IPCrypt *ipcrypt, char ip_str[IPCRYPT_MAX_IP_STR_BYTES], |
1402 | | const char *encrypted_ip_str) |
1403 | 0 | { |
1404 | 0 | uint8_t ip16[16]; |
1405 | 0 | uint8_t ndip[IPCRYPT_NDIP_BYTES]; |
1406 | 0 | memset(ip_str, 0, IPCRYPT_MAX_IP_STR_BYTES); |
1407 | | // Convert the hex string back to a 24-byte buffer. |
1408 | 0 | if (hex2bin(ndip, sizeof ndip, encrypted_ip_str, strlen(encrypted_ip_str)) != sizeof ndip) { |
1409 | 0 | return 0; |
1410 | 0 | } |
1411 | | // Decrypt the IP. |
1412 | 0 | ipcrypt_nd_decrypt_ip16(ipcrypt, ip16, ndip); |
1413 | | // Convert binary IP to string. |
1414 | 0 | return ipcrypt_ip16_to_str(ip_str, ip16); |
1415 | 0 | } |
1416 | | |
1417 | | /** |
1418 | | * ipcrypt_ndx_encrypt_ip16 performs non-deterministic encryption of a 16-byte IP. |
1419 | | * A random 16-byte tweak (random) must be provided. |
1420 | | * Output is 32 bytes: the tweak + the encrypted IP. |
1421 | | */ |
1422 | | void |
1423 | | ipcrypt_ndx_encrypt_ip16(const IPCryptNDX *ipcrypt, uint8_t ndip[IPCRYPT_NDX_NDIP_BYTES], |
1424 | | const uint8_t ip16[16], const uint8_t random[IPCRYPT_NDX_TWEAKBYTES]) |
1425 | 0 | { |
1426 | 0 | NDXState st; |
1427 | |
|
1428 | 0 | COMPILER_ASSERT(IPCRYPT_NDX_NDIP_BYTES == 16 + IPCRYPT_NDX_TWEAKBYTES); |
1429 | 0 | memcpy(&st, ipcrypt->opaque, sizeof st); |
1430 | | // Copy the tweak into the first 8 bytes. |
1431 | 0 | memcpy(ndip, random, IPCRYPT_NDX_TWEAKBYTES); |
1432 | | // Copy the IP into the next 16 bytes. |
1433 | 0 | memcpy(ndip + IPCRYPT_NDX_TWEAKBYTES, ip16, 16); |
1434 | | // Encrypt the IP portion with the tweak. |
1435 | 0 | aes_xex_encrypt(ndip + IPCRYPT_NDX_TWEAKBYTES, &st, random); |
1436 | 0 | } |
1437 | | |
1438 | | /** |
1439 | | * ipcrypt_ndx_decrypt_ip16 decrypts a 32 byte (tweak + IP) buffer produced by |
1440 | | * ipcrypt_ndx_encrypt_ip16. The original IP is restored in ip16. |
1441 | | */ |
1442 | | void |
1443 | | ipcrypt_ndx_decrypt_ip16(const IPCryptNDX *ipcrypt, uint8_t ip16[16], |
1444 | | const uint8_t ndip[IPCRYPT_NDX_NDIP_BYTES]) |
1445 | 0 | { |
1446 | 0 | NDXState st; |
1447 | |
|
1448 | 0 | COMPILER_ASSERT(IPCRYPT_NDX_NDIP_BYTES == 16 + IPCRYPT_NDX_TWEAKBYTES); |
1449 | 0 | memcpy(&st, ipcrypt->opaque, sizeof st); |
1450 | | // Copy the IP portion from ndip. |
1451 | 0 | memcpy(ip16, ndip + IPCRYPT_NDX_TWEAKBYTES, 16); |
1452 | | // Decrypt using the tweak from the first 16 bytes. |
1453 | 0 | aes_ndx_decrypt(ip16, &st, ndip); |
1454 | 0 | } |
1455 | | |
1456 | | /** |
1457 | | * ipcrypt_ndx_encrypt_ip_str encrypts an IP address string in NDX mode. |
1458 | | * The output is a hex-encoded string of length IPCRYPT_NDIP_STR_BYTES (64 hex chars + null |
1459 | | * terminator). random must be an 8-byte random value. |
1460 | | */ |
1461 | | size_t |
1462 | | ipcrypt_ndx_encrypt_ip_str(const IPCryptNDX *ipcrypt, |
1463 | | char encrypted_ip_str[IPCRYPT_NDX_NDIP_STR_BYTES], const char *ip_str, |
1464 | | const uint8_t random[IPCRYPT_NDX_TWEAKBYTES]) |
1465 | 0 | { |
1466 | 0 | uint8_t ip16[16]; |
1467 | 0 | uint8_t ndip[IPCRYPT_NDX_NDIP_BYTES]; |
1468 | |
|
1469 | 0 | COMPILER_ASSERT(IPCRYPT_NDX_NDIP_STR_BYTES == IPCRYPT_NDX_NDIP_BYTES * 2 + 1); |
1470 | | // Convert to 16-byte IP. |
1471 | 0 | ipcrypt_str_to_ip16(ip16, ip_str); |
1472 | | // Perform non-deterministic encryption. |
1473 | 0 | ipcrypt_ndx_encrypt_ip16(ipcrypt, ndip, ip16, random); |
1474 | | // Convert the 32-byte ndip to a hex string. |
1475 | 0 | bin2hex(encrypted_ip_str, IPCRYPT_NDX_NDIP_STR_BYTES, ndip, IPCRYPT_NDX_NDIP_BYTES); |
1476 | |
|
1477 | 0 | return IPCRYPT_NDX_NDIP_STR_BYTES - 1; |
1478 | 0 | } |
1479 | | |
1480 | | /** |
1481 | | * ipcrypt_ndx_decrypt_ip_str decrypts a hex-encoded string produced by ipcrypt_ndx_encrypt_ip_str. |
1482 | | * The original IP address string is written to ip_str. |
1483 | | * Returns the length of the resulting IP string on success, or 0 on error. |
1484 | | */ |
1485 | | size_t |
1486 | | ipcrypt_ndx_decrypt_ip_str(const IPCryptNDX *ipcrypt, char ip_str[IPCRYPT_MAX_IP_STR_BYTES], |
1487 | | const char *encrypted_ip_str) |
1488 | 0 | { |
1489 | 0 | uint8_t ip16[16]; |
1490 | 0 | uint8_t ndip[IPCRYPT_NDX_NDIP_BYTES]; |
1491 | 0 | memset(ip_str, 0, IPCRYPT_MAX_IP_STR_BYTES); |
1492 | | // Convert the hex string back to a 32-byte buffer. |
1493 | 0 | if (hex2bin(ndip, sizeof ndip, encrypted_ip_str, strlen(encrypted_ip_str)) != sizeof ndip) { |
1494 | 0 | return 0; |
1495 | 0 | } |
1496 | | // Decrypt the IP. |
1497 | 0 | ipcrypt_ndx_decrypt_ip16(ipcrypt, ip16, ndip); |
1498 | | // Convert binary IP to string. |
1499 | 0 | return ipcrypt_ip16_to_str(ip_str, ip16); |
1500 | 0 | } |
1501 | | |
1502 | | #ifdef __clang__ |
1503 | | # pragma clang attribute pop |
1504 | | #endif |