You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
303 lines
12 KiB
303 lines
12 KiB
"use strict"; |
|
Object.defineProperty(exports, "__esModule", { value: true }); |
|
exports.argon2id = exports.argon2i = exports.argon2d = void 0; |
|
const _assert_js_1 = require("./_assert.js"); |
|
const utils_js_1 = require("./utils.js"); |
|
const blake2b_js_1 = require("./blake2b.js"); |
|
const _u64_js_1 = require("./_u64.js"); |
|
const ARGON2_SYNC_POINTS = 4; |
|
const toBytesOptional = (buf) => (buf !== undefined ? (0, utils_js_1.toBytes)(buf) : new Uint8Array([])); |
|
function mul(a, b) { |
|
const aL = a & 0xffff; |
|
const aH = a >>> 16; |
|
const bL = b & 0xffff; |
|
const bH = b >>> 16; |
|
const ll = Math.imul(aL, bL); |
|
const hl = Math.imul(aH, bL); |
|
const lh = Math.imul(aL, bH); |
|
const hh = Math.imul(aH, bH); |
|
const BUF = ((ll >>> 16) + (hl & 0xffff) + lh) | 0; |
|
const h = ((hl >>> 16) + (BUF >>> 16) + hh) | 0; |
|
return { h, l: (BUF << 16) | (ll & 0xffff) }; |
|
} |
|
function relPos(areaSize, relativePos) { |
|
// areaSize - 1 - ((areaSize * ((relativePos ** 2) >>> 32)) >>> 32) |
|
return areaSize - 1 - mul(areaSize, mul(relativePos, relativePos).h).h; |
|
} |
|
function mul2(a, b) { |
|
// 2 * a * b (via shifts) |
|
const { h, l } = mul(a, b); |
|
return { h: ((h << 1) | (l >>> 31)) & 4294967295, l: (l << 1) & 4294967295 }; |
|
} |
|
function blamka(Ah, Al, Bh, Bl) { |
|
const { h: Ch, l: Cl } = mul2(Al, Bl); |
|
// A + B + (2 * A * B) |
|
const Rll = (0, _u64_js_1.add3L)(Al, Bl, Cl); |
|
return { h: (0, _u64_js_1.add3H)(Rll, Ah, Bh, Ch), l: Rll | 0 }; |
|
} |
|
// Temporary block buffer |
|
const BUF = new Uint32Array(256); |
|
function G(a, b, c, d) { |
|
let Al = BUF[2 * a], Ah = BUF[2 * a + 1]; // prettier-ignore |
|
let Bl = BUF[2 * b], Bh = BUF[2 * b + 1]; // prettier-ignore |
|
let Cl = BUF[2 * c], Ch = BUF[2 * c + 1]; // prettier-ignore |
|
let Dl = BUF[2 * d], Dh = BUF[2 * d + 1]; // prettier-ignore |
|
({ h: Ah, l: Al } = blamka(Ah, Al, Bh, Bl)); |
|
({ Dh, Dl } = { Dh: Dh ^ Ah, Dl: Dl ^ Al }); |
|
({ Dh, Dl } = { Dh: (0, _u64_js_1.rotr32H)(Dh, Dl), Dl: (0, _u64_js_1.rotr32L)(Dh, Dl) }); |
|
({ h: Ch, l: Cl } = blamka(Ch, Cl, Dh, Dl)); |
|
({ Bh, Bl } = { Bh: Bh ^ Ch, Bl: Bl ^ Cl }); |
|
({ Bh, Bl } = { Bh: (0, _u64_js_1.rotrSH)(Bh, Bl, 24), Bl: (0, _u64_js_1.rotrSL)(Bh, Bl, 24) }); |
|
({ h: Ah, l: Al } = blamka(Ah, Al, Bh, Bl)); |
|
({ Dh, Dl } = { Dh: Dh ^ Ah, Dl: Dl ^ Al }); |
|
({ Dh, Dl } = { Dh: (0, _u64_js_1.rotrSH)(Dh, Dl, 16), Dl: (0, _u64_js_1.rotrSL)(Dh, Dl, 16) }); |
|
({ h: Ch, l: Cl } = blamka(Ch, Cl, Dh, Dl)); |
|
({ Bh, Bl } = { Bh: Bh ^ Ch, Bl: Bl ^ Cl }); |
|
({ Bh, Bl } = { Bh: (0, _u64_js_1.rotrBH)(Bh, Bl, 63), Bl: (0, _u64_js_1.rotrBL)(Bh, Bl, 63) }); |
|
(BUF[2 * a] = Al), (BUF[2 * a + 1] = Ah); |
|
(BUF[2 * b] = Bl), (BUF[2 * b + 1] = Bh); |
|
(BUF[2 * c] = Cl), (BUF[2 * c + 1] = Ch); |
|
(BUF[2 * d] = Dl), (BUF[2 * d + 1] = Dh); |
|
} |
|
// prettier-ignore |
|
function P(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12, v13, v14, v15) { |
|
G(v00, v04, v08, v12); |
|
G(v01, v05, v09, v13); |
|
G(v02, v06, v10, v14); |
|
G(v03, v07, v11, v15); |
|
G(v00, v05, v10, v15); |
|
G(v01, v06, v11, v12); |
|
G(v02, v07, v08, v13); |
|
G(v03, v04, v09, v14); |
|
} |
|
function block(x, xPos, yPos, outPos, needXor) { |
|
for (let i = 0; i < 256; i++) |
|
BUF[i] = x[xPos + i] ^ x[yPos + i]; |
|
// columns |
|
for (let i = 0; i < 128; i += 16) { |
|
// prettier-ignore |
|
P(i, i + 1, i + 2, i + 3, i + 4, i + 5, i + 6, i + 7, i + 8, i + 9, i + 10, i + 11, i + 12, i + 13, i + 14, i + 15); |
|
} |
|
// rows |
|
for (let i = 0; i < 16; i += 2) { |
|
// prettier-ignore |
|
P(i, i + 1, i + 16, i + 17, i + 32, i + 33, i + 48, i + 49, i + 64, i + 65, i + 80, i + 81, i + 96, i + 97, i + 112, i + 113); |
|
} |
|
if (needXor) |
|
for (let i = 0; i < 256; i++) |
|
x[outPos + i] ^= BUF[i] ^ x[xPos + i] ^ x[yPos + i]; |
|
else |
|
for (let i = 0; i < 256; i++) |
|
x[outPos + i] = BUF[i] ^ x[xPos + i] ^ x[yPos + i]; |
|
} |
|
// Variable-Length Hash Function H' |
|
function Hp(A, dkLen) { |
|
const A8 = (0, utils_js_1.u8)(A); |
|
const T = new Uint32Array(1); |
|
const T8 = (0, utils_js_1.u8)(T); |
|
T[0] = dkLen; |
|
// Fast path |
|
if (dkLen <= 64) |
|
return blake2b_js_1.blake2b.create({ dkLen }).update(T8).update(A8).digest(); |
|
const out = new Uint8Array(dkLen); |
|
let V = blake2b_js_1.blake2b.create({}).update(T8).update(A8).digest(); |
|
let pos = 0; |
|
// First block |
|
out.set(V.subarray(0, 32)); |
|
pos += 32; |
|
// Rest blocks |
|
for (; dkLen - pos > 64; pos += 32) |
|
out.set((V = (0, blake2b_js_1.blake2b)(V)).subarray(0, 32), pos); |
|
// Last block |
|
out.set((0, blake2b_js_1.blake2b)(V, { dkLen: dkLen - pos }), pos); |
|
return (0, utils_js_1.u32)(out); |
|
} |
|
function indexAlpha(r, s, laneLen, segmentLen, index, randL, sameLane = false) { |
|
let area; |
|
if (0 == r) { |
|
if (0 == s) |
|
area = index - 1; |
|
else if (sameLane) |
|
area = s * segmentLen + index - 1; |
|
else |
|
area = s * segmentLen + (index == 0 ? -1 : 0); |
|
} |
|
else if (sameLane) |
|
area = laneLen - segmentLen + index - 1; |
|
else |
|
area = laneLen - segmentLen + (index == 0 ? -1 : 0); |
|
const startPos = r !== 0 && s !== ARGON2_SYNC_POINTS - 1 ? (s + 1) * segmentLen : 0; |
|
const rel = relPos(area, randL); |
|
// NOTE: check about overflows here |
|
// absPos = (startPos + relPos) % laneLength; |
|
return (startPos + rel) % laneLen; |
|
} |
|
function argon2Init(type, password, salt, opts) { |
|
password = (0, utils_js_1.toBytes)(password); |
|
salt = (0, utils_js_1.toBytes)(salt); |
|
let { p, dkLen, m, t, version, key, personalization, maxmem, onProgress } = { |
|
...opts, |
|
version: opts.version || 0x13, |
|
dkLen: opts.dkLen || 32, |
|
maxmem: 2 ** 32, |
|
}; |
|
// Validation |
|
(0, _assert_js_1.number)(p); |
|
(0, _assert_js_1.number)(dkLen); |
|
(0, _assert_js_1.number)(m); |
|
(0, _assert_js_1.number)(t); |
|
(0, _assert_js_1.number)(version); |
|
if (dkLen < 4 || dkLen >= 2 ** 32) |
|
throw new Error('Argon2: dkLen should be at least 4 bytes'); |
|
if (p < 1 || p >= 2 ** 32) |
|
throw new Error('Argon2: p (parallelism) should be at least 1'); |
|
if (t < 1 || t >= 2 ** 32) |
|
throw new Error('Argon2: t (iterations) should be at least 1'); |
|
if (m < 8 * p) |
|
throw new Error(`Argon2: memory should be at least 8*p bytes`); |
|
if (version !== 16 && version !== 19) |
|
throw new Error(`Argon2: unknown version=${version}`); |
|
password = (0, utils_js_1.toBytes)(password); |
|
if (password.length < 0 || password.length >= 2 ** 32) |
|
throw new Error('Argon2: password should be less than 4 GB'); |
|
salt = (0, utils_js_1.toBytes)(salt); |
|
if (salt.length < 8) |
|
throw new Error('Argon2: salt should be at least 8 bytes'); |
|
key = toBytesOptional(key); |
|
personalization = toBytesOptional(personalization); |
|
if (onProgress !== undefined && typeof onProgress !== 'function') |
|
throw new Error('progressCb should be function'); |
|
// Params |
|
const lanes = p; |
|
// m' = 4 * p * floor (m / 4p) |
|
const mP = 4 * p * Math.floor(m / (ARGON2_SYNC_POINTS * p)); |
|
//q = m' / p columns |
|
const laneLen = Math.floor(mP / p); |
|
const segmentLen = Math.floor(laneLen / ARGON2_SYNC_POINTS); |
|
// H0 |
|
const h = blake2b_js_1.blake2b.create({}); |
|
const BUF = new Uint32Array(1); |
|
const BUF8 = (0, utils_js_1.u8)(BUF); |
|
for (const i of [p, dkLen, m, t, version, type]) { |
|
if (i < 0 || i >= 2 ** 32) |
|
throw new Error(`Argon2: wrong parameter=${i}, expected uint32`); |
|
BUF[0] = i; |
|
h.update(BUF8); |
|
} |
|
for (let i of [password, salt, key, personalization]) { |
|
BUF[0] = i.length; |
|
h.update(BUF8).update(i); |
|
} |
|
const H0 = new Uint32Array(18); |
|
const H0_8 = (0, utils_js_1.u8)(H0); |
|
h.digestInto(H0_8); |
|
// 256 u32 = 1024 (BLOCK_SIZE) |
|
const memUsed = mP * 256; |
|
if (memUsed < 0 || memUsed >= 2 ** 32 || memUsed > maxmem) { |
|
throw new Error(`Argon2: wrong params (memUsed=${memUsed} maxmem=${maxmem}), should be less than 2**32`); |
|
} |
|
const B = new Uint32Array(memUsed); |
|
// Fill first blocks |
|
for (let l = 0; l < p; l++) { |
|
const i = 256 * laneLen * l; |
|
// B[i][0] = H'^(1024)(H_0 || LE32(0) || LE32(i)) |
|
H0[17] = l; |
|
H0[16] = 0; |
|
B.set(Hp(H0, 1024), i); |
|
// B[i][1] = H'^(1024)(H_0 || LE32(1) || LE32(i)) |
|
H0[16] = 1; |
|
B.set(Hp(H0, 1024), i + 256); |
|
} |
|
let perBlock = () => { }; |
|
if (onProgress) { |
|
const totalBlock = t * ARGON2_SYNC_POINTS * p * segmentLen; |
|
// Invoke callback if progress changes from 10.01 to 10.02 |
|
// Allows to draw smooth progress bar on up to 8K screen |
|
const callbackPer = Math.max(Math.floor(totalBlock / 10000), 1); |
|
let blockCnt = 0; |
|
perBlock = () => { |
|
blockCnt++; |
|
if (onProgress && (!(blockCnt % callbackPer) || blockCnt === totalBlock)) |
|
onProgress(blockCnt / totalBlock); |
|
}; |
|
} |
|
return { type, mP, p, t, version, B, laneLen, lanes, segmentLen, dkLen, perBlock }; |
|
} |
|
function argon2Output(B, p, laneLen, dkLen) { |
|
const B_final = new Uint32Array(256); |
|
for (let l = 0; l < p; l++) |
|
for (let j = 0; j < 256; j++) |
|
B_final[j] ^= B[256 * (laneLen * l + laneLen - 1) + j]; |
|
return (0, utils_js_1.u8)(Hp(B_final, dkLen)); |
|
} |
|
function processBlock(B, address, l, r, s, index, laneLen, segmentLen, lanes, offset, prev, dataIndependent, needXor) { |
|
if (offset % laneLen) |
|
prev = offset - 1; |
|
let randL, randH; |
|
if (dataIndependent) { |
|
if (index % 128 === 0) { |
|
address[256 + 12]++; |
|
block(address, 256, 2 * 256, 0, false); |
|
block(address, 0, 2 * 256, 0, false); |
|
} |
|
randL = address[2 * (index % 128)]; |
|
randH = address[2 * (index % 128) + 1]; |
|
} |
|
else { |
|
const T = 256 * prev; |
|
randL = B[T]; |
|
randH = B[T + 1]; |
|
} |
|
// address block |
|
const refLane = r === 0 && s === 0 ? l : randH % lanes; |
|
const refPos = indexAlpha(r, s, laneLen, segmentLen, index, randL, refLane == l); |
|
const refBlock = laneLen * refLane + refPos; |
|
// B[i][j] = G(B[i][j-1], B[l][z]) |
|
block(B, 256 * prev, 256 * refBlock, offset * 256, needXor); |
|
} |
|
function argon2(type, password, salt, opts) { |
|
const { mP, p, t, version, B, laneLen, lanes, segmentLen, dkLen, perBlock } = argon2Init(type, password, salt, opts); |
|
// Pre-loop setup |
|
// [address, input, zero_block] format so we can pass single U32 to block function |
|
const address = new Uint32Array(3 * 256); |
|
address[256 + 6] = mP; |
|
address[256 + 8] = t; |
|
address[256 + 10] = type; |
|
for (let r = 0; r < t; r++) { |
|
const needXor = r !== 0 && version === 0x13; |
|
address[256 + 0] = r; |
|
for (let s = 0; s < ARGON2_SYNC_POINTS; s++) { |
|
address[256 + 4] = s; |
|
const dataIndependent = type == 1 /* Types.Argon2i */ || (type == 2 /* Types.Argon2id */ && r === 0 && s < 2); |
|
for (let l = 0; l < p; l++) { |
|
address[256 + 2] = l; |
|
address[256 + 12] = 0; |
|
let startPos = 0; |
|
if (r === 0 && s === 0) { |
|
startPos = 2; |
|
if (dataIndependent) { |
|
address[256 + 12]++; |
|
block(address, 256, 2 * 256, 0, false); |
|
block(address, 0, 2 * 256, 0, false); |
|
} |
|
} |
|
// current block postion |
|
let offset = l * laneLen + s * segmentLen + startPos; |
|
// previous block position |
|
let prev = offset % laneLen ? offset - 1 : offset + laneLen - 1; |
|
for (let index = startPos; index < segmentLen; index++, offset++, prev++) { |
|
perBlock(); |
|
processBlock(B, address, l, r, s, index, laneLen, segmentLen, lanes, offset, prev, dataIndependent, needXor); |
|
} |
|
} |
|
} |
|
} |
|
return argon2Output(B, p, laneLen, dkLen); |
|
} |
|
const argon2d = (password, salt, opts) => argon2(0 /* Types.Argond2d */, password, salt, opts); |
|
exports.argon2d = argon2d; |
|
const argon2i = (password, salt, opts) => argon2(1 /* Types.Argon2i */, password, salt, opts); |
|
exports.argon2i = argon2i; |
|
const argon2id = (password, salt, opts) => argon2(2 /* Types.Argon2id */, password, salt, opts); |
|
exports.argon2id = argon2id; |
|
//# sourceMappingURL=argon2.js.map
|