I'm trying to validate data integrity using NodeJS Crypto library. It requires calculating the Hmac of a JSON string.
After some test, I've been able to locate the issue: it happens whenever it contains a unicode character. For instance:
var hasher = crypto.createHmac("sha256", 'secret_key');
hasher.write('{"timezone":"(GMT-05:00) Eastern Time (US \u0026 Canada)"}');
hasher.end();
var calculatedHmac = new Buffer(hasher.read(), 'utf8').toString('base64');
console.log(calculatedHmac);
However this returns the wrong hmac. The same code in PHP matched the signature I received from the third party service:
$data = '{"timezone":"(GMT-05:00) Eastern Time (US \u0026 Canada)"}';
$calculated_hmac = base64_encode(hash_hmac('sha256', $data, 'secret_key', true));
var_dump($calculated_hmac); // Result is correct here
If I remove the "\u0026" in the NodeJS payload, then I get the same correct result as in PHP.
Am I doing something wrong here?
Thanks!
The \uXXXX
escape sequence notation is only supported by PHP from version 7 (reference).
If you're using an older PHP version, these escape sequences will be passed literally (so \u0026
is a 6-character substring), whereas Node will interpret it as a single character (&
).
If you want Node to stop interpreting the escape sequence, you need to escape the backslash:
hasher.write('{"timezone":"(GMT-05:00) Eastern Time (US \\u0026 Canada)"}');
When you do that, the result for Node and PHP will be the same (0CE0++Kn9mi5xd7nAz/mWOrr7939RWwzfxhBzxAWtAk=
to be exact).