Skip to content

Double speed of PBKDF2 #1387

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
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
51 changes: 35 additions & 16 deletions ext/hash/hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,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_continue(unsigned char *final, const php_hash_ops *ops, void *start_context, void *context, const unsigned char *data, const long data_size) {
ops->hash_copy(ops, start_context, context);
ops->hash_update(context, data, data_size);
ops->hash_final(final, context);
}

static void php_hash_do_hash_hmac(INTERNAL_FUNCTION_PARAMETERS, int isfilename, zend_bool raw_output_default) /* {{{ */
{
char *algo, *data, *digest, *key, *K;
Expand Down Expand Up @@ -615,12 +621,12 @@ Returns lowercase hexits by default */
PHP_FUNCTION(hash_pbkdf2)
{
char *returnval, *algo, *salt, *pass;
unsigned char *computed_salt, *digest, *temp, *result, *K1, *K2;
unsigned char *computed_salt, *digest, *temp, *result, *K;
long loops, i, j, iterations, length = 0, digest_length;
int algo_len, pass_len, salt_len;
zend_bool raw_output = 0;
const php_hash_ops *ops;
void *context;
void *context, *inner_context, *outer_context;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sssl|lb", &algo, &algo_len, &pass, &pass_len, &salt, &salt_len, &iterations, &length, &raw_output) == FAILURE) {
return;
Expand All @@ -647,18 +653,28 @@ PHP_FUNCTION(hash_pbkdf2)
RETURN_FALSE;
}

/* inner_context: hash of the key block ^ 0x36
* outer_context: hash of the key block ^ 0x5c
* context: misc scratch hashing context */
inner_context = emalloc(ops->context_size);
outer_context = emalloc(ops->context_size);
context = emalloc(ops->context_size);
ops->hash_init(context);

K1 = emalloc(ops->block_size);
K2 = emalloc(ops->block_size);
K = emalloc(ops->block_size);
digest = emalloc(ops->digest_size);
temp = emalloc(ops->digest_size);

/* Setup Keys that will be used for all hmac rounds */
php_hash_hmac_prep_key(K1, ops, context, (unsigned char *) pass, pass_len);
/* Convert K1 to opad -- 0x6A = 0x36 ^ 0x5C */
php_hash_string_xor_char(K2, K1, 0x6A, ops->block_size);
php_hash_hmac_prep_key(K, ops, context, (unsigned char *) pass, pass_len);

ops->hash_init(inner_context);
ops->hash_update(inner_context, K, ops->block_size);

/* Convert K from ipad to opad -- 0x6A = 0x36 ^ 0x5C */
php_hash_string_xor_char(K, K, 0x6A, ops->block_size);

ops->hash_init(outer_context);
ops->hash_update(outer_context, K, ops->block_size);

/* Setup Main Loop to build a long enough result */
if (length == 0) {
Expand Down Expand Up @@ -688,8 +704,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, (long) salt_len + 4);
php_hash_hmac_round(digest, ops, context, K2, digest, ops->digest_size);
php_hash_hmac_continue(digest, ops, inner_context, context ,computed_salt, (long) salt_len + 4);
php_hash_hmac_continue(digest, ops, outer_context, context, digest, ops->digest_size);
/* } */

/* temp = digest */
Expand All @@ -701,8 +717,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_continue(digest, ops, inner_context, context, digest, ops->digest_size);
php_hash_hmac_continue(digest, ops, outer_context, context, digest, ops->digest_size);
/* } */
/* temp ^= digest */
php_hash_string_xor(temp, temp, digest, ops->digest_size);
Expand All @@ -711,12 +727,15 @@ PHP_FUNCTION(hash_pbkdf2)
memcpy(result + ((i - 1) * ops->digest_size), temp, ops->digest_size);
}
/* Zero potentially sensitive variables */
memset(K1, 0, ops->block_size);
memset(K2, 0, ops->block_size);
memset(K, 0, ops->block_size);
memset(computed_salt, 0, salt_len + 4);
efree(K1);
efree(K2);
memset(inner_context, 0, ops->context_size);
memset(outer_context, 0, ops->context_size);
memset(context, 0, ops->context_size);
efree(K);
efree(computed_salt);
efree(inner_context);
efree(outer_context);
efree(context);
efree(digest);
efree(temp);
Expand Down