Coverage Report

Created: 2026-10-03 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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