¿Cómo puedo obtener el hash sha1 de una cadena en node.js?


108

Estoy intentando crear un servidor websocket escrito en node.js

Para que el servidor funcione, necesito obtener el hash SHA1 de una cadena.

Lo que tengo que hacer se explica en la sección 5.2.2 página 35 de los documentos .

NOTA: Como ejemplo, si el valor del "Sec-WebSocket-Key" encabezado en el protocolo de enlace del cliente fuera "dGhlIHNhbXBsZSBub25jZQ==", el servidor agregaría "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"la cadena para formar la cadena "dGhlIHNhbXBsZSBub25jZQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11". El servidor tomaría el hash SHA-1 de esta cadena, dando el valor 0xb3 0x7a 0x4f 0x2c 0xc0 0x62 0x4f 0x16 0x90 0xf6 0x46 0x06 0xcf 0x38 0x59 0x45 0xb2 0xbe 0xc4 0xea. Este valor luego se codifica en base64, para dar el valor "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", que se devolvería en el "Sec-WebSocket-Accept"encabezado.


9
Me altamente recomendar el uso de la excelente socket.io biblioteca en vez de rodar su propio. Esto no solo ha sido probado y parcheado exhaustivamente, sino que también es compatible con la mayoría de los navegadores (incluso aquellos sin la API de WebSocket) a través de varios métodos.
Alex Turpin

1
Una buena referencia para los futuros visitantes: stackoverflow.com/questions/9407892/…
Damodaran

Respuestas:



32

Obligatorio: SHA1 está roto , puede calcular las colisiones SHA1 por 45,000 USD . Deberías usar sha256:

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

Para responder a su pregunta y hacer un hash SHA1:

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

Luego:

getSHA256ofJSON('whatever')

o

getSHA256ofJSON(['whatever'])

o

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

Documentos oficiales de nodo en crypto.createHash()


7
Buena idea. Sin embargo, tenga en cuenta que todos los objetos (excepto matrices y null) tendrán el mismo valor sha1sum ya que se Object.toString()devuelve [object Object]de forma predeterminada. Así sha1sum({})=== sha1sum({"foo":"bar"})=== sha1sum({"a":1}), etc.
maerics

sha1 (JSON.stringify ("alguna cadena")) => sha1 ("\" alguna cadena \ "") que no se espera en absoluto y no es multiplataforma. A veces, lo mejor es enemigo del bien.
Pierre

3
Se espera que sha1 de una cadena dada sea el mismo en cualquier plataforma. Su implementación usando JSON.stringify está alterando la cadena original y sha1sum ("abcd") da f805c8fb0d5c466362ce9f0dc798bd5b3b32d512 donde cualquiera esperaría 81fe8bfe87576c3ecb22426f8e57847382917acf
Pierre

2
@Pierre Ese es un punto excelente. Creo que nombrar la función sha1sumes inexacto dado lo que ha dicho; esto claramente hace más de lo que haría un sha1 normal. Cambié el nombre de la función en la respuesta.
mikemaccana

A partir de hoy, no hay colisión conocida para el SHA-1 estándar de 80 rondas de acuerdo con stackoverflow.com/a/3476791/1236215
kzahel


7

Consejos para evitar problemas (mal hash):

Experimenté que NodeJS está procesando la representación UTF-8 de la cadena. Otros lenguajes (como Python, PHP o PERL ...) están usando hash en la cadena de bytes.

Podemos agregar un argumento binario para usar la cadena de bytes.

const crypto = require("crypto");

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

sha1("Your text ;)");

Puedes probar con: "\ xac", "\ xd1", "\ xb9", "\ xe2", "\ xbb", "\ x93", etc.

Otros lenguajes (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

1
'binary'- Alias ​​para 'latin1' nodejs.org/api/…
Jossef Harush

1
^^ ¡Comentario extremadamente importante de @JossefHarush! Si no necesita codificar específicamente el texto como latin1 antes del hash (por ejemplo, exactamente para compatibilidad con PHP), y existe la posibilidad de que su texto contenga símbolos Unicode fuera del rango latin1 (por ejemplo, emoji), ¡no lo use binary! El uso de binaryo latin1en la codificación perderá información y aumentará la probabilidad de colisiones. Pruebe el fragmento anterior con estos dos, por ejemplo: y
cbr

Todos los hashes se realizan con datos binarios. El problema que está experimentando es que los otros idiomas que menciona no usan UTF-8, y no al revés. Esto se hará muy evidente una vez que intente hacer hash en algo fuera de Latin1. En el caso de PHP en particular, la codificación está completamente determinada por la fuente, como el archivo de texto en sí para el texto codificado. Es posible que Perl necesite algo de trabajo pesado para usar UTF-8.
Ryan Hanekamp

3

Puedes usar:

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

Para instalar:

  sudo npm install -g sha1
  npm install sha1 --save

Hola user944550, bienvenido. Considere agregar más información.
Tiago Martins Peres 李大仁
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.