12

I am having an issue generating the correct signature in NodeJS (using crypto.js) when the text I am trying to encrypt has accented characters (such as ä,ï,ë)

generateSignature = function (str, secKey) { 
 var hmac = crypto.createHmac('sha1', secKey);
 var sig = hmac.update(str).digest('hex');
 return sig;
};

This function will return the correct HMAC signature if 'str' contains no accented characters (chars such as ä,ï,ë). If there are accented chars present in the text, it will not return the correct HMAC. The accented characters are valid in UTF8 encoding so I dont know why crypto has a problem with them. It may be the case that I need to somehow tell crypto that I am signing utf8 encoded text, but I don't know how to do this.

The exact same problem is described in this post: NodeJS hmac digest issue with accents However, the post itself, as well as the answer, do not make sense to me (as they are passing the data they want to encrypt where the secret key should go).

Here is a version of the code with hard coded values for str and secKey:

  var crypto = require('crypto');

  str="äïë";  
  secKey="secret"; 
  var hmac = crypto.createHmac('sha1', secKey);
  var sig = hmac.update(new Buffer(str, 'utf8')).digest('hex');
  console.log("Sig:      " + sig);
  console.log("Expected: 094b2ba039775bbf970a58e4a0a61b248953d30b"); 
  // "Expected" was generated using http://hash.online-convert.com/sha1-generator

Output::

Sig: 39c9f1a6094c76534157739681456e7878557f58

Expected: 094b2ba039775bbf970a58e4a0a61b248953d30b

Thanks

Community
  • 1
  • 1
Tommy
  • 178
  • 1
  • 2
  • 16
  • Subsequently found out that the test above returned a matched "expected" value when I ran the exact same script on a Macbook - had been running on windows previously – Tommy Aug 30 '12 at 13:09

1 Answers1

20

The default encoding used by the crypto module is usually 'binary'. So, you'll have to specify 'utf-8' via a Buffer to use it as the encoding:

var sig = hmac.update(new Buffer(str, 'utf-8')).digest('hex');

That's what the answer for the other question was demonstrating, just for the key:

var hmac = crypto.createHmac('sha1', new Buffer(secKey, 'utf-8'));

You can also use Buffer to view the differences:

new Buffer('äïë', 'binary')
// <Buffer e4 ef eb>

new Buffer('äïë', 'utf-8')
// <Buffer c3 a4 c3 af c3 ab>

[Edit]

Running the example code you provided, I get:

Sig:      094b2ba039775bbf970a58e4a0a61b248953d30b
Expected: 094b2ba039775bbf970a58e4a0a61b248953d30b

And, modifying it slightly, I get true:

var crypto = require('crypto');

function sig(str, key) {
  return crypto.createHmac('sha1', key)
    .update(new Buffer(str, 'utf-8'))
    .digest('hex');
}

console.log(sig('äïë', 'secret') === '094b2ba039775bbf970a58e4a0a61b248953d30b');
Community
  • 1
  • 1
Jonathan Lonowski
  • 112,514
  • 31
  • 189
  • 193
  • Thanks but this did not resolve the issue and I actually had tried that, I also tried converting str to a buffer and that didnt work either. As you said, there is no "encoding" arg for createHmac so the 'utf8' parameter in this line: var hmac = crypto.createHmac('sha1', new Buffer(secKey, 'utf-8')); – Tommy Aug 30 '12 at 12:06
  • @Tommy Do you have an example you can share of what you're expecting vs. getting from particular inputs? – Jonathan Lonowski Aug 30 '12 at 12:24
  • [missing piece from my comment], in the line where you called "hmac.update(str, 'utf8')", your second parameter, 'utf8' - is ignored as hmac.update only takes 1 argument. Converting str to a buffer on this same line doesn't work either. Thanks – Tommy Aug 30 '12 at 12:35
  • I am trying to but I cannot post code into the comment.. dont understand this "mini markdown" format stackoverflow is telling me about below – Tommy Aug 30 '12 at 12:46
  • Have added an example of expected v getting to the original post now.. thanks for taking an interest in this Jonathan – Tommy Aug 30 '12 at 12:50
  • 1
    Thanks again, I just realised that I get the expected output when running on a mac, but not on windows – Tommy Aug 30 '12 at 13:08
  • @Tommy Try saving the script with `'\u00e4\u00ef\u00eb'` for the `str`. The issue might be the encoding used for saving the script file to disk (it may be saved as Windows-1252 or "ANSI" rather than UTF-8). – Jonathan Lonowski Aug 30 '12 at 13:09
  • 1
    think you may be right Jonathan, the text inside str looked differnt when opened on a mac. Thanks for all your help – Tommy Aug 31 '12 at 13:06
  • @JonathanLonowski nodejs documentation at times miss the finer details at nodejs.org/api - I am curious how to get at such parameter specific details. for example - in this thread for the crypto.createHmac(data, key) for the key parameter. should one enlist in source code at github? can you give some lead? thanks for help – Sushil May 07 '13 at 03:54
  • 1
    @Sushil It would probably be worth asking that as a formal question. But, in short, `key` is just a 2nd `String` or `Buffer` used as a "*cryptographic key*" along with the "*message*" or [`data`](http://nodejs.org/api/crypto.html#crypto_hmac_update_data) to calculate a hash. There's a good write-up on HMACs on Security.SE: http://security.stackexchange.com/a/20301. And, Wikipedia's article can help explain how the `key` is used: http://en.wikipedia.org/wiki/HMAC. – Jonathan Lonowski May 07 '13 at 07:09