Hi all,
Anyone mind if I make a PHPAPI for this?
--
Yasuo Ohgaki
[email protected]
On Mon, Mar 17, 2014 at 5:37 PM, Adam Harvey <[email protected]> wrote:
> Commit: 2148a88b3d6d8b25151e2da168c37f5e3bdfd22b
> Author: Rouven Weßling <[email protected]> Sun, 10 Nov 2013
> 22:37:10 +0100
> Parents: 2499b6518c4b0112c79295145d5f09d3658c31f4
> Branches: PHP-5.6 master
>
> Link:
> http://git.php.net/?p=php-src.git;a=commitdiff;h=2148a88b3d6d8b25151e2da168c37f5e3bdfd22b
>
> Log:
> Add hash_equals() to perform string comparisons that are not vulnerable to
> timing attacks.
>
> Changed paths:
> M NEWS
> M UPGRADING
> M ext/hash/hash.c
> M ext/hash/php_hash.h
> A ext/hash/tests/hash_equals.phpt
>
>
> Diff:
> diff --git a/NEWS b/NEWS
> index c5fbb6c..a2f563b 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -30,6 +30,8 @@ PHP
> NEWS
> - Hash:
> . Fixed bug #66698 (Missing FNV1a32 and FNV1a64 hash functions).
> (Michael M Slusarz).
> + . Implemented timing attack safe string comparison function
> + (RFC: https://wiki.php.net/rfc/timing_attack). (Rouven
> Weßling)
>
> - Intl:
> . Fixed bug #66873 (A reproductible crash in UConverter when given
> invalid
> diff --git a/UPGRADING b/UPGRADING
> index 9cfc0a6..8b20f51 100755
> --- a/UPGRADING
> +++ b/UPGRADING
> @@ -71,6 +71,9 @@ PHP 5.6 UPGRADE NOTES
> - Added use function and use const.
> (https://wiki.php.net/rfc/use_function)
>
> +- Added a function for timing attack safe string comparison
> + (https://wiki.php.net/rfc/timing_attack)
> +
> - Added gost-crypto (CryptoPro S-box) hash algorithm.
>
> - Stream wrappers verify peer certificates and host names by default in
> @@ -182,6 +185,9 @@ PHP 5.6 UPGRADE NOTES
> 5. New Functions
> ========================================
>
> +- Hash
> + Added hash_equals($known_string, $user_string)
> +
> - GMP:
> Added gmp_root($a, $nth) and gmp_rootrem($a, $nth) for calculating nth
> roots.
>
> diff --git a/ext/hash/hash.c b/ext/hash/hash.c
> index 41c7a70..f14437d 100644
> --- a/ext/hash/hash.c
> +++ b/ext/hash/hash.c
> @@ -728,6 +728,46 @@ PHP_FUNCTION(hash_pbkdf2)
> }
> /* }}} */
>
> +/* {{{ proto bool hash_equals(string known_string, string user_string)
> + Compares two strings using the same time whether they're equal or not..
> + A difference in length will leak */
> +PHP_FUNCTION(hash_equals)
> +{
> + zval *known_zval, *user_zval;
> + char *known_str, *user_str;
> + int result = 0, j;
> +
> + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz",
> &known_zval, &user_zval) == FAILURE) {
> + return;
> + }
> +
> + /* We only allow comparing string to prevent unexpected results. */
> + if (Z_TYPE_P(known_zval) != IS_STRING) {
> + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected
> known_string to be a string, %s given", zend_zval_type_name(known_zval));
> + RETURN_FALSE;
> + }
> +
> + if (Z_TYPE_P(user_zval) != IS_STRING) {
> + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expected
> user_string to be a string, %s given", zend_zval_type_name(user_zval));
> + RETURN_FALSE;
> + }
> +
> + if (Z_STRLEN_P(known_zval) != Z_STRLEN_P(user_zval)) {
> + RETURN_FALSE;
> + }
> +
> + known_str = Z_STRVAL_P(known_zval);
> + user_str = Z_STRVAL_P(user_zval);
> +
> + /* This is security sensitive code. Do not optimize this for
> speed. */
> + for (j = 0; j < Z_STRLEN_P(known_zval); j++) {
> + result |= known_str[j] ^ user_str[j];
> + }
> +
> + RETURN_BOOL(0 == result);
> +}
> +/* }}} */
> +
> /* Module Housekeeping */
>
> static void php_hash_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */
> @@ -1152,6 +1192,11 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_hash_pbkdf2, 0, 0, 4)
> ZEND_ARG_INFO(0, raw_output)
> ZEND_END_ARG_INFO()
>
> +ZEND_BEGIN_ARG_INFO(arginfo_hash_equals, 0)
> + ZEND_ARG_INFO(0, known_string)
> + ZEND_ARG_INFO(0, user_string)
> +ZEND_END_ARG_INFO()
> +
> /* BC Land */
> #ifdef PHP_MHASH_BC
> ZEND_BEGIN_ARG_INFO(arginfo_mhash_get_block_size, 0)
> @@ -1199,6 +1244,7 @@ const zend_function_entry hash_functions[] = {
>
> PHP_FE(hash_algos,
> arginfo_hash_algos)
> PHP_FE(hash_pbkdf2,
> arginfo_hash_pbkdf2)
> + PHP_FE(hash_equals,
> arginfo_hash_equals)
>
> /* BC Land */
> #ifdef PHP_HASH_MD5_NOT_IN_CORE
> diff --git a/ext/hash/php_hash.h b/ext/hash/php_hash.h
> index c5cb660..c75b930 100644
> --- a/ext/hash/php_hash.h
> +++ b/ext/hash/php_hash.h
> @@ -136,6 +136,7 @@ PHP_FUNCTION(hash_update_file);
> PHP_FUNCTION(hash_final);
> PHP_FUNCTION(hash_algos);
> PHP_FUNCTION(hash_pbkdf2);
> +PHP_FUNCTION(hash_equals);
>
> PHP_HASH_API const php_hash_ops *php_hash_fetch_ops(const char *algo, int
> algo_len);
> PHP_HASH_API void php_hash_register_algo(const char *algo, const
> php_hash_ops *ops);
> diff --git a/ext/hash/tests/hash_equals.phpt
> b/ext/hash/tests/hash_equals.phpt
> new file mode 100644
> index 0000000..8f87985
> --- /dev/null
> +++ b/ext/hash/tests/hash_equals.phpt
> @@ -0,0 +1,43 @@
> +--TEST--
> +hash_equals() function
> +--FILE--
> +<?php
> +var_dump(hash_equals("same", "same"));
> +var_dump(hash_equals("not1same", "not2same"));
> +var_dump(hash_equals("short", "longer"));
> +var_dump(hash_equals("longer", "short"));
> +var_dump(hash_equals("", "notempty"));
> +var_dump(hash_equals("notempty", ""));
> +var_dump(hash_equals("", ""));
> +var_dump(hash_equals(123, "NaN"));
> +var_dump(hash_equals("NaN", 123));
> +var_dump(hash_equals(123, 123));
> +var_dump(hash_equals(null, ""));
> +var_dump(hash_equals(null, 123));
> +var_dump(hash_equals(null, null));
> +--EXPECTF--
> +bool(true)
> +bool(false)
> +bool(false)
> +bool(false)
> +bool(false)
> +bool(false)
> +bool(true)
> +
> +Warning: hash_equals(): Expected known_string to be a string, integer
> given in %s on line %d
> +bool(false)
> +
> +Warning: hash_equals(): Expected user_string to be a string, integer
> given in %s on line %d
> +bool(false)
> +
> +Warning: hash_equals(): Expected known_string to be a string, integer
> given in %s on line %d
> +bool(false)
> +
> +Warning: hash_equals(): Expected known_string to be a string, null given
> in %s on line %d
> +bool(false)
> +
> +Warning: hash_equals(): Expected known_string to be a string, null given
> in %s on line %d
> +bool(false)
> +
> +Warning: hash_equals(): Expected known_string to be a string, null given
> in %s on line %d
> +bool(false)
>
>
> --
> PHP CVS Mailing List (http://www.php.net/)
> To unsubscribe, visit: http://www.php.net/unsub.php
>
>