295 lines
No EOL
9.4 KiB
JavaScript
295 lines
No EOL
9.4 KiB
JavaScript
/*
|
|
* Copyright (c) 2010-2011 Intalio Pte, All Rights Reserved
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
// https://github.com/cheongwy/node-scrypt-js
|
|
(function () {
|
|
|
|
var MAX_VALUE = 2147483647;
|
|
var workerUrl = null;
|
|
|
|
//function scrypt(byte[] passwd, byte[] salt, int N, int r, int p, int dkLen)
|
|
/*
|
|
* N = Cpu cost
|
|
* r = Memory cost
|
|
* p = parallelization cost
|
|
*
|
|
*/
|
|
window.Crypto_scrypt = function (passwd, salt, N, r, p, dkLen, callback) {
|
|
if (N == 0 || (N & (N - 1)) != 0) throw Error("N must be > 0 and a power of 2");
|
|
|
|
if (N > MAX_VALUE / 128 / r) throw Error("Parameter N is too large");
|
|
if (r > MAX_VALUE / 128 / p) throw Error("Parameter r is too large");
|
|
|
|
var PBKDF2_opts = { iterations: 1, hasher: Crypto.SHA256, asBytes: true };
|
|
|
|
var B = Crypto.PBKDF2(passwd, salt, p * 128 * r, PBKDF2_opts);
|
|
|
|
try {
|
|
var i = 0;
|
|
var worksDone = 0;
|
|
var makeWorker = function () {
|
|
if (!workerUrl) {
|
|
var code = '(' + scryptCore.toString() + ')()';
|
|
var blob;
|
|
try {
|
|
blob = new Blob([code], { type: "text/javascript" });
|
|
} catch (e) {
|
|
window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
|
|
blob = new BlobBuilder();
|
|
blob.append(code);
|
|
blob = blob.getBlob("text/javascript");
|
|
}
|
|
workerUrl = URL.createObjectURL(blob);
|
|
}
|
|
var worker = new Worker(workerUrl);
|
|
worker.onmessage = function (event) {
|
|
var Bi = event.data[0], Bslice = event.data[1];
|
|
worksDone++;
|
|
|
|
if (i < p) {
|
|
worker.postMessage([N, r, p, B, i++]);
|
|
}
|
|
|
|
var length = Bslice.length, destPos = Bi * 128 * r, srcPos = 0;
|
|
while (length--) {
|
|
B[destPos++] = Bslice[srcPos++];
|
|
}
|
|
|
|
if (worksDone == p) {
|
|
callback(Crypto.PBKDF2(passwd, B, dkLen, PBKDF2_opts));
|
|
}
|
|
};
|
|
return worker;
|
|
};
|
|
var workers = [makeWorker(), makeWorker()];
|
|
workers[0].postMessage([N, r, p, B, i++]);
|
|
if (p > 1) {
|
|
workers[1].postMessage([N, r, p, B, i++]);
|
|
}
|
|
} catch (e) {
|
|
window.setTimeout(function () {
|
|
scryptCore();
|
|
callback(Crypto.PBKDF2(passwd, B, dkLen, PBKDF2_opts));
|
|
}, 0);
|
|
}
|
|
|
|
// using this function to enclose everything needed to create a worker (but also invokable directly for synchronous use)
|
|
function scryptCore() {
|
|
var XY = [], V = [];
|
|
|
|
if (typeof B === 'undefined') {
|
|
onmessage = function (event) {
|
|
var data = event.data;
|
|
var N = data[0], r = data[1], p = data[2], B = data[3], i = data[4];
|
|
|
|
var Bslice = [];
|
|
arraycopy32(B, i * 128 * r, Bslice, 0, 128 * r);
|
|
smix(Bslice, 0, r, N, V, XY);
|
|
|
|
postMessage([i, Bslice]);
|
|
};
|
|
} else {
|
|
for (var i = 0; i < p; i++) {
|
|
smix(B, i * 128 * r, r, N, V, XY);
|
|
}
|
|
}
|
|
|
|
function smix(B, Bi, r, N, V, XY) {
|
|
var Xi = 0;
|
|
var Yi = 128 * r;
|
|
var i;
|
|
|
|
arraycopy32(B, Bi, XY, Xi, Yi);
|
|
|
|
for (i = 0; i < N; i++) {
|
|
arraycopy32(XY, Xi, V, i * Yi, Yi);
|
|
blockmix_salsa8(XY, Xi, Yi, r);
|
|
}
|
|
|
|
for (i = 0; i < N; i++) {
|
|
var j = integerify(XY, Xi, r) & (N - 1);
|
|
blockxor(V, j * Yi, XY, Xi, Yi);
|
|
blockmix_salsa8(XY, Xi, Yi, r);
|
|
}
|
|
|
|
arraycopy32(XY, Xi, B, Bi, Yi);
|
|
}
|
|
|
|
function blockmix_salsa8(BY, Bi, Yi, r) {
|
|
var X = [];
|
|
var i;
|
|
|
|
arraycopy32(BY, Bi + (2 * r - 1) * 64, X, 0, 64);
|
|
|
|
for (i = 0; i < 2 * r; i++) {
|
|
blockxor(BY, i * 64, X, 0, 64);
|
|
salsa20_8(X);
|
|
arraycopy32(X, 0, BY, Yi + (i * 64), 64);
|
|
}
|
|
|
|
for (i = 0; i < r; i++) {
|
|
arraycopy32(BY, Yi + (i * 2) * 64, BY, Bi + (i * 64), 64);
|
|
}
|
|
|
|
for (i = 0; i < r; i++) {
|
|
arraycopy32(BY, Yi + (i * 2 + 1) * 64, BY, Bi + (i + r) * 64, 64);
|
|
}
|
|
}
|
|
|
|
function R(a, b) {
|
|
return (a << b) | (a >>> (32 - b));
|
|
}
|
|
|
|
function salsa20_8(B) {
|
|
var B32 = new Array(32);
|
|
var x = new Array(32);
|
|
var i;
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
B32[i] = (B[i * 4 + 0] & 0xff) << 0;
|
|
B32[i] |= (B[i * 4 + 1] & 0xff) << 8;
|
|
B32[i] |= (B[i * 4 + 2] & 0xff) << 16;
|
|
B32[i] |= (B[i * 4 + 3] & 0xff) << 24;
|
|
}
|
|
|
|
arraycopy(B32, 0, x, 0, 16);
|
|
|
|
for (i = 8; i > 0; i -= 2) {
|
|
x[4] ^= R(x[0] + x[12], 7); x[8] ^= R(x[4] + x[0], 9);
|
|
x[12] ^= R(x[8] + x[4], 13); x[0] ^= R(x[12] + x[8], 18);
|
|
x[9] ^= R(x[5] + x[1], 7); x[13] ^= R(x[9] + x[5], 9);
|
|
x[1] ^= R(x[13] + x[9], 13); x[5] ^= R(x[1] + x[13], 18);
|
|
x[14] ^= R(x[10] + x[6], 7); x[2] ^= R(x[14] + x[10], 9);
|
|
x[6] ^= R(x[2] + x[14], 13); x[10] ^= R(x[6] + x[2], 18);
|
|
x[3] ^= R(x[15] + x[11], 7); x[7] ^= R(x[3] + x[15], 9);
|
|
x[11] ^= R(x[7] + x[3], 13); x[15] ^= R(x[11] + x[7], 18);
|
|
x[1] ^= R(x[0] + x[3], 7); x[2] ^= R(x[1] + x[0], 9);
|
|
x[3] ^= R(x[2] + x[1], 13); x[0] ^= R(x[3] + x[2], 18);
|
|
x[6] ^= R(x[5] + x[4], 7); x[7] ^= R(x[6] + x[5], 9);
|
|
x[4] ^= R(x[7] + x[6], 13); x[5] ^= R(x[4] + x[7], 18);
|
|
x[11] ^= R(x[10] + x[9], 7); x[8] ^= R(x[11] + x[10], 9);
|
|
x[9] ^= R(x[8] + x[11], 13); x[10] ^= R(x[9] + x[8], 18);
|
|
x[12] ^= R(x[15] + x[14], 7); x[13] ^= R(x[12] + x[15], 9);
|
|
x[14] ^= R(x[13] + x[12], 13); x[15] ^= R(x[14] + x[13], 18);
|
|
}
|
|
|
|
for (i = 0; i < 16; ++i) B32[i] = x[i] + B32[i];
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
var bi = i * 4;
|
|
B[bi + 0] = (B32[i] >> 0 & 0xff);
|
|
B[bi + 1] = (B32[i] >> 8 & 0xff);
|
|
B[bi + 2] = (B32[i] >> 16 & 0xff);
|
|
B[bi + 3] = (B32[i] >> 24 & 0xff);
|
|
}
|
|
}
|
|
|
|
function blockxor(S, Si, D, Di, len) {
|
|
var i = len >> 6;
|
|
while (i--) {
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
D[Di++] ^= S[Si++]; D[Di++] ^= S[Si++];
|
|
}
|
|
}
|
|
|
|
function integerify(B, bi, r) {
|
|
var n;
|
|
|
|
bi += (2 * r - 1) * 64;
|
|
|
|
n = (B[bi + 0] & 0xff) << 0;
|
|
n |= (B[bi + 1] & 0xff) << 8;
|
|
n |= (B[bi + 2] & 0xff) << 16;
|
|
n |= (B[bi + 3] & 0xff) << 24;
|
|
|
|
return n;
|
|
}
|
|
|
|
function arraycopy(src, srcPos, dest, destPos, length) {
|
|
while (length--) {
|
|
dest[destPos++] = src[srcPos++];
|
|
}
|
|
}
|
|
|
|
function arraycopy32(src, srcPos, dest, destPos, length) {
|
|
var i = length >> 5;
|
|
while (i--) {
|
|
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
|
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
|
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
|
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
|
|
|
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
|
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
|
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
|
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
|
|
|
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
|
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
|
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
|
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
|
|
|
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
|
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
|
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
|
dest[destPos++] = src[srcPos++]; dest[destPos++] = src[srcPos++];
|
|
}
|
|
}
|
|
} // scryptCore
|
|
}; // window.Crypto_scrypt
|
|
})(); |