Comparing version 2.7.0 to 2.7.1
# lucia | ||
## 2.7.1 | ||
### Patch changes | ||
- [#1171](https://github.com/lucia-auth/lucia/pull/1171) by [@pilcrowOnPaper](https://github.com/pilcrowOnPaper) : Add proper attributes for `@noble/hashes` | ||
## 2.7.0 | ||
@@ -4,0 +10,0 @@ |
@@ -1,2 +0,7 @@ | ||
export type ScryptOpts = { | ||
/** | ||
* Scrypt KDF from RFC 7914. | ||
*/ | ||
declare const _default: (password: Uint8Array, salt: Uint8Array, options: ScryptOptions) => Promise<Uint8Array>; | ||
export default _default; | ||
type ScryptOptions = { | ||
N: number; | ||
@@ -6,10 +11,3 @@ r: number; | ||
dkLen?: number; | ||
asyncTick?: number; | ||
maxmem?: number; | ||
onProgress?: (progress: number) => void; | ||
}; | ||
/** | ||
* Scrypt KDF from RFC 7914. | ||
*/ | ||
declare const _default: (password: Uint8Array, salt: Uint8Array, opts: ScryptOpts) => Promise<Uint8Array>; | ||
export default _default; |
import { pbkdf2 } from "./pbkdf.js"; | ||
import { asyncLoop, checkOpts, u32 } from "./utils.js"; | ||
/** | ||
* Scrypt KDF from RFC 7914. | ||
*/ | ||
export default async (password, salt, options) => { | ||
const { N, r, p } = options; | ||
const dkLen = options.dkLen ?? 32; | ||
const maxmem = 1024 ** 3 + 1024; | ||
const blockSize = 128 * r; | ||
const blockSize32 = blockSize / 4; | ||
if (N <= 1 || | ||
(N & (N - 1)) !== 0 || | ||
N >= 2 ** (blockSize / 8) || | ||
N > 2 ** 32) { | ||
throw new Error("Scrypt: N must be larger than 1, a power of 2, less than 2^(128 * r / 8) and less than 2^32"); | ||
} | ||
if (p < 0 || p > ((2 ** 32 - 1) * 32) / blockSize) { | ||
throw new Error("Scrypt: p must be a positive integer less than or equal to ((2^32 - 1) * 32) / (128 * r)"); | ||
} | ||
if (dkLen < 0 || dkLen > (2 ** 32 - 1) * 32) { | ||
throw new Error("Scrypt: dkLen should be positive integer less than or equal to (2^32 - 1) * 32"); | ||
} | ||
const memUsed = blockSize * (N + p); | ||
if (memUsed > maxmem) { | ||
throw new Error(`Scrypt: parameters too large, ${memUsed} (128 * r * (N + p)) > ${maxmem} (maxmem)`); | ||
} | ||
const B = await pbkdf2(password, salt, { c: 1, dkLen: blockSize * p }); | ||
const B32 = u32(B); | ||
const V = u32(new Uint8Array(blockSize * N)); | ||
const tmp = u32(new Uint8Array(blockSize)); | ||
for (let pi = 0; pi < p; pi++) { | ||
const Pi = blockSize32 * pi; | ||
for (let i = 0; i < blockSize32; i++) | ||
V[i] = B32[Pi + i]; // V[0] = B[i] | ||
for (let i = 0, pos = 0; i < N - 1; i++) { | ||
BlockMix(V, pos, V, (pos += blockSize32), r); // V[i] = BlockMix(V[i-1]); | ||
} | ||
BlockMix(V, (N - 1) * blockSize32, B32, Pi, r); // Process last element | ||
for (let i = 0; i < N; i++) { | ||
// First u32 of the last 64-byte block (u32 is LE) | ||
const j = B32[Pi + blockSize32 - 16] % N; // j = Integrify(X) % iterations | ||
for (let k = 0; k < blockSize32; k++) | ||
tmp[k] = B32[Pi + k] ^ V[j * blockSize32 + k]; // tmp = B ^ V[j] | ||
BlockMix(tmp, 0, B32, Pi, r); // B = BlockMix(B ^ V[j]) | ||
} | ||
} | ||
const res = await pbkdf2(password, B, { c: 1, dkLen }); | ||
B.fill(0); | ||
V.fill(0); | ||
tmp.fill(0); | ||
return res; | ||
}; | ||
const rotl = (a, b) => (a << b) | (a >>> (32 - b)); | ||
@@ -77,77 +127,4 @@ const XorAndSalsa = (prev, pi, input, ii, out, oi) => { | ||
}; | ||
const scryptInit = async (password, salt, _opts) => { | ||
const opts = checkOpts({ | ||
dkLen: 32, | ||
asyncTick: 10, | ||
maxmem: 1024 ** 3 + 1024 | ||
}, _opts); | ||
const { N, r, p, dkLen, asyncTick, maxmem, onProgress } = opts; | ||
if (onProgress !== undefined && typeof onProgress !== "function") | ||
throw new Error("progressCb should be function"); | ||
const blockSize = 128 * r; | ||
const blockSize32 = blockSize / 4; | ||
if (N <= 1 || | ||
(N & (N - 1)) !== 0 || | ||
N >= 2 ** (blockSize / 8) || | ||
N > 2 ** 32) { | ||
throw new Error("Scrypt: N must be larger than 1, a power of 2, less than 2^(128 * r / 8) and less than 2^32"); | ||
} | ||
if (p < 0 || p > ((2 ** 32 - 1) * 32) / blockSize) { | ||
throw new Error("Scrypt: p must be a positive integer less than or equal to ((2^32 - 1) * 32) / (128 * r)"); | ||
} | ||
if (dkLen < 0 || dkLen > (2 ** 32 - 1) * 32) { | ||
throw new Error("Scrypt: dkLen should be positive integer less than or equal to (2^32 - 1) * 32"); | ||
} | ||
const memUsed = blockSize * (N + p); | ||
if (memUsed > maxmem) { | ||
throw new Error(`Scrypt: parameters too large, ${memUsed} (128 * r * (N + p)) > ${maxmem} (maxmem)`); | ||
} | ||
const B = await pbkdf2(password, salt, { c: 1, dkLen: blockSize * p }); | ||
const B32 = u32(B); | ||
const V = u32(new Uint8Array(blockSize * N)); | ||
const tmp = u32(new Uint8Array(blockSize)); | ||
let blockMixCb = () => { }; | ||
if (onProgress) { | ||
const totalBlockMix = 2 * N * p; | ||
const callbackPer = Math.max(Math.floor(totalBlockMix / 10000), 1); | ||
let blockMixCnt = 0; | ||
blockMixCb = () => { | ||
blockMixCnt++; | ||
if (onProgress && | ||
(!(blockMixCnt % callbackPer) || blockMixCnt === totalBlockMix)) | ||
onProgress(blockMixCnt / totalBlockMix); | ||
}; | ||
} | ||
return { N, r, p, dkLen, blockSize32, V, B32, B, tmp, blockMixCb, asyncTick }; | ||
const u32 = (arr) => { | ||
return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4)); | ||
}; | ||
/** | ||
* Scrypt KDF from RFC 7914. | ||
*/ | ||
export default async (password, salt, opts) => { | ||
const { N, r, p, dkLen, blockSize32, V, B32, B, tmp, blockMixCb, asyncTick } = await scryptInit(password, salt, opts); | ||
for (let pi = 0; pi < p; pi++) { | ||
const Pi = blockSize32 * pi; | ||
for (let i = 0; i < blockSize32; i++) | ||
V[i] = B32[Pi + i]; // V[0] = B[i] | ||
let pos = 0; | ||
await asyncLoop(N - 1, asyncTick, (i) => { | ||
BlockMix(V, pos, V, (pos += blockSize32), r); // V[i] = BlockMix(V[i-1]); | ||
blockMixCb(); | ||
}); | ||
BlockMix(V, (N - 1) * blockSize32, B32, Pi, r); // Process last element | ||
blockMixCb(); | ||
await asyncLoop(N, asyncTick, (i) => { | ||
// First u32 of the last 64-byte block (u32 is LE) | ||
const j = B32[Pi + blockSize32 - 16] % N; // j = Integrify(X) % iterations | ||
for (let k = 0; k < blockSize32; k++) | ||
tmp[k] = B32[Pi + k] ^ V[j * blockSize32 + k]; // tmp = B ^ V[j] | ||
BlockMix(tmp, 0, B32, Pi, r); // B = BlockMix(B ^ V[j]) | ||
blockMixCb(); | ||
}); | ||
} | ||
const res = await pbkdf2(password, B, { c: 1, dkLen }); | ||
B.fill(0); | ||
V.fill(0); | ||
tmp.fill(0); | ||
return res; | ||
}; |
{ | ||
"name": "lucia", | ||
"version": "2.7.0", | ||
"version": "2.7.1", | ||
"description": "A simple and flexible authentication library", | ||
@@ -55,3 +55,3 @@ "main": "dist/index.js", | ||
"scripts": { | ||
"build": "shx rm -rf ./dist/* && tsc", | ||
"build": "shx rm -rf ./dist/* && tsc && cp ./src/scrypt/MODULE_LICENSE ./dist/scrypt/MODULE_LICENSE", | ||
"auri.build": "pnpm build", | ||
@@ -58,0 +58,0 @@ "test": "vitest run", |
92090
48
1972