9

I'm doing a side by side comparison with Ruby, PHP and NodeJS for the following code, getting an incorrect response in NodeJS using the crypto module.

PHP

hash_hmac('sha256', 'text', 'á');

Ruby

OpenSSL::HMAC.hexdigest('sha256', 'á', 'text')

NodeJS

var signer = crypto.createHmac('sha256', 'á');
var expected = signer.update("text").digest('hex');

Both Ruby and PHP return 34b3ba4ea7e8ff214f2f36b31c6a6d88cfbf542e0ae3b98ba6c0203330c9f55b, while, NodeJS returns 7dc85acba66d21e4394be4f8ead2a327c9f1adc64a99c710c98f60c425bd7411. I noticed that, if I try with utf8_encode('á') in PHP, it actually gives me the result Node expects.

I'm loading the accented text in Node from a file, like so:

JSON.parse(fs.readFileSync('keys.js', 'utf8'));

How would I go about changing my code in Node to get the resulting hash that both PHP and Ruby present?

Thanks!

Roberto
  • 1,804
  • 1
  • 29
  • 41
  • What version of node? Running your sample code under node v0.6.11, I get your expected result. – Linus Thiel Feb 27 '12 at 13:20
  • I have Node 0.6.11 as well, on OSX 10.7 but `7dc85acba66d21e4394be4f8ead2a327c9f1adc64a99c710c98f60c425bd7411` is NOT the expected result. – Roberto Feb 27 '12 at 13:29
  • Sure thing, I get `34b3ba4ea7e8ff214f2f36b31c6a6d88cfbf542e0ae3b98ba6c0203330c9f55b` (on Ubuntu, my locale is `en_US.UTF-8`). – Linus Thiel Feb 27 '12 at 13:31
  • Sorry - I got the expected but only after copy-pasting your source code above, munging the `à` in the process. I get `á` in my source code, and that yields your expected result (`34b3ba4ea7e8ff214f2f36b31c6a6d88cfbf542e0ae3b98ba6c0203330c9f55b`). How are ruby and php doing this, is it utf8 or some other encoding? – Linus Thiel Feb 27 '12 at 13:36
  • That is weird, neither in OSX nor Ubuntu, both with the same `en_US.UTF-8` locale, did I get that hash. – Roberto Feb 27 '12 at 13:39
  • It is UTF-8, my guess is it has something to do with the way I load the file and how it gets parsed. Weird thing is, when I `console.log(theKey)`, I see the output correctly as `á`. – Roberto Feb 27 '12 at 13:41
  • Honestly I think your Ruby and PHP implementations don't have a UTF-8 string. That's why PHP `utf8_encode` works. That's why `á` in Node.js gives the same result as `à` in Ruby & PHP. – Linus Thiel Mar 05 '12 at 15:09

1 Answers1

15

This code will give you the correct result:

var crypto = require('crypto');

var signer = crypto.createHmac('sha256', new Buffer('á', 'utf8'));
var result = signer.update("text").digest('hex');
console.log(result);
Vadim Baryshev
  • 22,958
  • 4
  • 51
  • 46
  • Thank you, this actually works! Could you help me out to figure out why so? – Roberto Mar 06 '12 at 21:27
  • 5
    crypto.createHmac is a binding to C++ library. Issue occurs when converting JavaScript string to C++ char*. This is repeated for all non-single-byte characters. Buffer can do this conversion correctly. – Vadim Baryshev Mar 06 '12 at 22:49