Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,11 @@ PHP NEWS
. Fixed bug GH-24315 (Harden SoapClient cross-origin redirect handling).
(Ilia Alshanetsky)

- Sodium:
. sodium_crypto_ipcrypt_nd_encrypt() and sodium_crypto_ipcrypt_ndx_encrypt()
accept an optional tweak. Omitting it still generates a random one.
(rafamolina1)

- SPL:
. Fixed bug GH-23385 (SplDoublyLinkedList::serialize() use-after-free when
__serialize() removes an element). (David Carlier)
Expand Down
5 changes: 5 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ PHP 8.7 UPGRADE NOTES
5. Changed Functions
========================================

- Sodium:
. sodium_crypto_ipcrypt_nd_encrypt() and sodium_crypto_ipcrypt_ndx_encrypt()
accept an optional $tweak argument. Omitting it keeps the previous
behavior of generating a random tweak.

- Standard:
. stream_select() no longer fails once a watched descriptor exceeds
FD_SETSIZE. The descriptor set now grows on demand on both POSIX (bitset)
Expand Down
42 changes: 32 additions & 10 deletions ext/sodium/libsodium.c
Original file line number Diff line number Diff line change
Expand Up @@ -4193,26 +4193,37 @@ PHP_FUNCTION(sodium_crypto_ipcrypt_nd_encrypt)
size_t ip_len;
unsigned char *key;
size_t key_len;
char *tweak = NULL;
size_t tweak_len = 0;
unsigned char bin[crypto_ipcrypt_ND_INPUTBYTES];
unsigned char tweak[crypto_ipcrypt_ND_TWEAKBYTES];
unsigned char tweak_buf[crypto_ipcrypt_ND_TWEAKBYTES];
const unsigned char *tweak_ptr;
unsigned char encrypted[crypto_ipcrypt_ND_OUTPUTBYTES];
char hex_out[crypto_ipcrypt_ND_OUTPUTBYTES * 2 + 1];

if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
&ip, &ip_len, &key, &key_len) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|s!",
&ip, &ip_len, &key, &key_len, &tweak, &tweak_len) == FAILURE) {
sodium_remove_param_values_from_backtrace(EG(exception));
RETURN_THROWS();
}
if (key_len != crypto_ipcrypt_ND_KEYBYTES) {
zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_IPCRYPT_ND_KEYBYTES bytes long");
RETURN_THROWS();
}
if (tweak == NULL) {
randombytes_buf(tweak_buf, sizeof tweak_buf);
tweak_ptr = tweak_buf;
} else if (tweak_len != crypto_ipcrypt_ND_TWEAKBYTES) {
zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_IPCRYPT_ND_TWEAKBYTES bytes long");
RETURN_THROWS();
} else {
tweak_ptr = (const unsigned char *) tweak;
}
if (sodium_ip2bin(bin, ip, ip_len) != 0) {
zend_argument_error(sodium_exception_ce, 1, "must be a valid IP address");
RETURN_THROWS();
}
randombytes_buf(tweak, sizeof tweak);
crypto_ipcrypt_nd_encrypt(encrypted, bin, tweak, key);
crypto_ipcrypt_nd_encrypt(encrypted, bin, tweak_ptr, key);
sodium_bin2hex(hex_out, sizeof hex_out, encrypted, sizeof encrypted);
RETURN_STRINGL(hex_out, crypto_ipcrypt_ND_OUTPUTBYTES * 2);
}
Expand Down Expand Up @@ -4269,26 +4280,37 @@ PHP_FUNCTION(sodium_crypto_ipcrypt_ndx_encrypt)
size_t ip_len;
unsigned char *key;
size_t key_len;
char *tweak = NULL;
size_t tweak_len = 0;
unsigned char bin[crypto_ipcrypt_NDX_INPUTBYTES];
unsigned char tweak[crypto_ipcrypt_NDX_TWEAKBYTES];
unsigned char tweak_buf[crypto_ipcrypt_NDX_TWEAKBYTES];
const unsigned char *tweak_ptr;
unsigned char encrypted[crypto_ipcrypt_NDX_OUTPUTBYTES];
char hex_out[crypto_ipcrypt_NDX_OUTPUTBYTES * 2 + 1];

