@@ -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+
490496static 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