Hash_hmac equivalent in Node.js

Sara Tibbetts picture Sara Tibbetts · Apr 28, 2016 · Viewed 10.7k times · Source

I have code that is working in my PHP app. In the PHP I sign the url with the following code:

private static function __getHash($string)
{
    return hash_hmac('sha1', $string, self::$__secretKey, true);    
}

I am attempting to sign the URL in the same way in a Node.js application. This is what I'm trying:

S3.prototype.getHash = function(string){
    var key = this.secret_key; 
    var hmac = crypto.createHash('sha1', key);
    hmac.update(string); 
    return hmac.digest('binary'); 
}; 

However, I am getting the following error:

The request signature we calculated does not match the signature you provided. Check your key and signing method.

Do these pieces of code do the same thing? Am I missing something?

Answer

keyvan picture keyvan · Jun 9, 2017

This answer from Chris is good if you are porting hash_hmac with the last parameter being true. In this case, binary is produced, as is the case with Chris's javascript.

To add to that, this example:

 $sign = hash_hmac('sha512', $post_data, $secret);

Would be ported with a function like so in nodejs:

const crypto = require("crypto");

function signHmacSha512(key, str) {
  let hmac = crypto.createHmac("sha512", key);
  let signed = hmac.update(Buffer.from(str, 'utf-8')).digest("hex");
  return signed
}

The difference here being that when you leave off the last argument to hash_hmac (or set it to something not true), it behaves as defined in the PHP docs:

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

In order to do this with node.js we use digest('hex') as you can see in the snippet.