Skip to content

Commit 302a53d

Browse files
author
Yasuo Ohgaki
committed
Add timing safe comparison, compares chars by word size. It could be faster than simple byte by byte comparison
1 parent e0cc716 commit 302a53d

File tree

3 files changed

+53
-5
lines changed

3 files changed

+53
-5
lines changed

ext/standard/basic_functions.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2778,11 +2778,12 @@ const zend_function_entry basic_functions[] = { /* {{{ */
27782778
PHP_FE(str_split, arginfo_str_split)
27792779
PHP_FE(strpbrk, arginfo_strpbrk)
27802780
PHP_FE(substr_compare, arginfo_substr_compare)
2781-
PHP_FE(str_siphash_compare, arginfo_str_compare)
2782-
PHP_FE(str_xxhash32_compare, arginfo_str_compare)
2783-
PHP_FE(str_md5_compare, arginfo_str_compare)
2784-
PHP_FE(str_byte_compare, arginfo_str_compare)
2785-
PHP_FE(str_byte_compare2, arginfo_str_compare)
2781+
PHP_FE(str_siphash_compare, arginfo_str_compare)
2782+
PHP_FE(str_xxhash32_compare, arginfo_str_compare)
2783+
PHP_FE(str_md5_compare, arginfo_str_compare)
2784+
PHP_FE(str_byte_compare, arginfo_str_compare)
2785+
PHP_FE(str_byte_compare2, arginfo_str_compare)
2786+
PHP_FE(str_word_compare, arginfo_str_compare)
27862787
PHP_FE(str_compare, arginfo_str_compare)
27872788

27882789
#ifdef HAVE_STRCOLL

ext/standard/php_string.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ PHP_FUNCTION(str_xxhash32_compare);
9898
PHP_FUNCTION(str_md5_compare);
9999
PHP_FUNCTION(str_byte_compare);
100100
PHP_FUNCTION(str_byte_compare2);
101+
PHP_FUNCTION(str_word_compare);
101102
PHP_FUNCTION(str_compare);
102103
#ifdef HAVE_STRCOLL
103104
PHP_FUNCTION(strcoll);

ext/standard/string.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5754,6 +5754,7 @@ PHP_FUNCTION(str_byte_compare)
57545754
}
57555755
/* }}} */
57565756

5757+
57575758
/* {{{ proto bool str_compare2(string str1, string str2)
57585759
Timing safe string compare */
57595760
PHP_FUNCTION(str_byte_compare2)
@@ -5776,6 +5777,51 @@ PHP_FUNCTION(str_byte_compare2)
57765777
/* }}} */
57775778

57785779

5780+
/* Timing safe compare */
5781+
PHPAPI int php_word_compare(const void *b1, size_t b1_len, const void *b2, size_t b2_len) /* {{{ */
5782+
{
5783+
const unsigned char *p1 = b1, *p2 = b2;
5784+
long ret = b1_len - b2_len;
5785+
int mod_len = MAX(b1_len, 1);
5786+
int min_len = MIN(b1_len, b2_len);
5787+
int n, sz=sizeof(long);
5788+
5789+
/* Optimize by using word size comparison */
5790+
for (n = 0; n+sz < min_len ; n += sz) {
5791+
ret |= (long)p1 ^ (long)p2;
5792+
}
5793+
/* Comparet the rest, byte by byte */
5794+
for (; n < b2_len ; n++) {
5795+
ret |= p1[n % mod_len] ^ p2[n];
5796+
}
5797+
return (ret == 0);
5798+
}
5799+
/* }}} */
5800+
5801+
5802+
/* {{{ proto bool str_word_compare(string str1, string str2)
5803+
Timing safe string compare. Word size optimized. */
5804+
PHP_FUNCTION(str_word_compare)
5805+
{
5806+
zval *s1, *s2;
5807+
size_t mod_len;
5808+
long buf;
5809+
5810+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &s1, &s2) == FAILURE) {
5811+
RETURN_FALSE;
5812+
}
5813+
5814+
if (Z_TYPE_P(s1) != IS_STRING || Z_TYPE_P(s2) != IS_STRING) {
5815+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Paremeters must be string");
5816+
RETURN_FALSE;
5817+
}
5818+
5819+
RETURN_BOOL(php_word_compare(Z_STRVAL_P(s1), Z_STRLEN_P(s1),
5820+
Z_STRVAL_P(s2), Z_STRLEN_P(s2)));
5821+
}
5822+
/* }}} */
5823+
5824+
57795825
/* {{{ proto bool str_compare(string str1, string str2)
57805826
strncmp string compare */
57815827
PHP_FUNCTION(str_compare)

0 commit comments

Comments
 (0)