How do I use Node.js Crypto to create a HMAC-SHA1 hash?

139,564

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

Share:
139,564

Related videos on Youtube

user847495
Author by

user847495

Updated on January 04, 2022

Comments

  • user847495
    user847495 over 2 years

    I want to create a hash of I love cupcakes (signed with the key abcdeg)

    How can I create that hash, using Node.js Crypto?

  • tim-montague
    tim-montague almost 10 years
    Not a one-liner, and calls can't be daisy-chained... but I'll use this approach.
  • AngraX
    AngraX almost 10 years
    I 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
    Dave over 9 years
    Perhaps 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
    stroncium over 8 years
    You 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
    Dave over 8 years
    Are you trolling? Perhaps you should read the documentation. If you try to read the stream before the finish event, it will fail.
  • stroncium
    stroncium over 8 years
    From [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
    Dave over 8 years
    createHmac 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
    stroncium over 8 years
    I'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
    stroncium over 8 years
    And even some abstract solution which reads hmacs from all over the world should not depend on writable finish event, but on readable readable and end events.
  • stroncium
    stroncium over 8 years
    By 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
    SCBuergel almost 8 years
    Actually the link that you posted explicitely mentions the use of update and not write. I am confused, which is best practice now? I cant find resources that tell that as clearly as you mention it.
  • Ricardo Tomasi
    Ricardo Tomasi over 7 years
    As of Nov. 2016, digest and update 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
    Adam Griffiths about 7 years
    It's true, update and digest 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 using update and digest (as in Ricardo's answer) are both valid methods. Here is where the docs were changed and here are the current docs.
  • Raz
    Raz over 6 years
    @AdamGriffiths works good both of them. What you recommend to use?
  • htafoya
    htafoya over 5 years
    'hex' is not always needed, for example for doing the hmac digest equivalent of ruby.
  • baptx
    baptx almost 5 years
    And to verify a hash, you should use crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b)): stackoverflow.com/questions/31095905/…
  • Ricardo Tomasi
    Ricardo Tomasi over 4 years