Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hash_hmac equivalent in Node.js

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?

like image 538
Sara Fuerst Avatar asked Apr 28 '16 19:04

Sara Fuerst


2 Answers

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.

like image 139
keyvan Avatar answered Nov 16 '22 08:11

keyvan


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
like image 7
Chris Avatar answered Nov 16 '22 08:11

Chris