hash_hmac

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

hash_hmacГенерация хеш-кода на основе ключа, используя метод HMAC

Описание

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

Список параметров

algo

Имя выбранного алгоритма хеширования (например, "md5", "sha256", "haval160,4" и т.д.) Смотрите hash_algos() для получения списка поддерживаемых алгоритмов.

data

Сообщение для хеширования.

key

Общий секретный ключ, используемый для генерации HMAC хеш кода.

raw_output

Когда установлено в TRUE, выводит необработанные двоичные данные. При FALSE выводит данные в шестнадцатеричной кодировке в нижнем регистре.

Возвращаемые значения

Возвращает строку содержащую вычисленный хеш-код в шестнадцатеричной кодировке в нижнем регистре. Если raw_output задан как TRUE, то возвращается хеш-код в виде бинарных данных. Возвращает FALSE, если algo неизвестен.

Примеры

Пример #1 Пример использования hash_hmac()

<?php
echo hash_hmac('ripemd160''Наглый коричневый лисёнок прыгает вокруг ленивой собаки.''secret');
?>

Результат выполнения данного примера:

b95d4abec7c27ec87fb54da1621f9942948879e4

Смотрите также

  • hash() - Генерирует хеш-код (дайджест сообщения)
  • hash_algos() - Возвращает список зарегистрированных алгоритмов хеширования
  • hash_init() - Инициализация инкрементального контекста хеширования
  • hash_hmac_file() - Генерация хэш-кода на основе ключа, используя метод HMAC и содержимое полученного файла

Коментарии

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), 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 ($hash38)) & 0xf;

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

        return 
substr ($dec_truncated$length);
}
?>
2008-07-03 18:54:52
http://php5.kiev.ua/manual/ru/function.hash-hmac.html
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) << ) |
         (
$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";
2009-03-22 13:40:43
http://php5.kiev.ua/manual/ru/function.hash-hmac.html
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), 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) << ) |
        (
$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";
}
?>
2009-05-21 11:17:56
http://php5.kiev.ua/manual/ru/function.hash-hmac.html
Автор:
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)), $sizechr(0x00));
    } else {
       
$key str_pad($key$sizechr(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);

?>
2009-09-10 02:16:30
http://php5.kiev.ua/manual/ru/function.hash-hmac.html
Автор:
For signing an Amazon AWS query, base64-encode the binary value:

<?php
  $Sig 
base64_encode(hash_hmac('sha256'$Request$AmazonSecretKeytrue));
?>
2010-10-10 12:48:32
http://php5.kiev.ua/manual/ru/function.hash-hmac.html
Автор:
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$salt1032'sha1');
 
$p base64_encode($p);

 
$iv str_hash_pbkdf2($pw$salt1016'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), $ptrue);

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

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

   
// Return derived key of correct length
   
return substr($dk$start$kl);
  }
?>
2010-12-23 05:44:48
http://php5.kiev.ua/manual/ru/function.hash-hmac.html
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($keytrue), 64chr(0));
    }
    if (
strlen($key) < 64) {
       
$key str_pad($key64chr(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.$datatrue));
}
2011-07-27 13:24:07
http://php5.kiev.ua/manual/ru/function.hash-hmac.html
Yet another OATH HOTP function. Has a 64 bit counter and is a lot shorter. Enjoy.

<?php

function oath_hotp ($secret$ctr$len=6) {
       
$binctr pack ('NNC*'$ctr>>32$ctr 0xFFFFFFFF);
       
$hash hash_hmac ("sha1"$binctr$secret);
// This is where hashing stops and truncation begins
       
$ofs 2*hexdec (substr ($hash391));
       
$int hexdec (substr ($hash$ofs8)) & 0x7FFFFFFF;
       
$pin substr ($int, -$len);
       
$pin str_pad ($pin$len"0"STR_PAD_LEFT);
        return 
$pin;
}

?>
2012-06-09 10:38:58
http://php5.kiev.ua/manual/ru/function.hash-hmac.html
Here is an efficient PBDKF2 implementation:

