4

I have issues with crypto module while upgrading my node version. The created HMAC depends on the version of node. You'll find below the piece of code that reproduces the problem.

If I encode my key as BASE64 (or any) the HMAC does not depends on node.js version.

If I encode it as binary, the HMAC is different if I change my node.js version.

[EDIT] according to Why crypto.createHash returns different output in new version? I have added the encoding when calling the update function

code snippet

"use strict";

const crypto = require('crypto');

console.log(process.version);

let key = '5ece799aa73a7a8e687876f8e0eabe2e200b967ef5728d845f72fc9ea27dbcd90cd4e06e8bc90d823ac8a54ce91f68ca37fc2e7bbf3f5ef9d82b4c6b938f1936';

let _key64 = (new Buffer(key, 'hex')).toString('base64');
console.log("B64 KEY: "+crypto.createHmac('sha512', _key64).update("hey", "binary").digest('hex').toUpperCase());

let _keyBin = (new Buffer(key, 'hex')).toString('binary');
console.log("BIN KEY: "+crypto.createHmac('sha512', _keyBin).update("hey", "binary").digest('hex').toUpperCase());

The output is the following with 2 versions of node.js

v5.6.0
B64 KEY: 0DC11C737E575B17DD575042F8F372E3D63A86C3B56C06FB74C9B0AB8E96A5FC8A2DC33667280DC5B306C93AA3DECBAF0D8EDE56F3666C11BFC25A70CFC027D0
BIN KEY: E5A9F813D9AA64A6791BEA91035553FFC730DBE635D0CE7AC722C0195DFDD77A969323FDDFB4E5054E59073DAE9B9BF00CFF73CF20F2FACEE01F79F25E7B9303
v8.1.4
B64 KEY: 0DC11C737E575B17DD575042F8F372E3D63A86C3B56C06FB74C9B0AB8E96A5FC8A2DC33667280DC5B306C93AA3DECBAF0D8EDE56F3666C11BFC25A70CFC027D0
BIN KEY: 6F089BCA7A24BF6C3F8E0F75349C8B446C4E69336CF41AA7A390C9B17086417E475545197B0312B4D9240A9F0388CA8722ADCF04BFD554321290EBBCD61F800E

note: this is a narrowing of this question: HMAC changes according to node version (paybox module)

By the way, If I do

const key = '5ece799aa73a7a8e687876f8e0eabe2e200b967ef5728d845f72fc9ea27dbcd90cd4e06e8bc90d823ac8a54ce91f68ca37fc2e7bbf3f5ef9d82b4c6b938f1936'
const bkey = (new Buffer(key, 'hex')).toString('binary');
console.log((new Buffer(bkey, 'binary')).toString('hex'));

no problem, I obtain the same key 5ece799aa73a7a8e687... whatever the version of node.

dao hodac
  • 361
  • 2
  • 5
  • 14
  • This gives the same result if I change `"BIN KEY: ....update("hey")` into `"BIN KEY: ....update("hey", "utf-8")` to answer the comments in https://stackoverflow.com/questions/45530779/hmac-changes-according-to-node-version-paybox-module – dao hodac Aug 06 '17 at 17:20
  • Try and narrow it down even further. You encode stuff and such using both methods. You should compare the results of that *as binary*, re-encoded to hexadecimals for instance between the runs in both of the runtimes. It's unlikely the hash algorithm itself, but then again PHP and JavaScript never ceases to amaze me. – Maarten Bodewes Aug 07 '17 at 22:17
  • @MaartenBodewes I have added the narrowing in the question (bottom) as suggested. The passed buffer seems to be consistent, as hex -> binary -> hex is stable. The mystery is still alive – dao hodac Aug 08 '17 at 20:15
  • What happens if you use an empty string or binary value for `"hey"` (the message)? If it's not the key it must be something else (although internal handling of the key / message encoding could be an issue as well). – Maarten Bodewes Aug 08 '17 at 23:10
  • 1
    I suspect https://github.com/nodejs/node/commit/b010c8716498dca398e61c388859fea92296feb3 might be the reason for this difference. The way a string is converted to a buffer changed inside `createHmac`. If you use a buffer directly (i.e. `let _keyBin = new Buffer(key, 'hex');` I think you’ll get the same results for both versions. – matt Aug 08 '17 at 23:37

1 Answers1

3

Solved thanks to @matt: To sum up his comment

Because of https://github.com/nodejs/node/commit/b010c8716498dca398e61c388859fea92296feb3, it is preferable to pass the buffer to crypto, by removing .toString('binary')

So this

"use strict";

const crypto = require('crypto');

console.log(process.version);
let key = '5ece799aa73a7a8e687876f8e0eabe2e200b967ef5728d845f72fc9ea27dbcd90cd4e06e8bc90d823ac8a54ce91f68ca37fc2e7bbf3f5ef9d82b4c6b938f1936';

let _key64 = (new Buffer(key, 'hex')).toString('base64');
console.log("B64 KEY: "+crypto.createHmac('sha512', _key64).update("hey", "binary").digest('hex').toUpperCase());

let _keyBin = (new Buffer(key, 'hex'));
console.log("BIN KEY: "+crypto.createHmac('sha512', _keyBin).update("hey", "binary").digest('hex').toUpperCase());

works (of course)

v5.6.0
B64 KEY: 0DC11C737E575B17DD575042F8F372E3D63A86C3B56C06FB74C9B0AB8E96A5FC8A2DC33667280DC5B306C93AA3DECBAF0D8EDE56F3666C11BFC25A70CFC027D0
BIN KEY: E5A9F813D9AA64A6791BEA91035553FFC730DBE635D0CE7AC722C0195DFDD77A969323FDDFB4E5054E59073DAE9B9BF00CFF73CF20F2FACEE01F79F25E7B9303
v8.1.4
B64 KEY: 0DC11C737E575B17DD575042F8F372E3D63A86C3B56C06FB74C9B0AB8E96A5FC8A2DC33667280DC5B306C93AA3DECBAF0D8EDE56F3666C11BFC25A70CFC027D0
BIN KEY: E5A9F813D9AA64A6791BEA91035553FFC730DBE635D0CE7AC722C0195DFDD77A969323FDDFB4E5054E59073DAE9B9BF00CFF73CF20F2FACEE01F79F25E7B9303
dao hodac
  • 361
  • 2
  • 5
  • 14