Hash_hmac equivalent in Node.js
Solution 1
The primary problem here is that you are using createHash
which creates a hash, rather than createHmac
which creates an HMAC.
Change createHash
to createHmac
and you should find it produces the same result.
This is the output you should expect:
chris /tmp/hmac $ cat node.js
var crypto = require('crypto');
var key = 'abcd';
var data = 'wxyz';
function getHash(string){
var hmac = crypto.createHmac('sha1', key);
hmac.update(string);
return hmac.digest('binary');
};
process.stdout.write(getHash(data));
chris /tmp/hmac $ cat php.php
<?php
$key = "abcd";
$data = "wxyz";
function __getHash($string)
{
global $key;
return hash_hmac('sha1', $string, $key, true);
}
echo utf8_encode(__getHash($data));
chris /tmp/hmac $ node node.js | base64
WsOKw4xgw4jDlFHDl3jDuEPDuCfCmsOFwoDCrsK/w6ka
chris /tmp/hmac $ php php.php | base64
WsOKw4xgw4jDlFHDl3jDuEPDuCfCmsOFwoDCrsK/w6ka
Solution 2
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.
Sara Fuerst
I am the Founder and Lead Developer of Tibsar Software LLC. I have always had a passion for software development. Today I use this passion to help aspiring business owners build their software based business. I focus on creating quality software products that can scale with their business and meet their unique needs.
Updated on June 11, 2022Comments
-
Sara Fuerst almost 2 years
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?
-
Sara Fuerst about 8 yearsI'm still getting that the Signature does not match. Any idea why?
-
Chris about 8 yearsWell how are you comparing the binary data? If you compare them as strings you will need to make sure the encoding is correct. I've attached the output I get. Note I've converted the PHP output from latin-1 to UTF-8 and base64 encoded both outputs for easy comparison.
-
keyvan almost 7 yearsSara: hash_hmac produces a hex digest by default