@@ -487,13 +487,32 @@ static inline void php_hash_hmac_round(unsigned char *final, const php_hash_ops
487487 ops -> hash_final (final , context );
488488}
489489
490+ /* Computes HMAC(key, data) using the given hash algorithm and writes the
491+ * result into `digest`, which must be at least ops->digest_size bytes.
492+ * Intended for internal (C-level) use by other extensions; avoids the
493+ * zval/zend_string overhead of the userland hash_hmac() API. */
494+ PHPAPI void php_hash_hmac (const php_hash_ops * ops , const unsigned char * key , size_t key_len ,
495+ const unsigned char * data , size_t data_len , unsigned char * digest )
496+ {
497+ void * context = php_hash_alloc_context (ops );
498+ unsigned char * K = emalloc (ops -> block_size );
499+
500+ php_hash_hmac_prep_key (K , ops , context , key , key_len );
501+ php_hash_hmac_round (digest , ops , context , K , data , data_len );
502+
503+ php_hash_string_xor_char (K , K , 0x6A , ops -> block_size );
504+ php_hash_hmac_round (digest , ops , context , K , digest , ops -> digest_size );
505+
506+ ZEND_SECURE_ZERO (K , ops -> block_size );
507+ efree (K );
508+ php_hash_free_context (ops , context );
509+ }
510+
490511static void php_hash_do_hash_hmac (
491512 zval * return_value , zend_string * algo , char * data , size_t data_len , char * key , size_t key_len , bool raw_output , bool isfilename
492513) /* {{{ */ {
493514 zend_string * digest ;
494- unsigned char * K ;
495515 const php_hash_ops * ops ;
496- void * context ;
497516 php_stream * stream = NULL ;
498517
499518 ops = php_hash_fetch_ops (algo );
@@ -514,16 +533,16 @@ static void php_hash_do_hash_hmac(
514533 }
515534 }
516535
517- context = php_hash_alloc_context (ops );
518-
519- K = emalloc (ops -> block_size );
520536 digest = zend_string_alloc (ops -> digest_size , 0 );
521537
522- php_hash_hmac_prep_key (K , ops , context , (unsigned char * ) key , key_len );
523-
524538 if (isfilename ) {
539+ void * context = php_hash_alloc_context (ops );
540+ unsigned char * K = emalloc (ops -> block_size );
525541 char buf [1024 ];
526542 ssize_t n ;
543+
544+ php_hash_hmac_prep_key (K , ops , context , (unsigned char * ) key , key_len );
545+
527546 ops -> hash_init (context , NULL );
528547 ops -> hash_update (context , K , ops -> block_size );
529548 while ((n = php_stream_read (stream , buf , sizeof (buf ))) > 0 ) {
@@ -536,20 +555,17 @@ static void php_hash_do_hash_hmac(
536555 zend_string_efree (digest );
537556 RETURN_FALSE ;
538557 }
539-
540558 ops -> hash_final ((unsigned char * ) ZSTR_VAL (digest ), context );
541- } else {
542- php_hash_hmac_round ((unsigned char * ) ZSTR_VAL (digest ), ops , context , K , (unsigned char * ) data , data_len );
543- }
544-
545- php_hash_string_xor_char (K , K , 0x6A , ops -> block_size );
546559
547- php_hash_hmac_round ((unsigned char * ) ZSTR_VAL (digest ), ops , context , K , (unsigned char * ) ZSTR_VAL (digest ), ops -> digest_size );
560+ php_hash_string_xor_char (K , K , 0x6A , ops -> block_size );
561+ php_hash_hmac_round ((unsigned char * ) ZSTR_VAL (digest ), ops , context , K , (unsigned char * ) ZSTR_VAL (digest ), ops -> digest_size );
548562
549- /* Zero the key */
550- ZEND_SECURE_ZERO (K , ops -> block_size );
551- efree (K );
552- php_hash_free_context (ops , context );
563+ ZEND_SECURE_ZERO (K , ops -> block_size );
564+ efree (K );
565+ php_hash_free_context (ops , context );
566+ } else {
567+ php_hash_hmac (ops , (unsigned char * ) key , key_len , (unsigned char * ) data , data_len , (unsigned char * ) ZSTR_VAL (digest ));
568+ }
553569
554570 if (raw_output ) {
555571 ZSTR_VAL (digest )[ops -> digest_size ] = 0 ;
0 commit comments