Create SHA-256 hash from a Blob/File in javascript

后端 未结 4 1769
不思量自难忘°
不思量自难忘° 2021-02-02 09:20

I need to create a SHA-256 digest from a file (~6MB) inside the browser. The only way that I\'ve managed to do it so far was like this:

var reader = new FileRead         


        
4条回答
  •  野性不改
    2021-02-02 10:12

    Here is what your looking for. I derived this from a C version of the SHA256 algorithm. It also includes SHA256D. I don't think your going to get much faster than this with javascript. I tried expanding the loops and it ran slower due to optimizations run by the javascript interpreter.

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

提交回复
热议问题