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

Я хочу создать хеш I love cupcakes (подписанный ключом abcdeg)

Как я могу создать этот хеш с помощью Node.js Crypto?


person user847495    schedule 20.09.2011    source источник


Ответы (3)


Документация по криптографии: 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')
person Ricardo Tomasi    schedule 20.09.2011
comment
'hex' не всегда требуется, например, для выполнения дайджеста hmac, эквивалентного рубину. - person htafoya; 20.09.2018
comment
А чтобы проверить хеш, вы должны использовать crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b)): stackoverflow.com/questions/31095905/ - person baptx; 02.08.2019
comment
Круг замкнут: nodejs.org/api/crypto.html#crypto_crypto - person Ricardo Tomasi; 02.12.2019

Несколько лет назад было сказано, что 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. Дает больше примеров использования потокового подхода.

person Adam Griffiths    schedule 15.09.2013
comment
Не однострочный, и вызовы не могут быть подключены гирляндой ... но я буду использовать этот подход. - person tim-montague; 27.07.2014
comment
Я не могу, хоть убей, заставить это работать. hmac.read () возвращает [объект SlowBuffer], и если я попытаюсь прочитать содержимое с помощью hmac.read (). toString ('hex'); Я не получаю ожидаемого значения. Если я использую устаревший подход обновления / дайджеста, он возвращает ожидаемую строку. Я использую это для проверки подписи стороннего POST на моих серверах. Есть идеи, что происходит? - person AngraX; 25.08.2014
comment
Возможно, hmac.read происходит до того, как данные были сброшены в поток? Может быть, hmac.read должен управляться событием завершения потока? - person Dave; 30.09.2014
comment
На самом деле в опубликованной вами ссылке прямо упоминается использование update, а не write. Я не понимаю, что сейчас лучше всего? Я не могу найти ресурсы, которые говорят об этом так ясно, как вы об этом упомянули. - person SCBuergel; 31.07.2016
comment
По состоянию на ноябрь 2016 г. digest и update не устарели и представлены в документации: nodejs.org/api/crypto.html#crypto_class_hmac. Я рекомендую использовать потоковый API только в том случае, если вы читаете из потока. - person Ricardo Tomasi; 15.11.2016
comment
Это правда, update и digest не амортизировались. Когда я первоначально ответил на этот вопрос в 2013 году, документы сказали, что это устаревшие методы, но в 2015 году они были изменены, чтобы сказать, что использование конвейерных потоков (как в моем ответе) или использование update и digest (как в ответе Рикардо) являются допустимыми методами. Здесь были изменены <документы и документы href = "https://github.com/nodejs/node/blob/master/doc/api/crypto.md#class-hash" rel = "nofollow noreferrer"> здесь текущие документы. - person Adam Griffiths; 25.04.2017
comment
@AdamGriffiths отлично работает с ними обоими. Что посоветуете использовать? - person Raz; 21.02.2018

Решение Гвердера не сработает, потому что 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

person Dave    schedule 09.10.2014
comment
Вы ошибаетесь, нет необходимости добавлять обратный вызов. Этот поток синхронный и доступен для чтения сразу после вызова end (). Самое интересное, что это написано в официальной документации, но каждый должен вложить свои 5 (согнутых) центов. - person stroncium; 02.11.2015
comment
Вы троллите? Возможно, вам стоит прочитать документацию. Если вы попытаетесь прочитать поток до финиша, это не удастся. - person Dave; 03.11.2015
comment
Из [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. Вы читаете когда доступная для записи сторона закончилась, вам даже не нужно ждать, когда читаемая сторона станет читаемой (хотя конечно, делает). Прочтите, пожалуйста, вашу документацию. - person stroncium; 03.11.2015
comment
createHmac создает поток. закончился в строке документации, которую вы цитируете выше, не означает, что hmac.end(...) был вызван, закончился означает, что поток поднял свое событие завершения, которое почему команда принимает обратный вызов. После вызова метода end () потоку требуется время, чтобы сбросить данные в базовую систему. Если вы вызовете read () до того, как будет сгенерировано событие finish, произойдет сбой. Вставьте код Гвердера в JSbin и убедитесь в этом сами. Вам следует прочитать документацию по Streams, чтобы понять, как это работает. - person Dave; 04.11.2015
comment
Некоторое время я использовал его в производственном коде, и он чертовски стабилен. Я, честно говоря, не знаю, что такое JSBin, но я также пробовал поддерживаемый код в nodejs с помощью простого копирования и вставки, и он тоже работает. Вы не должны придавать дополнительное значение документации. закончился всегда означает закончился везде в документации. И снова вы, кажется, неправильно понимаете, что у потока есть две стороны. И в документации явно указано, что человек может использовать read(), когда доступная для записи сторона закончилась, и ничего не говорится о событии завершения. - person stroncium; 04.11.2015
comment
И даже какое-то абстрактное решение, которое читает hmacs со всего мира, должно зависеть не от события Writable finish, а от событий readable readable и end. - person stroncium; 04.11.2015
comment
По вашей логике нормально читать данные, когда некоторая система решает, что она выполнила очистку всех данных, необходимых для их генерации, но до того, как фактический производитель данных что-либо сгенерировал. Так как насчет того, чтобы не вводить чрезвычайно дырявые абстракции и ад обратных вызовов, когда у нас есть система (которая на самом деле является чисто синхронной), которая гарантированно работает простым, эффективным и предсказуемым образом? - person stroncium; 04.11.2015