From: Sara Golemon Date: Thu, 1 Dec 2005 04:53:55 +0000 (+0000) Subject: Add hash_hmac() and hash_hmac_file() for single shot HMAC calculations X-Git-Tag: RELEASE_2_0_2~12 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=73012ee25776c7c01a85bd695eb7295fd5031aba;p=php Add hash_hmac() and hash_hmac_file() for single shot HMAC calculations --- diff --git a/ext/hash/hash.c b/ext/hash/hash.c index 8597041ae9..c1f1b097e9 100644 --- a/ext/hash/hash.c +++ b/ext/hash/hash.c @@ -137,6 +137,116 @@ PHP_FUNCTION(hash_file) { } /* }}} */ +static void php_hash_do_hash_hmac(INTERNAL_FUNCTION_PARAMETERS, int isfilename) +{ + char *algo, *data, *digest, *key, *K; + int algo_len, data_len, key_len, i; + zend_bool raw_output = 0; + php_hash_ops *ops; + void *context; + php_stream *stream = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|b", &algo, &algo_len, &data, &data_len, + &key, &key_len, &raw_output) == FAILURE) { + return; + } + + ops = php_hash_fetch_ops(algo, algo_len); + if (!ops) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown hashing algorithm: %s", algo); + RETURN_FALSE; + } + if (isfilename) { + stream = php_stream_open_wrapper_ex(data, "rb", REPORT_ERRORS | ENFORCE_SAFE_MODE, NULL, DEFAULT_CONTEXT); + if (!stream) { + /* Stream will report errors opening file */ + RETURN_FALSE; + } + } + + context = emalloc(ops->context_size); + ops->hash_init(context); + + K = emalloc(ops->block_size); + memset(K, 0, ops->block_size); + + if (key_len > ops->block_size) { + /* Reduce the key first */ + ops->hash_update(context, key, key_len); + ops->hash_final(K, context); + /* Make the context ready to start over */ + ops->hash_init(context); + } else { + memcpy(K, key, key_len); + } + + /* XOR ipad */ + for(i=0; i < ops->block_size; i++) { + K[i] ^= 0x36; + } + ops->hash_update(context, K, ops->block_size); + + if (isfilename) { + char buf[1024]; + int n; + + while ((n = php_stream_read(stream, buf, sizeof(buf))) > 0) { + ops->hash_update(context, buf, n); + } + php_stream_close(stream); + } else { + ops->hash_update(context, data, data_len); + } + + digest = emalloc(ops->digest_size + 1); + ops->hash_final(digest, context); + + /* Convert K to opad -- 0x6A = 0x36 ^ 0x5C */ + for(i=0; i < ops->block_size; i++) { + K[i] ^= 0x6A; + } + + /* Feed this result into the outter hash */ + ops->hash_init(context); + ops->hash_update(context, K, ops->block_size); + ops->hash_update(context, digest, ops->digest_size); + ops->hash_final(digest, context); + + /* Zero the key */ + memset(K, 0, ops->block_size); + efree(K); + efree(context); + + if (raw_output) { + digest[ops->digest_size] = 0; + RETURN_STRINGL(digest, ops->digest_size, 0); + } else { + char *hex_digest = safe_emalloc(ops->digest_size, 2, 1); + + php_hash_bin2hex(hex_digest, digest, ops->digest_size); + hex_digest[2 * ops->digest_size] = 0; + efree(digest); + RETURN_STRINGL(hex_digest, 2 * ops->digest_size, 0); + } +} + +/* {{{ proto string hash_hmac(string algo, string data, string key[, bool raw_output = false]) +Generate a hash of a given input string with a key using HMAC +Returns lowercase hexits by default */ +PHP_FUNCTION(hash_hmac) { + php_hash_do_hash_hmac(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); +} +/* }}} */ + +/* {{{ proto string hash_hmac_file(string algo, string filename, string key[, bool raw_output = false]) +Generate a hash of a given file with a key using HMAC +Returns lowercase hexits by default */ +PHP_FUNCTION(hash_hmac_file) { + php_hash_do_hash_hmac(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); +} +/* }}} */ + + /* {{{ proto resource hash_init(string algo[, int options, string key]) Initialize a hashing context */ PHP_FUNCTION(hash_init) @@ -489,6 +599,9 @@ function_entry hash_functions[] = { PHP_FE(hash, NULL) PHP_FE(hash_file, NULL) + PHP_FE(hash_hmac, NULL) + PHP_FE(hash_hmac_file, NULL) + PHP_FE(hash_init, NULL) PHP_FE(hash_update, NULL) PHP_FE(hash_update_stream, NULL) diff --git a/ext/hash/tests/hmac-md5.phpt b/ext/hash/tests/hmac-md5.phpt index 3069f8a56f..283285a544 100644 --- a/ext/hash/tests/hmac-md5.phpt +++ b/ext/hash/tests/hmac-md5.phpt @@ -13,9 +13,7 @@ $ctx = hash_init('md5',HASH_HMAC,'Jefe'); hash_update($ctx, 'what do ya want for nothing?'); echo hash_final($ctx) . "\n"; -$ctx = hash_init('md5',HASH_HMAC,str_repeat(chr(0xAA), 16)); -hash_update($ctx, str_repeat(chr(0xDD), 50)); -echo hash_final($ctx) . "\n"; +echo hash_hmac('md5', str_repeat(chr(0xDD), 50), str_repeat(chr(0xAA), 16)) . "\n"; --EXPECT-- 9294727a3638bb1c13f48ef8158bfc9d 750c783e6ab0b503eaa86e310a5db738