node encriptar javascript html5 performance hash sha

encriptar - Crear hash SHA-256 desde una Blob/archivo en javascript



sha256 jquery (4)

Necesito crear un compendio SHA-256 desde un archivo (~ 6MB) dentro del navegador. La única forma en que logré hacerlo hasta ahora fue así:

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

Si bien esto funciona correctamente, el problema es que es muy lento. Tomó ~ 2-3 segundos para un archivo de 6MB. ¿Cómo puedo mejorar esto?


Es posible que desee echar un vistazo a la biblioteca de criptografía Stanford JS

GitHub

Sitio web con ejemplos

Desde el sitio web:

SJCL es seguro. Utiliza el algoritmo AES estándar de la industria a 128, 192 o 256 bits; la función hash SHA256; el código de autenticación HMAC; el reforzador de contraseñas PBKDF2; y los modos de cifrado autenticado CCM y OCB.

SJCL tiene una página de prueba que muestra cuánto tiempo tomará.

184 milisegundos para un iterativo SHA256. Y 50 milisegundos para un SHA-256 de catameringue.

Página de prueba

Código de muestra:

Cifrar datos: sjcl.encrypt("password", "data")

Descifrar datos: sjcl.decrypt("password", "encrypted-data")


Esta es una vieja pregunta, pero pensé que vale la pena señalar que asmCrypto es significativamente más rápido que jsSHA , y más rápido que CryptoJS y SJCL

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

También hay una versión lite (un tenedor de los anteriores) mantenida por OpenPGP.js

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

Que solo incluye SHA256 y un par de características de AES.

Para usar asmCrypto , simplemente puede hacer lo siguiente:

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

Puedo copiar un archivo de 150MB + en <2 segundos de forma consistente en Chrome.


Esto es lo que estás buscando. Lo obtuve de una versión C del algoritmo SHA256. También incluye SHA256D. No creo que vayas a obtener mucho más rápido que esto con javascript. Traté de expandir los bucles y corrió más lento debido a las optimizaciones ejecutadas por el intérprete de 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; };


Puede ser más rápido usar una versión compilada de emscripten de las bibliotecas de cifrado,

P. ¿Qué tan rápido será el código compilado?

El modo de generación de código predeterminado de Emscripten está en formato asm.js, que es un subconjunto de JavaScript diseñado para permitir que los motores de JavaScript se ejecuten muy rápidamente. Vea aquí los resultados de referencia actualizados. En muchos casos, asm.js puede acercarse bastante a la velocidad nativa.

Aquí puede encontrar una biblioteca criptográfica NaCl compilada por Emscripten.