¿Cómo uso Node.js Crypto para crear un hash HMAC-SHA1?

Respuestas:

366

Documentación para 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')
Ricardo Tomasi
fuente
'hexadecimal' no siempre es necesario, por ejemplo, para hacer el equivalente de resumen hmac de ruby.
htafoya
66
Y para verificar un hash, debe usar crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b)): stackoverflow.com/questions/31095905/…
baptx
1
El círculo está completo: nodejs.org/api/crypto.html#crypto_crypto
Ricardo Tomasi
98

Hace unos años se decía que update()y digest()eran métodos heredados y se introdujo el nuevo enfoque de la API de streaming. Ahora los documentos dicen que se puede usar cualquier método. Por ejemplo:

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

Probado en el nodo v6.2.2 y v7.7.2

Ver https://nodejs.org/api/crypto.html#crypto_class_hmac . Da más ejemplos para usar el enfoque de transmisión.

Adam Griffiths
fuente
No es una línea, y las llamadas no se pueden encadenar ... pero usaré este enfoque.
tfmontague
2
No puedo, por mi vida, hacer que esto funcione. hmac.read () devuelve un "[objeto SlowBuffer]" y si intento leer el contenido usando hmac.read (). toString ('hex'); No obtengo el valor esperado. Si uso el enfoque obsoleto de actualización / resumen, devuelve la cadena esperada. Estoy usando esto para validar una firma de un POST de terceros en mis servidores. ¿Alguna idea de lo que está pasando?
AngraX
¿Quizás hmac.read está sucediendo antes de que los datos se hayan vaciado a la transmisión? ¿Quizás hmac.read debería ser impulsado por el evento de finalización de la transmisión?
Dave
En realidad, el enlace que publicaste menciona explícitamente el uso de updatey no write. Estoy confundido, ¿cuál es la mejor práctica ahora? No puedo encontrar recursos que lo digan tan claramente como lo mencionas.
SCBuergel.eth
55
A partir de noviembre de 2016, digesty noupdate han quedado en desuso y aparecen en la documentación: nodejs.org/api/crypto.html#crypto_class_hmac . Recomiendo usar la API de transmisión solo si está leyendo desde una transmisión.
Ricardo Tomasi
22

La solución de Gwerder no funcionará porque hash = hmac.read();sucede antes de que finalice la transmisión. De ahí los problemas de AngraX. Además, la hmac.writedeclaración no es necesaria en este ejemplo.

En cambio, haz esto:

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

Más formalmente, si lo desea, la línea

hmac.end(text, function () {

podría ser escrito

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

porque en este ejemplo el texto es una cadena utf

Dave
fuente
Estás equivocado, no hay necesidad de agregar una devolución de llamada. Este flujo es sincrónico y se puede leer justo después de que se llame a end (). La mayoría Lo fascinante es que está escrito en la documentación oficial, pero todo el mundo tiene que poner sus 5 centavos (dobladas) en.
stroncium
¿Estás trolleando? Quizás deberías leer la documentación. Si intenta leer la secuencia antes del evento de finalización, fallará.
Dave
1
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. Lo lees cuando finalizó el lado de escritura , ni siquiera necesitas esperar cuando el lado legible se vuelve legible (aunque seguramente lo hace). Lea su documentación por favor.
strongcium
createHmac crea una secuencia . " finalizado " en la línea de documentación que cita arriba no significa que hmac.end(...)se haya llamado, " finalizado " significa que la secuencia ha generado su evento de finalización , por lo que el comando acepta una devolución de llamada. Después de llamar al método end (), la secuencia requiere tiempo para vaciar los datos al sistema subyacente. Si llama a read () antes de que se genere el evento de finalización, fallará. Siga adelante y pegue el código de Gwerder en JSbin y compruébelo usted mismo. Debería leer la documentación de Streams para comprender cómo funciona.
Dave
Lo he usado en el código de producción durante algún tiempo y es estable como el infierno. Sinceramente, no sé qué es JSBin, pero también probé el código compatible en nodejs con solo copiar y pegar y también funciona. No debe imaginar significados adicionales para la documentación. "finalizado" siempre significa "finalizado" en todas partes en la documentación. Una vez más, parece malinterpretar que la transmisión tiene 2 lados. Y en la documentación se establece explícitamente que la persona puede usar read()cuando finalizó el lado de escritura , y no hay nada sobre el evento de finalización.
strongcium