Como uso o Node.js Crypto para criar um hash HMAC-SHA1?

198

Quero criar um hash de I love cupcakes(assinado com a chave abcdeg)

Como posso criar esse hash usando o Node.js Crypto?

user847495
fonte

Respostas:

366

Documentação para criptografia: 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')
Ricardo Tomasi
fonte
'hex' nem sempre é necessário, por exemplo, para fazer o hmac digest equivalente ao ruby.
Htafoya # 20/18
6
E para verificar um hash, você deve usar crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b)): stackoverflow.com/questions/31095905/...
baptx
1
O círculo está completo: nodejs.org/api/crypto.html#crypto_crypto
Ricardo Tomasi -
98

Alguns anos atrás foi dito que update()e digest()eram métodos legados e da nova abordagem de streaming API foi introduzido. Agora, os documentos dizem que qualquer um dos métodos pode ser usado. Por exemplo:

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);

Testado no nó v6.2.2 e v7.7.2

Consulte https://nodejs.org/api/crypto.html#crypto_class_hmac . Dá mais exemplos de como usar a abordagem de streaming.

Adam Griffiths
fonte
Não é uma linha, e as chamadas não podem ser encadeadas ... mas usarei essa abordagem.
tfmontague
2
Pela minha vida, não posso fazer isso funcionar. hmac.read () retorna um "[objeto SlowBuffer]" e se eu tentar ler o conteúdo usando hmac.read (). toString ('hex'); Eu não recebo o valor esperado. Se eu usar a abordagem obsoleta de atualização / compilação, ela retornará a sequência esperada. Estou usando isso para validar uma assinatura de um POST de terceiros para meus servidores. Alguma idéia do que está acontecendo?
AngraX
Talvez o hmac.read esteja acontecendo antes dos dados serem liberados no fluxo? Talvez o hmac.read deva ser orientado pelo evento de término do fluxo?
Dave
Na verdade, o link que você postou menciona explicitamente o uso updatee não write. Estou confuso, qual é a melhor prática agora? Não consigo encontrar recursos que digam isso tão claramente quanto você mencionou.
22416 SCBuergel.eth
5
A partir de novembro 2016, digeste updatenão se obsoleta e são apresentados na documentação: nodejs.org/api/crypto.html#crypto_class_hmac . Eu recomendo usar a API de fluxo apenas se você estiver lendo de um fluxo.
Ricardo Tomasi
22

A solução da Gwerder não funciona porque hash = hmac.read();acontece antes que o fluxo seja finalizado. Assim, os problemas do AngraX. Além disso, a hmac.writedeclaração é desnecessária neste exemplo.

Em vez disso, faça o seguinte:

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...
});

Mais formalmente, se você desejar, a linha

hmac.end(text, function () {

poderia ser escrito

hmac.end(text, 'utf8', function () {

porque neste exemplo o texto é uma string utf

Dave
fonte
Você está errado, não há necessidade de adicionar um retorno de chamada. Esse fluxo é síncrono e legível logo após o término () ser chamado. A coisa mais fascinante é que está escrito na documentação oficial, mas todo mundo tem que colocar seus 5 centavos (dobrados) no.
stroncium
Você está trollando? Talvez você deva ler a documentação. Se você tentar ler o fluxo antes do evento de término, ele falhará.
Dave
1
A partir de [ 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. Você lê-lo quando gravável lado terminou , você não precisa esperar ainda para quando legível lado se torna legível (embora ele certamente faz). Leia sua documentação, por favor.
Stroncium 3/15
createHmac cria um fluxo . " finalizado " na linha de documentação que você citou acima não significa hmac.end(...)que foi chamado, " finalizado " significa que o fluxo aumentou seu evento de conclusão , e é por isso que o comando aceita um retorno de chamada. Depois que o método end () é chamado, o fluxo exige tempo para liberar os dados no sistema subjacente. Se você chamar read () antes que o evento de término seja gerado, ele falhará. Vá em frente e cole o código de Gwerder no JSbin e veja você mesmo. Você deve ler a documentação do Streams para entender como ela funciona.
Dave
Eu o uso no código de produção há algum tempo e é estável como o inferno. Sinceramente, não sei o que é JSBin, mas também tentei o código suportado no nodejs com apenas copiar e colar e também funciona. Você não deve imaginar significados adicionais para a documentação. "terminou" sempre significa "terminou" em toda parte na documentação. Mais uma vez, você parece entender mal que o fluxo tem dois lados. E na documentação está explicitamente declarado que uma pessoa pode usar read()quando o lado gravável terminou, e não há nada sobre o evento de conclusão.
stroncium 4/11