diff options
author | Frank Denis <github@pureftpd.org> | 2017-08-24 16:12:18 +0200 |
---|---|---|
committer | Frank Denis <github@pureftpd.org> | 2017-08-24 16:12:18 +0200 |
commit | 3691f3691317af3f4aa950f99e8446666a0e7d83 (patch) | |
tree | f52f62388786f8802275d8f003445d8fdac09f46 /ext/sodium | |
parent | 5cd348c1d606b890abae076a38e47effcfda79be (diff) | |
download | php-git-3691f3691317af3f4aa950f99e8446666a0e7d83.tar.gz |
sodium ext: add bindings for sodium_pad() and sodium_unpad()
Diffstat (limited to 'ext/sodium')
-rw-r--r-- | ext/sodium/libsodium.c | 143 | ||||
-rw-r--r-- | ext/sodium/php_libsodium.h | 2 | ||||
-rw-r--r-- | ext/sodium/tests/utils.phpt | 9 |
3 files changed, 154 insertions, 0 deletions
diff --git a/ext/sodium/libsodium.c b/ext/sodium/libsodium.c index b1128d9c29..82c43a1da1 100644 --- a/ext/sodium/libsodium.c +++ b/ext/sodium/libsodium.c @@ -64,6 +64,11 @@ ZEND_BEGIN_ARG_INFO_EX(AI_StringAndKey, 0, 0, 2) ZEND_ARG_INFO(0, key) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(AI_StringAndLength, 0, 0, 2) + ZEND_ARG_INFO(0, string) + ZEND_ARG_INFO(0, key) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(AI_StringAndKeyPair, 0, 0, 2) ZEND_ARG_INFO(0, string) ZEND_ARG_INFO(0, keypair) @@ -280,6 +285,9 @@ 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_pad, AI_StringAndLength) + PHP_FE(sodium_unpad, AI_StringAndLength) + PHP_FALIAS(sodium_crypto_scalarmult_base, sodium_crypto_box_publickey_from_secretkey, AI_TwoStrings) PHP_FE_END @@ -3118,6 +3126,141 @@ PHP_FUNCTION(sodium_crypto_kdf_derive_from_key) RETURN_STR(subkey); } +PHP_FUNCTION(sodium_pad) +{ + zend_string *padded; + char *unpadded; + zend_long blocksize; + volatile size_t st; + size_t i, j, k; + size_t unpadded_len; + size_t xpadlen; + size_t xpadded_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl", + &unpadded, &unpadded_len, &blocksize) == FAILURE) { + sodium_remove_param_values_from_backtrace(EG(exception)); + return; + } + if (blocksize <= 0) { + zend_throw_exception(sodium_exception_ce, "block size cannot be less than 1", 0); + return; + } + if (blocksize > SIZE_MAX) { + zend_throw_exception(sodium_exception_ce, "block size is too large", 0); + return; + } + xpadlen = blocksize - 1U; + if ((blocksize & (blocksize - 1U)) == 0U) { + xpadlen -= unpadded_len & ((size_t) blocksize - 1U); + } else { + xpadlen -= unpadded_len % (size_t) blocksize; + } + if ((size_t) SIZE_MAX - unpadded_len <= xpadlen) { + zend_throw_exception(sodium_exception_ce, "input is too large", 0); + return; + } + xpadded_len = unpadded_len + xpadlen; + padded = zend_string_alloc(xpadded_len + 1U, 0); + st = 1U; + i = 0U; + k = unpadded_len; + for (j = 0U; j <= xpadded_len; j++) { + ZSTR_VAL(padded)[j] = unpadded[i]; + k -= st; + st = (~(((((k >> 48) | (k >> 32) | (k >> 16) | k) & 0xffff) - 1U) >> 16)) & 1U; + i += st; + } +#if SODIUM_LIBRARY_VERSION_MAJOR > 9 || (SODIUM_LIBRARY_VERSION_MAJOR == 9 && SODIUM_LIBRARY_VERSION_MINOR >= 6) + if (sodium_pad(NULL, (unsigned char *) ZSTR_VAL(padded), unpadded_len, + (size_t) blocksize, xpadded_len + 1U) != 0) { + zend_throw_exception(sodium_exception_ce, "internal error", 0); + return; + } +#else + { + char *tail; + volatile unsigned char mask; + unsigned char barrier_mask; + + tail = &ZSTR_VAL(padded)[xpadded_len]; + mask = 0U; + for (i = 0; i < blocksize; i++) { + barrier_mask = (unsigned char) (((i ^ xpadlen) - 1U) >> 8); + tail[-i] = (tail[-i] & mask) | (0x80 & barrier_mask); + mask |= barrier_mask; + } + } +#endif + ZSTR_VAL(padded)[xpadded_len + 1U] = 0; + + RETURN_STR(padded); +} + +PHP_FUNCTION(sodium_unpad) +{ + zend_string *unpadded; + char *padded; + size_t padded_len; + size_t unpadded_len; + zend_long blocksize; + int ret; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl", + &padded, &padded_len, &blocksize) == FAILURE) { + sodium_remove_param_values_from_backtrace(EG(exception)); + return; + } + if (blocksize <= 0) { + zend_throw_exception(sodium_exception_ce, "block size cannot be less than 1", 0); + return; + } + if (blocksize > SIZE_MAX) { + zend_throw_exception(sodium_exception_ce, "block size is too large", 0); + return; + } + if (padded_len < blocksize) { + zend_throw_exception(sodium_exception_ce, "invalid padding", 0); + return; + } + +#if SODIUM_LIBRARY_VERSION_MAJOR > 9 || (SODIUM_LIBRARY_VERSION_MAJOR == 9 && SODIUM_LIBRARY_VERSION_MINOR >= 6) + ret = sodium_unpad(&unpadded_len, (const unsigned char *) padded, + padded_len, (size_t) blocksize); +#else + { + const char *tail; + unsigned char acc = 0U; + unsigned char c; + unsigned char valid = 0U; + volatile size_t pad_len = 0U; + size_t i; + size_t is_barrier; + + tail = &padded[padded_len - 1U]; + + for (i = 0U; i < (size_t) blocksize; i++) { + c = tail[-i]; + is_barrier = + (( (acc - 1U) & (pad_len - 1U) & ((c ^ 0x80) - 1U) ) >> 8) & 1U; + acc |= c; + pad_len |= (i & - is_barrier); + valid |= (unsigned char) is_barrier; + } + unpadded_len = padded_len - 1U - pad_len; + ret = (int) (valid - 1U); + } +#endif + if (ret != 0 || unpadded_len > LONG_MAX) { + zend_throw_exception(sodium_exception_ce, "invalid padding", 0); + return; + } + unpadded = zend_string_init(padded, padded_len, 0); + PHP_SODIUM_ZSTR_TRUNCATE(unpadded, unpadded_len); + ZSTR_VAL(unpadded)[unpadded_len] = 0; + RETURN_STR(unpadded); +} + /* * Local variables: * tab-width: 4 diff --git a/ext/sodium/php_libsodium.h b/ext/sodium/php_libsodium.h index af12e27c56..18d90f82f2 100644 --- a/ext/sodium/php_libsodium.h +++ b/ext/sodium/php_libsodium.h @@ -108,6 +108,8 @@ PHP_FUNCTION(sodium_hex2bin); PHP_FUNCTION(sodium_increment); PHP_FUNCTION(sodium_memcmp); PHP_FUNCTION(sodium_memzero); +PHP_FUNCTION(sodium_pad); +PHP_FUNCTION(sodium_unpad); #endif /* PHP_LIBSODIUM_H */ diff --git a/ext/sodium/tests/utils.phpt b/ext/sodium/tests/utils.phpt index c413e01a81..610ce99c16 100644 --- a/ext/sodium/tests/utils.phpt +++ b/ext/sodium/tests/utils.phpt @@ -46,6 +46,13 @@ $str = 'stdClass'; sodium_memzero($str); $obj = (object)array('foo' => 'bar'); var_dump($obj); + +$str = 'xyz'; +$str_padded = sodium_pad($str, 16); +var_dump(bin2hex($str_padded)); + +$str_unpadded = sodium_unpad($str_padded, 16); +var_dump($str_unpadded == $str); ?> --EXPECT-- 0 @@ -60,3 +67,5 @@ object(stdClass)#1 (1) { ["foo"]=> string(3) "bar" } +string(32) "78797a80000000000000000000000000" +bool(true) |