<?php
/*
 * PBKDF2 key derivation function as defined by RSA's PKCS #5: https://www.ietf.org/rfc/rfc2898.txt
 * $algorithm - The hash algorithm to use. Recommended: SHA256
 * $password - The password.
 * $salt - A salt that is unique to the password.
 * $count - Iteration count. Higher is better, but slower. Recommended: At least 1024.
 * $key_length - The length of the derived key in bytes.
 * $raw_output - If true, the key is returned in raw binary format. Hex encoded otherwise.
 * Returns: A $key_length-byte key derived from the password and salt.
 *
 * Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt
 *
 * This implementation of PBKDF2 was originally created by defuse.ca
 * With improvements by variations-of-shadow.com
 */
function pbkdf2($algorithm$password$salt$count$key_length$raw_output false)
{
   
$algorithm strtolower($algorithm);
    if(!
in_array($algorithmhash_algos(), true))
        die(
'PBKDF2 ERROR: Invalid hash algorithm.');
    if(
$count <= || $key_length <= 0)
        die(
'PBKDF2 ERROR: Invalid parameters.');

   
$hash_length strlen(hash($algorithm""true));
   
$block_count ceil($key_length $hash_length);

   
$output "";
    for(
$i 1$i <= $block_count$i++) {
       
// $i encoded as 4 bytes, big endian.
       
$last $salt pack("N"$i);
       
// first iteration
       
$last $xorsum hash_hmac($algorithm$last$passwordtrue);
       
// perform the other $count - 1 iterations
       
for ($j 1$j $count$j++) {
           
$xorsum ^= ($last hash_hmac($algorithm$last$passwordtrue));
        }
       
$output .= $xorsum;
    }

    if(
$raw_output)
        return 
substr($output0$key_length);
    else
        return 
bin2hex(substr($output0$key_length));
}
?>
2012-06-30 19:30:00
http://php5.kiev.ua/manual/ru/function.hash-hmac.html
<?php 
/* Here is a solution for those who used hash_hmac 
   with Tiger algorithm in PHP 5.1 - 5.3
   and want to upgrade to PHP 5.4 (or newer?).
   
   The problem occured because the order of bytes for Tiger
   was changed to big endian since PHP 5.4.0.
   
   The two functions below assert $algo is one of Tiger algorithms, 
   for example tiger160,4.
   */
   
