Comment puis-je obtenir le hachage sha1 d'une chaîne dans node.js?

108

J'essaye de créer un serveur websocket écrit dans node.js

Pour que le serveur fonctionne, je dois obtenir le hachage SHA1 d'une chaîne.

Ce que je dois faire est expliqué dans la section 5.2.2 page 35 de la documentation .

Remarque: à titre d'exemple, si la valeur de l'en- "Sec-WebSocket-Key" tête dans la poignée de main du client était "dGhlIHNhbXBsZSBub25jZQ==", le serveur ajouterait la chaîne "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"pour former la chaîne "dGhlIHNhbXBsZSBub25jZQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11". Le serveur prendrait alors le hachage SHA-1 de cette chaîne, donnant la valeur 0xb3 0x7a 0x4f 0x2c 0xc0 0x62 0x4f 0x16 0x90 0xf6 0x46 0x06 0xcf 0x38 0x59 0x45 0xb2 0xbe 0xc4 0xea. Cette valeur est ensuite encodée en base64, pour donner la valeur "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", qui serait retournée dans l'en- "Sec-WebSocket-Accept"tête.

Eric
la source
9
Je recommande fortement d' utiliser l'excellente bibliothèque socket.io au lieu de rouler la vôtre. Non seulement cela a été testé et corrigé de manière approfondie, mais il prend en charge la plupart des navigateurs (même ceux sans API WebSocket) via diverses méthodes.
Alex Turpin
1
Une bonne référence pour les futurs visiteurs: stackoverflow.com/questions/9407892/…
Damodaran

Réponses:

32

Obligatoire: SHA1 est cassé , vous pouvez calculer les collisions SHA1 pour 45 000 USD . Vous devez utiliser sha256:

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

Pour répondre à votre question et faire un hachage SHA1:

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

Ensuite:

getSHA256ofJSON('whatever')

ou

getSHA256ofJSON(['whatever'])

ou

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

Documentation du nœud officiel sur crypto.createHash()

Mikemaccana
la source
7
Bonne idée. Notez, cependant, que tous les objets (à l'exception des tableaux et null) auront la même valeur sha1sum puisque Object.toString()retourne [object Object]par défaut. Donc sha1sum({})=== sha1sum({"foo":"bar"})=== sha1sum({"a":1}), etc.
maerics
sha1 (JSON.stringify ("some string")) => sha1 ("\" some string \ "") qui n'est absolument pas attendu et n'est pas multiplateforme. Parfois, le mieux est l'ennemi du bien.
Pierre
3
sha1 d'une chaîne donnée est censé être le même sur n'importe quelle plateforme. Votre implémentation à l'aide de JSON.stringify modifie la chaîne d'origine et sha1sum ("abcd") donne f805c8fb0d5c466362ce9f0dc798bd5b3b32d512 où tout le monde s'attendrait à 81fe8bfe87576c3ecb22426f8e57847382917acf
Pierre
2
@Pierre C'est un excellent point. Je pense que nommer la fonction sha1sumest inexact étant donné ce que vous avez dit - cela fait clairement plus que ce que ferait un sha1 normal. J'ai renommé la fonction dans la réponse.
mikemaccana
Il n'y a à ce jour aucune collision connue pour le SHA-1 standard de 80
coups
8

Veuillez lire et tenir compte de mes conseils dans les commentaires de votre message. Cela étant dit, si vous avez encore une bonne raison de le faire, consultez cette liste de modules cryptographiques pour Node . Il a des modules pour traiter à la fois sha1 et base64.

Alex Turpin
la source
7

Conseils pour éviter les problèmes (mauvais hachage):

J'ai constaté que NodeJS hachait la représentation UTF-8 de la chaîne. D'autres langages (comme Python, PHP ou PERL ...) hachent la chaîne d'octets.

Nous pouvons ajouter un argument binaire pour utiliser la chaîne d'octets.

const crypto = require("crypto");

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

sha1("Your text ;)");

Vous pouvez essayer avec: "\ xac", "\ xd1", "\ xb9", "\ xe2", "\ xbb", "\ x93", etc ...

Autres langages (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
la source
1
'binary'- Alias ​​pour 'latin1' nodejs.org/api
Jossef Harush
1
^^ Remarque extrêmement importante de @JossefHarush! Si vous n'avez pas spécifiquement besoin d'encoder le texte en latin1 avant le hachage (par exemple exactement pour la compatibilité avec PHP), et qu'il y a une chance que votre texte contienne des symboles Unicode en dehors de la plage latin1 (par exemple emoji!), Ne l'utilisez pas binary! Utiliser binaryou latin1dans le codage perdra des informations et augmentera la probabilité de collisions! Essayez l'extrait ci-dessus avec ces deux exemples: et
cbr
Tous les hachages sont effectués sur des données binaires. Le problème que vous rencontrez est que les autres langues que vous mentionnez n'utilisent pas UTF-8, et non l'inverse. Cela deviendra très apparent une fois que vous aurez essayé de hacher quelque chose en dehors de Latin1. Dans le cas de PHP en particulier, l'encodage est entièrement déterminé par la source, comme le fichier texte lui-même pour le texte codé en dur. Perl peut avoir besoin de gros efforts pour utiliser UTF-8.
Ryan Hanekamp le
3

Vous pouvez utiliser:

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

Pour installer:

  sudo npm install -g sha1
  npm install sha1 --save
user944550
la source
Bonjour user944550, bienvenue. Veuillez envisager d'ajouter plus d'informations.
Tiago Martins Peres 李大仁