Skip to content

Commit

Permalink
sodium ext: add bindings for sodium_pad() and sodium_unpad()
Browse files Browse the repository at this point in the history
  • Loading branch information
jedisct1 committed Aug 24, 2017
1 parent 5cd348c commit 3691f36
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 0 deletions.
143 changes: 143 additions & 0 deletions ext/sodium/libsodium.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions ext/sodium/php_libsodium.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand Down
9 changes: 9 additions & 0 deletions ext/sodium/tests/utils.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -60,3 +67,5 @@ object(stdClass)#1 (1) {
["foo"]=>
string(3) "bar"
}
string(32) "78797a80000000000000000000000000"
bool(true)

0 comments on commit 3691f36

Please sign in to comment.