Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HMAC-SHA-256 in PHP

Tags:

php

hmac

I have to build an authorization hash from this string:

kki98hkl-u5d0-w96i-62dp-xpmr6xlvfnjz:20151110171858:b2c13532-3416-47d9-8592-a541c208f755:hKSeRD98BHngrNa51Q2IgAXtoZ8oYebgY4vQHEYjlmzN9KSbAVTRvQkUPsjOGu4F

This secret is used for a HMAC hash function:

LRH9CAkNs-zoU3hxHbrtY0CUUcmqzibPeN7x6-vwNWQ=

The authorization hash I have to generate is this:

P-WgZ8CqV51aI-3TncZj5CpSZh98PjZTYxrvxkmQYmI=

There are some things to take care of:

  1. The signature have to be built with HMAC-SHA-256 as specified in RFC 2104.
  2. The signature have to be encoded with Base64 URL-compatible as specified in RFC 4648 Section 5 (Safe alphabet).

There is also some pseudo-code given for the generation:

Signatur(Request) = new String(encodeBase64URLCompatible(HMAC-SHA-256(getBytes(Z, "UTF-8"), decodeBase64URLCompatible(getBytes(S, "UTF-8")))), "UTF-8")

I tried various things in PHP but have not found the correct algorithm yet. This is the code I have now:

if(!function_exists('base64url_encode')){
    function base64url_encode($data) {
        $data = str_replace(array('+', '/'), array('-', '_'), base64_encode($data));
        return $data;
    }
}

$str = "kki98hkl-u5d0-w96i-62dp-xpmr6xlvfnjz:20151110171858:b2c13532-3416-47d9-8592-a541c208f755:hKSeRD98BHngrNa51Q2IgAXtoZ8oYebgY4vQHEYjlmzN9KSbAVTRvQkUPsjOGu4F";
$sec = "LRH9CAkNs-zoU3hxHbrtY0CUUcmqzibPeN7x6-vwNWQ=";
$signature = mhash(MHASH_SHA256, $str, $sec);
$signature = base64url_encode($signature);

if($signature != "P-WgZ8CqV51aI-3TncZj5CpSZh98PjZTYxrvxkmQYmI=")
    echo "wrong: $signature";
else
    echo "correct";

It gives this signature:

K9lw3V-k5gOedmVwmO5vC7cOn82JSEXsNguozCAOU2c=

As you can see, the length of 44 characters is correct. Please help me with finding the mistake, this simple problem takes me hours yet and there is no solution.

like image 667
Richard Avatar asked Jan 22 '16 22:01

Richard


2 Answers

There's a couple of things to notice:

  1. Your key is base64-encoded. You have to decode it before you could use it with php functions. That's the most important thing you have missed.
  2. Mhash is obsoleted by Hash extension.
  3. You want output to be encoded in a custom fashion, so it follows that you need raw output from hmac function (php, by default, will hex-encode it).

So, using hash extension this becomes:

$key = "LRH9CAkNs-zoU3hxHbrtY0CUUcmqzibPeN7x6-vwNWQ=";
$str = "kki98hkl-u5d0-w96i-62dp-xpmr6xlvfnjz:20151110171858:b2c13532-3416-47d9-8592-a541c208f755:hKSeRD98BHngrNa51Q2IgAXtoZ8oYebgY4vQHEYjlmzN9KSbAVTRvQkUPsjOGu4F";

function encode($data) {
    return str_replace(['+', '/'], ['-', '_'], base64_encode($data));
}

function decode($data) {
    return base64_decode(str_replace(['-', '_'], ['+', '/'], $data));
}

$binaryKey = decode($key);

var_dump(encode(hash_hmac("sha256", $str, $binaryKey, true)));

Outputs:

string(44) "P-WgZ8CqV51aI-3TncZj5CpSZh98PjZTYxrvxkmQYmI="
like image 69
weirdan Avatar answered Sep 22 '22 08:09

weirdan


Simply use hash_hmac() function available in PHP.

Example :

hash_hmac('sha256', $string, $secret);

Doc here : http://php.net/manual/fr/function.hash-hmac.php

like image 20
Meloman Avatar answered Sep 19 '22 08:09

Meloman