Search code examples
node.jsopensslhmacdigest

Nodejs different HMAC signature from OpenSSL


I've been struggling with creating a correct HMAC signature in Node.

Use case

I'm currently working a Jointspace API client for Node to control Philips smart tv's. But to get this working I need to sign a string for a pairing request.

Current situation

My nodejs code looks like this:

const crypto = require('crypto');

let secret = Buffer.from('ZmVay1EQVFOaZhwQ4Kv81ypLAZNczV9sG4KkseXWn1NEk6cXmPKO/MCa9sryslvLCFMnNe4Z4CPXzToowvhHvA==', 'base64');
let text = '12345';
let algorithm = 'sha1';
let hmac = crypto.createHmac(algorithm, secret);
hmac.write(text);
hmac.end();

console.log(hmac.read('binary').toString('base64'));

When I run it, it results to this:

~ $ node test.js
DURLMkx7YdrIlWdUKo3iNDC3cp0=

Expected

When I do the exact same thing with the openssl command via the command line, I get a different result. (The correct result)

~ $ echo -n "ZmVay1EQVFOaZhwQ4Kv81ypLAZNczV9sG4KkseXWn1NEk6cXmPKO/MCa9sryslvLCFMnNe4Z4CPXzToowvhHvA==" | base64 -d | openssl dgst -sha1 -hmac "12345" -binary | base64
GvbRLlBSY8r/jPqUGox8zZHxOew=

References

There is an issue on the node Github page which addresses an issue of a difference between Node and openssl. In that issue they basically say that crypto in node is just a wrapper for the C++ openssl library. And in order for it to properly work you need to provide the secret as a Buffer instead of a string because of conversion issues.

E.g.

crypto.createHmac('sha1', new Buffer('secret_key', 'utf8'));

But this does not resolve my issue.

Differences in output

~ $ echo "DURLMkx7YdrIlWdUKo3iNDC3cp0=" | base64 -d | hexdump -C
00000000  0d 44 4b 32 4c 7b 61 da  c8 95 67 54 2a 8d e2 34  |.DK2L{a...gT*..4|
00000010  30 b7 72 9d                                       |0.r.|
00000014
~ $ echo "GvbRLlBSY8r/jPqUGox8zZHxOew=" | base64 -d | hexdump -C
00000000  1a f6 d1 2e 50 52 63 ca  ff 8c fa 94 1a 8c 7c cd  |....PRc.......|.|
00000010  91 f1 39 ec                                       |..9.|
00000014

Solution

  • In your command you're using 12345 as the HMAC key but in your code you're using it as data! so here's an update on the code

    const crypto = require('crypto');
    
    let secret = 'ZmVay1EQVFOaZhwQ4Kv81ypLAZNczV9sG4KkseXWn1NEk6cXmPKO/MCa9sryslvLCFMnNe4Z4CPXzToowvhHvA=='
    let key = '12345';
    let algorithm = 'sha1';
    let hmac = crypto.createHmac(algorithm, key);
    hmac.write(secret);
    hmac.end();
    
    console.log(hmac.read('binary').toString('base64'));
    

    And here's the command

    echo -n "ZmVay1EQVFOaZhwQ4Kv81ypLAZNczV9sG4KkseXWn1NEk6cXmPKO/MCa9sryslvLCFMnNe4Z4CPXzToowvhHvA==" | openssl dgst -sha1 -hmac "12345" -binary | base64
    

    They both return the same hash.