Skip to content
Open
Show file tree
Hide file tree
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
52 changes: 34 additions & 18 deletions ext/hash/hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -487,13 +487,32 @@ static inline void php_hash_hmac_round(unsigned char *final, const php_hash_ops
ops->hash_final(final, context);
}

/* Computes HMAC(key, data) using the given hash algorithm and writes the
* result into `digest`, which must be at least ops->digest_size bytes.
* Intended for internal (C-level) use by other extensions; avoids the
* zval/zend_string overhead of the userland hash_hmac() API. */
PHPAPI void php_hash_hmac(const php_hash_ops *ops, const unsigned char *key, size_t key_len,
const unsigned char *data, size_t data_len, unsigned char *digest)
{
void *context = php_hash_alloc_context(ops);
unsigned char *K = emalloc(ops->block_size);

php_hash_hmac_prep_key(K, ops, context, key, key_len);
php_hash_hmac_round(digest, ops, context, K, data, data_len);

php_hash_string_xor_char(K, K, 0x6A, ops->block_size);
php_hash_hmac_round(digest, ops, context, K, digest, ops->digest_size);

ZEND_SECURE_ZERO(K, ops->block_size);
efree(K);
php_hash_free_context(ops, 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
) /* {{{ */ {
zend_string *digest;
unsigned char *K;
const php_hash_ops *ops;
void *context;
php_stream *stream = NULL;

ops = php_hash_fetch_ops(algo);
Expand All @@ -514,16 +533,16 @@ static void php_hash_do_hash_hmac(
}
}

context = php_hash_alloc_context(ops);

K = emalloc(ops->block_size);
digest = zend_string_alloc(ops->digest_size, 0);

php_hash_hmac_prep_key(K, ops, context, (unsigned char *) key, key_len);

if (isfilename) {
void *context = php_hash_alloc_context(ops);
unsigned char *K = emalloc(ops->block_size);
char buf[1024];
ssize_t n;

php_hash_hmac_prep_key(K, ops, context, (unsigned char *) key, key_len);

ops->hash_init(context, NULL);
ops->hash_update(context, K, ops->block_size);
while ((n = php_stream_read(stream, buf, sizeof(buf))) > 0) {
Expand All @@ -536,20 +555,17 @@ static void php_hash_do_hash_hmac(
zend_string_efree(digest);
RETURN_FALSE;
}

ops->hash_final((unsigned char *) ZSTR_VAL(digest), context);
} else {
php_hash_hmac_round((unsigned char *) ZSTR_VAL(digest), ops, context, K, (unsigned char *) data, data_len);
}

php_hash_string_xor_char(K, K, 0x6A, ops->block_size);

php_hash_hmac_round((unsigned char *) ZSTR_VAL(digest), ops, context, K, (unsigned char *) ZSTR_VAL(digest), ops->digest_size);
php_hash_string_xor_char(K, K, 0x6A, ops->block_size);
php_hash_hmac_round((unsigned char *) ZSTR_VAL(digest), ops, context, K, (unsigned char *) ZSTR_VAL(digest), ops->digest_size);

/* Zero the key */
ZEND_SECURE_ZERO(K, ops->block_size);
efree(K);
php_hash_free_context(ops, context);
ZEND_SECURE_ZERO(K, ops->block_size);
efree(K);
php_hash_free_context(ops, context);
} else {
php_hash_hmac(ops, (unsigned char *) key, key_len, (unsigned char *) data, data_len, (unsigned char *) ZSTR_VAL(digest));
}

if (raw_output) {
ZSTR_VAL(digest)[ops->digest_size] = 0;
Expand Down
2 changes: 2 additions & 0 deletions ext/hash/php_hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ PHP_HASH_API hash_spec_result php_hash_serialize(const php_hashcontext_object *c
PHP_HASH_API hash_spec_result php_hash_unserialize(php_hashcontext_object *context, zend_long magic, const zval *zv);
PHP_HASH_API hash_spec_result php_hash_serialize_spec(const php_hashcontext_object *context, zval *zv, const char *spec);
PHP_HASH_API hash_spec_result php_hash_unserialize_spec(php_hashcontext_object *hash, const zval *zv, const char *spec);
PHP_HASH_API void php_hash_hmac(const php_hash_ops *ops, const unsigned char *key, size_t key_len,
const unsigned char *data, size_t data_len, unsigned char *digest);

static inline void *php_hash_alloc_context(const php_hash_ops *ops) {
/* Zero out context memory so serialization doesn't expose internals */
Expand Down
2 changes: 2 additions & 0 deletions ext/standard/config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -457,5 +457,7 @@ PHP_NEW_EXTENSION([standard], m4_normalize([

PHP_ADD_BUILD_DIR([$ext_builddir/libavifinfo])

PHP_ADD_EXTENSION_DEP([standard], [hash])

PHP_ADD_MAKEFILE_FRAGMENT
PHP_INSTALL_HEADERS([ext/standard/])
Loading
Loading