¿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.

Eric
fuente
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()

mikemaccana
fuente
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
8

Por favor lea y considere seriamente mi consejo en los comentarios de su publicación. Dicho esto, si aún tiene una buena razón para hacer esto, consulte esta lista de módulos criptográficos para Node . Tiene módulos para tratar tanto con sha1 como con base64.

Alex Turpin
fuente
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
A-312
fuente
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
usuario944550
fuente
Hola user944550, bienvenido. Considere agregar más información.
Tiago Martins Peres 李大仁