sha256 function - Genera un hash da una stringa in Javascript





9 Answers

MODIFICARE

basato sui miei test jsperf, la risposta accettata è in realtà più veloce: http://jsperf.com/hashcodelordvlad

ORIGINALE

se qualcuno è interessato, ecco una versione migliorata (più veloce), che fallirà sui browser più vecchi che non hanno la funzione di reduce dell'array.

hashCode = function(s){
  return s.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0);              
}
md5 string-hash npm

Ho bisogno di convertire stringhe in una qualche forma di hash. È possibile in JavaScript?

Non sto utilizzando un linguaggio lato server, quindi non posso farlo in quel modo.




Basato sulla risposta accettata in ES6. Più piccolo, manutenibile e funziona nei browser moderni.

function hashCode(str) {
  return str.split('').reduce((prevHash, currVal) =>
    (((prevHash << 5) - prevHash) + currVal.charCodeAt(0))|0, 0);
}

// Test
console.log("hashCode(\"Hello!\"): ", hashCode('Hello!'));




Questa è una variante raffinata e migliore:

String.prototype.hashCode = function() {
    var hash = 0, i = 0, len = this.length;
    while ( i < len ) {
        hash  = ((hash << 5) - hash + this.charCodeAt(i++)) << 0;
    }
    return hash;
};

object.hashCode() all'applicazione Java dello standard object.hashCode()

Ecco anche uno che restituisce solo hashcode positivi:

String.prototype.hashcode = function() {
    return (this.hashCode() + 2147483647) + 1;
};

Ed ecco un matching per Java che restituisce solo hashcode positivi:

public static long hashcode(Object obj) {
    return ((long) obj.hashCode()) + Integer.MAX_VALUE + 1l;
}

Godere!




Grazie all'esempio di mar10, ho trovato un modo per ottenere gli stessi risultati in C # e Javascript per un FNV-1a. Se sono presenti caratteri unicode, la parte superiore viene scartata per motivi di prestazioni. Non so perché sarebbe utile per mantenere quelli quando hashing, come sono solo percorsi di URL hashing per ora.

Versione C #

private static readonly UInt32 FNV_OFFSET_32 = 0x811c9dc5;   // 2166136261
private static readonly UInt32 FNV_PRIME_32 = 0x1000193;     // 16777619

// Unsigned 32bit integer FNV-1a
public static UInt32 HashFnv32u(this string s)
{
    // byte[] arr = Encoding.UTF8.GetBytes(s);      // 8 bit expanded unicode array
    char[] arr = s.ToCharArray();                   // 16 bit unicode is native .net 

    UInt32 hash = FNV_OFFSET_32;
    for (var i = 0; i < s.Length; i++)
    {
        // Strips unicode bits, only the lower 8 bits of the values are used
        hash = hash ^ unchecked((byte)(arr[i] & 0xFF));
        hash = hash * FNV_PRIME_32;
    }
    return hash;
}

// Signed hash for storing in SQL Server
public static Int32 HashFnv32s(this string s)
{
    return unchecked((int)s.HashFnv32u());
}

Versione JavaScript

var utils = utils || {};

utils.FNV_OFFSET_32 = 0x811c9dc5;

utils.hashFnv32a = function (input) {
    var hval = utils.FNV_OFFSET_32;

    // Strips unicode bits, only the lower 8 bits of the values are used
    for (var i = 0; i < input.length; i++) {
        hval = hval ^ (input.charCodeAt(i) & 0xFF);
        hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
    }

    return hval >>> 0;
}

utils.toHex = function (val) {
    return ("0000000" + (val >>> 0).toString(16)).substr(-8);
}



Uno veloce e conciso che è stato adattato da here :

String.prototype.hashCode = function() {
  var hash = 5381, i = this.length
  while(i)
    hash = (hash * 33) ^ this.charCodeAt(--i)
  return hash >>> 0;
}






