2014-02-13 12 views
20

Ich muss einen SHA-256-Digest aus einer Datei (~ 6 MB) im Browser erstellen. Der einzige Weg, dass ich es geschafft habe, es zu tun war bisher wie folgt aus:Erstellen SHA-256-Hash aus einem Blob/Datei in Javascript

var reader = new FileReader(); 
reader.onload = function() { 
    // this gets read of the mime-type data header 
    var actual_contents = reader.result.slice(reader.result.indexOf(',') + 1); 
    var what_i_need = new jsSHA(actual_contents, "B64").getHash("SHA-256", "HEX"); 
} 
reader.readAsDataURL(some_file); 

Während dies korrekt funktioniert, das Problem ist, dass es sehr langsam. Es dauerte ~ 2-3 Sekunden für eine 6MB Datei. Wie kann ich das verbessern?

+0

Ich bin nicht vertraut mit dem _SHA256_ Algorithmus, aber wenn Sie die Datei zu einem _ArrayBuffer_ dann zu einem _Uint8Array_ konvertieren, kann dies schneller sein als über _Base64_ gehen und Sie können direkt mit dem _bytes_ arbeiten. –

+0

Können Sie mir ein Beispiel zeigen, wie das gemacht würde? –

+0

'var fr = neuer FileReader; fr.onload = function() {var hash = byteArrayToSHA256 (neues Uint8Array (this.result));} fr.readAsArrayBuffer (some_file); 'wobei' byteArrayToSHA256' der Hashalgorithmus ist. Das bedeutet, dass Sie sich keine Gedanken über utf-encodings/encoding-decoding base64/strings usw. machen müssen. Sie müssen möglicherweise den Algorithmus, den Sie für diese Eingabe haben, neu schreiben. –

Antwort

14

Sie können einen Blick auf die Stanford JS Crypto-Bibliothek

GitHub

Website with Examples

von der Website nehmen wollen:

SJCL sicher ist. Es verwendet den Industriestandard-AES-Algorithmus mit 128, 192 oder 256 Bit; die SHA256-Hash-Funktion; der HMAC-Authentifizierungscode; der PBKDF2-Passwortverstärker; und die authentifizierten CCM- und OCB-Verschlüsselungsmodi.

SJCL hat eine Testseite, die zeigt, wie lange es dauern wird.

184 Millisekunden für einen iterativen SHA256. Und 50 Millisekunden für einen SHA-256 aus dem Kameramodus.

-Test page

Beispielcode:

Daten verschlüsseln: sjcl.encrypt("password", "data")

Decrypt Daten: sjcl.decrypt("password", "encrypted-data")

+2

ein schneller Test zeigte, dass sjcl ~ 10x schneller ist als CryptoJS (für die Berechnung eines SHA-256 Hash für die Zeichenfolge "1234567890"). Obwohl es File/Blob/ArrayBuffer-Hashing nicht zu unterstützen scheint, bringt mich das zurück auf Platz eins. Von dem, was ich gefunden habe, ist CryptoJS der einzige, der das direkte Hashing eines ArrayBuffers unterstützt, was viel schneller ist als der Durchlauf von Base-64, und kombiniert mit Web Workers ist es tatsächlich verwendbar. Aber wenn es einen Weg gibt, stattdessen sjcl zu verwenden, wäre das viel besser. –

4

Es könnte schneller sein, eine emscripten kompilierte Version der Krypto-Bibliotheken zu verwenden,

Q. Wie schnell wird der kompilierte Code sein?

A. Emscriptens Standardcode-Generierungsmodus ist im asm.js-Format, , das eine Teilmenge von JavaScript ist, die es ermöglicht, dass JavaScript-Engines sehr schnell ausgeführt werden können. Sehen Sie hier für aktuelle Benchmark-Ergebnisse. In vielen Fällen kann asm.js der ursprünglichen Geschwindigkeit sehr nahe kommen.

Sie können eine Emscript-kompilierte NaCl-kryptographische Bibliothek here finden.

2

Hier ist was Sie suchen. Ich habe dies von einer C-Version des SHA256-Algorithmus abgeleitet. Es enthält auch SHA256D. Ich glaube nicht, dass Sie mit JavaScript viel schneller als das bekommen werden. Ich habe versucht, die Schleifen zu erweitern, und es lief langsamer aufgrund von Optimierungen, die vom Javascript-Interpreter ausgeführt wurden.

