Hash 函数
在线手册:中文 英文
PHP手册

hash_hmac

(PHP 5 >= 5.1.2, PECL hash >= 1.1)

hash_hmacGenerate a keyed hash value using the HMAC method

说明

string hash_hmac ( string $algo , string $data , string $key [, bool $raw_output = false ] )

参数

algo

Name of selected hashing algorithm (i.e. "md5", "sha256", "haval160,4", etc..) See hash_algos() for a list of supported algorithms.

data

Message to be hashed.

key

Shared secret key used for generating the HMAC variant of the message digest.

raw_output

When set to TRUE, outputs raw binary data. FALSE outputs lowercase hexits.

返回值

Returns a string containing the calculated message digest as lowercase hexits unless raw_output is set to true in which case the raw binary representation of the message digest is returned.

范例

Example #1 hash_hmac() example

<?php
echo hash_hmac('ripemd160''The quick brown fox jumped over the lazy dog.''secret');
?>

以上例程会输出:

b8e7ae12510bdfb1812e463a7f086122cf37e4f7

参见


Hash 函数
在线手册:中文 英文
PHP手册
PHP手册 - N: Generate a keyed hash value using the HMAC method

用户评论:

josefkoh at hotmail dot com (27-Jul-2011 06:24)

Simple implementation of hmac sha1

<?php

function hmac_sha1($key, $data)
{
   
// Adjust key to exactly 64 bytes
   
if (strlen($key) > 64) {
       
$key = str_pad(sha1($key, true), 64, chr(0));
    }
    if (
strlen($key) < 64) {
       
$key = str_pad($key, 64, chr(0));
    }

   
// Outter and Inner pad
   
$opad = str_repeat(chr(0x5C), 64);
   
$ipad = str_repeat(chr(0x36), 64);

   
// Xor key with opad & ipad
   
for ($i = 0; $i < strlen($key); $i++) {
       
$opad[$i] = $opad[$i] ^ $key[$i];
       
$ipad[$i] = $ipad[$i] ^ $key[$i];
    }

    return
sha1($opad.sha1($ipad.$data, true));
}

Peter Terence Roux (23-Dec-2010 11:44)

The Implementation of the PBKDF2 key derivation function as described in RFC 2898 can be used to not only get the hashed KEY but also a specific IV.

To use, one would use it as follows:-

<?php
  $p
= str_hash_pbkdf2($pw, $salt, 10, 32, 'sha1');
 
$p = base64_encode($p);

 
$iv = str_hash_pbkdf2($pw, $salt, 10, 16, 'sha1', 32);
 
$iv = base64_encode($iv);
?>

The function should be:-

<?php
 
// PBKDF2 Implementation (described in RFC 2898)
  //
  // @param   string  p   password
  // @param   string  s   salt
  // @param   int     c   iteration count (use 1000 or higher)
  // @param   int     kl  derived key length
  // @param   string  a   hash algorithm
  // @param   int     st  start position of result
  //
  // @return  string  derived key
 
function str_hash_pbkdf2($p, $s, $c, $kl, $a = 'sha256', $st=0)
  {
   
$kb = $start+$kl;                        // Key blocks to compute
   
$dk = '';                                    // Derived key

    // Create key
   
for ($block=1; $block<=$kb; $block++)
    {
     
// Initial hash for this block
     
$ib = $h = hash_hmac($a, $s . pack('N', $block), $p, true);

     
// Perform block iterations
     
for ($i=1; $i<$c; $i++)
      {
       
// XOR each iterate
       
$ib ^= ($h = hash_hmac($a, $h, $p, true));
      }

     
$dk .= $ib;                                // Append iterated block
   
}

   
// Return derived key of correct length
   
return substr($dk, $start, $kl);
  }
?>

Siann Beck (10-Oct-2010 05:48)

For signing an Amazon AWS query, base64-encode the binary value:

<?php
  $Sig
= base64_encode(hash_hmac('sha256', $Request, $AmazonSecretKey, true));
?>

KC Cloyd (10-Sep-2009 07:16)

