Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions ext/hash/hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,12 @@ static inline void php_hash_hmac_round(unsigned char *final, const php_hash_ops
ops->hash_final(final, context);
}

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) {
ZEND_ASSERT(SUCCESS == ops->hash_copy(ops, base_context, context));
ops->hash_update(context, data, data_size);
ops->hash_final(final, context);
}

static void php_hash_do_hash_hmac(
zval *return_value, zend_string *algo, char *data, size_t data_len, char *key, size_t key_len, bool raw_output, bool isfilename
) /* {{{ */ {
Expand Down Expand Up @@ -982,7 +988,7 @@ PHP_FUNCTION(hash_pbkdf2)
size_t pass_len, salt_len = 0;
bool raw_output = false;
const php_hash_ops *ops;
void *context;
void *context, *inner_context, *outer_context;
HashTable *args = NULL;

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

inner_context = php_hash_alloc_context(ops);
outer_context = php_hash_alloc_context(ops);

K1 = emalloc(ops->block_size);
K2 = emalloc(ops->block_size);
digest = emalloc(ops->digest_size);
Expand All @@ -1023,6 +1032,12 @@ PHP_FUNCTION(hash_pbkdf2)
/* Convert K1 to opad -- 0x6A = 0x36 ^ 0x5C */
php_hash_string_xor_char(K2, K1, 0x6A, ops->block_size);

/* Precompute the hash states after absorbing the ipad and opad blocks */
ops->hash_init(inner_context, NULL);
ops->hash_update(inner_context, K1, ops->block_size);
ops->hash_init(outer_context, NULL);
ops->hash_update(outer_context, K2, ops->block_size);

/* Setup Main Loop to build a long enough result */
if (length == 0) {
length = ops->digest_size;
Expand Down Expand Up @@ -1051,8 +1066,8 @@ PHP_FUNCTION(hash_pbkdf2)
computed_salt[salt_len + 2] = (unsigned char) ((i & 0xFF00) >> 8);
computed_salt[salt_len + 3] = (unsigned char) (i & 0xFF);

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

/* temp = digest */
Expand All @@ -1064,8 +1079,8 @@ PHP_FUNCTION(hash_pbkdf2)
*/
for (j = 1; j < iterations; j++) {
/* digest = hash_hmac(digest, password) { */
php_hash_hmac_round(digest, ops, context, K1, digest, ops->digest_size);
php_hash_hmac_round(digest, ops, context, K2, digest, ops->digest_size);
php_hash_hmac_round_with_copy(digest, ops, inner_context, context, digest, ops->digest_size);
php_hash_hmac_round_with_copy(digest, ops, outer_context, context, digest, ops->digest_size);
/* } */
/* temp ^= digest */
php_hash_string_xor(temp, temp, digest, ops->digest_size);
Expand All @@ -1081,6 +1096,8 @@ PHP_FUNCTION(hash_pbkdf2)
efree(K2);
efree(computed_salt);
php_hash_free_context(ops, context);
php_hash_free_context(ops, inner_context);
php_hash_free_context(ops, outer_context);
efree(digest);
efree(temp);

Expand Down
Loading