Skip to content

Commit 7e1f1b6

Browse files
committed
Ensure that weak keys are not used in ipcrypt_ndx and ipcrypt_pfx
Having keys with two identical halves is unlikely to ever happen if key have been sampled from a uniform distribution. If this happens, it reveals that the RNG is completely broken. Return an error code, and mask the second half in case the application doesn't care about error codes.
1 parent 079c949 commit 7e1f1b6

3 files changed

Lines changed: 74 additions & 26 deletions

File tree

src/include/ipcrypt2.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,10 @@ typedef struct IPCryptPFX {
217217
* The key must:
218218
* - Be exactly IPCRYPT_PFX_KEYBYTES bytes.
219219
* - Be secret and randomly generated.
220+
*
221+
* Returns 0 on success.
220222
*/
221-
void ipcrypt_pfx_init(IPCryptPFX *ipcrypt, const uint8_t key[IPCRYPT_PFX_KEYBYTES]);
223+
int ipcrypt_pfx_init(IPCryptPFX *ipcrypt, const uint8_t key[IPCRYPT_PFX_KEYBYTES]);
222224

223225
/**
224226
* Securely clear and deinitialize the IPCryptPFX context.
@@ -280,8 +282,10 @@ typedef struct IPCryptNDX {
280282
* The key must:
281283
* - Be exactly IPCRYPT_NDX_KEYBYTES bytes.
282284
* - Be secret and randomly generated.
285+
*
286+
* Returns 0 on success.
283287
*/
284-
void ipcrypt_ndx_init(IPCryptNDX *ipcrypt, const uint8_t key[IPCRYPT_NDX_KEYBYTES]);
288+
int ipcrypt_ndx_init(IPCryptNDX *ipcrypt, const uint8_t key[IPCRYPT_NDX_KEYBYTES]);
285289

286290
/**
287291
* Securely clear and deinitialize the IPCryptNDX context.

src/ipcrypt2.c

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -905,16 +905,38 @@ ipcrypt_deinit(IPCrypt *ipcrypt)
905905
/**
906906
* ipcrypt_pfx_init initializes the IPCryptPFX context with a 32-byte secret key.
907907
* This prepares the context for prefix-preserving IP address encryption operations.
908+
* Returns 0 on success.
908909
*/
909-
void
910+
int
910911
ipcrypt_pfx_init(IPCryptPFX *ipcrypt, const uint8_t key[IPCRYPT_PFX_KEYBYTES])
911912
{
912913
PFXState st;
914+
uint8_t diff[16];
915+
size_t i;
916+
uint8_t d;
913917

914918
expand_key(st.k1keys, key);
915919
expand_key(st.k2keys, key + 16);
920+
921+
/**
922+
* Ensure the two keys differ in case of misuse.
923+
*/
924+
STORE128(diff, XOR128(st.k1keys[ROUNDS / 2], st.k2keys[ROUNDS / 2]));
925+
d = 0;
926+
for (i = 0; i < 16; i++) {
927+
d |= diff[i];
928+
}
929+
if (d == 0) {
930+
for (i = 0; i < 16; i++) {
931+
diff[i] = key[i] ^ 0x5a;
932+
}
933+
expand_key(st.k2keys, diff);
934+
}
935+
916936
COMPILER_ASSERT(sizeof ipcrypt->opaque >= sizeof st);
917937
memcpy(ipcrypt->opaque, &st, sizeof st);
938+
939+
return -(d == 0);
918940
}
919941

920942
/**
@@ -1201,16 +1223,38 @@ ipcrypt_pfx_decrypt_ip_str(const IPCryptPFX *ipcrypt,
12011223
/**
12021224
* ipcrypt_init initializes an IPCrypt context with a 16-byte key.
12031225
* Expands the key into round keys and stores them in ipcrypt->opaque.
1226+
* Returns 0 on success.
12041227
*/
1205-
void
1228+
int
12061229
ipcrypt_ndx_init(IPCryptNDX *ipcrypt, const uint8_t key[IPCRYPT_NDX_KEYBYTES])
12071230
{
12081231
NDXState st;
1232+
uint8_t diff[16];
1233+
size_t i;
1234+
uint8_t d;
12091235

12101236
expand_key(st.tkeys, key + 16);
12111237
expand_key(st.rkeys, key);
1238+
1239+
/**
1240+
* Ensure the two keys differ in case of misuse.
1241+
*/
1242+
STORE128(diff, XOR128(st.tkeys[ROUNDS / 2], st.rkeys[ROUNDS / 2]));
1243+
d = 0;
1244+
for (i = 0; i < 16; i++) {
1245+
d |= diff[i];
1246+
}
1247+
if (d == 0) {
1248+
for (i = 0; i < 16; i++) {
1249+
diff[i] = key[i] ^ 0x5a;
1250+
}
1251+
expand_key(st.rkeys, diff);
1252+
}
1253+
12121254
COMPILER_ASSERT(sizeof ipcrypt->opaque >= sizeof st);
12131255
memcpy(ipcrypt->opaque, &st, sizeof st);
1256+
1257+
return -(d == 0);
12141258
}
12151259

12161260
/**

src/test/main.zig

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ test "binary ip NDX encryption and decryption" {
9797
const key = "0123456789abcdef1032547698badcfe";
9898
const tweak: [16]u8 = .{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
9999
var st: ipcrypt.IPCryptNDX = undefined;
100-
ipcrypt.ipcrypt_ndx_init(&st, key);
100+
_ = ipcrypt.ipcrypt_ndx_init(&st, key);
101101
defer ipcrypt.ipcrypt_ndx_deinit(&st);
102102
var encrypted_ip: [ipcrypt.IPCRYPT_NDX_NDIP_BYTES]u8 = undefined;
103103
ipcrypt.ipcrypt_ndx_encrypt_ip16(&st, &encrypted_ip, &ip, &tweak);
@@ -109,7 +109,7 @@ test "binary ip NDX encryption and decryption" {
109109
test "ip string NDX encryption and decryption" {
110110
const key = "0123456789abcdef1032547698badcfe";
111111
var st: ipcrypt.IPCryptNDX = undefined;
112-
ipcrypt.ipcrypt_ndx_init(&st, key);
112+
_ = ipcrypt.ipcrypt_ndx_init(&st, key);
113113
defer ipcrypt.ipcrypt_ndx_deinit(&st);
114114

115115
const ip_str = "1.2.3.4";
@@ -207,7 +207,7 @@ test "test vector 1 for ipcrypt-ndx" {
207207
var tweak: [16]u8 = undefined;
208208
_ = try std.fmt.hexToBytes(&tweak, tweak_hex);
209209
var st: ipcrypt.IPCryptNDX = undefined;
210-
ipcrypt.ipcrypt_ndx_init(&st, &key);
210+
_ = ipcrypt.ipcrypt_ndx_init(&st, &key);
211211
defer ipcrypt.ipcrypt_ndx_deinit(&st);
212212
var encrypted_ip_buf: [ipcrypt.IPCRYPT_NDX_NDIP_STR_BYTES:0]u8 = undefined;
213213
const encrypted_ip_len = ipcrypt.ipcrypt_ndx_encrypt_ip_str(&st, &encrypted_ip_buf, ip_str, &tweak);
@@ -225,7 +225,7 @@ test "test vector 2 for ipcrypt-ndx" {
225225
var tweak: [16]u8 = undefined;
226226
_ = try std.fmt.hexToBytes(&tweak, tweak_hex);
227227
var st: ipcrypt.IPCryptNDX = undefined;
228-
ipcrypt.ipcrypt_ndx_init(&st, &key);
228+
_ = ipcrypt.ipcrypt_ndx_init(&st, &key);
229229
defer ipcrypt.ipcrypt_ndx_deinit(&st);
230230
var encrypted_ip_buf: [ipcrypt.IPCRYPT_NDX_NDIP_STR_BYTES:0]u8 = undefined;
231231
const encrypted_ip_len = ipcrypt.ipcrypt_ndx_encrypt_ip_str(&st, &encrypted_ip_buf, ip_str, &tweak);
@@ -243,7 +243,7 @@ test "test vector 3 for ipcrypt-ndx" {
243243
var tweak: [16]u8 = undefined;
244244
_ = try std.fmt.hexToBytes(&tweak, tweak_hex);
245245
var st: ipcrypt.IPCryptNDX = undefined;
246-
ipcrypt.ipcrypt_ndx_init(&st, &key);
246+
_ = ipcrypt.ipcrypt_ndx_init(&st, &key);
247247
defer ipcrypt.ipcrypt_ndx_deinit(&st);
248248
var encrypted_ip_buf: [ipcrypt.IPCRYPT_NDX_NDIP_STR_BYTES:0]u8 = undefined;
249249
const encrypted_ip_len = ipcrypt.ipcrypt_ndx_encrypt_ip_str(&st, &encrypted_ip_buf, ip_str, &tweak);
@@ -311,7 +311,7 @@ test "ipcrypt-pfx round-trip" {
311311
_ = try std.fmt.hexToBytes(&key, key_hex);
312312

313313
var st: ipcrypt.IPCryptPFX = undefined;
314-
ipcrypt.ipcrypt_pfx_init(&st, &key);
314+
_ = ipcrypt.ipcrypt_pfx_init(&st, &key);
315315
defer ipcrypt.ipcrypt_pfx_deinit(&st);
316316

317317
// Test with IPv4 address string
@@ -365,7 +365,7 @@ test "ipcrypt-pfx test vectors from python reference" {
365365
_ = try std.fmt.hexToBytes(&key, key_hex);
366366

367367
var st: ipcrypt.IPCryptPFX = undefined;
368-
ipcrypt.ipcrypt_pfx_init(&st, &key);
368+
_ = ipcrypt.ipcrypt_pfx_init(&st, &key);
369369
defer ipcrypt.ipcrypt_pfx_deinit(&st);
370370

371371
const ip_str = "0.0.0.0";
@@ -385,7 +385,7 @@ test "ipcrypt-pfx test vectors from python reference" {
385385
_ = try std.fmt.hexToBytes(&key, key_hex);
386386

387387
var st: ipcrypt.IPCryptPFX = undefined;
388-
ipcrypt.ipcrypt_pfx_init(&st, &key);
388+
_ = ipcrypt.ipcrypt_pfx_init(&st, &key);
389389
defer ipcrypt.ipcrypt_pfx_deinit(&st);
390390

391391
const ip_str = "255.255.255.255";
@@ -405,7 +405,7 @@ test "ipcrypt-pfx test vectors from python reference" {
405405
_ = try std.fmt.hexToBytes(&key, key_hex);
406406

407407
var st: ipcrypt.IPCryptPFX = undefined;
408-
ipcrypt.ipcrypt_pfx_init(&st, &key);
408+
_ = ipcrypt.ipcrypt_pfx_init(&st, &key);
409409
defer ipcrypt.ipcrypt_pfx_deinit(&st);
410410

411411
const ip_str = "192.0.2.1";
@@ -425,7 +425,7 @@ test "ipcrypt-pfx test vectors from python reference" {
425425
_ = try std.fmt.hexToBytes(&key, key_hex);
426426

427427
var st: ipcrypt.IPCryptPFX = undefined;
428-
ipcrypt.ipcrypt_pfx_init(&st, &key);
428+
_ = ipcrypt.ipcrypt_pfx_init(&st, &key);
429429
defer ipcrypt.ipcrypt_pfx_deinit(&st);
430430

431431
const ip_str = "2001:db8::1";
@@ -446,7 +446,7 @@ test "ipcrypt-pfx test vectors from python reference" {
446446
_ = try std.fmt.hexToBytes(&key, key_hex);
447447

448448
var st: ipcrypt.IPCryptPFX = undefined;
449-
ipcrypt.ipcrypt_pfx_init(&st, &key);
449+
_ = ipcrypt.ipcrypt_pfx_init(&st, &key);
450450
defer ipcrypt.ipcrypt_pfx_deinit(&st);
451451

452452
const ip_str = "10.0.0.47";
@@ -466,7 +466,7 @@ test "ipcrypt-pfx test vectors from python reference" {
466466
_ = try std.fmt.hexToBytes(&key, key_hex);
467467

468468
var st: ipcrypt.IPCryptPFX = undefined;
469-
ipcrypt.ipcrypt_pfx_init(&st, &key);
469+
_ = ipcrypt.ipcrypt_pfx_init(&st, &key);
470470
defer ipcrypt.ipcrypt_pfx_deinit(&st);
471471

472472
const ip_str = "10.0.0.129";
@@ -486,7 +486,7 @@ test "ipcrypt-pfx test vectors from python reference" {
486486
_ = try std.fmt.hexToBytes(&key, key_hex);
487487

488488
var st: ipcrypt.IPCryptPFX = undefined;
489-
ipcrypt.ipcrypt_pfx_init(&st, &key);
489+
_ = ipcrypt.ipcrypt_pfx_init(&st, &key);
490490
defer ipcrypt.ipcrypt_pfx_deinit(&st);
491491

492492
const ip_str = "10.0.0.234";
@@ -506,7 +506,7 @@ test "ipcrypt-pfx test vectors from python reference" {
506506
_ = try std.fmt.hexToBytes(&key, key_hex);
507507

508508
var st: ipcrypt.IPCryptPFX = undefined;
509-
ipcrypt.ipcrypt_pfx_init(&st, &key);
509+
_ = ipcrypt.ipcrypt_pfx_init(&st, &key);
510510
defer ipcrypt.ipcrypt_pfx_deinit(&st);
511511

512512
const ip_str = "172.16.5.193";
@@ -526,7 +526,7 @@ test "ipcrypt-pfx test vectors from python reference" {
526526
_ = try std.fmt.hexToBytes(&key, key_hex);
527527

528528
var st: ipcrypt.IPCryptPFX = undefined;
529-
ipcrypt.ipcrypt_pfx_init(&st, &key);
529+
_ = ipcrypt.ipcrypt_pfx_init(&st, &key);
530530
defer ipcrypt.ipcrypt_pfx_deinit(&st);
531531

532532
const ip_str = "172.16.97.42";
@@ -546,7 +546,7 @@ test "ipcrypt-pfx test vectors from python reference" {
546546
_ = try std.fmt.hexToBytes(&key, key_hex);
547547

548548
var st: ipcrypt.IPCryptPFX = undefined;
549-
ipcrypt.ipcrypt_pfx_init(&st, &key);
549+
_ = ipcrypt.ipcrypt_pfx_init(&st, &key);
550550
defer ipcrypt.ipcrypt_pfx_deinit(&st);
551551

552552
const ip_str = "172.16.248.177";
@@ -567,7 +567,7 @@ test "ipcrypt-pfx test vectors from python reference" {
567567
_ = try std.fmt.hexToBytes(&key, key_hex);
568568

569569
var st: ipcrypt.IPCryptPFX = undefined;
570-
ipcrypt.ipcrypt_pfx_init(&st, &key);
570+
_ = ipcrypt.ipcrypt_pfx_init(&st, &key);
571571
defer ipcrypt.ipcrypt_pfx_deinit(&st);
572572

573573
const ip_str = "2001:db8::a5c9:4e2f:bb91:5a7d";
@@ -587,7 +587,7 @@ test "ipcrypt-pfx test vectors from python reference" {
587587
_ = try std.fmt.hexToBytes(&key, key_hex);
588588

589589
var st: ipcrypt.IPCryptPFX = undefined;
590-
ipcrypt.ipcrypt_pfx_init(&st, &key);
590+
_ = ipcrypt.ipcrypt_pfx_init(&st, &key);
591591
defer ipcrypt.ipcrypt_pfx_deinit(&st);
592592

593593
const ip_str = "2001:db8::7234:d8f1:3c6e:9a52";
@@ -607,7 +607,7 @@ test "ipcrypt-pfx test vectors from python reference" {
607607
_ = try std.fmt.hexToBytes(&key, key_hex);
608608

609609
var st: ipcrypt.IPCryptPFX = undefined;
610-
ipcrypt.ipcrypt_pfx_init(&st, &key);
610+
_ = ipcrypt.ipcrypt_pfx_init(&st, &key);
611611
defer ipcrypt.ipcrypt_pfx_deinit(&st);
612612

613613
const ip_str = "2001:db8::f1e0:937b:26d4:8c1a";
@@ -627,7 +627,7 @@ test "ipcrypt-pfx test vectors from python reference" {
627627
_ = try std.fmt.hexToBytes(&key, key_hex);
628628

629629
var st: ipcrypt.IPCryptPFX = undefined;
630-
ipcrypt.ipcrypt_pfx_init(&st, &key);
630+
_ = ipcrypt.ipcrypt_pfx_init(&st, &key);
631631
defer ipcrypt.ipcrypt_pfx_deinit(&st);
632632

633633
const ip_str = "2001:db8:3a5c::e7d1:4b9f:2c8a:f673";
@@ -647,7 +647,7 @@ test "ipcrypt-pfx test vectors from python reference" {
647647
_ = try std.fmt.hexToBytes(&key, key_hex);
648648

649649
var st: ipcrypt.IPCryptPFX = undefined;
650-
ipcrypt.ipcrypt_pfx_init(&st, &key);
650+
_ = ipcrypt.ipcrypt_pfx_init(&st, &key);
651651
defer ipcrypt.ipcrypt_pfx_deinit(&st);
652652

653653
const ip_str = "2001:db8:9f27::b4e2:7a3d:5f91:c8e6";
@@ -667,7 +667,7 @@ test "ipcrypt-pfx test vectors from python reference" {
667667
_ = try std.fmt.hexToBytes(&key, key_hex);
668668

669669
var st: ipcrypt.IPCryptPFX = undefined;
670-
ipcrypt.ipcrypt_pfx_init(&st, &key);
670+
_ = ipcrypt.ipcrypt_pfx_init(&st, &key);
671671
defer ipcrypt.ipcrypt_pfx_deinit(&st);
672672

673673
const ip_str = "2001:db8:d8b4::193c:a5e7:8b2f:46d1";

0 commit comments

Comments
 (0)