diff --git a/scrypt-async.js b/scrypt-async.js index ac8a647..b3564de 100644 --- a/scrypt-async.js +++ b/scrypt-async.js @@ -1,5 +1,5 @@ /*! - * Fast "async" scrypt implementation in JavaScript. + * Fast scrypt implementation in JavaScript, using Promises. * Copyright (c) 2013-2015 Dmitry Chestnykh | BSD License * https://github.com/dchest/scrypt-async-js */ @@ -9,475 +9,430 @@ */ /** - * scrypt(password, salt, logN, r, dkLen, [interruptStep], callback, [encoding]) + * scrypt(password, salt, logN, r, dkLen, [encoding]) * - * Derives a key from password and salt and calls callback + * Derives a key from password and salt and returns a Promise * with derived key as the only argument. * - * Calculations are interrupted with setImmediate (or zero setTimeout) at the - * given interruptSteps to avoid freezing the browser. If interruptStep is not - * given, it defaults to 1000. If it's zero, the callback is called immediately - * after the calculation, avoiding setImmediate. - * * @param {string|Array.} password Password. * @param {string|Array.} salt Salt. * @param {number} logN CPU/memory cost parameter (1 to 31). * @param {number} r Block size parameter. * @param {number} dkLen Length of derived key. - * @param {number?} interruptStep (optional) Steps to split calculation with timeouts (default 1000). - * @param {function(string|Array.)} callback Callback function. * @param {string?} encoding (optional) Result encoding ("base64", "hex", or null). * */ -function scrypt(password, salt, logN, r, dkLen, interruptStep, callback, encoding) { +function scrypt(password, salt, logN, r, dkLen, encoding) { 'use strict'; - function SHA256(m) { - /** @const */ var 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 h0 = 0x6a09e667, h1 = 0xbb67ae85, h2 = 0x3c6ef372, h3 = 0xa54ff53a, - h4 = 0x510e527f, h5 = 0x9b05688c, h6 = 0x1f83d9ab, h7 = 0x5be0cd19, - w = new Array(64); - - function blocks(p) { - var off = 0, len = p.length; - while (len >= 64) { - var a = h0, b = h1, c = h2, d = h3, e = h4, f = h5, g = h6, h = h7, - u, i, j, t1, t2; - - for (i = 0; i < 16; i++) { - j = off + i*4; - w[i] = ((p[j] & 0xff)<<24) | ((p[j+1] & 0xff)<<16) | - ((p[j+2] & 0xff)<<8) | (p[j+3] & 0xff); - } + return new Promise(function (callback, reject) { + function SHA256(m) { + /** @const */ var 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 h0 = 0x6a09e667, h1 = 0xbb67ae85, h2 = 0x3c6ef372, h3 = 0xa54ff53a, + h4 = 0x510e527f, h5 = 0x9b05688c, h6 = 0x1f83d9ab, h7 = 0x5be0cd19, + w = new Array(64); + + function blocks(p) { + var off = 0, len = p.length; + while (len >= 64) { + var a = h0, b = h1, c = h2, d = h3, e = h4, f = h5, g = h6, h = h7, + u, i, j, t1, t2; + + for (i = 0; i < 16; i++) { + j = off + i*4; + w[i] = ((p[j] & 0xff)<<24) | ((p[j+1] & 0xff)<<16) | + ((p[j+2] & 0xff)<<8) | (p[j+3] & 0xff); + } + + for (i = 16; i < 64; i++) { + u = w[i-2]; + t1 = ((u>>>17) | (u<<(32-17))) ^ ((u>>>19) | (u<<(32-19))) ^ (u>>>10); + + u = w[i-15]; + t2 = ((u>>>7) | (u<<(32-7))) ^ ((u>>>18) | (u<<(32-18))) ^ (u>>>3); - for (i = 16; i < 64; i++) { - u = w[i-2]; - t1 = ((u>>>17) | (u<<(32-17))) ^ ((u>>>19) | (u<<(32-19))) ^ (u>>>10); + w[i] = (((t1 + w[i-7]) | 0) + ((t2 + w[i-16]) | 0)) | 0; + } - u = w[i-15]; - t2 = ((u>>>7) | (u<<(32-7))) ^ ((u>>>18) | (u<<(32-18))) ^ (u>>>3); + for (i = 0; i < 64; i++) { + t1 = ((((((e>>>6) | (e<<(32-6))) ^ ((e>>>11) | (e<<(32-11))) ^ + ((e>>>25) | (e<<(32-25)))) + ((e & f) ^ (~e & g))) | 0) + + ((h + ((K[i] + w[i]) | 0)) | 0)) | 0; + + t2 = ((((a>>>2) | (a<<(32-2))) ^ ((a>>>13) | (a<<(32-13))) ^ + ((a>>>22) | (a<<(32-22)))) + ((a & b) ^ (a & c) ^ (b & c))) | 0; + + h = g; + g = f; + f = e; + e = (d + t1) | 0; + d = c; + c = b; + b = a; + a = (t1 + t2) | 0; + } - w[i] = (((t1 + w[i-7]) | 0) + ((t2 + w[i-16]) | 0)) | 0; + h0 = (h0 + a) | 0; + h1 = (h1 + b) | 0; + h2 = (h2 + c) | 0; + h3 = (h3 + d) | 0; + h4 = (h4 + e) | 0; + h5 = (h5 + f) | 0; + h6 = (h6 + g) | 0; + h7 = (h7 + h) | 0; + + off += 64; + len -= 64; } + } + + blocks(m); + + var i, bytesLeft = m.length % 64, + bitLenHi = (m.length / 0x20000000) | 0, + bitLenLo = m.length << 3, + numZeros = (bytesLeft < 56) ? 56 : 120, + p = m.slice(m.length - bytesLeft, m.length); + + p.push(0x80); + for (i = bytesLeft + 1; i < numZeros; i++) p.push(0); + p.push((bitLenHi>>>24) & 0xff); + p.push((bitLenHi>>>16) & 0xff); + p.push((bitLenHi>>>8) & 0xff); + p.push((bitLenHi>>>0) & 0xff); + p.push((bitLenLo>>>24) & 0xff); + p.push((bitLenLo>>>16) & 0xff); + p.push((bitLenLo>>>8) & 0xff); + p.push((bitLenLo>>>0) & 0xff); + + blocks(p); + + return [ + (h0>>>24) & 0xff, (h0>>>16) & 0xff, (h0>>>8) & 0xff, (h0>>>0) & 0xff, + (h1>>>24) & 0xff, (h1>>>16) & 0xff, (h1>>>8) & 0xff, (h1>>>0) & 0xff, + (h2>>>24) & 0xff, (h2>>>16) & 0xff, (h2>>>8) & 0xff, (h2>>>0) & 0xff, + (h3>>>24) & 0xff, (h3>>>16) & 0xff, (h3>>>8) & 0xff, (h3>>>0) & 0xff, + (h4>>>24) & 0xff, (h4>>>16) & 0xff, (h4>>>8) & 0xff, (h4>>>0) & 0xff, + (h5>>>24) & 0xff, (h5>>>16) & 0xff, (h5>>>8) & 0xff, (h5>>>0) & 0xff, + (h6>>>24) & 0xff, (h6>>>16) & 0xff, (h6>>>8) & 0xff, (h6>>>0) & 0xff, + (h7>>>24) & 0xff, (h7>>>16) & 0xff, (h7>>>8) & 0xff, (h7>>>0) & 0xff + ]; + } - for (i = 0; i < 64; i++) { - t1 = ((((((e>>>6) | (e<<(32-6))) ^ ((e>>>11) | (e<<(32-11))) ^ - ((e>>>25) | (e<<(32-25)))) + ((e & f) ^ (~e & g))) | 0) + - ((h + ((K[i] + w[i]) | 0)) | 0)) | 0; - - t2 = ((((a>>>2) | (a<<(32-2))) ^ ((a>>>13) | (a<<(32-13))) ^ - ((a>>>22) | (a<<(32-22)))) + ((a & b) ^ (a & c) ^ (b & c))) | 0; - - h = g; - g = f; - f = e; - e = (d + t1) | 0; - d = c; - c = b; - b = a; - a = (t1 + t2) | 0; + function PBKDF2_HMAC_SHA256_OneIter(password, salt, dkLen) { + // compress password if it's longer than hash block length + password = password.length <= 64 ? password : SHA256(password); + + var i, innerLen = 64 + salt.length + 4, + inner = new Array(innerLen), + outerKey = new Array(64), + dk = []; + + // inner = (password ^ ipad) || salt || counter + for (i = 0; i < 64; i++) inner[i] = 0x36; + for (i = 0; i < password.length; i++) inner[i] ^= password[i]; + for (i = 0; i < salt.length; i++) inner[64+i] = salt[i]; + for (i = innerLen - 4; i < innerLen; i++) inner[i] = 0; + + // outerKey = password ^ opad + for (i = 0; i < 64; i++) outerKey[i] = 0x5c; + for (i = 0; i < password.length; i++) outerKey[i] ^= password[i]; + + // increments counter inside inner + function incrementCounter() { + for (var i = innerLen-1; i >= innerLen-4; i--) { + inner[i]++; + if (inner[i] <= 0xff) return; + inner[i] = 0; } + } - h0 = (h0 + a) | 0; - h1 = (h1 + b) | 0; - h2 = (h2 + c) | 0; - h3 = (h3 + d) | 0; - h4 = (h4 + e) | 0; - h5 = (h5 + f) | 0; - h6 = (h6 + g) | 0; - h7 = (h7 + h) | 0; - - off += 64; - len -= 64; + // output blocks = SHA256(outerKey || SHA256(inner)) ... + while (dkLen >= 32) { + incrementCounter(); + dk = dk.concat(SHA256(outerKey.concat(SHA256(inner)))); + dkLen -= 32; + } + if (dkLen > 0) { + incrementCounter(); + dk = dk.concat(SHA256(outerKey.concat(SHA256(inner))).slice(0, dkLen)); } + return dk; } - blocks(m); - - var i, bytesLeft = m.length % 64, - bitLenHi = (m.length / 0x20000000) | 0, - bitLenLo = m.length << 3, - numZeros = (bytesLeft < 56) ? 56 : 120, - p = m.slice(m.length - bytesLeft, m.length); - - p.push(0x80); - for (i = bytesLeft + 1; i < numZeros; i++) p.push(0); - p.push((bitLenHi>>>24) & 0xff); - p.push((bitLenHi>>>16) & 0xff); - p.push((bitLenHi>>>8) & 0xff); - p.push((bitLenHi>>>0) & 0xff); - p.push((bitLenLo>>>24) & 0xff); - p.push((bitLenLo>>>16) & 0xff); - p.push((bitLenLo>>>8) & 0xff); - p.push((bitLenLo>>>0) & 0xff); - - blocks(p); - - return [ - (h0>>>24) & 0xff, (h0>>>16) & 0xff, (h0>>>8) & 0xff, (h0>>>0) & 0xff, - (h1>>>24) & 0xff, (h1>>>16) & 0xff, (h1>>>8) & 0xff, (h1>>>0) & 0xff, - (h2>>>24) & 0xff, (h2>>>16) & 0xff, (h2>>>8) & 0xff, (h2>>>0) & 0xff, - (h3>>>24) & 0xff, (h3>>>16) & 0xff, (h3>>>8) & 0xff, (h3>>>0) & 0xff, - (h4>>>24) & 0xff, (h4>>>16) & 0xff, (h4>>>8) & 0xff, (h4>>>0) & 0xff, - (h5>>>24) & 0xff, (h5>>>16) & 0xff, (h5>>>8) & 0xff, (h5>>>0) & 0xff, - (h6>>>24) & 0xff, (h6>>>16) & 0xff, (h6>>>8) & 0xff, (h6>>>0) & 0xff, - (h7>>>24) & 0xff, (h7>>>16) & 0xff, (h7>>>8) & 0xff, (h7>>>0) & 0xff - ]; - } - - function PBKDF2_HMAC_SHA256_OneIter(password, salt, dkLen) { - // compress password if it's longer than hash block length - password = password.length <= 64 ? password : SHA256(password); - - var i, innerLen = 64 + salt.length + 4, - inner = new Array(innerLen), - outerKey = new Array(64), - dk = []; - - // inner = (password ^ ipad) || salt || counter - for (i = 0; i < 64; i++) inner[i] = 0x36; - for (i = 0; i < password.length; i++) inner[i] ^= password[i]; - for (i = 0; i < salt.length; i++) inner[64+i] = salt[i]; - for (i = innerLen - 4; i < innerLen; i++) inner[i] = 0; - - // outerKey = password ^ opad - for (i = 0; i < 64; i++) outerKey[i] = 0x5c; - for (i = 0; i < password.length; i++) outerKey[i] ^= password[i]; - - // increments counter inside inner - function incrementCounter() { - for (var i = innerLen-1; i >= innerLen-4; i--) { - inner[i]++; - if (inner[i] <= 0xff) return; - inner[i] = 0; + function salsaXOR(tmp, B, bin, bout) { + var j0 = tmp[0] ^ B[bin++], + j1 = tmp[1] ^ B[bin++], + j2 = tmp[2] ^ B[bin++], + j3 = tmp[3] ^ B[bin++], + j4 = tmp[4] ^ B[bin++], + j5 = tmp[5] ^ B[bin++], + j6 = tmp[6] ^ B[bin++], + j7 = tmp[7] ^ B[bin++], + j8 = tmp[8] ^ B[bin++], + j9 = tmp[9] ^ B[bin++], + j10 = tmp[10] ^ B[bin++], + j11 = tmp[11] ^ B[bin++], + j12 = tmp[12] ^ B[bin++], + j13 = tmp[13] ^ B[bin++], + j14 = tmp[14] ^ B[bin++], + j15 = tmp[15] ^ B[bin++], + u, i; + + var x0 = j0, x1 = j1, x2 = j2, x3 = j3, x4 = j4, x5 = j5, x6 = j6, x7 = j7, + x8 = j8, x9 = j9, x10 = j10, x11 = j11, x12 = j12, x13 = j13, x14 = j14, + x15 = j15; + + for (i = 0; i < 8; i += 2) { + u = x0 + x12; x4 ^= u<<7 | u>>>(32-7); + u = x4 + x0; x8 ^= u<<9 | u>>>(32-9); + u = x8 + x4; x12 ^= u<<13 | u>>>(32-13); + u = x12 + x8; x0 ^= u<<18 | u>>>(32-18); + + u = x5 + x1; x9 ^= u<<7 | u>>>(32-7); + u = x9 + x5; x13 ^= u<<9 | u>>>(32-9); + u = x13 + x9; x1 ^= u<<13 | u>>>(32-13); + u = x1 + x13; x5 ^= u<<18 | u>>>(32-18); + + u = x10 + x6; x14 ^= u<<7 | u>>>(32-7); + u = x14 + x10; x2 ^= u<<9 | u>>>(32-9); + u = x2 + x14; x6 ^= u<<13 | u>>>(32-13); + u = x6 + x2; x10 ^= u<<18 | u>>>(32-18); + + u = x15 + x11; x3 ^= u<<7 | u>>>(32-7); + u = x3 + x15; x7 ^= u<<9 | u>>>(32-9); + u = x7 + x3; x11 ^= u<<13 | u>>>(32-13); + u = x11 + x7; x15 ^= u<<18 | u>>>(32-18); + + u = x0 + x3; x1 ^= u<<7 | u>>>(32-7); + u = x1 + x0; x2 ^= u<<9 | u>>>(32-9); + u = x2 + x1; x3 ^= u<<13 | u>>>(32-13); + u = x3 + x2; x0 ^= u<<18 | u>>>(32-18); + + u = x5 + x4; x6 ^= u<<7 | u>>>(32-7); + u = x6 + x5; x7 ^= u<<9 | u>>>(32-9); + u = x7 + x6; x4 ^= u<<13 | u>>>(32-13); + u = x4 + x7; x5 ^= u<<18 | u>>>(32-18); + + u = x10 + x9; x11 ^= u<<7 | u>>>(32-7); + u = x11 + x10; x8 ^= u<<9 | u>>>(32-9); + u = x8 + x11; x9 ^= u<<13 | u>>>(32-13); + u = x9 + x8; x10 ^= u<<18 | u>>>(32-18); + + u = x15 + x14; x12 ^= u<<7 | u>>>(32-7); + u = x12 + x15; x13 ^= u<<9 | u>>>(32-9); + u = x13 + x12; x14 ^= u<<13 | u>>>(32-13); + u = x14 + x13; x15 ^= u<<18 | u>>>(32-18); } + + B[bout++] = tmp[0] = (x0 + j0) | 0; + B[bout++] = tmp[1] = (x1 + j1) | 0; + B[bout++] = tmp[2] = (x2 + j2) | 0; + B[bout++] = tmp[3] = (x3 + j3) | 0; + B[bout++] = tmp[4] = (x4 + j4) | 0; + B[bout++] = tmp[5] = (x5 + j5) | 0; + B[bout++] = tmp[6] = (x6 + j6) | 0; + B[bout++] = tmp[7] = (x7 + j7) | 0; + B[bout++] = tmp[8] = (x8 + j8) | 0; + B[bout++] = tmp[9] = (x9 + j9) | 0; + B[bout++] = tmp[10] = (x10 + j10) | 0; + B[bout++] = tmp[11] = (x11 + j11) | 0; + B[bout++] = tmp[12] = (x12 + j12) | 0; + B[bout++] = tmp[13] = (x13 + j13) | 0; + B[bout++] = tmp[14] = (x14 + j14) | 0; + B[bout++] = tmp[15] = (x15 + j15) | 0; } - // output blocks = SHA256(outerKey || SHA256(inner)) ... - while (dkLen >= 32) { - incrementCounter(); - dk = dk.concat(SHA256(outerKey.concat(SHA256(inner)))); - dkLen -= 32; + function blockCopy(dst, di, src, si, len) { + while (len--) dst[di++] = src[si++]; } - if (dkLen > 0) { - incrementCounter(); - dk = dk.concat(SHA256(outerKey.concat(SHA256(inner))).slice(0, dkLen)); + + function blockXOR(dst, di, src, si, len) { + while (len--) dst[di++] ^= src[si++]; } - return dk; - } - - function salsaXOR(tmp, B, bin, bout) { - var j0 = tmp[0] ^ B[bin++], - j1 = tmp[1] ^ B[bin++], - j2 = tmp[2] ^ B[bin++], - j3 = tmp[3] ^ B[bin++], - j4 = tmp[4] ^ B[bin++], - j5 = tmp[5] ^ B[bin++], - j6 = tmp[6] ^ B[bin++], - j7 = tmp[7] ^ B[bin++], - j8 = tmp[8] ^ B[bin++], - j9 = tmp[9] ^ B[bin++], - j10 = tmp[10] ^ B[bin++], - j11 = tmp[11] ^ B[bin++], - j12 = tmp[12] ^ B[bin++], - j13 = tmp[13] ^ B[bin++], - j14 = tmp[14] ^ B[bin++], - j15 = tmp[15] ^ B[bin++], - u, i; - - var x0 = j0, x1 = j1, x2 = j2, x3 = j3, x4 = j4, x5 = j5, x6 = j6, x7 = j7, - x8 = j8, x9 = j9, x10 = j10, x11 = j11, x12 = j12, x13 = j13, x14 = j14, - x15 = j15; - - for (i = 0; i < 8; i += 2) { - u = x0 + x12; x4 ^= u<<7 | u>>>(32-7); - u = x4 + x0; x8 ^= u<<9 | u>>>(32-9); - u = x8 + x4; x12 ^= u<<13 | u>>>(32-13); - u = x12 + x8; x0 ^= u<<18 | u>>>(32-18); - - u = x5 + x1; x9 ^= u<<7 | u>>>(32-7); - u = x9 + x5; x13 ^= u<<9 | u>>>(32-9); - u = x13 + x9; x1 ^= u<<13 | u>>>(32-13); - u = x1 + x13; x5 ^= u<<18 | u>>>(32-18); - - u = x10 + x6; x14 ^= u<<7 | u>>>(32-7); - u = x14 + x10; x2 ^= u<<9 | u>>>(32-9); - u = x2 + x14; x6 ^= u<<13 | u>>>(32-13); - u = x6 + x2; x10 ^= u<<18 | u>>>(32-18); - - u = x15 + x11; x3 ^= u<<7 | u>>>(32-7); - u = x3 + x15; x7 ^= u<<9 | u>>>(32-9); - u = x7 + x3; x11 ^= u<<13 | u>>>(32-13); - u = x11 + x7; x15 ^= u<<18 | u>>>(32-18); - - u = x0 + x3; x1 ^= u<<7 | u>>>(32-7); - u = x1 + x0; x2 ^= u<<9 | u>>>(32-9); - u = x2 + x1; x3 ^= u<<13 | u>>>(32-13); - u = x3 + x2; x0 ^= u<<18 | u>>>(32-18); - - u = x5 + x4; x6 ^= u<<7 | u>>>(32-7); - u = x6 + x5; x7 ^= u<<9 | u>>>(32-9); - u = x7 + x6; x4 ^= u<<13 | u>>>(32-13); - u = x4 + x7; x5 ^= u<<18 | u>>>(32-18); - - u = x10 + x9; x11 ^= u<<7 | u>>>(32-7); - u = x11 + x10; x8 ^= u<<9 | u>>>(32-9); - u = x8 + x11; x9 ^= u<<13 | u>>>(32-13); - u = x9 + x8; x10 ^= u<<18 | u>>>(32-18); - - u = x15 + x14; x12 ^= u<<7 | u>>>(32-7); - u = x12 + x15; x13 ^= u<<9 | u>>>(32-9); - u = x13 + x12; x14 ^= u<<13 | u>>>(32-13); - u = x14 + x13; x15 ^= u<<18 | u>>>(32-18); + + function blockMix(tmp, B, bin, bout, r) { + blockCopy(tmp, 0, B, bin + (2*r-1)*16, 16); + for (var i = 0; i < 2*r; i += 2) { + salsaXOR(tmp, B, bin + i*16, bout + i*8); + salsaXOR(tmp, B, bin + i*16 + 16, bout + i*8 + r*16); + } } - B[bout++] = tmp[0] = (x0 + j0) | 0; - B[bout++] = tmp[1] = (x1 + j1) | 0; - B[bout++] = tmp[2] = (x2 + j2) | 0; - B[bout++] = tmp[3] = (x3 + j3) | 0; - B[bout++] = tmp[4] = (x4 + j4) | 0; - B[bout++] = tmp[5] = (x5 + j5) | 0; - B[bout++] = tmp[6] = (x6 + j6) | 0; - B[bout++] = tmp[7] = (x7 + j7) | 0; - B[bout++] = tmp[8] = (x8 + j8) | 0; - B[bout++] = tmp[9] = (x9 + j9) | 0; - B[bout++] = tmp[10] = (x10 + j10) | 0; - B[bout++] = tmp[11] = (x11 + j11) | 0; - B[bout++] = tmp[12] = (x12 + j12) | 0; - B[bout++] = tmp[13] = (x13 + j13) | 0; - B[bout++] = tmp[14] = (x14 + j14) | 0; - B[bout++] = tmp[15] = (x15 + j15) | 0; - } - - function blockCopy(dst, di, src, si, len) { - while (len--) dst[di++] = src[si++]; - } - - function blockXOR(dst, di, src, si, len) { - while (len--) dst[di++] ^= src[si++]; - } - - function blockMix(tmp, B, bin, bout, r) { - blockCopy(tmp, 0, B, bin + (2*r-1)*16, 16); - for (var i = 0; i < 2*r; i += 2) { - salsaXOR(tmp, B, bin + i*16, bout + i*8); - salsaXOR(tmp, B, bin + i*16 + 16, bout + i*8 + r*16); + function integerify(B, bi, r) { + return B[bi+(2*r-1)*16]; } - } - - function integerify(B, bi, r) { - return B[bi+(2*r-1)*16]; - } - - function stringToUTF8Bytes(s) { - var arr = []; - for (var i = 0; i < s.length; i++) { - var c = s.charCodeAt(i); - if (c < 128) { - arr.push(c); - } else if (c > 127 && c < 2048) { - arr.push((c>>6) | 192); - arr.push((c & 63) | 128); - } else { - arr.push((c>>12) | 224); - arr.push(((c>>6) & 63) | 128); - arr.push((c & 63) | 128); - } - } - return arr; - } - function bytesToHex(p) { - /** @const */ - var enc = '0123456789abcdef'.split(''); + function stringToUTF8Bytes(s) { + var arr = []; + for (var i = 0; i < s.length; i++) { + var c = s.charCodeAt(i); + if (c < 128) { + arr.push(c); + } else if (c > 127 && c < 2048) { + arr.push((c>>6) | 192); + arr.push((c & 63) | 128); + } else { + arr.push((c>>12) | 224); + arr.push(((c>>6) & 63) | 128); + arr.push((c & 63) | 128); + } + } + return arr; + } - var len = p.length, - arr = [], - i = 0; + function bytesToHex(p) { + /** @const */ + var enc = '0123456789abcdef'.split(''); - for (; i < len; i++) { - arr.push(enc[(p[i]>>>4) & 15]); - arr.push(enc[(p[i]>>>0) & 15]); - } - return arr.join(''); - } - - function bytesToBase64(p) { - /** @const */ - var enc = ('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' + - '0123456789+/').split(''); - - var len = p.length, - arr = [], - i = 0, - a, b, c, t; - - while (i < len) { - a = i < len ? p[i++] : 0; - b = i < len ? p[i++] : 0; - c = i < len ? p[i++] : 0; - t = (a << 16) + (b << 8) + c; - arr.push(enc[(t >>> 3 * 6) & 63]); - arr.push(enc[(t >>> 2 * 6) & 63]); - arr.push(enc[(t >>> 1 * 6) & 63]); - arr.push(enc[(t >>> 0 * 6) & 63]); + var len = p.length, + arr = [], + i = 0; + + for (; i < len; i++) { + arr.push(enc[(p[i]>>>4) & 15]); + arr.push(enc[(p[i]>>>0) & 15]); + } + return arr.join(''); } - if (len % 3 > 0) { - arr[arr.length-1] = '='; - if (len % 3 === 1) arr[arr.length-2] = '='; + + function bytesToBase64(p) { + /** @const */ + var enc = ('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' + + '0123456789+/').split(''); + + var len = p.length, + arr = [], + i = 0, + a, b, c, t; + + while (i < len) { + a = i < len ? p[i++] : 0; + b = i < len ? p[i++] : 0; + c = i < len ? p[i++] : 0; + t = (a << 16) + (b << 8) + c; + arr.push(enc[(t >>> 3 * 6) & 63]); + arr.push(enc[(t >>> 2 * 6) & 63]); + arr.push(enc[(t >>> 1 * 6) & 63]); + arr.push(enc[(t >>> 0 * 6) & 63]); + } + if (len % 3 > 0) { + arr[arr.length-1] = '='; + if (len % 3 === 1) arr[arr.length-2] = '='; + } + return arr.join(''); } - return arr.join(''); - } - // Generate key. + // Generate key. - // Set parallelization parameter to 1. - var p = 1; + // Set parallelization parameter to 1. + var p = 1; - if (r <= 0) - throw new Error('scrypt: invalid r'); + if (r <= 0) + return reject('scrypt: invalid r'); - if (logN < 1 || logN > 31) - throw new Error('scrypt: logN not be between 1 and 31'); + if (logN < 1 || logN > 31) + return reject('scrypt: logN not be between 1 and 31'); - var MAX_INT = (1<<31)>>>0, - N = (1<>>0, - XY, V, B, tmp; + var MAX_INT = (1<<31)>>>0, + N = (1<>>0, + XY, V, B, tmp; - if (r*p >= 1<<30 || r > MAX_INT/128/p || r > MAX_INT/256 || N > MAX_INT/128/r) - throw new Error('scrypt: parameters are too large'); + if (r*p >= 1<<30 || r > MAX_INT/128/p || r > MAX_INT/256 || N > MAX_INT/128/r) + return reject('scrypt: parameters are too large'); - // Decode strings. - if (typeof password === 'string') - password = stringToUTF8Bytes(password); - if (typeof salt === 'string') - salt = stringToUTF8Bytes(salt); + // Decode strings. + if (typeof password === 'string') + password = stringToUTF8Bytes(password); + if (typeof salt === 'string') + salt = stringToUTF8Bytes(salt); - if (typeof Int32Array !== 'undefined') { - //XXX We can use Uint32Array, but Int32Array is faster in Safari. - XY = new Int32Array(64*r); - V = new Int32Array(32*N*r); - tmp = new Int32Array(16); - } else { - XY = []; - V = []; - tmp = new Array(16); - } - B = PBKDF2_HMAC_SHA256_OneIter(password, salt, p*128*r); + if (typeof Int32Array !== 'undefined') { + //XXX We can use Uint32Array, but Int32Array is faster in Safari. + XY = new Int32Array(64*r); + V = new Int32Array(32*N*r); + tmp = new Int32Array(16); + } else { + XY = []; + V = []; + tmp = new Array(16); + } + B = PBKDF2_HMAC_SHA256_OneIter(password, salt, p*128*r); - var xi = 0, yi = 32 * r; + var xi = 0, yi = 32 * r; - function smixStart() { - for (var i = 0; i < 32*r; i++) { - var j = i*4; - XY[xi+i] = ((B[j+3] & 0xff)<<24) | ((B[j+2] & 0xff)<<16) | - ((B[j+1] & 0xff)<<8) | ((B[j+0] & 0xff)<<0); + function smixStart() { + for (var i = 0; i < 32*r; i++) { + var j = i*4; + XY[xi+i] = ((B[j+3] & 0xff)<<24) | ((B[j+2] & 0xff)<<16) | + ((B[j+1] & 0xff)<<8) | ((B[j+0] & 0xff)<<0); + } } - } - function smixStep1(start, end) { - for (var i = start; i < end; i += 2) { - blockCopy(V, i*(32*r), XY, xi, 32*r); - blockMix(tmp, XY, xi, yi, r); + function smixStep1(start, end) { + for (var i = start; i < end; i += 2) { + blockCopy(V, i*(32*r), XY, xi, 32*r); + blockMix(tmp, XY, xi, yi, r); - blockCopy(V, (i+1)*(32*r), XY, yi, 32*r); - blockMix(tmp, XY, yi, xi, r); + blockCopy(V, (i+1)*(32*r), XY, yi, 32*r); + blockMix(tmp, XY, yi, xi, r); + } } - } - function smixStep2(start, end) { - for (var i = start; i < end; i += 2) { - var j = integerify(XY, xi, r) & (N-1); - blockXOR(XY, xi, V, j*(32*r), 32*r); - blockMix(tmp, XY, xi, yi, r); + function smixStep2(start, end) { + for (var i = start; i < end; i += 2) { + var j = integerify(XY, xi, r) & (N-1); + blockXOR(XY, xi, V, j*(32*r), 32*r); + blockMix(tmp, XY, xi, yi, r); - j = integerify(XY, yi, r) & (N-1); - blockXOR(XY, yi, V, j*(32*r), 32*r); - blockMix(tmp, XY, yi, xi, r); - } - } - - function smixFinish() { - for (var i = 0; i < 32*r; i++) { - var j = XY[xi+i]; - B[i*4+0] = (j>>>0) & 0xff; - B[i*4+1] = (j>>>8) & 0xff; - B[i*4+2] = (j>>>16) & 0xff; - B[i*4+3] = (j>>>24) & 0xff; + j = integerify(XY, yi, r) & (N-1); + blockXOR(XY, yi, V, j*(32*r), 32*r); + blockMix(tmp, XY, yi, xi, r); + } } - } - var nextTick = (typeof setImmediate !== 'undefined') ? setImmediate : setTimeout; + function smixFinish() { + for (var i = 0; i < 32*r; i++) { + var j = XY[xi+i]; + B[i*4+0] = (j>>>0) & 0xff; + B[i*4+1] = (j>>>8) & 0xff; + B[i*4+2] = (j>>>16) & 0xff; + B[i*4+3] = (j>>>24) & 0xff; + } + } - function interruptedFor(start, end, step, fn, donefn) { - (function performStep() { - nextTick(function() { - fn(start, start + step < end ? start + step : end); - start += step; - if (start < end) - performStep(); + function getResult(enc) { + var result = PBKDF2_HMAC_SHA256_OneIter(password, B, dkLen); + if (enc === 'base64') + return bytesToBase64(result); + else if (enc === 'hex') + return bytesToHex(result); else - donefn(); - }); - })(); - } - - function getResult(enc) { - var result = PBKDF2_HMAC_SHA256_OneIter(password, B, dkLen); - if (enc === 'base64') - return bytesToBase64(result); - else if (enc === 'hex') - return bytesToHex(result); - else - return result; - } - - if (typeof interruptStep === 'function') { - // Called as: scrypt(..., callback, [encoding]) - // shifting: scrypt(..., interruptStep, callback, [encoding]) - encoding = callback; - callback = interruptStep; - interruptStep = 1000; - } - - if (interruptStep <= 0) { - // - // Blocking async variant, calls callback. - // + return result; + } + smixStart(); smixStep1(0, N); smixStep2(0, N); smixFinish(); - callback(getResult(encoding)); - - } else { - // - // Async variant with interruptions, calls callback. - // - smixStart(); - interruptedFor(0, N, interruptStep*2, smixStep1, function() { - interruptedFor(0, N, interruptStep*2, smixStep2, function () { - smixFinish(); - callback(getResult(encoding)); - }); - }); - } + return callback(getResult(encoding)); + }); } if (typeof module !== 'undefined') module.exports = scrypt; diff --git a/scrypt-async.min.js b/scrypt-async.min.js index 1d4897f..6568618 100644 --- a/scrypt-async.min.js +++ b/scrypt-async.min.js @@ -1,6 +1,43 @@ /*! - * Fast "async" scrypt implementation in JavaScript. + * Fast scrypt implementation in JavaScript, using Promises. * Copyright (c) 2013-2015 Dmitry Chestnykh | BSD License * https://github.com/dchest/scrypt-async-js */ -function scrypt(a,b,c,d,e,f,g,h){"use strict";function i(a){function b(a){for(var b=0,m=a.length;m>=64;){var n,o,p,q,r,s=d,t=e,u=f,v=g,w=h,x=i,y=j,z=k;for(o=0;16>o;o++)p=b+4*o,l[o]=(255&a[p])<<24|(255&a[p+1])<<16|(255&a[p+2])<<8|255&a[p+3];for(o=16;64>o;o++)n=l[o-2],q=(n>>>17|n<<15)^(n>>>19|n<<13)^n>>>10,n=l[o-15],r=(n>>>7|n<<25)^(n>>>18|n<<14)^n>>>3,l[o]=(q+l[o-7]|0)+(r+l[o-16]|0)|0;for(o=0;64>o;o++)q=(((w>>>6|w<<26)^(w>>>11|w<<21)^(w>>>25|w<<7))+(w&x^~w&y)|0)+(z+(c[o]+l[o]|0)|0)|0,r=((s>>>2|s<<30)^(s>>>13|s<<19)^(s>>>22|s<<10))+(s&t^s&u^t&u)|0,z=y,y=x,x=w,w=v+q|0,v=u,u=t,t=s,s=q+r|0;d=d+s|0,e=e+t|0,f=f+u|0,g=g+v|0,h=h+w|0,i=i+x|0,j=j+y|0,k=k+z|0,b+=64,m-=64}}var c=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298],d=1779033703,e=3144134277,f=1013904242,g=2773480762,h=1359893119,i=2600822924,j=528734635,k=1541459225,l=new Array(64);b(a);var m,n=a.length%64,o=a.length/536870912|0,p=a.length<<3,q=56>n?56:120,r=a.slice(a.length-n,a.length);for(r.push(128),m=n+1;q>m;m++)r.push(0);return r.push(o>>>24&255),r.push(o>>>16&255),r.push(o>>>8&255),r.push(o>>>0&255),r.push(p>>>24&255),r.push(p>>>16&255),r.push(p>>>8&255),r.push(p>>>0&255),b(r),[d>>>24&255,d>>>16&255,d>>>8&255,d>>>0&255,e>>>24&255,e>>>16&255,e>>>8&255,e>>>0&255,f>>>24&255,f>>>16&255,f>>>8&255,f>>>0&255,g>>>24&255,g>>>16&255,g>>>8&255,g>>>0&255,h>>>24&255,h>>>16&255,h>>>8&255,h>>>0&255,i>>>24&255,i>>>16&255,i>>>8&255,i>>>0&255,j>>>24&255,j>>>16&255,j>>>8&255,j>>>0&255,k>>>24&255,k>>>16&255,k>>>8&255,k>>>0&255]}function j(a,b,c){function d(){for(var a=f-1;a>=f-4;a--){if(g[a]++,g[a]<=255)return;g[a]=0}}a=a.length<=64?a:i(a);var e,f=64+b.length+4,g=new Array(f),h=new Array(64),j=[];for(e=0;64>e;e++)g[e]=54;for(e=0;ee;e++)g[e]=0;for(e=0;64>e;e++)h[e]=92;for(e=0;e=32;)d(),j=j.concat(i(h.concat(i(g)))),c-=32;return c>0&&(d(),j=j.concat(i(h.concat(i(g))).slice(0,c))),j}function k(a,b,c,d){var e,f,g=a[0]^b[c++],h=a[1]^b[c++],i=a[2]^b[c++],j=a[3]^b[c++],k=a[4]^b[c++],l=a[5]^b[c++],m=a[6]^b[c++],n=a[7]^b[c++],o=a[8]^b[c++],p=a[9]^b[c++],q=a[10]^b[c++],r=a[11]^b[c++],s=a[12]^b[c++],t=a[13]^b[c++],u=a[14]^b[c++],v=a[15]^b[c++],w=g,x=h,y=i,z=j,A=k,B=l,C=m,D=n,E=o,F=p,G=q,H=r,I=s,J=t,K=u,L=v;for(f=0;8>f;f+=2)e=w+I,A^=e<<7|e>>>25,e=A+w,E^=e<<9|e>>>23,e=E+A,I^=e<<13|e>>>19,e=I+E,w^=e<<18|e>>>14,e=B+x,F^=e<<7|e>>>25,e=F+B,J^=e<<9|e>>>23,e=J+F,x^=e<<13|e>>>19,e=x+J,B^=e<<18|e>>>14,e=G+C,K^=e<<7|e>>>25,e=K+G,y^=e<<9|e>>>23,e=y+K,C^=e<<13|e>>>19,e=C+y,G^=e<<18|e>>>14,e=L+H,z^=e<<7|e>>>25,e=z+L,D^=e<<9|e>>>23,e=D+z,H^=e<<13|e>>>19,e=H+D,L^=e<<18|e>>>14,e=w+z,x^=e<<7|e>>>25,e=x+w,y^=e<<9|e>>>23,e=y+x,z^=e<<13|e>>>19,e=z+y,w^=e<<18|e>>>14,e=B+A,C^=e<<7|e>>>25,e=C+B,D^=e<<9|e>>>23,e=D+C,A^=e<<13|e>>>19,e=A+D,B^=e<<18|e>>>14,e=G+F,H^=e<<7|e>>>25,e=H+G,E^=e<<9|e>>>23,e=E+H,F^=e<<13|e>>>19,e=F+E,G^=e<<18|e>>>14,e=L+K,I^=e<<7|e>>>25,e=I+L,J^=e<<9|e>>>23,e=J+I,K^=e<<13|e>>>19,e=K+J,L^=e<<18|e>>>14;b[d++]=a[0]=w+g|0,b[d++]=a[1]=x+h|0,b[d++]=a[2]=y+i|0,b[d++]=a[3]=z+j|0,b[d++]=a[4]=A+k|0,b[d++]=a[5]=B+l|0,b[d++]=a[6]=C+m|0,b[d++]=a[7]=D+n|0,b[d++]=a[8]=E+o|0,b[d++]=a[9]=F+p|0,b[d++]=a[10]=G+q|0,b[d++]=a[11]=H+r|0,b[d++]=a[12]=I+s|0,b[d++]=a[13]=J+t|0,b[d++]=a[14]=K+u|0,b[d++]=a[15]=L+v|0}function l(a,b,c,d,e){for(;e--;)a[b++]=c[d++]}function m(a,b,c,d,e){for(;e--;)a[b++]^=c[d++]}function n(a,b,c,d,e){l(a,0,b,c+16*(2*e-1),16);for(var f=0;2*e>f;f+=2)k(a,b,c+16*f,d+8*f),k(a,b,c+16*f+16,d+8*f+16*e)}function o(a,b,c){return a[b+16*(2*c-1)]}function p(a){for(var b=[],c=0;cd?b.push(d):d>127&&2048>d?(b.push(d>>6|192),b.push(63&d|128)):(b.push(d>>12|224),b.push(d>>6&63|128),b.push(63&d|128))}return b}function q(a){for(var b="0123456789abcdef".split(""),c=a.length,d=[],e=0;c>e;e++)d.push(b[a[e]>>>4&15]),d.push(b[a[e]>>>0&15]);return d.join("")}function r(a){for(var b,c,d,e,f="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split(""),g=a.length,h=[],i=0;g>i;)b=g>i?a[i++]:0,c=g>i?a[i++]:0,d=g>i?a[i++]:0,e=(b<<16)+(c<<8)+d,h.push(f[e>>>18&63]),h.push(f[e>>>12&63]),h.push(f[e>>>6&63]),h.push(f[e>>>0&63]);return g%3>0&&(h[h.length-1]="=",g%3===1&&(h[h.length-2]="=")),h.join("")}function s(){for(var a=0;32*d>a;a++){var b=4*a;z[F+a]=(255&B[b+3])<<24|(255&B[b+2])<<16|(255&B[b+1])<<8|(255&B[b+0])<<0}}function t(a,b){for(var c=a;b>c;c+=2)l(A,32*c*d,z,F,32*d),n(C,z,F,G,d),l(A,32*(c+1)*d,z,G,32*d),n(C,z,G,F,d)}function u(a,b){for(var c=a;b>c;c+=2){var e=o(z,F,d)&E-1;m(z,F,A,32*e*d,32*d),n(C,z,F,G,d),e=o(z,G,d)&E-1,m(z,G,A,32*e*d,32*d),n(C,z,G,F,d)}}function v(){for(var a=0;32*d>a;a++){var b=z[F+a];B[4*a+0]=b>>>0&255,B[4*a+1]=b>>>8&255,B[4*a+2]=b>>>16&255,B[4*a+3]=b>>>24&255}}function w(a,b,c,d,e){!function f(){H(function(){d(a,b>a+c?a+c:b),a+=c,b>a?f():e()})}()}function x(b){var c=j(a,B,e);return"base64"===b?r(c):"hex"===b?q(c):c}var y=1;if(0>=d)throw new Error("scrypt: invalid r");if(1>c||c>31)throw new Error("scrypt: logN not be between 1 and 31");var z,A,B,C,D=1<<31>>>0,E=1<>>0;if(d*y>=1<<30||d>D/128/y||d>D/256||E>D/128/d)throw new Error("scrypt: parameters are too large");"string"==typeof a&&(a=p(a)),"string"==typeof b&&(b=p(b)),"undefined"!=typeof Int32Array?(z=new Int32Array(64*d),A=new Int32Array(32*E*d),C=new Int32Array(16)):(z=[],A=[],C=new Array(16)),B=j(a,b,128*y*d);var F=0,G=32*d,H="undefined"!=typeof setImmediate?setImmediate:setTimeout;"function"==typeof f&&(h=g,g=f,f=1e3),0>=f?(s(),t(0,E),u(0,E),v(),g(x(h))):(s(),w(0,E,2*f,t,function(){w(0,E,2*f,u,function(){v(),g(x(h))})}))}"undefined"!=typeof module&&(module.exports=scrypt); \ No newline at end of file +/* + * Limitation: doesn't support parallelization parameter greater than 1. + */ +/** + * scrypt(password, salt, logN, r, dkLen, [encoding]) + * + * Derives a key from password and salt and returns a Promise + * with derived key as the only argument. + * + * @param {string|Array.} password Password. + * @param {string|Array.} salt Salt. + * @param {number} logN CPU/memory cost parameter (1 to 31). + * @param {number} r Block size parameter. + * @param {number} dkLen Length of derived key. + * @param {string?} encoding (optional) Result encoding ("base64", "hex", or null). + * + */ +function scrypt(a,b,c,d,e,f){"use strict";return new Promise(function(g,h){function i(a){function b(a){for(var b=0,m=a.length;m>=64;){var n,o,p,q,r,s=d,t=e,u=f,v=g,w=h,x=i,y=j,z=k;for(o=0;o<16;o++)p=b+4*o,l[o]=(255&a[p])<<24|(255&a[p+1])<<16|(255&a[p+2])<<8|255&a[p+3];for(o=16;o<64;o++)n=l[o-2],q=(n>>>17|n<<15)^(n>>>19|n<<13)^n>>>10,n=l[o-15],r=(n>>>7|n<<25)^(n>>>18|n<<14)^n>>>3,l[o]=(q+l[o-7]|0)+(r+l[o-16]|0)|0;for(o=0;o<64;o++)q=(((w>>>6|w<<26)^(w>>>11|w<<21)^(w>>>25|w<<7))+(w&x^~w&y)|0)+(z+(c[o]+l[o]|0)|0)|0,r=((s>>>2|s<<30)^(s>>>13|s<<19)^(s>>>22|s<<10))+(s&t^s&u^t&u)|0,z=y,y=x,x=w,w=v+q|0,v=u,u=t,t=s,s=q+r|0;d=d+s|0,e=e+t|0,f=f+u|0,g=g+v|0,h=h+w|0,i=i+x|0,j=j+y|0,k=k+z|0,b+=64,m-=64}}/** @const */ +var c=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298],d=1779033703,e=3144134277,f=1013904242,g=2773480762,h=1359893119,i=2600822924,j=528734635,k=1541459225,l=new Array(64);b(a);var m,n=a.length%64,o=a.length/536870912|0,p=a.length<<3,q=n<56?56:120,r=a.slice(a.length-n,a.length);for(r.push(128),m=n+1;m>>24&255),r.push(o>>>16&255),r.push(o>>>8&255),r.push(o>>>0&255),r.push(p>>>24&255),r.push(p>>>16&255),r.push(p>>>8&255),r.push(p>>>0&255),b(r),[d>>>24&255,d>>>16&255,d>>>8&255,d>>>0&255,e>>>24&255,e>>>16&255,e>>>8&255,e>>>0&255,f>>>24&255,f>>>16&255,f>>>8&255,f>>>0&255,g>>>24&255,g>>>16&255,g>>>8&255,g>>>0&255,h>>>24&255,h>>>16&255,h>>>8&255,h>>>0&255,i>>>24&255,i>>>16&255,i>>>8&255,i>>>0&255,j>>>24&255,j>>>16&255,j>>>8&255,j>>>0&255,k>>>24&255,k>>>16&255,k>>>8&255,k>>>0&255]}function j(a,b,c){ +// increments counter inside inner +function d(){for(var a=f-1;a>=f-4;a--){if(g[a]++,g[a]<=255)return;g[a]=0}} +// compress password if it's longer than hash block length +a=a.length<=64?a:i(a);var e,f=64+b.length+4,g=new Array(f),h=new Array(64),j=[]; +// inner = (password ^ ipad) || salt || counter +for(e=0;e<64;e++)g[e]=54;for(e=0;e=32;)d(),j=j.concat(i(h.concat(i(g)))),c-=32;return c>0&&(d(),j=j.concat(i(h.concat(i(g))).slice(0,c))),j}function k(a,b,c,d){var e,f,g=a[0]^b[c++],h=a[1]^b[c++],i=a[2]^b[c++],j=a[3]^b[c++],k=a[4]^b[c++],l=a[5]^b[c++],m=a[6]^b[c++],n=a[7]^b[c++],o=a[8]^b[c++],p=a[9]^b[c++],q=a[10]^b[c++],r=a[11]^b[c++],s=a[12]^b[c++],t=a[13]^b[c++],u=a[14]^b[c++],v=a[15]^b[c++],w=g,x=h,y=i,z=j,A=k,B=l,C=m,D=n,E=o,F=p,G=q,H=r,I=s,J=t,K=u,L=v;for(f=0;f<8;f+=2)e=w+I,A^=e<<7|e>>>25,e=A+w,E^=e<<9|e>>>23,e=E+A,I^=e<<13|e>>>19,e=I+E,w^=e<<18|e>>>14,e=B+x,F^=e<<7|e>>>25,e=F+B,J^=e<<9|e>>>23,e=J+F,x^=e<<13|e>>>19,e=x+J,B^=e<<18|e>>>14,e=G+C,K^=e<<7|e>>>25,e=K+G,y^=e<<9|e>>>23,e=y+K,C^=e<<13|e>>>19,e=C+y,G^=e<<18|e>>>14,e=L+H,z^=e<<7|e>>>25,e=z+L,D^=e<<9|e>>>23,e=D+z,H^=e<<13|e>>>19,e=H+D,L^=e<<18|e>>>14,e=w+z,x^=e<<7|e>>>25,e=x+w,y^=e<<9|e>>>23,e=y+x,z^=e<<13|e>>>19,e=z+y,w^=e<<18|e>>>14,e=B+A,C^=e<<7|e>>>25,e=C+B,D^=e<<9|e>>>23,e=D+C,A^=e<<13|e>>>19,e=A+D,B^=e<<18|e>>>14,e=G+F,H^=e<<7|e>>>25,e=H+G,E^=e<<9|e>>>23,e=E+H,F^=e<<13|e>>>19,e=F+E,G^=e<<18|e>>>14,e=L+K,I^=e<<7|e>>>25,e=I+L,J^=e<<9|e>>>23,e=J+I,K^=e<<13|e>>>19,e=K+J,L^=e<<18|e>>>14;b[d++]=a[0]=w+g|0,b[d++]=a[1]=x+h|0,b[d++]=a[2]=y+i|0,b[d++]=a[3]=z+j|0,b[d++]=a[4]=A+k|0,b[d++]=a[5]=B+l|0,b[d++]=a[6]=C+m|0,b[d++]=a[7]=D+n|0,b[d++]=a[8]=E+o|0,b[d++]=a[9]=F+p|0,b[d++]=a[10]=G+q|0,b[d++]=a[11]=H+r|0,b[d++]=a[12]=I+s|0,b[d++]=a[13]=J+t|0,b[d++]=a[14]=K+u|0,b[d++]=a[15]=L+v|0}function l(a,b,c,d,e){for(;e--;)a[b++]=c[d++]}function m(a,b,c,d,e){for(;e--;)a[b++]^=c[d++]}function n(a,b,c,d,e){l(a,0,b,c+16*(2*e-1),16);for(var f=0;f<2*e;f+=2)k(a,b,c+16*f,d+8*f),k(a,b,c+16*f+16,d+8*f+16*e)}function o(a,b,c){return a[b+16*(2*c-1)]}function p(a){for(var b=[],c=0;c127&&d<2048?(b.push(d>>6|192),b.push(63&d|128)):(b.push(d>>12|224),b.push(d>>6&63|128),b.push(63&d|128))}return b}function q(a){for(/** @const */ +var b="0123456789abcdef".split(""),c=a.length,d=[],e=0;e>>4&15]),d.push(b[a[e]>>>0&15]);return d.join("")}function r(a){for(/** @const */ +var b,c,d,e,f="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split(""),g=a.length,h=[],i=0;i>>18&63]),h.push(f[e>>>12&63]),h.push(f[e>>>6&63]),h.push(f[e>>>0&63]);return g%3>0&&(h[h.length-1]="=",g%3===1&&(h[h.length-2]="=")),h.join("")}function s(){for(var a=0;a<32*d;a++){var b=4*a;y[E+a]=(255&A[b+3])<<24|(255&A[b+2])<<16|(255&A[b+1])<<8|(255&A[b+0])<<0}}function t(a,b){for(var c=a;c>>0&255,A[4*a+1]=b>>>8&255,A[4*a+2]=b>>>16&255,A[4*a+3]=b>>>24&255}}function w(b){var c=j(a,A,e);return"base64"===b?r(c):"hex"===b?q(c):c} +// Generate key. +// Set parallelization parameter to 1. +var x=1;if(d<=0)return h("scrypt: invalid r");if(c<1||c>31)return h("scrypt: logN not be between 1 and 31");var y,z,A,B,C=1<<31>>>0,D=1<>>0;if(d*x>=1<<30||d>C/128/x||d>C/256||D>C/128/d)return h("scrypt: parameters are too large"); +// Decode strings. +"string"==typeof a&&(a=p(a)),"string"==typeof b&&(b=p(b)),"undefined"!=typeof Int32Array?( +//XXX We can use Uint32Array, but Int32Array is faster in Safari. +y=new Int32Array(64*d),z=new Int32Array(32*D*d),B=new Int32Array(16)):(y=[],z=[],B=new Array(16)),A=j(a,b,128*x*d);var E=0,F=32*d;return s(),t(0,D),u(0,D),v(),g(w(f))})}"undefined"!=typeof module&&(module.exports=scrypt); \ No newline at end of file diff --git a/test/unittests.js b/test/unittests.js index 01b751b..3e649cc 100644 --- a/test/unittests.js +++ b/test/unittests.js @@ -255,28 +255,32 @@ var shortInput = { describe('limits test', function() { var v = shortInput; - it('should throw with too small logN', function() { - assert.throws(function() { - scrypt(v.password, v.salt, 0, v.r, v.dkLen); - }, Error); + it('should reject with too small logN', function() { + scrypt(v.password, v.salt, 0, v.r, v.dkLen) + .catch(function (err) { + assert.equal('should reject with too small logN', err); + }); }); - it('should throw with too big logN', function() { - assert.throws(function() { - scrypt(v.password, v.salt, 32, v.r, v.dkLen); - }, Error); + it('should reject with too big logN', function() { + scrypt(v.password, v.salt, 32, v.r, v.dkLen) + .catch(function (err) { + assert.equal('should reject with too big logN', err); + }); }); - it('should throw with too large parameters', function() { - assert.throws(function() { - scrypt(v.password, v.salt, v.logN, 1<<31, v.dkLen); - }, Error); + it('should reject with too large parameters', function() { + scrypt(v.password, v.salt, v.logN, 1<<31, v.dkLen) + .catch(function (err) { + assert.equal('should reject with too large parameters', err); + }); }); - it('should throw when r = 0', function() { - assert.throws(function() { - scrypt(v.password, v.salt, v.logN, 0, v.dkLen); - }, Error); + it('should reject when r = 0', function() { + scrypt(v.password, v.salt, v.logN, 0, v.dkLen) + .catch(function (err) { + assert.equal('should reject when r = 0', err); + }); }); }); @@ -287,101 +291,67 @@ describe('argument order test', function() { var v = shortInput; it('all arguments', function(done) { - scrypt(v.password, v.salt, v.logN, v.r, v.dkLen, 1000, function(out) { + scrypt(v.password, v.salt, v.logN, v.r, v.dkLen, "hex") + .then(function (out) { assert.equal(v.hexResult, out); done(); - }, "hex"); - }); - - it('all arguments, zero interruptStep', function(done) { - scrypt(v.password, v.salt, v.logN, v.r, v.dkLen, 0, function(out) { - assert.equal(v.hexResult, out); - done(); - }, "hex"); + }); }); it('drop encoding', function(done) { - scrypt(v.password, v.salt, v.logN, v.r, v.dkLen, 1000, function(out) { + scrypt(v.password, v.salt, v.logN, v.r, v.dkLen) + .then(function (out) { assert.deepEqual(v.result, out); done(); }); }); - it('drop interruptStep, keep encoding', function(done) { - scrypt(v.password, v.salt, v.logN, v.r, v.dkLen, function(out) { - assert.equal(v.hexResult, out); - done(); - }, 'hex'); - }); - }); -function async_test(i, interruptStep, done) { +function async_test(i, done) { var v = inputs[i]; - scrypt(v.password, v.salt, v.logN, v.r, v.dkLen, interruptStep, function(out) { + scrypt(v.password, v.salt, v.logN, v.r, v.dkLen, v.encoding) + .then(function(out) { assert.deepEqual(v.result, out); done(); - }, v.encoding); + }); } describe('async input/output test', function() { this.timeout(100000); - var step = 1000; - it('input 0', function(done) { - async_test(0, step, done); + async_test(0, done); }); it('input 1', function(done) { - async_test(1, step, done); + async_test(1, done); }); it('input 2', function(done) { - async_test(2, step, done); + async_test(2, done); }); it('input 3', function(done) { - async_test(3, step, done); + async_test(3, done); }); it('input 4', function(done) { - async_test(4, step, done); + async_test(4, done); }); it('input 5', function(done) { - async_test(5, step, done); + async_test(5, done); }); it('input 6', function(done) { - async_test(6, step, done); + async_test(6, done); }); it('input 7', function(done) { - async_test(7, step, done); + async_test(7, done); }); it('input 8', function(done) { - async_test(8, step, done); + async_test(8, done); }); it('input 9', function(done) { - async_test(9, step, done); + async_test(9, done); }); it('input 10', function(done) { - async_test(10, step, done); - }); - -}); - -describe('async input/output test with zero interruptStep', function() { - this.timeout(100000); - - // Only shorter tests: - var step = 0; - - it('input 0', function(done) { - async_test(0, step, done); - }); - it('input 1', function(done) { - async_test(1, step, done); - }); - it('input 2', function(done) { - async_test(2, step, done); - }); - it('input 3', function(done) { - async_test(3, step, done); + async_test(10, done); }); });