@@ -497,6 +497,12 @@ static inline void php_hash_hmac_round(unsigned char *final, const php_hash_ops
497497 ops -> hash_final (final , context );
498498}
499499
500+ 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 ) {
501+ ZEND_ASSERT (SUCCESS == ops -> hash_copy (ops , base_context , context ));
502+ ops -> hash_update (context , data , data_size );
503+ ops -> hash_final (final , context );
504+ }
505+
500506static void php_hash_do_hash_hmac (
501507 zval * return_value , zend_string * algo , char * data , size_t data_len , char * key , size_t key_len , bool raw_output , bool isfilename
502508) /* {{{ */ {
@@ -996,7 +1002,7 @@ PHP_FUNCTION(hash_pbkdf2)
9961002 size_t pass_len , salt_len = 0 ;
9971003 bool raw_output = 0 ;
9981004 const php_hash_ops * ops ;
999- void * context ;
1005+ void * context , * inner_context , * outer_context ;
10001006 HashTable * args = NULL ;
10011007
10021008 if (zend_parse_parameters (ZEND_NUM_ARGS (), "Sssl|lbh" , & algo , & pass , & pass_len , & salt , & salt_len , & iterations , & length , & raw_output , & args ) == FAILURE ) {
@@ -1027,6 +1033,9 @@ PHP_FUNCTION(hash_pbkdf2)
10271033 context = php_hash_alloc_context (ops );
10281034 ops -> hash_init (context , args );
10291035
1036+ inner_context = php_hash_alloc_context (ops );
1037+ outer_context = php_hash_alloc_context (ops );
1038+
10301039 K1 = emalloc (ops -> block_size );
10311040 K2 = emalloc (ops -> block_size );
10321041 digest = emalloc (ops -> digest_size );
@@ -1037,6 +1046,12 @@ PHP_FUNCTION(hash_pbkdf2)
10371046 /* Convert K1 to opad -- 0x6A = 0x36 ^ 0x5C */
10381047 php_hash_string_xor_char (K2 , K1 , 0x6A , ops -> block_size );
10391048
1049+ /* Precompute the hash states after absorbing the ipad and opad blocks */
1050+ ops -> hash_init (inner_context , NULL );
1051+ ops -> hash_update (inner_context , K1 , ops -> block_size );
1052+ ops -> hash_init (outer_context , NULL );
1053+ ops -> hash_update (outer_context , K2 , ops -> block_size );
1054+
10401055 /* Setup Main Loop to build a long enough result */
10411056 if (length == 0 ) {
10421057 length = ops -> digest_size ;
@@ -1065,8 +1080,8 @@ PHP_FUNCTION(hash_pbkdf2)
10651080 computed_salt [salt_len + 2 ] = (unsigned char ) ((i & 0xFF00 ) >> 8 );
10661081 computed_salt [salt_len + 3 ] = (unsigned char ) (i & 0xFF );
10671082
1068- php_hash_hmac_round (digest , ops , context , K1 , computed_salt , (zend_long ) salt_len + 4 );
1069- php_hash_hmac_round (digest , ops , context , K2 , digest , ops -> digest_size );
1083+ php_hash_hmac_round_with_copy (digest , ops , inner_context , context , computed_salt , (zend_long ) salt_len + 4 );
1084+ php_hash_hmac_round_with_copy (digest , ops , outer_context , context , digest , ops -> digest_size );
10701085 /* } */
10711086
10721087 /* temp = digest */
@@ -1078,8 +1093,8 @@ PHP_FUNCTION(hash_pbkdf2)
10781093 */
10791094 for (j = 1 ; j < iterations ; j ++ ) {
10801095 /* digest = hash_hmac(digest, password) { */
1081- php_hash_hmac_round (digest , ops , context , K1 , digest , ops -> digest_size );
1082- php_hash_hmac_round (digest , ops , context , K2 , digest , ops -> digest_size );
1096+ php_hash_hmac_round_with_copy (digest , ops , inner_context , context , digest , ops -> digest_size );
1097+ php_hash_hmac_round_with_copy (digest , ops , outer_context , context , digest , ops -> digest_size );
10831098 /* } */
10841099 /* temp ^= digest */
10851100 php_hash_string_xor (temp , temp , digest , ops -> digest_size );
@@ -1095,6 +1110,8 @@ PHP_FUNCTION(hash_pbkdf2)
10951110 efree (K2 );
10961111 efree (computed_salt );
10971112 efree (context );
1113+ efree (inner_context );
1114+ efree (outer_context );
10981115 efree (digest );
10991116 efree (temp );
11001117
0 commit comments