web-dev-qa-db-ja.com

javascriptのBlob /ファイルからSHA-256ハッシュを作成します

ブラウザ内のファイル(〜6MB)からSHA-256ダイジェストを作成する必要があります。私がこれまでにそれを行うことができた唯一の方法は次のようなものでした:

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);

これは正しく機能しますが、問題は非常に遅いことです。 6MBのファイルの場合は2〜3秒かかりました。どうすればこれを改善できますか?

24
Gabi Purcaru

スタンフォードJS暗号ライブラリをご覧になることをお勧めします

GitHub

例のあるウェブサイト

ウェブサイトから:

SJCLは安全です。 128、192、または256ビットで業界標準のAESアルゴリズムを使用します。 SHA256ハッシュ関数。 HMAC認証コード。 PBKDF2パスワード強化; CCMおよびOCB認証付き暗号化モード。

SJCLには、所要時間を示すテストページがあります。

SHA256反復の場合は184ミリ秒。そして、カタメリングからのSHA-256の場合は50ミリ秒。

テスト ページ

サンプルコード:

データの暗号化:sjcl.encrypt("password", "data")

データの復号化:sjcl.decrypt("password", "encrypted-data")

18
Washcloth

これは古い質問ですが、asmCryptojsSHAよりも大幅に高速であり、CryptoJSおよびSJCLよりも高速であることに注意してください。

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

_OpenPGP.js_によって維持されているライトバージョン(上記のフォーク)もあります

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

これには、SHA256といくつかのAES機能のみが含まれます。

asmCryptoを使用するには次のようにするだけです。

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

150MB +ファイルを<2秒で一貫してハッシュすることができますChromeで。

6
Colin

emscripten コンパイルされたバージョンの暗号ライブラリを使用する方が速いかもしれません。

Q.コンパイルされたコードの速度はどれくらいですか?

A. Emscriptenのデフォルトのコード生成モードはasm.js形式です。これは、JavaScriptエンジンが非常に高速に実行できるように設計されたJavaScriptのサブセットです。最新のベンチマーク結果については、こちらをご覧ください。多くの場合、asm.jsはネイティブの速度にかなり近づくことができます。

EmscriptenでコンパイルされたNaCl暗号化ライブラリを見つけることができます ここ

4
sbridges

これがあなたが探しているものです。これは、SHA256アルゴリズムのCバージョンから派生しました。 SHA256Dも含まれています。 javascriptを使用すると、これよりもはるかに速くなるとは思いません。ループを拡張しようとしましたが、javascriptインタープリターによって実行される最適化のために実行速度が遅くなりました。

// 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;



};
3
Ralph Ritoch