Sometimes a hosting provider doesn't provide access to the Hash extension. Here is a clone of the hash_hmac function you can use in the event you need an HMAC generator and Hash is not available. It's only usable with MD5 and SHA1 encryption algorithms, but its output is identical to the official hash_hmac function (so far at least).

<?php

function custom_hmac($algo, $data, $key, $raw_output = false)
{
   
$algo = strtolower($algo);
   
$pack = 'H'.strlen($algo('test'));
   
$size = 64;
   
$opad = str_repeat(chr(0x5C), $size);
   
$ipad = str_repeat(chr(0x36), $size);

    if (
strlen($key) > $size) {
       
$key = str_pad(pack($pack, $algo($key)), $size, chr(0x00));
    } else {
       
$key = str_pad($key, $size, chr(0x00));
    }

    for (
$i = 0; $i < strlen($key) - 1; $i++) {
       
$opad[$i] = $opad[$i] ^ $key[$i];
       
$ipad[$i] = $ipad[$i] ^ $key[$i];
    }

   
$output = $algo($opad.pack($pack, $algo($ipad.$data)));

    return (
$raw_output) ? pack($pack, $output) : $output;
}

?>

Example Use:

<?php

custom_hmac
('sha1', 'Hello, world!', 'secret', true);

?>

Henry Merriam (04-Aug-2009 06:36)

<?php

/**
 * Implementation of the PBKDF2 key derivation function as described in RFC 2898.
 *
 * PBKDF2 was published as part of PKCS #5 v2.0 by RSA Security. The standard is
 * also documented in IETF RFC 2898.
 *
 * The first four function arguments are as the standard describes:
 *
 *     PBKDF2(P, S, c, dkLen)
 *
 * The fifth function argument specifies the hash function to be used. This should
 * be provided in the same format as used for the hash() function. The default
 * hash algorithm is SHA-1, but this is not recommended for new applications.
 *
 * The function returns false if dk_len is too large. Otherwise it returns the
 * derived key as a binary string.
 *
 * @author Henry Merriam <php@henrymerriam.com>
 *
 * @param    string    p        password
 * @param    string    s        salt
 * @param    int        c        iteration count
 * @param    int        dk_len    derived key length (octets)
 * @param    string    algo    hash algorithm
 *
 * @return    string            derived key
 */
function pbkdf2($p, $s, $c, $dk_len, $algo = 'sha1') {

   
// experimentally determine h_len for the algorithm in question
   
static $lengths;
    if (!isset(
$lengths[$algo])) { $lengths[$algo] = strlen(hash($algo, null, true)); }   
   
$h_len = $lengths[$algo];
   
    if (
$dk_len > (pow(2, 32) - 1) * $h_len) {
        return
false; // derived key is too long
   
} else {
       
$l = ceil($dk_len / $h_len); // number of derived key blocks to compute
       
$t = null;
        for (
$i = 1; $i <= $l; $i++) {
           
$f = $u = hash_hmac($algo, $s . pack('N', $i), $p, true); // first iterate
           
for ($j = 1; $j < $c; $j++) {
               
$f ^= ($u = hash_hmac($algo, $u, $p, true)); // xor each iterate
           
}
           
$t .= $f; // concatenate blocks of the derived key
       
}
        return
substr($t, 0, $dk_len); // return the derived key of correct length
   
}

}

?>

brent at thebrent dot net (21-May-2009 04:17)

The hotp algorithms above work with counter values less than 256, but since the counter can be larger, it's necessary to iterate through all the bytes of the counter:

<?php
function oath_hotp ($key, $counter)
{
   
// Counter
    //the counter value can be more than one byte long, so we need to go multiple times
   
$cur_counter = array(0,0,0,0,0,0,0,0);
    for(
$i=7;$i>=0;$i--)
    {
       
$cur_counter[$i] = pack ('C*', $counter);
       
$counter = $counter >> 8;
    }
   
$bin_counter = implode($cur_counter);
   
// Pad to 8 chars
   
if (strlen ($bin_counter) < 8)
    {
       
$bin_counter = str_repeat (chr(0), 8 - strlen ($bin_counter)) . $bin_counter;
    }

   
// HMAC
   
$hash = hash_hmac ('sha1', $bin_counter, $key);
    return
$hash;
}

