1 /* 2 MIT License 3 4 Copyright (c) 2025 Matheus C. França 5 6 Permission is hereby granted, free of charge, to any person obtaining a copy 7 of this software and associated documentation files (the "Software"), to deal 8 in the Software without restriction, including without limitation the rights 9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 copies of the Software, and to permit persons to whom the Software is 11 furnished to do so, subject to the following conditions: 12 13 The above copyright notice and this permission notice shall be included in all 14 copies or substantial portions of the Software. 15 16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 SOFTWARE. 23 */ 24 25 /++ 26 D bindings for IPCrypt2, a simple and secure IP address obfuscation scheme. 27 28 IPCrypt2 is a format-preserving encryption scheme for IPv4 and IPv6 addresses. 29 It allows IP addresses to be encrypted while maintaining their format, making it 30 suitable for logging and data retention purposes where IP addresses need to be 31 pseudonymized. 32 33 $(SECTION Features) 34 $(UL 35 $(LI Format-preserving encryption for both IPv4 and IPv6 addresses) 36 $(LI Cryptographically secure using AES-128 as the underlying cipher) 37 $(LI Preserves subnets: addresses sharing a prefix are encrypted to addresses sharing the same prefix) 38 $(LI Deterministic: same input and key always produces the same output) 39 $(LI Fast and constant-time operation) 40 ) 41 +/ 42 43 module ipcrypt2; 44 45 /// IPCrypt2 C bindings 46 public import c.ipcrypt2c; // @system 47 48 /** 49 * IPCrypt context, providing encryption/decryption of IP addresses. 50 * Ensures proper initialization and cleanup of the underlying IPCrypt context. 51 */ 52 struct IPCrypt2 53 { 54 private IPCrypt context; // Opaque IPCrypt context 55 56 /** 57 * Constructs an IPCrypt2 with the given 16-byte key. 58 */ 59 this(scope const(ubyte)[] key) nothrow @nogc @safe 60 { 61 assert(key.length == IPCRYPT_KEYBYTES, "Invalid key length"); 62 () @trusted { ipcrypt_init(&context, &key[0]); }(); 63 } 64 65 /// Ditto, but constructs from a hexadecimal key string. 66 this(string hexKey) nothrow @nogc @safe 67 { 68 ubyte[IPCRYPT_KEYBYTES] key; 69 assert(() @trusted { 70 return ipcrypt_key_from_hex(&key[0], IPCRYPT_KEYBYTES, &hexKey[0], hexKey.length); 71 }() == 0, "Invalid hex key"); 72 () @trusted { ipcrypt_init(&context, &key[0]); }(); 73 } 74 75 /// Destructor ensures the IPCrypt context is cleaned up. 76 ~this() nothrow @nogc @safe 77 { 78 () @trusted { ipcrypt_deinit(&context); }(); 79 } 80 81 // Disable copying to prevent double-free 82 @disable this(this); 83 84 /** 85 * Encrypts a 16-byte IP address (IPv4 or IPv6). 86 * Params: 87 * ip16 = The 16-byte IP address to encrypt. 88 * Returns: The encrypted 16-byte IP address. 89 */ 90 ubyte[IPCRYPT_KEYBYTES] encryptIP16(scope const(ubyte)[] ip16) nothrow @nogc @safe 91 { 92 ubyte[IPCRYPT_KEYBYTES] result; 93 result[] = ip16[0 .. IPCRYPT_KEYBYTES]; 94 () @trusted { ipcrypt_encrypt_ip16(&context, &result[0]); }(); 95 return result; 96 } 97 98 /** 99 * Decrypts a 16-byte IP address (IPv4 or IPv6). 100 * Params: 101 * ip16 = The 16-byte encrypted IP address. 102 * Returns: The decrypted 16-byte IP address. 103 */ 104 ubyte[IPCRYPT_KEYBYTES] decryptIP16(scope const(ubyte)[] ip16) nothrow @nogc @safe 105 { 106 ubyte[IPCRYPT_KEYBYTES] result; 107 result[] = ip16[0 .. IPCRYPT_KEYBYTES]; 108 () @trusted { ipcrypt_decrypt_ip16(&context, &result[0]); }(); 109 return result; 110 } 111 112 /** 113 * Encrypts an IP address string (IPv4 or IPv6). 114 * Params: 115 * output = Buffer to store the encrypted IP string (must be at least IPCRYPT_MAX_IP_STR_BYTES). 116 * ipStr = The IP address string to encrypt. 117 * Returns: The length of the encrypted IP string, or 0 on error. 118 */ 119 size_t encryptIPStr(scope char[] output, scope const(char)[] ipStr) nothrow @safe 120 { 121 assert(output.length >= IPCRYPT_MAX_IP_STR_BYTES); 122 return () @trusted { 123 return ipcrypt_encrypt_ip_str(&context, &output[0], &ipStr[0]); 124 }(); 125 } 126 127 /** 128 * Decrypts an encrypted IP address string. 129 * Params: 130 * output = Buffer to store the decrypted IP string (must be at least IPCRYPT_MAX_IP_STR_BYTES). 131 * encryptedIPStr = The encrypted IP address string. 132 * Returns: The length of the decrypted IP string, or 0 on error. 133 */ 134 size_t decryptIPStr(scope char[] output, scope const(char)[] encryptedIPStr) nothrow @safe 135 { 136 assert(output.length >= IPCRYPT_MAX_IP_STR_BYTES); 137 return () @trusted { 138 return ipcrypt_decrypt_ip_str(&context, &output[0], &encryptedIPStr[0]); 139 }(); 140 } 141 142 /** 143 * Non-deterministic encryption of a 16-byte IP address. 144 * Params: 145 * ip16 = The 16-byte IP address to encrypt. 146 * random = 8-byte random data for non-determinism. 147 * Returns: The 24-byte encrypted IP address. 148 */ 149 ubyte[IPCRYPT_NDIP_BYTES] ndEncryptIP16(scope const(ubyte)[] ip16, scope const(ubyte)[] random) nothrow @nogc @safe 150 { 151 assert(random.length == IPCRYPT_TWEAKBYTES); 152 ubyte[IPCRYPT_NDIP_BYTES] result; 153 () @trusted { 154 ipcrypt_nd_encrypt_ip16(&context, &result[0], &ip16[0], &random[0]); 155 }(); 156 return result; 157 } 158 159 /** 160 * Non-deterministic decryption of a 24-byte encrypted IP address. 161 * Params: 162 * ndip = The 24-byte encrypted IP address. 163 * Returns: The 16-byte decrypted IP address. 164 */ 165 ubyte[IPCRYPT_KEYBYTES] ndDecryptIP16(scope const(ubyte)[] ndip) nothrow @nogc @safe 166 { 167 assert(ndip.length == IPCRYPT_NDIP_BYTES); 168 ubyte[IPCRYPT_KEYBYTES] result; 169 () @trusted { 170 ipcrypt_nd_decrypt_ip16(&context, &result[0], &ndip[0]); 171 }(); 172 return result; 173 } 174 175 /** 176 * Non-deterministic encryption of an IP address string. 177 * Params: 178 * output = Buffer to store the encrypted IP string (must be at least IPCRYPT_NDIP_STR_BYTES). 179 * ipStr = The IP address string to encrypt. 180 * random = 8-byte random data for non-determinism. 181 * Returns: The length of the encrypted IP string, or 0 on error. 182 */ 183 size_t ndEncryptIPStr(scope char[] output, scope const(char)[] ipStr, scope const(ubyte)[] random) nothrow @safe 184 { 185 assert(output.length >= IPCRYPT_NDIP_STR_BYTES); 186 assert(random.length == IPCRYPT_TWEAKBYTES); 187 return () @trusted { 188 return ipcrypt_nd_encrypt_ip_str(&context, &output[0], &ipStr[0], &random[0]); 189 }(); 190 } 191 192 /** 193 * Non-deterministic decryption of an encrypted IP address string. 194 * Params: 195 * output = Buffer to store the decrypted IP string (must be at least IPCRYPT_MAX_IP_STR_BYTES). 196 * encryptedIPStr = The encrypted IP address string. 197 * Returns: The length of the decrypted IP string, or 0 on error. 198 */ 199 size_t ndDecryptIPStr(scope char[] output, scope const(char)[] encryptedIPStr) nothrow @safe 200 { 201 assert(output.length >= IPCRYPT_MAX_IP_STR_BYTES); 202 return () @trusted { 203 return ipcrypt_nd_decrypt_ip_str(&context, &output[0], &encryptedIPStr[0]); 204 }(); 205 } 206 207 /** 208 * Converts a hexadecimal string to a non-deterministic encrypted IP address. 209 * Params: 210 * hex = The hexadecimal string. 211 * Returns: The non-deterministic encrypted IP address. 212 */ 213 ubyte[IPCRYPT_NDIP_BYTES] ndipFromHex(string hex) nothrow @safe 214 { 215 ubyte[IPCRYPT_NDIP_BYTES] result; 216 assert(() @trusted { 217 return ipcrypt_ndip_from_hex(&result[0], &hex[0], hex.length); 218 }() == 0, "Invalid hex string"); 219 return result; 220 } 221 } 222 223 /** 224 * IPCryptNDX context, providing extended encryption/decryption. 225 * Ensures proper initialization and cleanup of the underlying IPCryptNDX context. 226 */ 227 struct IPCryptNDXCtx 228 { 229 private IPCryptNDX context; // Opaque IPCryptNDX context 230 231 /** 232 * Constructs an IPCryptNDXCtx with the given 32-byte key. 233 */ 234 this(scope const(ubyte)[] key) nothrow @nogc @safe 235 { 236 assert(key.length == IPCRYPT_NDX_KEYBYTES, "Invalid key length"); 237 assert(() @trusted { return ipcrypt_ndx_init(&context, &key[0]); }() == 0, "Initialization failed"); 238 } 239 240 /// Ditto, but constructs from a hexadecimal key string. 241 this(string hexKey) nothrow @nogc @safe 242 { 243 ubyte[IPCRYPT_NDX_KEYBYTES] key; 244 assert(() @trusted { 245 return ipcrypt_key_from_hex(&key[0], IPCRYPT_NDX_KEYBYTES, &hexKey[0], hexKey.length); 246 }() == 0, "Invalid hex key"); 247 assert(() @trusted { return ipcrypt_ndx_init(&context, &key[0]); }() == 0, "Initialization failed"); 248 } 249 250 /// Destructor ensures the IPCryptNDX context is cleaned up. 251 ~this() nothrow @nogc @safe 252 { 253 () @trusted { ipcrypt_ndx_deinit(&context); }(); 254 } 255 256 // Disable copying to prevent double-free 257 @disable this(this); 258 259 /** 260 * Encrypts a 16-byte IP address (IPv4 or IPv6) with extended non-determinism. 261 * Params: 262 * ip16 = The 16-byte IP address to encrypt. 263 * random = 16-byte random data for non-determinism. 264 * Returns: The 32-byte encrypted IP address. 265 */ 266 ubyte[IPCRYPT_NDX_NDIP_BYTES] encryptIP16(scope const(ubyte)[] ip16, scope const(ubyte)[] random) nothrow @nogc @safe 267 { 268 assert(random.length == IPCRYPT_NDX_TWEAKBYTES); 269 ubyte[IPCRYPT_NDX_NDIP_BYTES] result; 270 () @trusted { 271 ipcrypt_ndx_encrypt_ip16(&context, &result[0], &ip16[0], &random[0]); 272 }(); 273 return result; 274 } 275 276 /** 277 * Decrypt a non-deterministically encrypted 16-byte IP address, previously encrypted with 278 * `ipcrypt_ndx_encrypt_ip16`. 279 * 280 * Input is ndip, and output is written to ip16. 281 */ 282 ubyte[IPCRYPT_KEYBYTES] decryptIP16(scope const(ubyte)[] ndip) nothrow @nogc @safe 283 { 284 assert(ndip.length == IPCRYPT_NDX_NDIP_BYTES); 285 ubyte[IPCRYPT_KEYBYTES] result; 286 () @trusted { 287 ipcrypt_ndx_decrypt_ip16(&context, &result[0], &ndip[0]); 288 }(); 289 return result; 290 } 291 292 /** 293 * Encrypts an IP address string with extended non-determinism. 294 * Params: 295 * output = Buffer to store the encrypted IP string (must be at least IPCRYPT_NDX_NDIP_STR_BYTES). 296 * ipStr = The IP address string to encrypt. 297 * random = 16-byte random data for non-determinism. 298 * Returns: The length of the encrypted IP string, or 0 on error. 299 */ 300 size_t encryptIPStr(scope char[] output, scope const(char)[] ipStr, scope const(ubyte)[] random) nothrow @safe 301 { 302 assert(output.length >= IPCRYPT_NDX_NDIP_STR_BYTES); 303 assert(random.length == IPCRYPT_NDX_TWEAKBYTES); 304 return () @trusted { 305 return ipcrypt_ndx_encrypt_ip_str(&context, &output[0], &ipStr[0], &random[0]); 306 }(); 307 } 308 309 /** 310 * Decrypts an encrypted IP address string. 311 * Params: 312 * output = Buffer to store the decrypted IP string (must be at least IPCRYPT_MAX_IP_STR_BYTES). 313 * encryptedIPStr = The encrypted IP address string. 314 * Returns: The length of the decrypted IP string, or 0 on error. 315 */ 316 size_t decryptIPStr(scope char[] output, scope const(char)[] encryptedIPStr) nothrow @safe 317 { 318 assert(output.length >= IPCRYPT_MAX_IP_STR_BYTES); 319 return () @trusted { 320 return ipcrypt_ndx_decrypt_ip_str(&context, &output[0], &encryptedIPStr[0]); 321 }(); 322 } 323 324 /** 325 * Converts a hexadecimal string to a non-deterministic encrypted IP address. 326 * Params: 327 * hex = The hexadecimal string. 328 * Returns: The non-deterministic encrypted IP address. 329 */ 330 ubyte[IPCRYPT_NDX_NDIP_BYTES] ndipFromHex(string hex) nothrow @safe 331 { 332 ubyte[IPCRYPT_NDX_NDIP_BYTES] result; 333 assert(() @trusted { 334 return ipcrypt_ndx_ndip_from_hex(&result[0], &hex[0], hex.length); 335 }() == 0, "Invalid hex string"); 336 return result; 337 } 338 } 339 340 /** 341 * IPCryptPFX context, providing prefix-preserving encryption/decryption. 342 * Ensures proper initialization and cleanup of the underlying IPCryptPFX context. 343 */ 344 struct IPCryptPFXCtx 345 { 346 private IPCryptPFX context; // Opaque IPCryptPFX context 347 348 /** 349 * Constructs an IPCryptPFXCtx with the given 32-byte key. 350 */ 351 this(scope const(ubyte)[] key) nothrow @nogc @safe 352 { 353 assert(key.length == IPCRYPT_PFX_KEYBYTES, "Invalid key length"); 354 assert(() @trusted { return ipcrypt_pfx_init(&context, &key[0]); }() == 0, "Initialization failed"); 355 } 356 357 /// Ditto, but constructs from a hexadecimal key string. 358 this(string hexKey) nothrow @nogc @safe 359 { 360 ubyte[IPCRYPT_PFX_KEYBYTES] key; 361 assert(() @trusted { 362 return ipcrypt_key_from_hex(&key[0], IPCRYPT_PFX_KEYBYTES, &hexKey[0], hexKey.length); 363 }() == 0, "Invalid hex key"); 364 assert(() @trusted { return ipcrypt_pfx_init(&context, &key[0]); }() == 0, "Initialization failed"); 365 } 366 367 /// Destructor ensures the IPCryptPFX context is cleaned up. 368 ~this() nothrow @nogc @safe 369 { 370 () @trusted { ipcrypt_pfx_deinit(&context); }(); 371 } 372 373 // Disable copying to prevent double-free 374 @disable this(this); 375 376 /** 377 * Encrypts a 16-byte IP address (IPv4 or IPv6) with prefix preservation. 378 * Params: 379 * ip16 = The 16-byte IP address to encrypt. 380 * Returns: The encrypted 16-byte IP address. 381 */ 382 ubyte[IPCRYPT_KEYBYTES] encryptIP16(scope const(ubyte)[] ip16) nothrow @nogc @safe 383 { 384 ubyte[IPCRYPT_KEYBYTES] result; 385 result[] = ip16[0 .. IPCRYPT_KEYBYTES]; 386 () @trusted { ipcrypt_pfx_encrypt_ip16(&context, &result[0]); }(); 387 return result; 388 } 389 390 /** 391 * Decrypts a 16-byte IP address (IPv4 or IPv6) with prefix preservation. 392 * Params: 393 * ip16 = The 16-byte encrypted IP address. 394 * Returns: The decrypted 16-byte IP address. 395 */ 396 ubyte[IPCRYPT_KEYBYTES] decryptIP16(scope const(ubyte)[] ip16) nothrow @nogc @safe 397 { 398 ubyte[IPCRYPT_KEYBYTES] result; 399 result[] = ip16[0 .. IPCRYPT_KEYBYTES]; 400 () @trusted { ipcrypt_pfx_decrypt_ip16(&context, &result[0]); }(); 401 return result; 402 } 403 404 /** 405 * Encrypts an IP address string (IPv4 or IPv6) with prefix preservation. 406 * Params: 407 * output = Buffer to store the encrypted IP string (must be at least IPCRYPT_MAX_IP_STR_BYTES). 408 * ipStr = The IP address string to encrypt. 409 * Returns: The length of the encrypted IP string, or 0 on error. 410 */ 411 size_t encryptIPStr(scope char[] output, scope const(char)[] ipStr) nothrow @safe 412 { 413 assert(output.length >= IPCRYPT_MAX_IP_STR_BYTES); 414 return () @trusted { 415 return ipcrypt_pfx_encrypt_ip_str(&context, &output[0], &ipStr[0]); 416 }(); 417 } 418 419 /** 420 * Decrypts an encrypted IP address string with prefix preservation. 421 * Params: 422 * output = Buffer to store the decrypted IP string (must be at least IPCRYPT_MAX_IP_STR_BYTES). 423 * encryptedIPStr = The encrypted IP address string. 424 * Returns: The length of the decrypted IP string, or 0 on error. 425 */ 426 size_t decryptIPStr(scope char[] output, scope const(char)[] encryptedIPStr) nothrow @safe 427 { 428 assert(output.length >= IPCRYPT_MAX_IP_STR_BYTES); 429 return () @trusted { 430 return ipcrypt_pfx_decrypt_ip_str(&context, &output[0], &encryptedIPStr[0]); 431 }(); 432 } 433 } 434 435 /** 436 * Converts an IP address string to a 16-byte representation. 437 * Params: 438 * ipStr = The IP address string (IPv4 or IPv6). 439 * Returns: The 16-byte IP address. 440 */ 441 ubyte[IPCRYPT_KEYBYTES] ipStrToIP16(scope const(char)[] ipStr) nothrow @safe 442 { 443 ubyte[IPCRYPT_KEYBYTES] result; 444 assert(() @trusted { return ipcrypt_str_to_ip16(&result[0], &ipStr[0]); }() == 0, "Invalid IP string"); 445 return result; 446 } 447 448 /** 449 * Converts a 16-byte IP address to a string. 450 * Params: 451 * output = Buffer to store the IP string (must be at least IPCRYPT_MAX_IP_STR_BYTES). 452 * ip16 = The 16-byte IP address. 453 * Returns: The length of the IP string, or 0 on error. 454 */ 455 size_t ip16ToStr(scope char[] output, scope const(ubyte)[] ip16) nothrow @safe 456 { 457 assert(output.length >= IPCRYPT_MAX_IP_STR_BYTES); 458 return () @trusted { return ipcrypt_ip16_to_str(&output[0], &ip16[0]); }(); 459 } 460 461 /** 462 * Converts a sockaddr to a 16-byte IP address. 463 * Params: 464 * sa = The sockaddr structure. 465 * Returns: The 16-byte IP address. 466 */ 467 ubyte[IPCRYPT_KEYBYTES] sockaddrToIP16(scope sockaddr* sa) nothrow @safe 468 { 469 ubyte[IPCRYPT_KEYBYTES] result; 470 assert(() @trusted { return ipcrypt_sockaddr_to_ip16(&result[0], sa); }() == 0, "Invalid sockaddr"); 471 return result; 472 } 473 474 /** 475 * Converts a 16-byte IP address to a sockaddr_storage. 476 * Params: 477 * ip16 = The 16-byte IP address. 478 * Returns: The sockaddr_storage structure. 479 */ 480 sockaddr_storage ip16ToSockaddr(scope const(ubyte)[] ip16) nothrow @nogc @safe 481 { 482 sockaddr_storage result; 483 () @trusted { ipcrypt_ip16_to_sockaddr(&result, &ip16[0]); }(); 484 return result; 485 } 486 487 version (unittest) 488 { 489 @("ip string encryption and decryption") unittest 490 { 491 ubyte[16] key = cast(ubyte[16]) "0123456789abcdef"; 492 493 auto crypt = IPCrypt2(key); 494 495 string ip_str = "1.2.3.4"; 496 497 char[IPCRYPT_MAX_IP_STR_BYTES] encrypted_ip_buf; 498 size_t encrypted_ip_len = crypt.encryptIPStr(encrypted_ip_buf[], ip_str); 499 assert(encrypted_ip_len > 0); 500 501 string encrypted_ip = encrypted_ip_buf[0 .. encrypted_ip_len].idup; 502 503 const string expected_encrypted_ip = "9f4:e6e1:c77e:ffe8:49ac:6a6a:9f11:620f"; 504 assert(expected_encrypted_ip == encrypted_ip); 505 506 char[IPCRYPT_MAX_IP_STR_BYTES] decrypted_ip_buf; 507 size_t decrypted_ip_len = crypt.decryptIPStr(decrypted_ip_buf[], encrypted_ip); 508 assert(decrypted_ip_len > 0); 509 string decrypted_ip_str = decrypted_ip_buf[0 .. decrypted_ip_len].idup; 510 assert(ip_str == decrypted_ip_str); 511 } 512 513 @("ip string non-deterministic encryption and decryption") unittest 514 { 515 ubyte[16] key = cast(ubyte[16]) "0123456789abcdef"; 516 517 auto crypt = IPCrypt2(key); 518 519 string ip_str = "1.2.3.4"; 520 ubyte[8] tweak = [1, 2, 3, 4, 5, 6, 7, 8]; 521 522 char[IPCRYPT_NDIP_STR_BYTES] encrypted_ip_buf; 523 size_t encrypted_ip_len = crypt.ndEncryptIPStr(encrypted_ip_buf[], ip_str, tweak); 524 assert(encrypted_ip_len > 0); 525 526 string encrypted_ip = encrypted_ip_buf[0 .. encrypted_ip_len].idup; 527 528 const string expected_encrypted_ip = "01020304050607085f8ec3223eaa68378ba06d3bc3df0209"; 529 assert(expected_encrypted_ip == encrypted_ip); 530 531 char[IPCRYPT_MAX_IP_STR_BYTES] decrypted_ip_buf; 532 size_t decrypted_ip_len = crypt.ndDecryptIPStr(decrypted_ip_buf[], encrypted_ip); 533 assert(decrypted_ip_len > 0); 534 string decrypted_ip_str = decrypted_ip_buf[0 .. decrypted_ip_len].idup; 535 assert(ip_str == decrypted_ip_str); 536 } 537 538 @("binary ip deterministic encryption and decryption") unittest 539 { 540 ubyte[16] expected_ip = [ 541 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 542 ]; 543 ubyte[16] key = cast(ubyte[16]) "0123456789abcdef"; 544 545 auto crypt = IPCrypt2(key); 546 547 ubyte[16] ip = expected_ip; 548 ip = crypt.encryptIP16(ip); 549 ip = crypt.decryptIP16(ip); 550 assert(expected_ip == ip); 551 } 552 553 @("binary ip non-deterministic encryption and decryption") unittest 554 { 555 ubyte[16] ip = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; 556 ubyte[16] key = cast(ubyte[16]) "0123456789abcdef"; 557 ubyte[8] tweak = [1, 2, 3, 4, 5, 6, 7, 8]; 558 559 auto crypt = IPCrypt2(key); 560 561 ubyte[24] encrypted_ip = crypt.ndEncryptIP16(ip, tweak); 562 ubyte[16] decrypted_ip = crypt.ndDecryptIP16(encrypted_ip); 563 assert(ip == decrypted_ip); 564 } 565 566 @("equivalence between AES and KIASU-BC with tweak=0*") unittest 567 { 568 ubyte[16] ip = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; 569 ubyte[16] key = cast(ubyte[16]) "0123456789abcdef"; 570 ubyte[8] tweak = [0, 0, 0, 0, 0, 0, 0, 0]; 571 572 auto crypt = IPCrypt2(key); 573 574 ubyte[24] encrypted_ip = crypt.ndEncryptIP16(ip, tweak); 575 576 ubyte[16] encrypted_ip2 = crypt.encryptIP16(ip); 577 578 assert(encrypted_ip[8 .. $] == encrypted_ip2); 579 } 580 581 @("binary ip NDX encryption and decryption") unittest 582 { 583 ubyte[16] ip = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; 584 ubyte[32] key = cast(ubyte[32]) "0123456789abcdef1032547698badcfe"; 585 ubyte[16] tweak = [ 586 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 587 ]; 588 589 auto crypt = IPCryptNDXCtx(key); 590 591 ubyte[32] encrypted_ip = crypt.encryptIP16(ip, tweak); 592 ubyte[16] decrypted_ip = crypt.decryptIP16(encrypted_ip); 593 assert(ip == decrypted_ip); 594 } 595 596 @("ip string NDX encryption and decryption") unittest 597 { 598 ubyte[32] key = cast(ubyte[32]) "0123456789abcdef1032547698badcfe"; 599 600 auto crypt = IPCryptNDXCtx(key); 601 602 string ip_str = "1.2.3.4"; 603 ubyte[16] tweak = [ 604 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 605 ]; 606 607 char[IPCRYPT_NDX_NDIP_STR_BYTES] encrypted_ip_buf; 608 size_t encrypted_ip_len = crypt.encryptIPStr(encrypted_ip_buf[], ip_str, tweak); 609 assert(encrypted_ip_len > 0); 610 611 string encrypted_ip = encrypted_ip_buf[0 .. encrypted_ip_len].idup; 612 613 const string expected_encrypted_ip = "0102030405060708090a0b0c0d0e0f10a472dd736f82eb599b85141580b21c40"; 614 assert(expected_encrypted_ip == encrypted_ip); 615 616 char[IPCRYPT_MAX_IP_STR_BYTES] decrypted_ip_buf; 617 size_t decrypted_ip_len = crypt.decryptIPStr(decrypted_ip_buf[], encrypted_ip); 618 assert(decrypted_ip_len > 0); 619 string decrypted_ip_str = decrypted_ip_buf[0 .. decrypted_ip_len].idup; 620 assert(ip_str == decrypted_ip_str); 621 } 622 623 @("test vector for ipcrypt-deterministic") unittest 624 { 625 ubyte[16] key = [ 626 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 627 0x76, 0x54, 0x32, 0x10 628 ]; 629 630 auto crypt = IPCrypt2(key); 631 632 string ip_str = "0.0.0.0"; 633 634 char[IPCRYPT_MAX_IP_STR_BYTES] encrypted_ip_buf; 635 size_t encrypted_ip_len = crypt.encryptIPStr(encrypted_ip_buf[], ip_str); 636 assert(encrypted_ip_len > 0); 637 638 string encrypted_ip = encrypted_ip_buf[0 .. encrypted_ip_len].idup; 639 640 const string expected = "bde9:6789:d353:824c:d7c6:f58a:6bd2:26eb"; 641 assert(expected == encrypted_ip); 642 } 643 644 @("test vector 1 for ipcrypt-nd") unittest 645 { 646 ubyte[16] key = [ 647 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 648 0x76, 0x54, 0x32, 0x10 649 ]; 650 651 auto crypt = IPCrypt2(key); 652 653 string ip_str = "0.0.0.0"; 654 ubyte[8] tweak = [0x08, 0xe0, 0xc2, 0x89, 0xbf, 0xf2, 0x3b, 0x7c]; 655 656 char[IPCRYPT_NDIP_STR_BYTES] encrypted_ip_buf; 657 size_t encrypted_ip_len = crypt.ndEncryptIPStr(encrypted_ip_buf[], ip_str, tweak); 658 assert(encrypted_ip_len > 0); 659 660 string encrypted_ip = encrypted_ip_buf[0 .. encrypted_ip_len].idup; 661 662 const string expected = "08e0c289bff23b7cb349aadfe3bcef56221c384c7c217b16"; 663 assert(expected == encrypted_ip); 664 } 665 666 @("test vector 2 for ipcrypt-nd") unittest 667 { 668 ubyte[16] key = [ 669 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xcd, 0xab, 0x89, 670 0x67, 0x45, 0x23, 0x01 671 ]; 672 673 auto crypt = IPCrypt2(key); 674 675 string ip_str = "192.0.2.1"; 676 ubyte[8] tweak = [0x21, 0xbd, 0x18, 0x34, 0xbc, 0x08, 0x8c, 0xd2]; 677 678 char[IPCRYPT_NDIP_STR_BYTES] encrypted_ip_buf; 679 size_t encrypted_ip_len = crypt.ndEncryptIPStr(encrypted_ip_buf[], ip_str, tweak); 680 assert(encrypted_ip_len > 0); 681 682 string encrypted_ip = encrypted_ip_buf[0 .. encrypted_ip_len].idup; 683 684 const string expected = "21bd1834bc088cd2e5e1fe55f95876e639faae2594a0caad"; 685 assert(expected == encrypted_ip); 686 } 687 688 @("test vector 3 for ipcrypt-nd") unittest 689 { 690 ubyte[16] key = [ 691 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 692 0x09, 0xcf, 0x4f, 0x3c 693 ]; 694 695 auto crypt = IPCrypt2(key); 696 697 string ip_str = "2001:db8::1"; 698 ubyte[8] tweak = [0xb4, 0xec, 0xbe, 0x30, 0xb7, 0x08, 0x98, 0xd7]; 699 700 char[IPCRYPT_NDIP_STR_BYTES] encrypted_ip_buf; 701 size_t encrypted_ip_len = crypt.ndEncryptIPStr(encrypted_ip_buf[], ip_str, tweak); 702 assert(encrypted_ip_len > 0); 703 704 string encrypted_ip = encrypted_ip_buf[0 .. encrypted_ip_len].idup; 705 706 const string expected = "b4ecbe30b70898d7553ac8974d1b4250eafc4b0aa1f80c96"; 707 assert(expected == encrypted_ip); 708 } 709 710 @("test vector 1 for ipcrypt-ndx") unittest 711 { 712 ubyte[32] key = [ 713 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 714 0x76, 0x54, 0x32, 0x10, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe, 715 0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01 716 ]; 717 718 auto crypt = IPCryptNDXCtx(key); 719 720 string ip_str = "0.0.0.0"; 721 ubyte[16] tweak = [ 722 0x21, 0xbd, 0x18, 0x34, 0xbc, 0x08, 0x8c, 0xd2, 0xb4, 0xec, 0xbe, 0x30, 723 0xb7, 0x08, 0x98, 0xd7 724 ]; 725 726 char[IPCRYPT_NDX_NDIP_STR_BYTES] encrypted_ip_buf; 727 size_t encrypted_ip_len = crypt.encryptIPStr(encrypted_ip_buf[], ip_str, tweak); 728 assert(encrypted_ip_len > 0); 729 730 string encrypted_ip = encrypted_ip_buf[0 .. encrypted_ip_len].idup; 731 732 const string expected = "21bd1834bc088cd2b4ecbe30b70898d782db0d4125fdace61db35b8339f20ee5"; 733 assert(expected == encrypted_ip); 734 } 735 736 @("test vector 2 for ipcrypt-ndx") unittest 737 { 738 ubyte[32] key = [ 739 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe, 0xef, 0xcd, 0xab, 0x89, 740 0x67, 0x45, 0x23, 0x01, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 741 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 742 ]; 743 744 auto crypt = IPCryptNDXCtx(key); 745 746 string ip_str = "192.0.2.1"; 747 ubyte[16] tweak = [ 748 0x08, 0xe0, 0xc2, 0x89, 0xbf, 0xf2, 0x3b, 0x7c, 0xb4, 0xec, 0xbe, 0x30, 749 0xb7, 0x08, 0x98, 0xd7 750 ]; 751 752 char[IPCRYPT_NDX_NDIP_STR_BYTES] encrypted_ip_buf; 753 size_t encrypted_ip_len = crypt.encryptIPStr(encrypted_ip_buf[], ip_str, tweak); 754 assert(encrypted_ip_len > 0); 755 756 string encrypted_ip = encrypted_ip_buf[0 .. encrypted_ip_len].idup; 757 758 const string expected = "08e0c289bff23b7cb4ecbe30b70898d7766a533392a69edf1ad0d3ce362ba98a"; 759 assert(expected == encrypted_ip); 760 } 761 762 @("test vector 3 for ipcrypt-ndx") unittest 763 { 764 ubyte[32] key = [ 765 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 766 0x09, 0xcf, 0x4f, 0x3c, 0x3c, 0x4f, 0xcf, 0x09, 0x88, 0x15, 0xf7, 0xab, 767 0xa6, 0xd2, 0xae, 0x28, 0x16, 0x15, 0x7e, 0x2b 768 ]; 769 770 auto crypt = IPCryptNDXCtx(key); 771 772 string ip_str = "2001:db8::1"; 773 ubyte[16] tweak = [ 774 0x21, 0xbd, 0x18, 0x34, 0xbc, 0x08, 0x8c, 0xd2, 0xb4, 0xec, 0xbe, 0x30, 775 0xb7, 0x08, 0x98, 0xd7 776 ]; 777 778 char[IPCRYPT_NDX_NDIP_STR_BYTES] encrypted_ip_buf; 779 size_t encrypted_ip_len = crypt.encryptIPStr(encrypted_ip_buf[], ip_str, tweak); 780 assert(encrypted_ip_len > 0); 781 782 string encrypted_ip = encrypted_ip_buf[0 .. encrypted_ip_len].idup; 783 784 const string expected = "21bd1834bc088cd2b4ecbe30b70898d76089c7e05ae30c2d10ca149870a263e4"; 785 assert(expected == encrypted_ip); 786 } 787 788 @("socket address conversion") unittest 789 { 790 // Test IPv4-mapped IPv6 address (1.2.3.4) 791 ubyte[16] ipv4_mapped = [ 792 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 1, 2, 3, 4 793 ]; 794 795 sockaddr_storage sa = ip16ToSockaddr(ipv4_mapped); 796 797 ubyte[16] ip16 = sockaddrToIP16(cast(sockaddr*)&sa); 798 799 assert(ipv4_mapped == ip16); 800 801 // Test IPv6 address (2001:db8::1) 802 ubyte[16] ipv6 = [ 803 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 804 ]; 805 806 sa = ip16ToSockaddr(ipv6); 807 808 ip16 = sockaddrToIP16(cast(sockaddr*)&sa); 809 810 assert(ipv6 == ip16); 811 } 812 813 @("key from hex conversion") unittest 814 { 815 // Test valid 16-byte key 816 string hex16 = "0123456789abcdef0123456789abcdef"; 817 ubyte[16] key16; 818 int ret = () @trusted { 819 return ipcrypt_key_from_hex(&key16[0], key16.length, &hex16[0], hex16.length); 820 }(); 821 assert(ret == 0); 822 ubyte[16] expected_key16 = [ 823 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 824 0x89, 0xab, 0xcd, 0xef 825 ]; 826 assert(expected_key16 == key16); 827 828 // Test valid 32-byte key 829 string hex32 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; 830 ubyte[32] key32; 831 ret = () @trusted { 832 return ipcrypt_key_from_hex(&key32[0], key32.length, &hex32[0], hex32.length); 833 }(); 834 assert(ret == 0); 835 ubyte[32] expected_key32 = [ 836 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 837 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 838 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef 839 ]; 840 assert(expected_key32 == key32); 841 842 // Test invalid hex length 843 string invalid_hex = "0123456789abcdef"; 844 ubyte[16] key; 845 ret = () @trusted { 846 return ipcrypt_key_from_hex(&key[0], key.length, &invalid_hex[0], invalid_hex.length); 847 }(); 848 assert(ret == -1); 849 850 // Test invalid hex characters 851 string invalid_chars = "0123456789abcdef0123456789abcdeg"; 852 ret = () @trusted { 853 return ipcrypt_key_from_hex(&key[0], key.length, &invalid_chars[0], invalid_chars 854 .length); 855 }(); 856 assert(ret == -1); 857 } 858 859 @("ipcrypt-pfx round-trip") unittest 860 { 861 ubyte[32] key = [ 862 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 863 0x76, 0x54, 0x32, 0x10, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe, 864 0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01 865 ]; 866 867 auto crypt = IPCryptPFXCtx(key); 868 869 // Test with IPv4 address string 870 string ipv4_str = "192.168.1.100"; 871 872 char[IPCRYPT_MAX_IP_STR_BYTES] encrypted_ipv4_buf; 873 size_t encrypted_ipv4_len = crypt.encryptIPStr(encrypted_ipv4_buf, ipv4_str); 874 assert(encrypted_ipv4_len > 0); 875 string encrypted_ipv4 = encrypted_ipv4_buf[0 .. $].idup; 876 877 char[IPCRYPT_MAX_IP_STR_BYTES] decrypted_ipv4_buf; 878 size_t decrypted_ipv4_len = crypt.decryptIPStr(decrypted_ipv4_buf, encrypted_ipv4); 879 assert(decrypted_ipv4_len > 0); 880 string decrypted_ipv4 = decrypted_ipv4_buf[0 .. $].idup; 881 882 import std.algorithm.comparison : cmp; 883 // import core.stdc.stdio; 884 885 // printf("ip: |%s|\n", &ipv4_str[0]); 886 // printf("encrypt: |%s|\n", &encrypted_ipv4[0]); 887 // printf("decrypt: |%s|\n", &decrypted_ipv4[0]); 888 889 assert(cmp(ipv4_str, decrypted_ipv4)); 890 891 // Test with IPv6 address string 892 string ipv6_str = "2001:db8:85a3::8a2e:370:7334"; 893 894 char[IPCRYPT_MAX_IP_STR_BYTES] encrypted_ipv6_buf; 895 size_t encrypted_ipv6_len = crypt.encryptIPStr(encrypted_ipv6_buf[], ipv6_str); 896 assert(encrypted_ipv6_len > 0); 897 string encrypted_ipv6 = encrypted_ipv6_buf[0 .. encrypted_ipv6_len].idup; 898 899 char[IPCRYPT_MAX_IP_STR_BYTES] decrypted_ipv6_buf; 900 size_t decrypted_ipv6_len = crypt.decryptIPStr(decrypted_ipv6_buf[], encrypted_ipv6); 901 assert(decrypted_ipv6_len > 0); 902 string decrypted_ipv6 = decrypted_ipv6_buf[0 .. decrypted_ipv6_len].idup; 903 904 assert(ipv6_str == decrypted_ipv6); 905 906 // Test with binary IP16 format for IPv4 907 ubyte[16] ipv4_binary = [ 908 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 192, 168, 1, 100 909 ]; 910 ubyte[16] original_ipv4_binary = ipv4_binary; 911 912 ipv4_binary = crypt.encryptIP16(ipv4_binary); 913 ipv4_binary = crypt.decryptIP16(ipv4_binary); 914 915 assert(original_ipv4_binary == ipv4_binary); 916 917 // Test with binary IP16 format for IPv6 918 ubyte[16] ipv6_binary = [ 919 0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 0x03, 0x70, 920 0x73, 0x34 921 ]; 922 ubyte[16] original_ipv6_binary = ipv6_binary; 923 924 ipv6_binary = crypt.encryptIP16(ipv6_binary); 925 ipv6_binary = crypt.decryptIP16(ipv6_binary); 926 927 assert(original_ipv6_binary == ipv6_binary); 928 } 929 930 @("ipcrypt-pfx test vectors from python reference") unittest 931 { 932 // Test vector 1 933 { 934 ubyte[32] key = [ 935 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 936 0x98, 0x76, 0x54, 0x32, 0x10, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 937 0xdc, 0xfe, 0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01 938 ]; 939 940 auto crypt = IPCryptPFXCtx(key); 941 942 string ip_str = "0.0.0.0"; 943 const string expected = "151.82.155.134"; 944 945 char[IPCRYPT_MAX_IP_STR_BYTES] encrypted_ip_buf; 946 size_t encrypted_ip_len = crypt.encryptIPStr(encrypted_ip_buf[], ip_str); 947 assert(encrypted_ip_len > 0); 948 string encrypted_ip = encrypted_ip_buf[0 .. encrypted_ip_len].idup; 949 950 assert(expected == encrypted_ip); 951 } 952 953 // Test vector 2 954 { 955 ubyte[32] key = [ 956 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 957 0x98, 0x76, 0x54, 0x32, 0x10, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 958 0xdc, 0xfe, 0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01 959 ]; 960 961 auto crypt = IPCryptPFXCtx(key); 962 963 string ip_str = "255.255.255.255"; 964 const string expected = "94.185.169.89"; 965 966 char[IPCRYPT_MAX_IP_STR_BYTES] encrypted_ip_buf; 967 size_t encrypted_ip_len = crypt.encryptIPStr(encrypted_ip_buf[], ip_str); 968 assert(encrypted_ip_len > 0); 969 string encrypted_ip = encrypted_ip_buf[0 .. encrypted_ip_len].idup; 970 971 assert(expected == encrypted_ip); 972 } 973 974 // Test vector 3 975 { 976 ubyte[32] key = [ 977 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 978 0x98, 0x76, 0x54, 0x32, 0x10, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 979 0xdc, 0xfe, 0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01 980 ]; 981 982 auto crypt = IPCryptPFXCtx(key); 983 984 string ip_str = "192.0.2.1"; 985 const string expected = "100.115.72.131"; 986 987 char[IPCRYPT_MAX_IP_STR_BYTES] encrypted_ip_buf; 988 size_t encrypted_ip_len = crypt.encryptIPStr(encrypted_ip_buf[], ip_str); 989 assert(encrypted_ip_len > 0); 990 string encrypted_ip = encrypted_ip_buf[0 .. encrypted_ip_len].idup; 991 992 assert(expected == encrypted_ip); 993 } 994 995 // Test vector 4 996 { 997 ubyte[32] key = [ 998 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 999 0x98, 0x76, 0x54, 0x32, 0x10, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 1000 0xdc, 0xfe, 0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01 1001 ]; 1002 1003 auto crypt = IPCryptPFXCtx(key); 1004 1005 string ip_str = "2001:db8::1"; 1006 const string expected = "c180:5dd4:2587:3524:30ab:fa65:6ab6:f88"; 1007 1008 char[IPCRYPT_MAX_IP_STR_BYTES] encrypted_ip_buf; 1009 size_t encrypted_ip_len = crypt.encryptIPStr(encrypted_ip_buf[], ip_str); 1010 assert(encrypted_ip_len > 0); 1011 string encrypted_ip = encrypted_ip_buf[0 .. encrypted_ip_len].idup; 1012 1013 assert(expected == encrypted_ip); 1014 } 1015 1016 // Test vector 5 1017 { 1018 ubyte[32] key = [ 1019 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 1020 0x88, 0x09, 0xcf, 0x4f, 0x3c, 0xa9, 0xf5, 0xba, 0x40, 0xdb, 0x21, 1021 0x4c, 0x37, 0x98, 0xf2, 0xe1, 0xc2, 0x34, 0x56, 0x78, 0x9a 1022 ]; 1023 1024 auto crypt = IPCryptPFXCtx(key); 1025 1026 string ip_str = "10.0.0.47"; 1027 const string expected = "19.214.210.244"; 1028 1029 char[IPCRYPT_MAX_IP_STR_BYTES] encrypted_ip_buf; 1030 size_t encrypted_ip_len = crypt.encryptIPStr(encrypted_ip_buf[], ip_str); 1031 assert(encrypted_ip_len > 0); 1032 string encrypted_ip = encrypted_ip_buf[0 .. encrypted_ip_len].idup; 1033 1034 assert(expected == encrypted_ip); 1035 } 1036 1037 // Test vector 6 1038 { 1039 ubyte[32] key = [ 1040 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 1041 0x88, 0x09, 0xcf, 0x4f, 0x3c, 0xa9, 0xf5, 0xba, 0x40, 0xdb, 0x21, 1042 0x4c, 0x37, 0x98, 0xf2, 0xe1, 0xc2, 0x34, 0x56, 0x78, 0x9a 1043 ]; 1044 1045 auto crypt = IPCryptPFXCtx(key); 1046 1047 string ip_str = "10.0.0.129"; 1048 const string expected = "19.214.210.80"; 1049 1050 char[IPCRYPT_MAX_IP_STR_BYTES] encrypted_ip_buf; 1051 size_t encrypted_ip_len = crypt.encryptIPStr(encrypted_ip_buf[], ip_str); 1052 assert(encrypted_ip_len > 0); 1053 string encrypted_ip = encrypted_ip_buf[0 .. encrypted_ip_len].idup; 1054 1055 assert(expected == encrypted_ip); 1056 } 1057 1058 // Test vector 7 1059 { 1060 ubyte[32] key = [ 1061 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 1062 0x88, 0x09, 0xcf, 0x4f, 0x3c, 0xa9, 0xf5, 0xba, 0x40, 0xdb, 0x21, 1063 0x4c, 0x37, 0x98, 0xf2, 0xe1, 0xc2, 0x34, 0x56, 0x78, 0x9a 1064 ]; 1065 1066 auto crypt = IPCryptPFXCtx(key); 1067 1068 string ip_str = "10.0.0.234"; 1069 const string expected = "19.214.210.30"; 1070 1071 char[IPCRYPT_MAX_IP_STR_BYTES] encrypted_ip_buf; 1072 size_t encrypted_ip_len = crypt.encryptIPStr(encrypted_ip_buf[], ip_str); 1073 assert(encrypted_ip_len > 0); 1074 string encrypted_ip = encrypted_ip_buf[0 .. encrypted_ip_len].idup; 1075 1076 assert(expected == encrypted_ip); 1077 } 1078 1079 // Test vector 8 1080 { 1081 ubyte[32] key = [ 1082 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 1083 0x88, 0x09, 0xcf, 0x4f, 0x3c, 0xa9, 0xf5, 0xba, 0x40, 0xdb, 0x21, 1084 0x4c, 0x37, 0x98, 0xf2, 0xe1, 0xc2, 0x34, 0x56, 0x78, 0x9a 1085 ]; 1086 1087 auto crypt = IPCryptPFXCtx(key); 1088 1089 string ip_str = "172.16.5.193"; 1090 const string expected = "210.78.229.136"; 1091 1092 char[IPCRYPT_MAX_IP_STR_BYTES] encrypted_ip_buf; 1093 size_t encrypted_ip_len = crypt.encryptIPStr(encrypted_ip_buf[], ip_str); 1094 assert(encrypted_ip_len > 0); 1095 string encrypted_ip = encrypted_ip_buf[0 .. encrypted_ip_len].idup; 1096 1097 assert(expected == encrypted_ip); 1098 } 1099 1100 // Test vector 9 1101 { 1102 ubyte[32] key = [ 1103 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 1104 0x88, 0x09, 0xcf, 0x4f, 0x3c, 0xa9, 0xf5, 0xba, 0x40, 0xdb, 0x21, 1105 0x4c, 0x37, 0x98, 0xf2, 0xe1, 0xc2, 0x34, 0x56, 0x78, 0x9a 1106 ]; 1107 1108 auto crypt = IPCryptPFXCtx(key); 1109 1110 string ip_str = "172.16.97.42"; 1111 const string expected = "210.78.179.241"; 1112 1113 char[IPCRYPT_MAX_IP_STR_BYTES] encrypted_ip_buf; 1114 size_t encrypted_ip_len = crypt.encryptIPStr(encrypted_ip_buf[], ip_str); 1115 assert(encrypted_ip_len > 0); 1116 string encrypted_ip = encrypted_ip_buf[0 .. encrypted_ip_len].idup; 1117 1118 assert(expected == encrypted_ip); 1119 } 1120 1121 // Test vector 10 1122 { 1123 ubyte[32] key = [ 1124 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 1125 0x88, 0x09, 0xcf, 0x4f, 0x3c, 0xa9, 0xf5, 0xba, 0x40, 0xdb, 0x21, 1126 0x4c, 0x37, 0x98, 0xf2, 0xe1, 0xc2, 0x34, 0x56, 0x78, 0x9a 1127 ]; 1128 1129 auto crypt = IPCryptPFXCtx(key); 1130 1131 string ip_str = "172.16.248.177"; 1132 const string expected = "210.78.121.215"; 1133 1134 char[IPCRYPT_MAX_IP_STR_BYTES] encrypted_ip_buf; 1135 size_t encrypted_ip_len = crypt.encryptIPStr(encrypted_ip_buf[], ip_str); 1136 assert(encrypted_ip_len > 0); 1137 string encrypted_ip = encrypted_ip_buf[0 .. encrypted_ip_len].idup; 1138 1139 assert(expected == encrypted_ip); 1140 } 1141 1142 // Test vector 11 1143 { 1144 ubyte[32] key = [ 1145 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 1146 0x88, 0x09, 0xcf, 0x4f, 0x3c, 0xa9, 0xf5, 0xba, 0x40, 0xdb, 0x21, 1147 0x4c, 0x37, 0x98, 0xf2, 0xe1, 0xc2, 0x34, 0x56, 0x78, 0x9a 1148 ]; 1149 1150 auto crypt = IPCryptPFXCtx(key); 1151 1152 string ip_str = "2001:db8::a5c9:4e2f:bb91:5a7d"; 1153 const string expected = "7cec:702c:1243:f70:1956:125:b9bd:1aba"; 1154 1155 char[IPCRYPT_MAX_IP_STR_BYTES] encrypted_ip_buf; 1156 size_t encrypted_ip_len = crypt.encryptIPStr(encrypted_ip_buf[], ip_str); 1157 assert(encrypted_ip_len > 0); 1158 string encrypted_ip = encrypted_ip_buf[0 .. encrypted_ip_len].idup; 1159 1160 assert(expected == encrypted_ip); 1161 } 1162 1163 // Test vector 12 1164 { 1165 ubyte[32] key = [ 1166 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 1167 0x88, 0x09, 0xcf, 0x4f, 0x3c, 0xa9, 0xf5, 0xba, 0x40, 0xdb, 0x21, 1168 0x4c, 0x37, 0x98, 0xf2, 0xe1, 0xc2, 0x34, 0x56, 0x78, 0x9a 1169 ]; 1170 1171 auto crypt = IPCryptPFXCtx(key); 1172 1173 string ip_str = "2001:db8::7234:d8f1:3c6e:9a52"; 1174 const string expected = "7cec:702c:1243:f70:a3ef:c8e:95c1:cd0d"; 1175 1176 char[IPCRYPT_MAX_IP_STR_BYTES] encrypted_ip_buf; 1177 size_t encrypted_ip_len = crypt.encryptIPStr(encrypted_ip_buf[], ip_str); 1178 assert(encrypted_ip_len > 0); 1179 string encrypted_ip = encrypted_ip_buf[0 .. encrypted_ip_len].idup; 1180 1181 assert(expected == encrypted_ip); 1182 } 1183 1184 // Test vector 13 1185 { 1186 ubyte[32] key = [ 1187 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 1188 0x88, 0x09, 0xcf, 0x4f, 0x3c, 0xa9, 0xf5, 0xba, 0x40, 0xdb, 0x21, 1189 0x4c, 0x37, 0x98, 0xf2, 0xe1, 0xc2, 0x34, 0x56, 0x78, 0x9a 1190 ]; 1191 1192 auto crypt = IPCryptPFXCtx(key); 1193 1194 string ip_str = "2001:db8::f1e0:937b:26d4:8c1a"; 1195 const string expected = "7cec:702c:1243:f70:443c:c8e:6a62:b64d"; 1196 1197 char[IPCRYPT_MAX_IP_STR_BYTES] encrypted_ip_buf; 1198 size_t encrypted_ip_len = crypt.encryptIPStr(encrypted_ip_buf[], ip_str); 1199 assert(encrypted_ip_len > 0); 1200 string encrypted_ip = encrypted_ip_buf[0 .. encrypted_ip_len].idup; 1201 1202 assert(expected == encrypted_ip); 1203 } 1204 1205 // Test vector 14 1206 { 1207 ubyte[32] key = [ 1208 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 1209 0x88, 0x09, 0xcf, 0x4f, 0x3c, 0xa9, 0xf5, 0xba, 0x40, 0xdb, 0x21, 1210 0x4c, 0x37, 0x98, 0xf2, 0xe1, 0xc2, 0x34, 0x56, 0x78, 0x9a 1211 ]; 1212 1213 auto crypt = IPCryptPFXCtx(key); 1214 1215 string ip_str = "2001:db8:3a5c::e7d1:4b9f:2c8a:f673"; 1216 const string expected = "7cec:702c:3503:bef:e616:96bd:be33:a9b9"; 1217 1218 char[IPCRYPT_MAX_IP_STR_BYTES] encrypted_ip_buf; 1219 size_t encrypted_ip_len = crypt.encryptIPStr(encrypted_ip_buf[], ip_str); 1220 assert(encrypted_ip_len > 0); 1221 string encrypted_ip = encrypted_ip_buf[0 .. encrypted_ip_len].idup; 1222 1223 assert(expected == encrypted_ip); 1224 } 1225 1226 // Test vector 15 1227 { 1228 ubyte[32] key = [ 1229 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 1230 0x88, 0x09, 0xcf, 0x4f, 0x3c, 0xa9, 0xf5, 0xba, 0x40, 0xdb, 0x21, 1231 0x4c, 0x37, 0x98, 0xf2, 0xe1, 0xc2, 0x34, 0x56, 0x78, 0x9a 1232 ]; 1233 1234 auto crypt = IPCryptPFXCtx(key); 1235 1236 string ip_str = "2001:db8:9f27::b4e2:7a3d:5f91:c8e6"; 1237 const string expected = "7cec:702c:a504:b74e:194a:3d90:b047:2d1a"; 1238 1239 char[IPCRYPT_MAX_IP_STR_BYTES] encrypted_ip_buf; 1240 size_t encrypted_ip_len = crypt.encryptIPStr(encrypted_ip_buf[], ip_str); 1241 assert(encrypted_ip_len > 0); 1242 string encrypted_ip = encrypted_ip_buf[0 .. encrypted_ip_len].idup; 1243 1244 assert(expected == encrypted_ip); 1245 } 1246 1247 // Test vector 16 1248 { 1249 ubyte[32] key = [ 1250 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 1251 0x88, 0x09, 0xcf, 0x4f, 0x3c, 0xa9, 0xf5, 0xba, 0x40, 0xdb, 0x21, 1252 0x4c, 0x37, 0x98, 0xf2, 0xe1, 0xc2, 0x34, 0x56, 0x78, 0x9a 1253 ]; 1254 1255 auto crypt = IPCryptPFXCtx(key); 1256 1257 string ip_str = "2001:db8:d8b4::193c:a5e7:8b2f:46d1"; 1258 const string expected = "7cec:702c:f840:aa67:1b8:e84f:ac9d:77fb"; 1259 1260 char[IPCRYPT_MAX_IP_STR_BYTES] encrypted_ip_buf; 1261 size_t encrypted_ip_len = crypt.encryptIPStr(encrypted_ip_buf[], ip_str); 1262 assert(encrypted_ip_len > 0); 1263 string encrypted_ip = encrypted_ip_buf[0 .. encrypted_ip_len].idup; 1264 1265 assert(expected == encrypted_ip); 1266 } 1267 } 1268 }