Node JS crypto, cannot create hmac on chars with a

2019-02-12 05:01发布

问题:

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

回答1:

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');