Sono andato per una semplice concatenazione di codici char convertiti in stringhe esadecimali. Questo ha uno scopo relativamente ristretto, ovvero richiede solo una rappresentazione hash di una stringa SHORT (ad esempio titoli, tag) da scambiare con un lato server che per motivi non rilevanti non può facilmente implementare la porta Java hashCode accettata. Ovviamente nessuna applicazione di sicurezza qui.

String.prototype.hash = function() {
  var self = this, range = Array(this.length);
  for(var i = 0; i < this.length; i++) {
    range[i] = i;
  }
  return Array.prototype.map.call(range, function(i) {
    return self.charCodeAt(i).toString(16);
  }).join('');
}

Questo può essere reso più conciso e tollerante per il browser con Underscore. Esempio:

"Lorem Ipsum".hash()
"4c6f72656d20497073756d"

Suppongo che se volessi stringere stringhe più grandi in modo simile, potresti semplicemente ridurre i codici char ed esagerare la somma risultante piuttosto che concatenare i singoli caratteri insieme:

String.prototype.hashLarge = function() {
  var self = this, range = Array(this.length);
  for(var i = 0; i < this.length; i++) {
    range[i] = i;
  }
  return Array.prototype.reduce.call(range, function(sum, i) {
    return sum + self.charCodeAt(i);
  }, 0).toString(16);
}

'One time, I hired a monkey to take notes for me in class. I would just sit back with my mind completely blank while the monkey scribbled on little pieces of paper. At the end of the week, the teacher said, "Class, I want you to write a paper using your notes." So I wrote a paper that said, "Hello! My name is Bingo! I like to climb on things! Can I have a banana? Eek, eek!" I got an F. When I told my mom about it, she said, "I told you, never trust a monkey!"'.hashLarge()
"9ce7"

Naturalmente più rischio di collisione con questo metodo, anche se si potrebbe giocare con l'aritmetica nella riduzione, tuttavia si voleva diversificare e allungare l'hash.




Ecco un semplice hash 53 bit ben distribuito. È abbastanza veloce e ha bassi tassi di collisione.

var cyrb53 = function(str) {
    var p1 = 2654435761, p2 = 1597334677, h1 = 0xdeadbeef | 0, h2 = 0x41c6ce57 | 0;
    for (var i = 0; i < str.length; i++)
        ch = str.charCodeAt(i), h1 = Math.imul(h1 + ch, p1), h2 = Math.imul(h2 + ch, p2);
    h1 = Math.imul(h1 ^ h1 >>> 16, p2), h2 = Math.imul(h2 ^ h2 >>> 15, p1);
    return (h2 & 2097151) * 4294967296 + h1;
};

Usa tecniche simili a xxHash / MurmurHash. Raggiunge la valanga (non severi), quindi i piccoli cambiamenti nell'input hanno grandi cambiamenti nell'output, rendendolo casuale:

0xe00c44e568f86 = "a"
0x893099dbedf04 = "b"
0x98f3f59367810 = "revenge"
0x45f880d099bbf = "revenue"

53 bit è il limite degli interi JS e ha una probabilità di collisione significativamente inferiore rispetto agli hash a 32 bit. Ma se 53 bit non ti bastano, puoi ancora usare tutti i 64 bit costruendo una stringa o una matrice esadecimale:

return (h2>>>0).toString(16).padStart(8,0)+(h1>>>0).toString(16).padStart(8,0);
// or
return [h2>>>0, h1>>>0];

Il problema è che la costruzione della stringa esadecimale diventa il collo di bottiglia sulle prestazioni e l'array ha bisogno di due operatori di confronto invece di uno, il che non è altrettanto conveniente.




Sono in ritardo per la festa, ma puoi usare questo modulo: crypto :

const crypto = require('crypto');

const SALT = '$ome$alt';

function generateHash(pass) {
  return crypto.createHmac('sha256', SALT)
    .update(pass)
    .digest('hex');
}

Il risultato di questa funzione è sempre 64 stringa di 64 caratteri; qualcosa come questo: "aa54e7563b1964037849528e7ba068eb7767b1fab74a8d80fe300828b996714a"






Related