2010-09-30 // HMAC-SHA-1 for PHP
Hash-based Message Authentication Codes (HMAC)1) are very useful. Especially HMAC-SHA-1 is used by more and more webservices (e.g. Amazon S3) to verify if a request comes from a valid user (by using a shared secret/key + submitting the result of HMAC-SHA-1($request)
). The easiest way to generate them – hash_hmac() – is only available for PHP > 5.1.2 and I saw many system where the function is not available. I even saw people installing the whole PEAR system just to get PEAR::Crypt_HMAC
running.
If you need a simple function for creating SHA-1 based HMACs, you may be interested in the following:
- hmac-sha1.php
<?php /** * Returns the HMAC-SHA-1 of a string * * @param string The data to hash. * @param string The key to use. Use ASCII only for best compatibility. * Otherwise, you have to take care about using the same encoding in * every case. * @param bool (optional) TRUE leads to PHP warnings if a non-ASCII-string was * submitted as key. FALSE will suppress this check. Default is TRUE. * @return string The HMAC-SHA1 of the data. * @author Andreas Haerter * @link http://en.wikipedia.org/wiki/HMAC * @link http://tools.ietf.org/html/rfc2104 * @link http://blog.andreas-haerter.com/2010/09/30/hmac-sha-1-php * @license GPLv2 (http://www.gnu.org/licenses/gpl2.html) * @license New/3-clause BSD (http://opensource.org/licenses/bsd-license.php) */ function hmac_sha1($str, $key, $warn_nonasciikey = true) { //check: key consists of ASCII chars only? //this should prevent unexpected (=not equal results) when mixing this //implementation and base64_encode(hash_hmac("sha1", $str, $key, true)) //regarding different encodings etc. if (!empty($warn_nonasciikey) //search for any bytes which are outside the ASCII range... //note: the regex is *REALLY* fast. Even a "quickcheck" with ctype_alnum() // won't make the things faster but slower on *common* input! && preg_match('/(?:[^\x00-\x7F])/u', $key) === 1) { //ATTENTION: single quotes are needed here! Otherwise, PCRE is not able to find the ending delimiter! //inform developers trigger_error(//text __FUNCTION__.":non-ASCII key may lead to unexpected results when switching encodings!", //type E_USER_WARNING); } //use PHP's built in functionality if available (~20% faster than the //following script implementation) if (function_exists("hash_hmac")) { return base64_encode(hash_hmac("sha1", $str, $key, true)); } //create the secret based on the given key $key_lenght = strlen($key); //key is longer than 64 bytes, use the hash of it if ($key_lenght > 64) { $key = sha1($key); $key_length = 40; } //pad secret with 0x0 to get a 64 byte secret? if ($key_lenght < 64) { $secret = $key.str_repeat(chr(0), (64 - $key_lenght)); } else { //64 bytes long, we can use the key directly $secret = $key; } //hash and return it return base64_encode(sha1(//create the string we have to hash ($secret^str_repeat(chr(0x5c), 64)). //pad the key for inner digest //subhash sha1(//create substring we have to hash ($secret^str_repeat(chr(0x36), 64)). //pad the key for outer digest $str, //we need RAW output! true), //we need RAW output! true)); } //example echo hmac_sha1("this is the data to hash", "my secret key, ASCII only for best compatibility"); ?>
The source code of this function is dual-licensed under GPLv2 and New/3-clause BSD. Have fun.
Leave a comment…
- E-Mail address will not be published.
- Formatting:
//italic// __underlined__
**bold**''preformatted''
- Links:
[[http://example.com]]
[[http://example.com|Link Text]] - Quotation:
> This is a quote. Don't forget the space in front of the text: "> "
- Code:
<code>This is unspecific source code</code>
<code [lang]>This is specifc [lang] code</code>
<code php><?php echo 'example'; ?></code>
Available: html, css, javascript, bash, cpp, … - Lists:
Indent your text by two spaces and use a * for
each unordered list item or a - for ordered ones.