Как я могу получить хеш sha1 строки в node.js?

108

Я пытаюсь создать сервер websocket, написанный на node.js

Чтобы сервер заработал, мне нужно получить SHA1-хэш строки.

То, что мне нужно сделать, объясняется в разделе 5.2.2 на стр. 35 документации .

ПРИМЕЧАНИЕ. В качестве примера, если бы значение "Sec-WebSocket-Key" заголовка в подтверждении связи клиента было "dGhlIHNhbXBsZSBub25jZQ=="равно, сервер добавил бы строку "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"для формирования строки "dGhlIHNhbXBsZSBub25jZQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11". Затем сервер берет хэш SHA-1 этой строки, давая значение 0xb3 0x7a 0x4f 0x2c 0xc0 0x62 0x4f 0x16 0x90 0xf6 0x46 0x06 0xcf 0x38 0x59 0x45 0xb2 0xbe 0xc4 0xea. Затем это значение кодируется в кодировке base64, чтобы получить значение "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", которое будет возвращено в "Sec-WebSocket-Accept"заголовке.

Эрик
источник
9
Я настоятельно рекомендую использовать отличную библиотеку socket.io вместо того, чтобы накатывать свою собственную. Он не только тщательно протестирован и исправлен, но и поддерживает большинство браузеров (за исключением тех, у которых нет WebSocket API) различными методами.
Alex Turpin
1
Хороший справочник для будущих посетителей: stackoverflow.com/questions/9407892/…
Дамодаран

Ответы:

32

Обязательно: SHA1 не работает , вы можете вычислить коллизии SHA1 за 45000 долларов США . Вам следует использовать sha256:

var getSHA256ofJSON = function(input){
    return crypto.createHash('sha256').update(JSON.stringify(input)).digest('hex')
}

Чтобы ответить на ваш вопрос и создать хеш SHA1:

const INSECURE_ALGORITHM = 'sha1'
var getInsecureSHA1ofJSON = function(input){
    return crypto.createHash(INSECURE_ALGORITHM).update(JSON.stringify(input)).digest('hex')
}

Затем:

getSHA256ofJSON('whatever')

или

getSHA256ofJSON(['whatever'])

или

getSHA256ofJSON({'this':'too'})

Официальная документация по узлам crypto.createHash()

микемаккана
источник
7
Отличная идея. Однако обратите внимание, что все объекты (кроме массивов и null) будут иметь одно и то же значение sha1sum, поскольку Object.toString()возвращается [object Object]по умолчанию. Итак sha1sum({})=== sha1sum({"foo":"bar"})=== sha1sum({"a":1})и т. Д.
maerics
sha1 (JSON.stringify ("some string")) => sha1 ("\" some string \ ""), что абсолютно не ожидается и не кросс-платформенный. Иногда лучшее - враг хорошего.
Pierre
3
Предполагается, что sha1 данной строки будет одинаковым на любой платформе. Ваша реализация с помощью JSON.stringify изменяет исходную строку и sha1sum ( «ABCD») дает f805c8fb0d5c466362ce9f0dc798bd5b3b32d512 , где каждый будет ожидать 81fe8bfe87576c3ecb22426f8e57847382917acf
Pierre
2
@Pierre Отличный аргумент. Я думаю, что название функции sha1sumнеточно, учитывая то, что вы сказали - это явно больше, чем то, что сделал бы обычный sha1. Я переименовал функцию в ответе.
mikemaccana
Существует на сегодняшний день не известно столкновения для стандартной 80-раундовом SHA-1 в соответствии с stackoverflow.com/a/3476791/1236215
kzahel
8

Пожалуйста, прочтите и внимательно примите во внимание мои советы в комментариях к вашему сообщению. При этом, если у вас все еще есть веская причина для этого, ознакомьтесь с этим списком модулей шифрования для Node . В нем есть модули для работы с sha1 и base64.

Алекс Терпин
источник
7

Советы по предотвращению проблемы (плохой хеш):

Я испытал, что NodeJS хеширует представление строки в кодировке UTF-8. Другие языки (например, Python, PHP или PERL ...) хешируют байтовую строку.

Мы можем добавить двоичный аргумент для использования байтовой строки.

const crypto = require("crypto");

function sha1(data) {
    return crypto.createHash("sha1").update(data, "binary").digest("hex");
}

sha1("Your text ;)");

Вы можете попробовать: «\ xac», «\ xd1», «\ xb9», «\ xe2», «\ xbb», «\ x93» и т. Д.

Другие языки (Python, PHP, ...):

sha1("\xac") //39527c59247a39d18ad48b9947ea738396a3bc47

Nodejs:

sha1 = crypto.createHash("sha1").update("\xac", "binary").digest("hex") //39527c59247a39d18ad48b9947ea738396a3bc47
//without:
sha1 = crypto.createHash("sha1").update("\xac").digest("hex") //f50eb35d94f1d75480496e54f4b4a472a9148752
А-312
источник
1
'binary'- Псевдоним для 'latin1' nodejs.org/api/…
Jossef Harush
1
^^ Чрезвычайно важное замечание от @JossefHarush! Если вам не нужно специально кодировать текст как latin1 перед хешированием (например, именно для совместимости с PHP), и есть вероятность того, что ваш текст содержит символы Unicode за пределами диапазона latin1 (например, эмодзи!), Не используйте binary! Использование binaryили latin1в кодировке приведет к потере информации и увеличению вероятности коллизий! Попробуйте использовать приведенный выше фрагмент, например, с этими двумя: и
cbr
Все хеши выполняются для двоичных данных. Проблема, с которой вы столкнулись, заключается в том, что другие языки, которые вы упомянули, не используют UTF-8, и не наоборот. Это станет очень очевидным, когда вы попытаетесь хешировать что-то за пределами Latin1. В частности, в случае PHP кодировка полностью определяется источником, например, сам текстовый файл для жестко закодированного текста. Для использования UTF-8 Perl может потребоваться некоторая тяжелая работа.
Райан Ханекамп,
3

Ты можешь использовать:

  const sha1 = require('sha1');
  const crypt = sha1('Text');
  console.log(crypt);

Для установки:

  sudo npm install -g sha1
  npm install sha1 --save
user944550
источник
Привет, user944550, добро пожаловать. Пожалуйста, подумайте о добавлении дополнительной информации.
Тьяго Мартинс Перес 李大仁,