Как использовать Node.js Crypto для создания хэша HMAC-SHA1?

Ответы:

369

Документация для шифрования: 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')
Рикардо Томази
источник
'hex' не всегда нужен, например, для выполнения hmac-дайджеста, эквивалентного ruby.
Хтафоя
6
И чтобы проверить хеш, вы должны использовать crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b)): stackoverflow.com/questions/31095905/…
baptx
1
Круг завершен: nodejs.org/api/crypto.html#crypto_crypto
Рикардо Томази,
98

Несколько лет назад было сказано , что update()и digest()были устаревшие методы и был введен новый потоковый API подход. Теперь в документах говорится, что любой метод может быть использован. Например:

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

Протестировано на узле v6.2.2 и v7.7.2

См. Https://nodejs.org/api/crypto.html#crypto_class_hmac . Дает больше примеров для использования потокового подхода.

Адам Гриффитс
источник
Не однострочно, и звонки не могут быть последовательными ... но я буду использовать этот подход.
tfmontague
2
Я не могу, ради моей жизни, сделать эту работу. hmac.read () возвращает «[object SlowBuffer]», и если я пытаюсь прочитать содержимое, используя hmac.read (). toString ('hex'); Я не получаю ожидаемое значение. Если я использую устаревший подход update / digest, он возвращает ожидаемую строку. Я использую это для проверки подписи стороннего POST на моих серверах. Есть идеи, что происходит?
AngraX
Возможно, hmac.read происходит до того, как данные были сброшены в поток? Может быть, hmac.read должен управляться событием финиша потока?
Дейв
На самом деле ссылка, которую вы разместили, явно упоминает об использовании, updateа не о write. Я в замешательстве, какая сейчас лучшая практика? Я не могу найти ресурсы, которые рассказывают об этом так же ясно, как вы это упоминаете.
SCBuergel.eth
5
По состоянию на 2016 ноября, digestи updateеще не были устаревшими и описаны в документации: nodejs.org/api/crypto.html#crypto_class_hmac . Я рекомендую использовать потоковый API, только если вы читаете из потока.
Рикардо Томази
22

Решение Gwerder не сработает, потому что оно hash = hmac.read();происходит до того, как поток будет завершен и завершен. Таким образом, проблемы AngraX. Кроме того, hmac.writeутверждение не является необходимым в этом примере.

Вместо этого сделайте это:

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

Более формально, если хотите, строка

hmac.end(text, function () {

может быть написано

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

потому что в этом примере текст является строкой UTF

Дейв
источник
Вы не правы, нет необходимости добавлять обратный вызов. Этот поток является синхронным и доступен для чтения сразу после вызова end (). Самое удивительное, что это написано в официальной документации, но каждый должен положить свои 5 (согнутых) центов.
Стронций
Ты троллинг? Возможно, вам следует прочитать документацию. Если вы попытаетесь прочитать поток до окончания события, оно не будет выполнено.
Дейв
1
Из [ 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. Вы читаете его, когда заканчивается сторона , доступная для записи , вам даже не нужно ждать, когда сторона, доступная для чтения, станет читаемой (хотя, безусловно, это так). Прочитайте свою документацию, пожалуйста.
стронций
createHmac создает поток . « конец » в строке документации, которую вы цитируете выше, не означает, hmac.end(...)что был вызван, « конец » означает, что поток вызвал событие завершения , поэтому команда принимает обратный вызов. После вызова метода end () потоку требуется время для сброса данных в базовую систему. Если вы вызовите read () до того, как будет завершено событие финиша, произойдет сбой. Идите вперед и вставьте код Gwerder в JSbin и убедитесь сами. Вы должны читать документацию по Streams, чтобы понять, как она работает.
Дейв
Я использовал его в производственном коде в течение некоторого времени, и он чертовски стабилен. Честно говоря, я не знаю, что такое JSBin, но я также пробовал поддерживаемый код в nodejs просто копировать-вставить, и он тоже работает. Вы не должны представлять дополнительные значения для документации. «Законченный» всегда означает «законченный» везде в документации. Опять же, вы, кажется, неправильно поняли, что поток имеет 2 стороны. И в документации явно указано, что человек может использовать, read()когда завершается доступная для записи сторона, и нет ничего о завершающем событии.
стронций