oudelitonalituridalp oudelitonalituridalp - 2 months ago 21
Node.js Question

Issue with base64 encoding of data using HMAC

Using Nodejs, I'm attempting to generate a HMAC SHA256, base64-encoded signature of an XML message. I currently have the signature generation working using PHP.

The process seems fairly straightforward, and I'm able to generate base64-encoded value with Nodejs but, for some reason, the value does not match and is much shorter than what I get using PHP.

Below, I've included an example PHP script and result as well as the Nodejs implementation and result. With Nodejs, I'm using the native crypto module.

// PHP implementation

$xml = <<<EOD
<?xml version='1.0' encoding='UTF-8'?>
<dataset>
<record>
<id>1</id>
<first_name>Carlos</first_name>
<last_name>Ruiz</last_name>
<email>cruiz0@engadget.com</email>
<gender>Male</gender>
<ip_address>156.225.191.154</ip_address>
</record>
</dataset>
EOD;

$secret = 'secret';
$sig = base64_encode(hash_hmac('sha256', $xml, $secret));

echo $sig;


Result:
ODhkYTc1YmQzNzc0NWUyNDJlNjY3YTY1NzZhYzFhZGYwOTJlMTIxODdjNzYxOWYyNGQxNGExOGVkYTIyZDQ0ZQ==


// Nodejs implementation

var crypto = require('crypto');

fs.readFile('example.xml', 'utf-8', function(err, data) {
function sig(str, key) {
return crypto.createHmac('sha256', key)
.update(str)
.digest('base64');
}
console.log(sig(data, 'secret'));
});


Result:
iNp1vTd0XiQuZnpldqwa3wkuEhh8dhnyTRShjtoi1E4=


I've spent the day trying to figure this out and after a year+ of using Stack Overflow, this is my first question.

Any assistance would be greatly appreciated!

Answer

The problem here is that PHP's hash_hmac() returns a hex-encoded string by default (see the $raw_output parameter here), so you are base64-encoding a hex string instead of the actual of the raw, binary result.

So change this:

$sig = base64_encode(hash_hmac('sha256', $xml, $secret));

to:

$sig = base64_encode(hash_hmac('sha256', $xml, $secret, true));