How do I use Node.js Crypto to create a HMAC-SHA1 hash?
Solution 1
Documentation for crypto: http://nodejs.org/api/crypto.html
const crypto = require('crypto')
const text = 'I love cupcakes'
const key = 'abcdeg'
crypto.createHmac('sha1', key)
.update(text)
.digest('hex')
Solution 2
A few years ago it was said that update()
and digest()
were legacy methods and the new streaming API approach was introduced. Now the docs say that either method can be used. For example:
var crypto = require('crypto');
var text = 'I love cupcakes';
var secret = 'abcdeg'; //make this your secret!!
var algorithm = 'sha1'; //consider using sha256
var hash, hmac;
// Method 1 - Writing to a stream
hmac = crypto.createHmac(algorithm, secret);
hmac.write(text); // write in to the stream
hmac.end(); // can't read from the stream until you call end()
hash = hmac.read().toString('hex'); // read out hmac digest
console.log("Method 1: ", hash);
// Method 2 - Using update and digest:
hmac = crypto.createHmac(algorithm, secret);
hmac.update(text);
hash = hmac.digest('hex');
console.log("Method 2: ", hash);
Tested on node v6.2.2 and v7.7.2
See https://nodejs.org/api/crypto.html#crypto_class_hmac. Gives more examples for using the streaming approach.
Solution 3
Gwerder's solution wont work because hash = hmac.read();
happens before the stream is done being finalized. Thus AngraX's issues. Also the hmac.write
statement is un-necessary in this example.
Instead do this:
var crypto = require('crypto');
var hmac;
var algorithm = 'sha1';
var key = 'abcdeg';
var text = 'I love cupcakes';
var hash;
hmac = crypto.createHmac(algorithm, key);
// readout format:
hmac.setEncoding('hex');
//or also commonly: hmac.setEncoding('base64');
// callback is attached as listener to stream's finish event:
hmac.end(text, function () {
hash = hmac.read();
//...do something with the hash...
});
More formally, if you wish, the line
hmac.end(text, function () {
could be written
hmac.end(text, 'utf8', function () {
because in this example text is a utf string
Related videos on Youtube
user847495
Updated on January 04, 2022Comments
-
user847495 over 2 years
I want to create a hash of
I love cupcakes
(signed with the keyabcdeg
)How can I create that hash, using Node.js Crypto?
-
tim-montague almost 10 yearsNot a one-liner, and calls can't be daisy-chained... but I'll use this approach.
-
AngraX almost 10 yearsI can't, for the life of me, make this work. hmac.read() returns a " [object SlowBuffer]" and if I try to read the contents using hmac.read().toString('hex'); I do not get the expected value. If I use the update/digest deprecated approach, it returns the expected string. I'm using this to validate a signature from a third party POST to my servers. Any ideas what is going on?
-
Dave over 9 yearsPerhaps the hmac.read is happening before the data has been flushed to the stream? Maybe hmac.read should be driven by the stream's finish event?
-
stroncium over 8 yearsYou are wrong, there is no need for adding a callback. This stream is synchronous and is readable right after end() is called. Most fascinating thing is it is written in official documentation, but everyone have to put their 5 (bent) cents in.
-
Dave over 8 yearsAre you trolling? Perhaps you should read the documentation. If you try to read the stream before the finish event, it will fail.
-
stroncium over 8 yearsFrom [nodejs.org/api/crypto.html#crypto_class_hmac]
It is a stream that is both readable and writable. The written data is used to compute the hmac. Once the writable side of the stream is ended, use the read() method to get the computed digest.
You read it when writable side ended, you don't need to even wait for when readable side becomes readable (though it surely does). Read your documentation please. -
Dave over 8 yearscreateHmac creates a stream. "ended" in the documentation line you quote above does not mean
hmac.end(...)
has been called, "ended" means that the stream has raised its finish event, which is why the command accepts a callback. After the end() method is called, the stream requires time to flush the data to the underlying system. If you call read() before the finish event is raised, it will fail. Go ahead and paster Gwerder's code into JSbin and see for yourself. You should be reading the Streams documentation to understand how it works. -
stroncium over 8 yearsI've used it in production code for some time and it is stable as hell. I honestly don't know what JSBin is, but I've also tried the supported code in nodejs with just copy-paste and it works too. You shouldn't imagine additional meanings to documentation. "ended" always means "ended" everywhere in documentation. Yet again, you seem to misunderstand that stream have 2 sides. And in documentation it is explicitly stated that person can use
read()
when writable side ended, and there is nothing about finish event. -
stroncium over 8 yearsAnd even some abstract solution which reads hmacs from all over the world should not depend on writable
finish
event, but on readablereadable
andend
events. -
stroncium over 8 yearsBy your logic it is ok to read data when some system decides that it have done flushing all the data required to generate it, but before actual data producer generated anything. So how about not introducing extremely leaky abstractions and callback hell when we have a system(which is actually purely synchronous) which is guaranteed to work in a simple, effective and predictable way?
-
SCBuergel almost 8 yearsActually the link that you posted explicitely mentions the use of
update
and notwrite
. I am confused, which is best practice now? I cant find resources that tell that as clearly as you mention it. -
Ricardo Tomasi over 7 yearsAs of Nov. 2016,
digest
andupdate
have not been deprecated and are featured in the documentation: nodejs.org/api/crypto.html#crypto_class_hmac. I recommend using the stream API only if you're reading from a stream. -
Adam Griffiths about 7 yearsIt's true,
update
anddigest
were not depreciated. When I originally answered this question in 2013 the docs said they were "legacy methods" but they were changed in 2015 to say using piped streams (as in my answer) or usingupdate
anddigest
(as in Ricardo's answer) are both valid methods. Here is where the docs were changed and here are the current docs. -
Raz over 6 years@AdamGriffiths works good both of them. What you recommend to use?
-
htafoya over 5 years'hex' is not always needed, for example for doing the hmac digest equivalent of ruby.
-
baptx almost 5 yearsAnd to verify a hash, you should use
crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b))
: stackoverflow.com/questions/31095905/… -
Ricardo Tomasi over 4 yearsThe circle is complete: nodejs.org/api/crypto.html#crypto_crypto