Skip to content

Commit baefd51

Browse files
committed
Improve the performance of PBKDF2
1 parent 3a2f9cb commit baefd51

1 file changed

Lines changed: 22 additions & 5 deletions

File tree

‎ext/hash/hash.c‎

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,12 @@ static inline void php_hash_hmac_round(unsigned char *final, const php_hash_ops
487487
ops->hash_final(final, context);
488488
}
489489

490+
static inline void php_hash_hmac_round_with_copy(unsigned char *final, const php_hash_ops *ops, const void *base_context, void *context, const unsigned char *data, const zend_long data_size) {
491+
ops->hash_copy(ops, base_context, context);
492+
ops->hash_update(context, data, data_size);
493+
ops->hash_final(final, context);
494+
}
495+
490496
static void php_hash_do_hash_hmac(
491497
zval *return_value, zend_string *algo, char *data, size_t data_len, char *key, size_t key_len, bool raw_output, bool isfilename
492498
) /* {{{ */ {
@@ -982,7 +988,7 @@ PHP_FUNCTION(hash_pbkdf2)
982988
size_t pass_len, salt_len = 0;
983989
bool raw_output = false;
984990
const php_hash_ops *ops;
985-
void *context;
991+
void *context, *inner_context, *outer_context;
986992
HashTable *args = NULL;
987993

988994
if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sssl|lbh", &algo, &pass, &pass_len, &salt, &salt_len, &iterations, &length, &raw_output, &args) == FAILURE) {
@@ -1013,6 +1019,9 @@ PHP_FUNCTION(hash_pbkdf2)
10131019
context = php_hash_alloc_context(ops);
10141020
ops->hash_init(context, args);
10151021

1022+
inner_context = php_hash_alloc_context(ops);
1023+
outer_context = php_hash_alloc_context(ops);
1024+
10161025
K1 = emalloc(ops->block_size);
10171026
K2 = emalloc(ops->block_size);
10181027
digest = emalloc(ops->digest_size);
@@ -1023,6 +1032,12 @@ PHP_FUNCTION(hash_pbkdf2)
10231032
/* Convert K1 to opad -- 0x6A = 0x36 ^ 0x5C */
10241033
php_hash_string_xor_char(K2, K1, 0x6A, ops->block_size);
10251034

1035+
/* Precompute the hash states after absorbing the ipad and opad blocks */
1036+
ops->hash_init(inner_context, NULL);
1037+
ops->hash_update(inner_context, K1, ops->block_size);
1038+
ops->hash_init(outer_context, NULL);
1039+
ops->hash_update(outer_context, K2, ops->block_size);
1040+
10261041
/* Setup Main Loop to build a long enough result */
10271042
if (length == 0) {
10281043
length = ops->digest_size;
@@ -1051,8 +1066,8 @@ PHP_FUNCTION(hash_pbkdf2)
10511066
computed_salt[salt_len + 2] = (unsigned char) ((i & 0xFF00) >> 8);
10521067
computed_salt[salt_len + 3] = (unsigned char) (i & 0xFF);
10531068

1054-
php_hash_hmac_round(digest, ops, context, K1, computed_salt, (zend_long) salt_len + 4);
1055-
php_hash_hmac_round(digest, ops, context, K2, digest, ops->digest_size);
1069+
php_hash_hmac_round_with_copy(digest, ops, inner_context, context, computed_salt, (zend_long) salt_len + 4);
1070+
php_hash_hmac_round_with_copy(digest, ops, outer_context, context, digest, ops->digest_size);
10561071
/* } */
10571072

10581073
/* temp = digest */
@@ -1064,8 +1079,8 @@ PHP_FUNCTION(hash_pbkdf2)
10641079
*/
10651080
for (j = 1; j < iterations; j++) {
10661081
/* digest = hash_hmac(digest, password) { */
1067-
php_hash_hmac_round(digest, ops, context, K1, digest, ops->digest_size);
1068-
php_hash_hmac_round(digest, ops, context, K2, digest, ops->digest_size);
1082+
php_hash_hmac_round_with_copy(digest, ops, inner_context, context, digest, ops->digest_size);
1083+
php_hash_hmac_round_with_copy(digest, ops, outer_context, context, digest, ops->digest_size);
10691084
/* } */
10701085
/* temp ^= digest */
10711086
php_hash_string_xor(temp, temp, digest, ops->digest_size);
@@ -1081,6 +1096,8 @@ PHP_FUNCTION(hash_pbkdf2)
10811096
efree(K2);
10821097
efree(computed_salt);
10831098
php_hash_free_context(ops, context);
1099+
php_hash_free_context(ops, inner_context);
1100+
php_hash_free_context(ops, outer_context);
10841101
efree(digest);
10851102
efree(temp);
10861103

0 commit comments

Comments
 (0)