function
oath_truncate($hash, $length = 6)
{
   
// Convert to dec
   
foreach(str_split($hash,2) as $hex)
    {
       
$hmac_result[]=hexdec($hex);
    }

   
// Find offset
   
$offset = $hmac_result[19] & 0xf;

   
// Algorithm from RFC
   
return
    (
        ((
$hmac_result[$offset+0] & 0x7f) << 24 ) |
        ((
$hmac_result[$offset+1] & 0xff) << 16 ) |
        ((
$hmac_result[$offset+2] & 0xff) << 8 ) |
        (
$hmac_result[$offset+3] & 0xff)
    ) %
pow(10,$length);
}
print
"<pre>";
print
"Compare results with:";
print
" http://tools.ietf.org/html/draft-mraihi-oath-hmac-otp-04\n";
print
"Count\tHash\t\t\t\t\t\tPin\n";
for(
$i=0;$i<=1024;$i=$i+128)
{
   print
$i."\t".($a=oath_hotp("12345678901234567890",$i));
   print
"\t".oath_truncate($a)."\n";
}
?>

torben dot egmose at gmail dot com (22-Mar-2009 07:40)

HOTP Algorithm that works according to the RCF http://tools.ietf.org/html/draft-mraihi-oath-hmac-otp-04
The test cases from the RCF document the ASCII string as "123456787901234567890".
But the hex decoded to a string is "12345678901234567890".
Secret="12345678901234567890";
Count:
0 755224
1 287082
<?php
function oath_hotp($key,$counter) {

  
// Convert to padded binary string
  
$data = pack ('C*', $counter);
  
$data = str_pad($data,8,chr(0),STR_PAD_LEFT);

  
// HMAC
  
return hash_hmac('sha1',$data,$key);
}

function
oath_truncate($hash, $length = 6) {

  
// Convert to dec
  
foreach(str_split($hash,2) as $hex) {
     
$hmac_result[]=hexdec($hex);
   }

  
// Find offset
  
$offset = $hmac_result[19] & 0xf;

  
// Algorithm from RFC
  
return (
         ((
$hmac_result[$offset+0] & 0x7f) << 24 ) |
         ((
$hmac_result[$offset+1] & 0xff) << 16 ) |
         ((
$hmac_result[$offset+2] & 0xff) << 8 ) |
         (
$hmac_result[$offset+3] & 0xff)
         ) %
pow(10,$length);
}

print
"<pre>";
print
"Compare results with:"
print " http://tools.ietf.org/html/draft-mraihi-oath-hmac-otp-04\n";
print
"Count\tHash\t\t\t\t\t\tPin\n";
for(
$i=0;$i<10;$i++)
   print
$i."\t".($a=oath_hotp("12345678901234567890",$i))
   print
"\t".oath_truncate($a)."\n";

Carlos Averett(caverett*@*corecodec,net) (03-Jul-2008 11:54)

Generating OATH-compliant OTP (one time passwords) results in PHP:

<?php
$otp
= oath_truncate (oath_hotp ($key, $counter), $length);
function
oath_hotp ($key, $counter) {
       
// Counter
       
$bin_counter = pack ('C*', $counter);

       
// Pad to 8 chars
       
if (strlen ($bin_counter) < 8) {
               
$bin_counter = str_repeat (chr(0), 8 - strlen ($bin_counter)) . $bin_counter;
        }

       
// HMAC
       
$hash = hash_hmac ('sha1', $bin_counter, $key);
        return
$hash;
}

function
oath_truncate ($hash, $length = 6) {
       
// The last byte is used as an offset
       
$offset = hexdec (substr ($hash, 38)) & 0xf;

       
// Extract the relevant part, and clear the first bit
       
$hex_truncated = substr ($hash, $offset * 2, 8);
       
$bin_truncated = decbin (hexdec ($hex_truncated));
       
$bin_truncated[0] = '0';
       
$dec_truncated = bindec ($bin_truncated);

        return
substr ($dec_truncated, 0 - $length);
}
?>