diff --git a/libsodium.c b/libsodium.c index 8337ae2..de4e020 100644 --- a/libsodium.c +++ b/libsodium.c @@ -38,6 +38,13 @@ ZEND_BEGIN_ARG_INFO_EX(AI_TwoStrings, 0, 0, 2) ZEND_ARG_INFO(0, string_2) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(AI_StringAndIdAndMaybeString, 0, 0, 2) + ZEND_ARG_INFO(0, string_1) + ZEND_ARG_INFO(0, id) + /* optional */ + ZEND_ARG_INFO(0, string_2) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(AI_StringRef_And_String, 0, 0, 2) ZEND_ARG_INFO(1, string_1) ZEND_ARG_INFO(0, string_2) @@ -53,6 +60,11 @@ ZEND_BEGIN_ARG_INFO_EX(AI_StringAndLength, 0, 0, 2) ZEND_ARG_INFO(0, length) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(AI_StringAndId, 0, 0, 2) + ZEND_ARG_INFO(0, string) + ZEND_ARG_INFO(0, id) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(AI_StringAndKeyPair, 0, 0, 2) ZEND_ARG_INFO(0, string) ZEND_ARG_INFO(0, keypair) @@ -239,9 +251,7 @@ const zend_function_entry sodium_functions[] = { PHP_FE(sodium_crypto_sign_verify_detached, AI_SignatureAndStringAndKey) PHP_FE(sodium_crypto_stream, AI_LengthAndNonceAndKey) PHP_FE(sodium_crypto_stream_xor, AI_StringAndNonceAndKey) - PHP_FE(sodium_bin2hex, AI_String) PHP_FE(sodium_compare, AI_TwoStrings) - PHP_FE(sodium_hex2bin, AI_TwoStrings) PHP_FE(sodium_increment, AI_StringRef) PHP_FE(sodium_add, AI_StringRef_And_String) PHP_FE(sodium_memcmp, AI_TwoStrings) @@ -262,6 +272,14 @@ const zend_function_entry sodium_functions[] = { PHP_FE(sodium_crypto_shorthash_keygen, AI_None) PHP_FE(sodium_crypto_stream_keygen, AI_None) + PHP_FE(sodium_bin2hex, AI_String) + PHP_FE(sodium_hex2bin, AI_TwoStrings) + +#ifdef sodium_base64_VARIANT_ORIGINAL + PHP_FE(sodium_bin2base64, AI_StringAndId) + PHP_FE(sodium_base642bin, AI_StringAndIdAndMaybeString) +#endif + PHP_FE(sodium_pad, AI_StringAndLength) PHP_FE(sodium_unpad, AI_StringAndLength) @@ -493,6 +511,16 @@ PHP_MINIT_FUNCTION(sodium) crypto_stream_NONCEBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_STREAM_KEYBYTES", crypto_stream_KEYBYTES, CONST_CS | CONST_PERSISTENT); +#ifdef sodium_base64_VARIANT_ORIGINAL + REGISTER_LONG_CONSTANT("SODIUM_BASE64_VARIANT_ORIGINAL", + sodium_base64_VARIANT_ORIGINAL, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING", + sodium_base64_VARIANT_ORIGINAL_NO_PADDING, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SODIUM_BASE64_VARIANT_URLSAFE", + sodium_base64_VARIANT_URLSAFE, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING", + sodium_base64_VARIANT_URLSAFE_NO_PADDING, CONST_CS | CONST_PERSISTENT); +#endif return SUCCESS; } @@ -2350,6 +2378,75 @@ PHP_FUNCTION(sodium_hex2bin) RETURN_STR(bin); } +#ifdef sodium_base64_VARIANT_ORIGINAL +PHP_FUNCTION(sodium_bin2base64) +{ + zend_string *b64; + unsigned char *bin; + zend_long variant; + size_t bin_len; + size_t b64_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl", + &bin, &bin_len, &variant) == FAILURE) { + return; + } + if ((((unsigned int) variant) & ~ 0x6U) != 0x1U) { + zend_throw_exception(sodium_exception_ce, + "invalid base64 variant identifier", 0); + return; + } + if (bin_len >= SIZE_MAX / 4U * 3U) { + zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); + return; + } + b64_len = bin_len * 4U / 3U; + b64 = zend_string_alloc((size_t) b64_len, 0); + sodium_bin2base64(ZSTR_VAL(b64), b64_len + 1U, + bin, bin_len, (int) variant); + ZSTR_VAL(b64)[b64_len] = 0; + + RETURN_STR(b64); +} + +PHP_FUNCTION(sodium_base642bin) +{ + zend_string *bin; + char *b64; + char *ignore = NULL; + zend_long variant; + size_t bin_real_len; + size_t bin_len; + size_t b64_len; + size_t ignore_len = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl|s", + &b64, &b64_len, &variant, + &ignore, &ignore_len) == FAILURE) { + return; + } + if ((((unsigned int) variant) & ~ 0x6U) != 0x1U) { + zend_throw_exception(sodium_exception_ce, + "invalid base64 variant identifier", 0); + return; + } + bin_len = b64_len / 4U * 3U; + bin = zend_string_alloc(bin_len, 0); + if (sodium_base642bin((unsigned char *) ZSTR_VAL(bin), bin_len, + b64, b64_len, + ignore, &bin_real_len, NULL, variant) != 0 || + bin_real_len >= SIZE_MAX || bin_real_len > bin_len) { + zend_string_free(bin); + zend_throw_exception(sodium_exception_ce, "arithmetic overflow", 0); + return; + } + PHP_SODIUM_ZSTR_TRUNCATE(bin, (size_t) bin_real_len); + ZSTR_VAL(bin)[bin_real_len] = 0; + + RETURN_STR(bin); +} +#endif + PHP_FUNCTION(sodium_crypto_scalarmult) { zend_string *q; diff --git a/php_libsodium.h b/php_libsodium.h index a86e0ac..997acbe 100644 --- a/php_libsodium.h +++ b/php_libsodium.h @@ -26,6 +26,8 @@ PHP_RSHUTDOWN_FUNCTION(sodium); PHP_MINFO_FUNCTION(sodium); PHP_FUNCTION(sodium_add); +PHP_FUNCTION(sodium_base642bin); +PHP_FUNCTION(sodium_bin2base64); PHP_FUNCTION(sodium_bin2hex); PHP_FUNCTION(sodium_compare); PHP_FUNCTION(sodium_crypto_aead_aes256gcm_decrypt); diff --git a/tests/utils.phpt b/tests/utils.phpt index 32894d3..938fc1a 100644 --- a/tests/utils.phpt +++ b/tests/utils.phpt @@ -53,6 +53,22 @@ var_dump(bin2hex($str_padded)); $str_unpadded = sodium_unpad($str_padded, 16); var_dump($str_unpadded == $str); + +if (defined('SODIUM_BASE64_VARIANT_ORIGINAL')) { + for ($i = 0; $i < 100; $i++) { + $bin = $i == 0 ? '' : random_bytes($i); + $b64 = base64_encode($bin); + if (sodium_bin2base64($bin, SODIUM_BASE64_VARIANT_ORIGINAL) !== $b64) { + echo "base64([$bin]) != [$b64]\n"; + } + if (sodium_base642bin($b64, SODIUM_BASE64_VARIANT_ORIGINAL) !== $bin) { + echo "bin([$b64]) != [$bin]\n"; + } + if (sodium_base642bin(" $b64\n", SODIUM_BASE64_VARIANT_ORIGINAL, " \n") !== $bin) { + echo "bin([ $b64\\n]) != [$bin]\n"; + } + } +} ?> --EXPECT-- 0