Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

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:

  • The signature have to be built with HMAC-SHA-256 as specified in RFC 2104.
  • 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";
        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.

    @CharlotteDunois: I need a HMAC hash from a string to sign and a secret. If I try to generate it with PHP, it fails / gives the wrong hash. I think the RFC specifications are not fulfilled. – Richard Jan 22, 2016 at 22:35 I think it's pretty much because of base64url_encode. If you need it to be urlencoded for whatever reason, use urlencode and then urldecode it on the server before verifying. – Charlotte Dunois Jan 22, 2016 at 22:37
  • 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.
  • Mhash is obsoleted by Hash extension.
  • 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="
                    Thank you very much, that is exactly the result I needed! The problem just was the true in hash_hmac and the base64 decode of the key, which needs base64 URL also.
    – Richard
                    Jan 23, 2016 at 10:14
                    No, it's output is based on input string and the key. Give it the same key and string, and it will generate the same output.
    – weirdan
                    Aug 8, 2017 at 14:01
                    The output is d6285e20328c93ef83aa34b2318e3d14c193fc517e81f4cf13e8120a7b995899, which is not the desired answer.
    – Raptor
                    Jun 9, 2022 at 2:56
            

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.