summaryrefslogtreecommitdiff
path: root/ext/sodium
diff options
context:
space:
mode:
authorFrank Denis <github@pureftpd.org>2017-08-24 16:12:18 +0200
committerFrank Denis <github@pureftpd.org>2017-08-24 16:12:18 +0200
commit3691f3691317af3f4aa950f99e8446666a0e7d83 (patch)
treef52f62388786f8802275d8f003445d8fdac09f46 /ext/sodium
parent5cd348c1d606b890abae076a38e47effcfda79be (diff)
downloadphp-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.c143
-rw-r--r--ext/sodium/php_libsodium.h2
-rw-r--r--ext/sodium/tests/utils.phpt9
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)