// From: https://github.com/Hartland/GPL-CPU-Miner/blob/master/sha2.c 

if ("undefined" == typeof vnet) { 
    vnet = new Array(); 
} 

if ("undefined" == typeof vnet.crypt) { 
    vnet.crypt = new Array(); 
} 

vnet.crypt.sha2 = function() { 

    var sha256_h = [ 
     0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 
     0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 
    ]; 

    var sha256_k = [ 
        0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 
        0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 
        0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 
        0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 
        0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 
        0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 
        0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 
        0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 
        0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 
        0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 
        0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 
        0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 
        0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 
        0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 
        0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 
        0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 
    ]; 

    var sha256_init = function(s) { 
     s.state = [ 
        sha256_h[0], 
        sha256_h[1], 
        sha256_h[2], 
        sha256_h[3], 
        sha256_h[4], 
        sha256_h[5], 
        sha256_h[6], 
        sha256_h[7], 
     ]; 
    }; this.sha256_init = sha256_init; 

/* 
* SHA256 block compression function. The 256-bit state is transformed via 
* the 512-bit input block to produce a new state. 
*/ 
    var sha256_transform = function(s, b, swap) { 

     var block = b.block; 
     var state = s.state; 

     var W; 
     var S; 
     var t0; 
     var t1; 
     var i; 

     /* 1. Prepare message schedule W. */ 
     if (swap) { 


      W = [ 
       ((((block[0]) << 24) & 0xff000000) | (((block[0]) << 8) & 0x00ff0000) | (((block[0]) >> 8) & 0x0000ff00) | (((block[0]) >> 24) & 0x000000ff)), 
       ((((block[1]) << 24) & 0xff000000) | (((block[1]) << 8) & 0x00ff0000) | (((block[1]) >> 8) & 0x0000ff00) | (((block[1]) >> 24) & 0x000000ff)), 
       ((((block[2]) << 24) & 0xff000000) | (((block[2]) << 8) & 0x00ff0000) | (((block[2]) >> 8) & 0x0000ff00) | (((block[2]) >> 24) & 0x000000ff)), 
       ((((block[3]) << 24) & 0xff000000) | (((block[3]) << 8) & 0x00ff0000) | (((block[3]) >> 8) & 0x0000ff00) | (((block[3]) >> 24) & 0x000000ff)), 
       ((((block[4]) << 24) & 0xff000000) | (((block[4]) << 8) & 0x00ff0000) | (((block[4]) >> 8) & 0x0000ff00) | (((block[4]) >> 24) & 0x000000ff)), 
       ((((block[5]) << 24) & 0xff000000) | (((block[5]) << 8) & 0x00ff0000) | (((block[5]) >> 8) & 0x0000ff00) | (((block[5]) >> 24) & 0x000000ff)), 
       ((((block[6]) << 24) & 0xff000000) | (((block[6]) << 8) & 0x00ff0000) | (((block[6]) >> 8) & 0x0000ff00) | (((block[6]) >> 24) & 0x000000ff)), 
       ((((block[7]) << 24) & 0xff000000) | (((block[7]) << 8) & 0x00ff0000) | (((block[7]) >> 8) & 0x0000ff00) | (((block[7]) >> 24) & 0x000000ff)), 
       ((((block[8]) << 24) & 0xff000000) | (((block[8]) << 8) & 0x00ff0000) | (((block[8]) >> 8) & 0x0000ff00) | (((block[8]) >> 24) & 0x000000ff)), 
       ((((block[9]) << 24) & 0xff000000) | (((block[9]) << 8) & 0x00ff0000) | (((block[9]) >> 8) & 0x0000ff00) | (((block[9]) >> 24) & 0x000000ff)), 
       ((((block[10]) << 24) & 0xff000000) | (((block[10]) << 8) & 0x00ff0000) | (((block[10]) >> 8) & 0x0000ff00) | (((block[10]) >> 24) & 0x000000ff)), 
       ((((block[11]) << 24) & 0xff000000) | (((block[11]) << 8) & 0x00ff0000) | (((block[11]) >> 8) & 0x0000ff00) | (((block[11]) >> 24) & 0x000000ff)), 
       ((((block[12]) << 24) & 0xff000000) | (((block[12]) << 8) & 0x00ff0000) | (((block[12]) >> 8) & 0x0000ff00) | (((block[12]) >> 24) & 0x000000ff)), 
       ((((block[13]) << 24) & 0xff000000) | (((block[13]) << 8) & 0x00ff0000) | (((block[13]) >> 8) & 0x0000ff00) | (((block[13]) >> 24) & 0x000000ff)), 
       ((((block[14]) << 24) & 0xff000000) | (((block[14]) << 8) & 0x00ff0000) | (((block[14]) >> 8) & 0x0000ff00) | (((block[14]) >> 24) & 0x000000ff)), 
       ((((block[15]) << 24) & 0xff000000) | (((block[15]) << 8) & 0x00ff0000) | (((block[15]) >> 8) & 0x0000ff00) | (((block[15]) >> 24) & 0x000000ff)) 
      ]; 
     } else { 
      W = [ 
       block[0], 
       block[1], 
       block[2], 
       block[3], 
       block[4], 
       block[5], 
       block[6], 
       block[7], 
       block[8], 
       block[9], 
       block[10], 
       block[11], 
       block[12], 
       block[13], 
       block[14], 
       block[15] 
      ]; 
     } 


     for (i = 16; i < 64; i += 2) { 
      W[i] = ((
       ((((W[i-2] >>> 17) | (W[i-2] << 15))^((W[i-2] >>> 19) | ((W[i-2] << 13)>>>0))^(W[i - 2] >>> 10)) >>> 0) + //s1 (W[i - 2]) + 
       W[i - 7] + 
       ((((W[i - 15] >>> 7) | (W[i - 15] << 25))^((W[i - 15] >>> 18) | ((W[i - 15] << 14) >>> 0))^(W[i - 15] >>> 3)) >>> 0) + //s0 (W[i - 15]) + 
       W[i - 16] 
      ) & 0xffffffff) >>> 0; 

      W[i+1] = ((
       ((((W[i-1] >>> 17) | (W[i-1] << 15))^((W[i-1] >>> 19) | (W[i-1] << 13))^(W[i - 1] >>> 10)) >>> 0)+ //s1 (W[i - 1]) + 
       W[i - 6] + 
       ((((W[i - 14] >>> 7) | (W[i - 14] << 25))^((W[i - 14] >>> 18) | (W[i - 14] << 14))^(W[i - 14] >>> 3)) >>> 0) + //s0 (W[i - 14]) + 
       W[i - 15] 
      ) & 0xffffffff) >>> 0; 
     } 


     /* 2. Initialize working variables. */ 

     S = [ 
     state[0], 
     state[1], 
     state[2], 
     state[3], 
     state[4], 
     state[5], 
     state[6], 
     state[7], 
     ]; 

     /* 3. Mix. */ 


     i=0; 
     for(;i<64;++i) { 

      //RNDr(S,W,i) 
      t0 = S[(71 - i) % 8] + 
       ((((S[(68 - i) % 8] >>> 6) | (S[(68 - i) % 8] << 26))^((S[(68 - i) % 8] >>> 11) | (S[(68 - i) % 8] << 21))^((S[(68 - i) % 8] >>> 25) | (S[(68 - i) % 8] << 7)))) + //S1 (S[(68 - i) % 8]) + 
       (((S[(68 - i) % 8] & (S[(69 - i) % 8]^S[(70 - i) % 8]))^S[(70 - i) % 8])) + // Ch 
       W[i] + 
       sha256_k[i]; 

      t1 = ((((S[(64 - i) % 8] >>> 2) | ((S[(64 - i) % 8] & 3) << 30))^((S[(64 - i) % 8] >>> 13) | (S[(64 - i) % 8] << 19))^((S[(64 - i) % 8] >>> 22) | (S[(64 - i) % 8] << 10)))) + //S0 (S[(64 - i) % 8]) + 
       (((S[(64 - i) % 8] & (S[(65 - i) % 8] | S[(66 - i) % 8])) | (S[(65 - i) % 8] & S[(66 - i) % 8]))); // Maj 

      S[(67 - i) % 8] = ((S[(67 - i) % 8] + t0) & 0xFFFFFFFF) >>> 0; 
      S[(71 - i) % 8] = ((t0 + t1) & 0xFFFFFFFF) >>> 0; 
     } 

     /* 4. Mix local working variables into global state */ 

     i=0; 
     for(;i<8;++i) { 
      s.state[i] = (0xFFFFFFFF & (state[i] + S[i])) >>> 0; 
     } 

    }; this.sha256_transform = sha256_transform; 

    var sha256d_hash1 = [ 
     0x00000000, 0x00000000, 0x00000000, 0x00000000, 
     0x00000000, 0x00000000, 0x00000000, 0x00000000, 
     0x80000000, 0x00000000, 0x00000000, 0x00000000, 
     0x00000000, 0x00000000, 0x00000000, 0x00000100 
    ]; 

    var sha256d_80_swap = function(hash, data) 
    { 

     var S = new Array(); 

     var i; 

     var b1 = new Array(); 
     var b2 = new Array(); 
     var b3 = new Array(); 

     b1.block = [ 
      data[0], 
      data[1], 
      data[2], 
      data[3], 
      data[4], 
      data[5], 
      data[6], 
      data[7], 
      data[8], 
      data[9], 
      data[10], 
      data[11], 
      data[12], 
      data[13], 
      data[14], 
      data[15] 
     ]; 

     b2.block = [ 
      data[16], 
      data[17], 
      data[18], 
      data[19], 
      data[20], 
      data[21], 
      data[22], 
      data[23], 
      data[24], 
      data[25], 
      data[26], 
      data[27], 
      data[28], 
      data[29], 
      data[30], 
      data[31] 
     ]; 

     sha256_init(S); 
     sha256_transform(S, b1, 0); 
     sha256_transform(S, b2, 0); 

     b3.block = [ 
      S.state[0], 
      S.state[1], 
      S.state[2], 
      S.state[3], 
      S.state[4], 
      S.state[5], 
      S.state[6], 
      S.state[7], 
      sha256d_hash1[8], 
      sha256d_hash1[9], 
      sha256d_hash1[10], 
      sha256d_hash1[11], 
      sha256d_hash1[12], 
      sha256d_hash1[13], 
      sha256d_hash1[14], 
      sha256d_hash1[15] 
     ]; 

     sha256_init(hash); 
     sha256_transform(hash, b3, 0); 

     for (i = 0; i < 8; i++) { 
      hash.state[i] = ((((hash.state[i]) << 24) & 0xff000000) | (((hash.state[i]) << 8) & 0x00ff0000) | (((hash.state[i]) >> 8) & 0x0000ff00) | (((hash.state[i]) >> 24) & 0x000000ff)); //swab32(hash[i]); 
     } 

    }; this.sha256d_80_swap = sha256d_80_swap; 

    var sha256d = function(hash, data) { 
     var S; 
     var T; 
     var block_in; 

     S = new Array(); 
     T = new Array(); 

     T.block = []; 

     var i, r; 

     //hash.hash = new Array(32).join('0').split('').map(parseFloat); 

     sha256_init(S); 

     for (r = data.length; r > -9; r -= 64) { 
      if (r < 64) { 
       if (r > 0) { 
        block_in = data.slice(data.length - r,data.length); 
        block_in.push.apply(block_in, new Array(64-r).join('0').split('').map(parseFloat)); 
       } else { 
        block_in = new Array(64).join('0').split('').map(parseFloat); 
       } 
      } else { 
       block_in = data.slice(data.length - r,data.length - r + 64); 
      } 

      //memcpy(T, data + len - r, r > 64 ? 64 : (r < 0 ? 0 : r)); 

      if (r >= 0 && r < 64) { 
       block_in[r] = 0x80; 
      } 

      for (i = 0; i < 16; i++) { 
       T.block[i] = (((0xff & block_in[(i*4)]) << 24) | ((0xff & block_in[(i*4)+1]) << 16) | ((0xff & block_in[(i*4)+2]) << 8) | (0xff & block_in[(i*4)+3])) >>> 0; 
      } 

      if (r < 56) { 
       T.block[15] = 8 * data.length; 
      } 

      sha256_transform(S, T, 0); 
     } 
     //memcpy(S + 8, sha256d_hash1 + 8, 32); 
     S.block = S.state; 
     for(i=8;i<16;i++) { 
      S.block[i] = sha256d_hash1[i]; 
     } 

     sha256_init(T); 
     sha256_transform(T, S, 0); 

     hash.hash = [ 
        (T.state[0] >> 24) & 0xff, 
        (T.state[0] >> 16) & 0xff, 
        (T.state[0] >> 8) & 0xff, 
        T.state[0] & 0xff, 

        (T.state[1] >> 24) & 0xff, 
        (T.state[1] >> 16) & 0xff, 
        (T.state[1] >> 8) & 0xff, 
        T.state[1] & 0xff, 

        (T.state[2] >> 24) & 0xff, 
        (T.state[2] >> 16) & 0xff, 
        (T.state[2] >> 8) & 0xff, 
        T.state[2] & 0xff, 

        (T.state[3] >> 24) & 0xff, 
        (T.state[3] >> 16) & 0xff, 
        (T.state[3] >> 8) & 0xff, 
        T.state[3] & 0xff, 

        (T.state[4] >> 24) & 0xff, 
        (T.state[4] >> 16) & 0xff, 
        (T.state[4] >> 8) & 0xff, 
        T.state[4] & 0xff, 

        (T.state[5] >> 24) & 0xff, 
        (T.state[5] >> 16) & 0xff, 
        (T.state[5] >> 8) & 0xff, 
        T.state[5] & 0xff, 

        (T.state[6] >> 24) & 0xff, 
        (T.state[6] >> 16) & 0xff, 
        (T.state[6] >> 8) & 0xff, 
        T.state[6] & 0xff, 

        (T.state[7] >> 24) & 0xff, 
        (T.state[7] >> 16) & 0xff, 
        (T.state[7] >> 8) & 0xff, 
        T.state[7] & 0xff 
     ]; 

    }; this.sha256d = sha256d; 



    var sha256 = function(hash, data) { 
     var S; 
     var T; 
     var block_in; 

     S = new Array(); 
     T = new Array(); 

     T.block = []; 

     var i, r; 

     hash.hash = new Array(32).join('0').split('').map(parseFloat); 

     sha256_init(S); 

     for (r = data.length; r > -9; r -= 64) { 

      if (r < 64) { 
       if (r > 0) { 
        block_in = data.slice(data.length - r,data.length); 
        block_in.push.apply(block_in, new Array(64-r).join('0').split('').map(parseFloat)); 
       } else { 
        block_in = new Array(64).join('0').split('').map(parseFloat); 
       } 
      } else { 
       block_in = data.slice(data.length - r,data.length - r + 64); 
      } 

      //memcpy(T, data + len - r, r > 64 ? 64 : (r < 0 ? 0 : r)); 

      if (r >= 0 && r < 64) { 
       block_in[r] = 0x80; 
      } 

      for (i = 0; i < 16; i++) { 
       T.block[i] = (((0xff & block_in[(i*4)]) << 24) | ((0xff & block_in[(i*4)+1]) << 16) | ((0xff & block_in[(i*4)+2]) << 8) | (0xff & block_in[(i*4)+3])) >>> 0; 
      } 

      if (r < 56) { 
       T.block[15] = 8 * data.length; 
      } 

      sha256_transform(S, T, 0); 
     } 

     for (i = 0; i < 8; i++) { 
      //be32enc((uint32_t *)hash + i, T[i]); 
      hash.hash[(i * 4)] = (S.state[i] >> 24) & 0xff; 
      hash.hash[(i * 4)+1] = (S.state[i] >> 16) & 0xff 
      hash.hash[(i * 4)+2] = (S.state[i] >> 8) & 0xff 
      hash.hash[(i * 4)+3] = S.state[i] & 0xff; 
     } 
    }; this.sha256 = sha256; 



}; 
4

Dies ist eine alte Frage, aber ich dachte, es ist erwähnenswert, dass asmCrypto ist deutlich schneller als jsSHA, und schneller als CryptoJS und SJCL

https://github.com/vibornoff/asmcrypto.js/

Es gibt auch eine Lite-Version (a fork von oben) gehalten von OpenPGP.js

https://github.com/openpgpjs/asmcrypto-lite

Die nur SHA256 und ein paar AES-Funktionen enthält.

verwenden asmCrypto Sie können die folgenden einfach tun:

var sha256HexValue = asmCrypto.SHA256.hex(myArraybuffer);

Ich bin in der Lage eine 150MB + Datei in < 2 Sekunden, um Hash konsequent in Chrome.

Verwandte Themen