if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
&ip, &ip_len, &key, &key_len) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|s!",
&ip, &ip_len, &key, &key_len, &tweak, &tweak_len) == FAILURE) {
sodium_remove_param_values_from_backtrace(EG(exception));
RETURN_THROWS();
}
if (key_len != crypto_ipcrypt_NDX_KEYBYTES) {
zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_IPCRYPT_NDX_KEYBYTES bytes long");
RETURN_THROWS();
}
if (tweak == NULL) {
randombytes_buf(tweak_buf, sizeof tweak_buf);
tweak_ptr = tweak_buf;
} else if (tweak_len != crypto_ipcrypt_NDX_TWEAKBYTES) {
zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_IPCRYPT_NDX_TWEAKBYTES bytes long");
RETURN_THROWS();
} else {
tweak_ptr = (const unsigned char *) tweak;
}
if (sodium_ip2bin(bin, ip, ip_len) != 0) {
zend_argument_error(sodium_exception_ce, 1, "must be a valid IP address");
RETURN_THROWS();
}
randombytes_buf(tweak, sizeof tweak);
crypto_ipcrypt_ndx_encrypt(encrypted, bin, tweak, key);
crypto_ipcrypt_ndx_encrypt(encrypted, bin, tweak_ptr, key);
sodium_bin2hex(hex_out, sizeof hex_out, encrypted, sizeof encrypted);
RETURN_STRINGL(hex_out, crypto_ipcrypt_NDX_OUTPUTBYTES * 2);
}
Expand Down
4 changes: 2 additions & 2 deletions ext/sodium/libsodium.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -871,13 +871,13 @@ function sodium_crypto_ipcrypt_decrypt(string $encrypted_ip, #[\SensitiveParamet

function sodium_crypto_ipcrypt_nd_keygen(): string {}

function sodium_crypto_ipcrypt_nd_encrypt(string $ip, #[\SensitiveParameter] string $key): string {}
function sodium_crypto_ipcrypt_nd_encrypt(string $ip, #[\SensitiveParameter] string $key, ?string $tweak = null): string {}

function sodium_crypto_ipcrypt_nd_decrypt(string $ciphertext_hex, #[\SensitiveParameter] string $key): string {}

function sodium_crypto_ipcrypt_ndx_keygen(): string {}

function sodium_crypto_ipcrypt_ndx_encrypt(string $ip, #[\SensitiveParameter] string $key): string {}
function sodium_crypto_ipcrypt_ndx_encrypt(string $ip, #[\SensitiveParameter] string $key, ?string $tweak = null): string {}

function sodium_crypto_ipcrypt_ndx_decrypt(string $ciphertext_hex, #[\SensitiveParameter] string $key): string {}

Expand Down
10 changes: 7 additions & 3 deletions ext/sodium/libsodium_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions ext/sodium/tests/crypto_ipcrypt.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ var_dump(sodium_crypto_ipcrypt_decrypt($enc6, $key));
$gen_key = sodium_crypto_ipcrypt_keygen();
var_dump(strlen($gen_key) === SODIUM_CRYPTO_IPCRYPT_KEYBYTES);

/* Known answer: draft-denis-ipcrypt A.1 vector 3 */
$kat_key = sodium_hex2bin("2b7e151628aed2a6abf7158809cf4f3c");
$kat = sodium_crypto_ipcrypt_encrypt("192.0.2.1", $kat_key);
var_dump($kat);
var_dump(sodium_crypto_ipcrypt_decrypt($kat, $kat_key));

/* Error: wrong key length */
try {
sodium_crypto_ipcrypt_encrypt("192.168.1.1", "short");
Expand Down Expand Up @@ -58,6 +64,8 @@ bool(true)
bool(true)
string(3) "::1"
bool(true)
string(39) "1dbd:c1b9:fff1:7586:7d0b:67b4:e76e:4777"
string(9) "192.0.2.1"
sodium_crypto_ipcrypt_encrypt(): Argument #2 ($key) must be SODIUM_CRYPTO_IPCRYPT_KEYBYTES bytes long
sodium_crypto_ipcrypt_encrypt(): Argument #1 ($ip) must be a valid IP address
sodium_crypto_ipcrypt_decrypt(): Argument #2 ($key) must be SODIUM_CRYPTO_IPCRYPT_KEYBYTES bytes long
34 changes: 34 additions & 0 deletions ext/sodium/tests/crypto_ipcrypt_nd.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@ try {
echo $e->getMessage() . "\n";
}

/* Known answer: draft-denis-ipcrypt A.3 vector 1 */
$nd_kat_key = sodium_hex2bin("0123456789abcdeffedcba9876543210");
$nd_tweak = sodium_hex2bin("08e0c289bff23b7c");
$nd_kat = sodium_crypto_ipcrypt_nd_encrypt("0.0.0.0", $nd_kat_key, $nd_tweak);
var_dump($nd_kat);
var_dump(sodium_crypto_ipcrypt_nd_decrypt($nd_kat, $nd_kat_key));

/* ND error: wrong tweak length */
try {
sodium_crypto_ipcrypt_nd_encrypt("192.168.1.1", $nd_key, "short");
} catch (SodiumException $e) {
echo $e->getMessage() . "\n";
}

/* ND error: bad ciphertext hex length */
try {
sodium_crypto_ipcrypt_nd_decrypt("tooshort", $nd_key);
Expand Down Expand Up @@ -72,6 +86,20 @@ try {
echo $e->getMessage() . "\n";
}

/* Known answer: draft-denis-ipcrypt A.4 vector 1 */
$ndx_kat_key = sodium_hex2bin("0123456789abcdeffedcba98765432101032547698badcfeefcdab8967452301");
$ndx_tweak = sodium_hex2bin("21bd1834bc088cd2b4ecbe30b70898d7");
$ndx_kat = sodium_crypto_ipcrypt_ndx_encrypt("0.0.0.0", $ndx_kat_key, $ndx_tweak);
var_dump($ndx_kat);
var_dump(sodium_crypto_ipcrypt_ndx_decrypt($ndx_kat, $ndx_kat_key));

/* NDX error: wrong tweak length */
try {
sodium_crypto_ipcrypt_ndx_encrypt("10.0.0.1", $ndx_key, "short");
} catch (SodiumException $e) {
echo $e->getMessage() . "\n";
}

/* NDX error: bad ciphertext hex */
try {
sodium_crypto_ipcrypt_ndx_decrypt("tooshort", $ndx_key);
Expand All @@ -88,11 +116,17 @@ string(11) "192.168.1.1"
string(3) "::1"
sodium_crypto_ipcrypt_nd_encrypt(): Argument #2 ($key) must be SODIUM_CRYPTO_IPCRYPT_ND_KEYBYTES bytes long
sodium_crypto_ipcrypt_nd_encrypt(): Argument #1 ($ip) must be a valid IP address
string(48) "08e0c289bff23b7cb349aadfe3bcef56221c384c7c217b16"
string(7) "0.0.0.0"
sodium_crypto_ipcrypt_nd_encrypt(): Argument #3 ($tweak) must be SODIUM_CRYPTO_IPCRYPT_ND_TWEAKBYTES bytes long
sodium_crypto_ipcrypt_nd_decrypt(): Argument #1 ($ciphertext_hex) must be a valid hex-encoded ciphertext
bool(true)
bool(true)
string(8) "10.0.0.1"
bool(true)
string(7) "fe80::1"
sodium_crypto_ipcrypt_ndx_encrypt(): Argument #2 ($key) must be SODIUM_CRYPTO_IPCRYPT_NDX_KEYBYTES bytes long
string(64) "21bd1834bc088cd2b4ecbe30b70898d782db0d4125fdace61db35b8339f20ee5"
string(7) "0.0.0.0"
sodium_crypto_ipcrypt_ndx_encrypt(): Argument #3 ($tweak) must be SODIUM_CRYPTO_IPCRYPT_NDX_TWEAKBYTES bytes long
sodium_crypto_ipcrypt_ndx_decrypt(): Argument #1 ($ciphertext_hex) must be a valid hex-encoded ciphertext
15 changes: 15 additions & 0 deletions ext/sodium/tests/crypto_ipcrypt_pfx.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,17 @@ var_dump(filter_var($enc6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false);
$gen_key = sodium_crypto_ipcrypt_pfx_keygen();
var_dump(strlen($gen_key) === SODIUM_CRYPTO_IPCRYPT_PFX_KEYBYTES);

/* Known answer: draft-denis-ipcrypt A.2.1 vector 3 */
$kat_key = sodium_hex2bin("0123456789abcdeffedcba98765432101032547698badcfeefcdab8967452301");
$kat = sodium_crypto_ipcrypt_pfx_encrypt("192.0.2.1", $kat_key);
var_dump($kat);
var_dump(sodium_crypto_ipcrypt_pfx_decrypt($kat, $kat_key));

/* Same /24 stays in the same encrypted /24 (A.2.2) */
$pfx_key = sodium_hex2bin("2b7e151628aed2a6abf7158809cf4f3ca9f5ba40db214c3798f2e1c23456789a");
var_dump(sodium_crypto_ipcrypt_pfx_encrypt("10.0.0.47", $pfx_key));
var_dump(sodium_crypto_ipcrypt_pfx_encrypt("10.0.0.129", $pfx_key));

/* PFX error: wrong key length */
try {
sodium_crypto_ipcrypt_pfx_encrypt("10.0.0.1", "short");
Expand Down Expand Up @@ -61,6 +72,10 @@ bool(true)
string(3) "::1"
bool(true)
bool(true)
string(14) "100.115.72.131"
string(9) "192.0.2.1"
string(14) "19.214.210.244"
string(13) "19.214.210.80"
sodium_crypto_ipcrypt_pfx_encrypt(): Argument #2 ($key) must be SODIUM_CRYPTO_IPCRYPT_PFX_KEYBYTES bytes long
sodium_crypto_ipcrypt_pfx_encrypt(): Argument #1 ($ip) must be a valid IP address
sodium_crypto_ipcrypt_pfx_decrypt(): Argument #2 ($key) must be SODIUM_CRYPTO_IPCRYPT_PFX_KEYBYTES bytes long
Loading