# replaces hash('tiger...
function hash_tiger_rev($algo$data$raw_output false) {
   
$len intval(substr($algo53)); # 128, 160 or 192 bits
   
$times substr($algo91); # 3 or 4
   
$revhash implode(""array_map("strrev"
       
str_split(hash('tiger192,'.$times$datatrue), 8)));
    if (
$len 192$revhash substr($revhash0$len >> 3);
    return 
$raw_output$revhashbin2hex($revhash);
}

# replaces hash_hmac('tiger...
function hash_hmac_tiger_rev($algo$data$key$raw_output false) {
    if (
strlen($key) > 64$key hash_tiger_rev($algo$key);
   
$key str_pad($key64chr(0));
   
$o_pad str_repeat("\\"64) ^ $key# "\" = chr(0x5C)
   
$i_pad str_repeat("6"64) ^ $key# "6" = chr(0x36)
   
return hash_tiger_rev($algo$o_pad 
           
hash_tiger_rev($algo$i_pad $datatrue), $raw_output);
}

# always the new version of tiger
function hash_hmac_new($algo$data$key$raw_output false) {
    if (
phpversion() > '5.4' || !preg_match('/^tiger(128|160|192),(3|4)$/'$algo)) 
        return 
hash_hmac($algo$data$key$raw_output);
    else
        return 
hash_hmac_tiger_rev($algo$data$key$raw_output);
}

# always the old version of tiger
function hash_hmac_old($algo$data$key$raw_output false) {
    if (
phpversion() < '5.4' || !preg_match('/^tiger(128|160|192),(3|4)$/'$algo)) 
        return 
hash_hmac($algo$data$key$raw_output);
    else
        return 
hash_hmac_tiger_rev($algo$data$key$raw_output);
}

# let's test it
$algo 'tiger160,4'$pwd 'foo'$key 'bar';
echo 
hash_hmac($algo$pwd$key), "<br>";
echo 
hash_hmac_tiger_rev($algo$pwd$key), "<br>"
echo 
"<br>";
echo 
hash_hmac_old($algo$pwd$key), "<br>";
echo 
hash_hmac_new($algo$pwd$key), "<br>";

/* With PHP 5.4 output would be 
   590546d9f425188da35e5dfa53306ba3953571cc
   bd6664330ed96b9b39ee063241b62e43f546a49d

   bd6664330ed96b9b39ee063241b62e43f546a49d
   590546d9f425188da35e5dfa53306ba3953571cc   
   
   With PHP 5.3 
   bd6664330ed96b9b39ee063241b62e43f546a49d
   590546d9f425188da35e5dfa53306ba3953571cc
   
   bd6664330ed96b9b39ee063241b62e43f546a49d
   590546d9f425188da35e5dfa53306ba3953571cc   
*/

?>
2012-07-14 15:52:23
http://php5.kiev.ua/manual/ru/function.hash-hmac.html
A function implementing the algorithm outlined in RFC 6238 (http://tools.ietf.org/html/rfc6238)

<?php
/**
 * This function implements the algorithm outlined
 * in RFC 6238 for Time-Based One-Time Passwords
 *
 * @link http://tools.ietf.org/html/rfc6238
 * @param string $key    the string to use for the HMAC key
 * @param mixed  $time   a value that reflects a time (unix
 *                       time in the example)
 * @param int    $digits the desired length of the OTP
 * @param string $crypto the desired HMAC crypto algorithm
 * @return string the generated OTP
 */
function oauth_totp($key$time$digits=8$crypto='sha256')
{
   
$digits intval($digits);
   
$result null;
   
   
// Convert counter to binary (64-bit)       
   
$data pack('NNC*'$time >> 32$time 0xFFFFFFFF);
   
   
// Pad to 8 chars (if necessary)
   
if (strlen ($data) < 8) {
       
$data str_pad($data8chr(0), STR_PAD_LEFT);
    }       
   
   
// Get the hash
   
$hash hash_hmac($crypto$data$key);
   
   
// Grab the offset
   
$offset hexdec(substr($hashstrlen($hash) - 11));
   
   
// Grab the portion we're interested in
   
$binary hexdec(substr($hash$offset8)) & 0x7fffffff;
   
   
// Modulus
   
$result $binary pow(10$digits);
   
   
// Pad (if necessary)
   
$result str_pad($result$digits"0"STR_PAD_LEFT);
   
    return 
$result;
}
?>
2012-10-08 17:13:00
http://php5.kiev.ua/manual/ru/function.hash-hmac.html
Автор:
Please be careful when comparing hashes. In certain cases, information can be leaked by using a timing attack. It takes advantage of the == operator only comparing until it finds a difference in the two strings. To prevent it, you have two options.

Option 1: hash both hashed strings first - this doesn't stop the timing difference, but it makes the information useless.

<?php
   
if (md5($hashed_value) === md5($hashed_expected)) {
        echo 
"hashes match!";
    }
?>

Option 2: always compare the whole string.

<?php
   
if (hash_compare($hashed_value$hashed_expected)) {
        echo 
"hashes match!";
    }

    function 
hash_compare($a$b) {
        if (!
is_string($a) || !is_string($b)) {
            return 
false;
        }
       
       
$len strlen($a);
        if (
$len !== strlen($b)) {
            return 
false;
        }

       
$status 0;
        for (
$i 0$i $len$i++) {
           
$status |= ord($a[$i]) ^ ord($b[$i]);
        }
        return 
$status === 0;
    }
?>
2013-02-19 22:52:21
http://php5.kiev.ua/manual/ru/function.hash-hmac.html
For signing an Amazon AWS query, base64-encode the binary value:

<?php
echo base64_encode(hash_hmac("sha1"$Request$AmazonSecretKeytrue));
?>
2016-03-31 21:24:50
http://php5.kiev.ua/manual/ru/function.hash-hmac.html
As  Michael  uggests we should take care not to compare the hash using == (or ===). Since PHP version 5.6 we can now use hash_equals().

So the example will be:

<?php
   
if (hash_equals($hashed_expected$hashed_value) ) {
        echo 
"hashes match!";
    }
?>
2016-10-13 18:54:38
http://php5.kiev.ua/manual/ru/function.hash-hmac.html
This Is The Most Secure Way To Hash Your Data,
It Will Be Almost Impossible To Retrieve Your Data.
--------------------------------------------------------
 --- Create Two Random Keys And Save Them In Your Configuration File ---
<?php
// Create A Random Key
echo base64_encode(openssl_random_pseudo_bytes(64));
?>
--------------------------------------------------------
<?php
// Save The Keys In Your Configuration File
define('FIRSTKEY','TNYazlbZ1Mq3HDMiEFDLrRMZBftFqpU2Ipytgytsc+jmQysE8lmigKtmGK+exB337ZOcAgwPpWmoPHL5niO3jA==');
define('SECONDKEY','z5hh/Kax4+HKZ8exOlvGlrHev/6ZynOEn904yiiIcWo/qLXWSfLkzm4NSJiGXu4uR7xxUowOkO26VqAi2p2DYQ==');
?>
--------------------------------------------------------
<?php
function secured_hash($data)
{       
$first_key base64_decode(FIRSTKEY);
$second_key base64_decode(SECONDKEY);   
   
$first_hashed hash_hmac('sha3-512'$data$first_keyTRUE);   
$second_hashed hash_hmac('sha3-512'$first_hashed$second_key);

return 
$second_hashed;
}
?>
2017-12-06 02:02:21
http://php5.kiev.ua/manual/ru/function.hash-hmac.html
Автор:
Very important notice, if you pass array to $data, php will generate a Warning, return a NULL and continue your application. Which I think is critical vulnerability as this function used to check authorisation typically.

Example:
<?php
var_dump
(hash_hmac('sha256', [], 'secret'));

WARNING hash_hmac() expects parameter 2 to be string, array given on line number 3
NULL
?>
Of course not documented feature.
2018-04-23 23:46:46
http://php5.kiev.ua/manual/ru/function.hash-hmac.html
Автор:
Function for those, who really need to use crc32 algorithm in PHP>7.1

<?php
   
function hash_hmac_crc32(string $keystring $data): string
   
{
       
$b 4;
        if (
strlen($key) > $b) {
           
$key pack("H*"hash('crc32'$key));
        }
       
$key  str_pad($key$bchr(0x00));
       
$ipad str_pad(''$bchr(0x36));
       
$opad str_pad(''$bchr(0x5c));
       
$k_ipad $key $ipad;
       
$k_opad $key $opad;
        return 
hash('crc32'$k_opad hash('crc32'$k_ipad $datatrue));
    }
?>
2021-03-11 12:32:11
http://php5.kiev.ua/manual/ru/function.hash-hmac.html
While implementing a TOTP application, please note that hash_hmac() must receive data in binary, not in a hexadecimal string, to generate a valid OTP across platforms.

This problem can be easily fixed by converting a hexadecimal string to its binary form before passing it to hash_hmac().

<?php
$time 
hex2bin('0000000003523f77'); // time must be in this "hexadecimal and padded" form
$key hex2bin('bb57d1...'); // 160-bits = 40-digit hexadecimal (4 bits) = 32-digit base32 (5 bits)

hash_hmac('sha1'$time$key);
?>
2022-12-21 23:23:31
http://php5.kiev.ua/manual/ru/function.hash-hmac.html

    Поддержать сайт на родительском проекте КГБ