Upload via GUI (7543 Dateien)
This commit is contained in:
+20
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Blake2s hash function. Focuses on 8-bit to 32-bit platforms. blake2b for 64-bit, but in JS it is slower.
|
||||
* @module
|
||||
* @deprecated
|
||||
*/
|
||||
import { G1s as G1s_n, G2s as G2s_n } from './_blake.ts';
|
||||
import { BLAKE2s as B2S, blake2s as b2s, compress as compress_n } from './blake2.ts';
|
||||
/** @deprecated Use import from `noble/hashes/blake2` module */
|
||||
export declare const B2S_IV: Uint32Array;
|
||||
/** @deprecated Use import from `noble/hashes/blake2` module */
|
||||
export declare const G1s: typeof G1s_n;
|
||||
/** @deprecated Use import from `noble/hashes/blake2` module */
|
||||
export declare const G2s: typeof G2s_n;
|
||||
/** @deprecated Use import from `noble/hashes/blake2` module */
|
||||
export declare const compress: typeof compress_n;
|
||||
/** @deprecated Use import from `noble/hashes/blake2` module */
|
||||
export declare const BLAKE2s: typeof B2S;
|
||||
/** @deprecated Use import from `noble/hashes/blake2` module */
|
||||
export declare const blake2s: typeof b2s;
|
||||
//# sourceMappingURL=blake2s.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"blake2s.d.ts","sourceRoot":"","sources":["../src/blake2s.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,GAAG,IAAI,KAAK,EAAE,GAAG,IAAI,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzD,OAAO,EAAE,OAAO,IAAI,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,QAAQ,IAAI,UAAU,EAAE,MAAM,aAAa,CAAC;AACrF,+DAA+D;AAC/D,eAAO,MAAM,MAAM,EAAE,WAAuB,CAAC;AAC7C,+DAA+D;AAC/D,eAAO,MAAM,GAAG,EAAE,OAAO,KAAa,CAAC;AACvC,+DAA+D;AAC/D,eAAO,MAAM,GAAG,EAAE,OAAO,KAAa,CAAC;AACvC,+DAA+D;AAC/D,eAAO,MAAM,QAAQ,EAAE,OAAO,UAAuB,CAAC;AACtD,+DAA+D;AAC/D,eAAO,MAAM,OAAO,EAAE,OAAO,GAAS,CAAC;AACvC,+DAA+D;AAC/D,eAAO,MAAM,OAAO,EAAE,OAAO,GAAS,CAAC"}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Blake2s hash function. Focuses on 8-bit to 32-bit platforms. blake2b for 64-bit, but in JS it is slower.
|
||||
* @module
|
||||
* @deprecated
|
||||
*/
|
||||
import { G1s as G1s_n, G2s as G2s_n } from "./_blake.js";
|
||||
import { SHA256_IV } from "./_md.js";
|
||||
import { BLAKE2s as B2S, blake2s as b2s, compress as compress_n } from "./blake2.js";
|
||||
/** @deprecated Use import from `noble/hashes/blake2` module */
|
||||
export const B2S_IV = SHA256_IV;
|
||||
/** @deprecated Use import from `noble/hashes/blake2` module */
|
||||
export const G1s = G1s_n;
|
||||
/** @deprecated Use import from `noble/hashes/blake2` module */
|
||||
export const G2s = G2s_n;
|
||||
/** @deprecated Use import from `noble/hashes/blake2` module */
|
||||
export const compress = compress_n;
|
||||
/** @deprecated Use import from `noble/hashes/blake2` module */
|
||||
export const BLAKE2s = B2S;
|
||||
/** @deprecated Use import from `noble/hashes/blake2` module */
|
||||
export const blake2s = b2s;
|
||||
//# sourceMappingURL=blake2s.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"blake2s.js","sourceRoot":"","sources":["../src/blake2s.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,GAAG,IAAI,KAAK,EAAE,GAAG,IAAI,KAAK,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,OAAO,IAAI,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,QAAQ,IAAI,UAAU,EAAE,MAAM,aAAa,CAAC;AACrF,+DAA+D;AAC/D,MAAM,CAAC,MAAM,MAAM,GAAgB,SAAS,CAAC;AAC7C,+DAA+D;AAC/D,MAAM,CAAC,MAAM,GAAG,GAAiB,KAAK,CAAC;AACvC,+DAA+D;AAC/D,MAAM,CAAC,MAAM,GAAG,GAAiB,KAAK,CAAC;AACvC,+DAA+D;AAC/D,MAAM,CAAC,MAAM,QAAQ,GAAsB,UAAU,CAAC;AACtD,+DAA+D;AAC/D,MAAM,CAAC,MAAM,OAAO,GAAe,GAAG,CAAC;AACvC,+DAA+D;AAC/D,MAAM,CAAC,MAAM,OAAO,GAAe,GAAG,CAAC"}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
import { BLAKE2 } from './blake2.ts';
|
||||
import { type CHashXO, type HashXOF, type Input } from './utils.ts';
|
||||
/**
|
||||
* Ensure to use EITHER `key` OR `context`, not both.
|
||||
*
|
||||
* * `key`: 32-byte MAC key.
|
||||
* * `context`: string for KDF. Should be hardcoded, globally unique, and application - specific.
|
||||
* A good default format for the context string is "[application] [commit timestamp] [purpose]".
|
||||
*/
|
||||
export type Blake3Opts = {
|
||||
dkLen?: number;
|
||||
key?: Input;
|
||||
context?: Input;
|
||||
};
|
||||
/** Blake3 hash. Can be used as MAC and KDF. */
|
||||
export declare class BLAKE3 extends BLAKE2<BLAKE3> implements HashXOF<BLAKE3> {
|
||||
private chunkPos;
|
||||
private chunksDone;
|
||||
private flags;
|
||||
private IV;
|
||||
private state;
|
||||
private stack;
|
||||
private posOut;
|
||||
private bufferOut32;
|
||||
private bufferOut;
|
||||
private chunkOut;
|
||||
private enableXOF;
|
||||
constructor(opts?: Blake3Opts, flags?: number);
|
||||
protected get(): [];
|
||||
protected set(): void;
|
||||
private b2Compress;
|
||||
protected compress(buf: Uint32Array, bufPos?: number, isLast?: boolean): void;
|
||||
_cloneInto(to?: BLAKE3): BLAKE3;
|
||||
destroy(): void;
|
||||
private b2CompressOut;
|
||||
protected finish(): void;
|
||||
private writeInto;
|
||||
xofInto(out: Uint8Array): Uint8Array;
|
||||
xof(bytes: number): Uint8Array;
|
||||
digestInto(out: Uint8Array): Uint8Array;
|
||||
digest(): Uint8Array;
|
||||
}
|
||||
/**
|
||||
* BLAKE3 hash function. Can be used as MAC and KDF.
|
||||
* @param msg - message that would be hashed
|
||||
* @param opts - `dkLen` for output length, `key` for MAC mode, `context` for KDF mode
|
||||
* @example
|
||||
* const data = new Uint8Array(32);
|
||||
* const hash = blake3(data);
|
||||
* const mac = blake3(data, { key: new Uint8Array(32) });
|
||||
* const kdf = blake3(data, { context: 'application name' });
|
||||
*/
|
||||
export declare const blake3: CHashXO;
|
||||
//# sourceMappingURL=blake3.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"blake3.d.ts","sourceRoot":"","sources":["../src/blake3.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,MAAM,EAAY,MAAM,aAAa,CAAC;AAE/C,OAAO,EAGL,KAAK,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,KAAK,EACvC,MAAM,YAAY,CAAC;AAwBpB;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,KAAK,CAAC;IAAC,OAAO,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC;AAE1E,+CAA+C;AAC/C,qBAAa,MAAO,SAAQ,MAAM,CAAC,MAAM,CAAE,YAAW,OAAO,CAAC,MAAM,CAAC;IACnE,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,EAAE,CAAc;IACxB,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,KAAK,CAAqB;IAElC,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,SAAS,CAAQ;gBAEb,IAAI,GAAE,UAAe,EAAE,KAAK,SAAI;IA2B5C,SAAS,CAAC,GAAG,IAAI,EAAE;IAGnB,SAAS,CAAC,GAAG,IAAI,IAAI;IACrB,OAAO,CAAC,UAAU;IAmBlB,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,WAAW,EAAE,MAAM,GAAE,MAAU,EAAE,MAAM,GAAE,OAAe,GAAG,IAAI;IAiCvF,UAAU,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM;IAe/B,OAAO,IAAI,IAAI;IAMf,OAAO,CAAC,aAAa;IA+BrB,SAAS,CAAC,MAAM,IAAI,IAAI;IAoBxB,OAAO,CAAC,SAAS;IAcjB,OAAO,CAAC,GAAG,EAAE,UAAU,GAAG,UAAU;IAIpC,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU;IAI9B,UAAU,CAAC,GAAG,EAAE,UAAU,GAAG,UAAU;IAQvC,MAAM,IAAI,UAAU;CAGrB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,MAAM,EAAE,OAEpB,CAAC"}
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
/**
|
||||
* Blake3 fast hash is Blake2 with reduced security (round count). Can also be used as MAC & KDF.
|
||||
*
|
||||
* It is advertised as "the fastest cryptographic hash". However, it isn't true in JS.
|
||||
* Why is this so slow? While it should be 6x faster than blake2b, perf diff is only 20%:
|
||||
*
|
||||
* * There is only 30% reduction in number of rounds from blake2s
|
||||
* * Speed-up comes from tree structure, which is parallelized using SIMD & threading.
|
||||
* These features are not present in JS, so we only get overhead from trees.
|
||||
* * Parallelization only happens on 1024-byte chunks: there is no benefit for small inputs.
|
||||
* * It is still possible to make it faster using: a) loop unrolling b) web workers c) wasm
|
||||
* @module
|
||||
*/
|
||||
import { SHA256_IV } from "./_md.js";
|
||||
import { fromBig } from "./_u64.js";
|
||||
import { BLAKE2, compress } from "./blake2.js";
|
||||
// prettier-ignore
|
||||
import { abytes, aexists, anumber, aoutput, clean, createXOFer, swap32IfBE, toBytes, u32, u8 } from "./utils.js";
|
||||
// Flag bitset
|
||||
const B3_Flags = {
|
||||
CHUNK_START: 0b1,
|
||||
CHUNK_END: 0b10,
|
||||
PARENT: 0b100,
|
||||
ROOT: 0b1000,
|
||||
KEYED_HASH: 0b10000,
|
||||
DERIVE_KEY_CONTEXT: 0b100000,
|
||||
DERIVE_KEY_MATERIAL: 0b1000000,
|
||||
};
|
||||
const B3_IV = SHA256_IV.slice();
|
||||
const B3_SIGMA = /* @__PURE__ */ (() => {
|
||||
const Id = Array.from({ length: 16 }, (_, i) => i);
|
||||
const permute = (arr) => [2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8].map((i) => arr[i]);
|
||||
const res = [];
|
||||
for (let i = 0, v = Id; i < 7; i++, v = permute(v))
|
||||
res.push(...v);
|
||||
return Uint8Array.from(res);
|
||||
})();
|
||||
/** Blake3 hash. Can be used as MAC and KDF. */
|
||||
export class BLAKE3 extends BLAKE2 {
|
||||
constructor(opts = {}, flags = 0) {
|
||||
super(64, opts.dkLen === undefined ? 32 : opts.dkLen);
|
||||
this.chunkPos = 0; // Position of current block in chunk
|
||||
this.chunksDone = 0; // How many chunks we already have
|
||||
this.flags = 0 | 0;
|
||||
this.stack = [];
|
||||
// Output
|
||||
this.posOut = 0;
|
||||
this.bufferOut32 = new Uint32Array(16);
|
||||
this.chunkOut = 0; // index of output chunk
|
||||
this.enableXOF = true;
|
||||
const { key, context } = opts;
|
||||
const hasContext = context !== undefined;
|
||||
if (key !== undefined) {
|
||||
if (hasContext)
|
||||
throw new Error('Only "key" or "context" can be specified at same time');
|
||||
const k = toBytes(key).slice();
|
||||
abytes(k, 32);
|
||||
this.IV = u32(k);
|
||||
swap32IfBE(this.IV);
|
||||
this.flags = flags | B3_Flags.KEYED_HASH;
|
||||
}
|
||||
else if (hasContext) {
|
||||
const ctx = toBytes(context);
|
||||
const contextKey = new BLAKE3({ dkLen: 32 }, B3_Flags.DERIVE_KEY_CONTEXT)
|
||||
.update(ctx)
|
||||
.digest();
|
||||
this.IV = u32(contextKey);
|
||||
swap32IfBE(this.IV);
|
||||
this.flags = flags | B3_Flags.DERIVE_KEY_MATERIAL;
|
||||
}
|
||||
else {
|
||||
this.IV = B3_IV.slice();
|
||||
this.flags = flags;
|
||||
}
|
||||
this.state = this.IV.slice();
|
||||
this.bufferOut = u8(this.bufferOut32);
|
||||
}
|
||||
// Unused
|
||||
get() {
|
||||
return [];
|
||||
}
|
||||
set() { }
|
||||
b2Compress(counter, flags, buf, bufPos = 0) {
|
||||
const { state: s, pos } = this;
|
||||
const { h, l } = fromBig(BigInt(counter), true);
|
||||
// prettier-ignore
|
||||
const { v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 } = compress(B3_SIGMA, bufPos, buf, 7, s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], B3_IV[0], B3_IV[1], B3_IV[2], B3_IV[3], h, l, pos, flags);
|
||||
s[0] = v0 ^ v8;
|
||||
s[1] = v1 ^ v9;
|
||||
s[2] = v2 ^ v10;
|
||||
s[3] = v3 ^ v11;
|
||||
s[4] = v4 ^ v12;
|
||||
s[5] = v5 ^ v13;
|
||||
s[6] = v6 ^ v14;
|
||||
s[7] = v7 ^ v15;
|
||||
}
|
||||
compress(buf, bufPos = 0, isLast = false) {
|
||||
// Compress last block
|
||||
let flags = this.flags;
|
||||
if (!this.chunkPos)
|
||||
flags |= B3_Flags.CHUNK_START;
|
||||
if (this.chunkPos === 15 || isLast)
|
||||
flags |= B3_Flags.CHUNK_END;
|
||||
if (!isLast)
|
||||
this.pos = this.blockLen;
|
||||
this.b2Compress(this.chunksDone, flags, buf, bufPos);
|
||||
this.chunkPos += 1;
|
||||
// If current block is last in chunk (16 blocks), then compress chunks
|
||||
if (this.chunkPos === 16 || isLast) {
|
||||
let chunk = this.state;
|
||||
this.state = this.IV.slice();
|
||||
// If not the last one, compress only when there are trailing zeros in chunk counter
|
||||
// chunks used as binary tree where current stack is path. Zero means current leaf is finished and can be compressed.
|
||||
// 1 (001) - leaf not finished (just push current chunk to stack)
|
||||
// 2 (010) - leaf finished at depth=1 (merge with last elm on stack and push back)
|
||||
// 3 (011) - last leaf not finished
|
||||
// 4 (100) - leafs finished at depth=1 and depth=2
|
||||
for (let last, chunks = this.chunksDone + 1; isLast || !(chunks & 1); chunks >>= 1) {
|
||||
if (!(last = this.stack.pop()))
|
||||
break;
|
||||
this.buffer32.set(last, 0);
|
||||
this.buffer32.set(chunk, 8);
|
||||
this.pos = this.blockLen;
|
||||
this.b2Compress(0, this.flags | B3_Flags.PARENT, this.buffer32, 0);
|
||||
chunk = this.state;
|
||||
this.state = this.IV.slice();
|
||||
}
|
||||
this.chunksDone++;
|
||||
this.chunkPos = 0;
|
||||
this.stack.push(chunk);
|
||||
}
|
||||
this.pos = 0;
|
||||
}
|
||||
_cloneInto(to) {
|
||||
to = super._cloneInto(to);
|
||||
const { IV, flags, state, chunkPos, posOut, chunkOut, stack, chunksDone } = this;
|
||||
to.state.set(state.slice());
|
||||
to.stack = stack.map((i) => Uint32Array.from(i));
|
||||
to.IV.set(IV);
|
||||
to.flags = flags;
|
||||
to.chunkPos = chunkPos;
|
||||
to.chunksDone = chunksDone;
|
||||
to.posOut = posOut;
|
||||
to.chunkOut = chunkOut;
|
||||
to.enableXOF = this.enableXOF;
|
||||
to.bufferOut32.set(this.bufferOut32);
|
||||
return to;
|
||||
}
|
||||
destroy() {
|
||||
this.destroyed = true;
|
||||
clean(this.state, this.buffer32, this.IV, this.bufferOut32);
|
||||
clean(...this.stack);
|
||||
}
|
||||
// Same as b2Compress, but doesn't modify state and returns 16 u32 array (instead of 8)
|
||||
b2CompressOut() {
|
||||
const { state: s, pos, flags, buffer32, bufferOut32: out32 } = this;
|
||||
const { h, l } = fromBig(BigInt(this.chunkOut++));
|
||||
swap32IfBE(buffer32);
|
||||
// prettier-ignore
|
||||
const { v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 } = compress(B3_SIGMA, 0, buffer32, 7, s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], B3_IV[0], B3_IV[1], B3_IV[2], B3_IV[3], l, h, pos, flags);
|
||||
out32[0] = v0 ^ v8;
|
||||
out32[1] = v1 ^ v9;
|
||||
out32[2] = v2 ^ v10;
|
||||
out32[3] = v3 ^ v11;
|
||||
out32[4] = v4 ^ v12;
|
||||
out32[5] = v5 ^ v13;
|
||||
out32[6] = v6 ^ v14;
|
||||
out32[7] = v7 ^ v15;
|
||||
out32[8] = s[0] ^ v8;
|
||||
out32[9] = s[1] ^ v9;
|
||||
out32[10] = s[2] ^ v10;
|
||||
out32[11] = s[3] ^ v11;
|
||||
out32[12] = s[4] ^ v12;
|
||||
out32[13] = s[5] ^ v13;
|
||||
out32[14] = s[6] ^ v14;
|
||||
out32[15] = s[7] ^ v15;
|
||||
swap32IfBE(buffer32);
|
||||
swap32IfBE(out32);
|
||||
this.posOut = 0;
|
||||
}
|
||||
finish() {
|
||||
if (this.finished)
|
||||
return;
|
||||
this.finished = true;
|
||||
// Padding
|
||||
clean(this.buffer.subarray(this.pos));
|
||||
// Process last chunk
|
||||
let flags = this.flags | B3_Flags.ROOT;
|
||||
if (this.stack.length) {
|
||||
flags |= B3_Flags.PARENT;
|
||||
swap32IfBE(this.buffer32);
|
||||
this.compress(this.buffer32, 0, true);
|
||||
swap32IfBE(this.buffer32);
|
||||
this.chunksDone = 0;
|
||||
this.pos = this.blockLen;
|
||||
}
|
||||
else {
|
||||
flags |= (!this.chunkPos ? B3_Flags.CHUNK_START : 0) | B3_Flags.CHUNK_END;
|
||||
}
|
||||
this.flags = flags;
|
||||
this.b2CompressOut();
|
||||
}
|
||||
writeInto(out) {
|
||||
aexists(this, false);
|
||||
abytes(out);
|
||||
this.finish();
|
||||
const { blockLen, bufferOut } = this;
|
||||
for (let pos = 0, len = out.length; pos < len;) {
|
||||
if (this.posOut >= blockLen)
|
||||
this.b2CompressOut();
|
||||
const take = Math.min(blockLen - this.posOut, len - pos);
|
||||
out.set(bufferOut.subarray(this.posOut, this.posOut + take), pos);
|
||||
this.posOut += take;
|
||||
pos += take;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
xofInto(out) {
|
||||
if (!this.enableXOF)
|
||||
throw new Error('XOF is not possible after digest call');
|
||||
return this.writeInto(out);
|
||||
}
|
||||
xof(bytes) {
|
||||
anumber(bytes);
|
||||
return this.xofInto(new Uint8Array(bytes));
|
||||
}
|
||||
digestInto(out) {
|
||||
aoutput(out, this);
|
||||
if (this.finished)
|
||||
throw new Error('digest() was already called');
|
||||
this.enableXOF = false;
|
||||
this.writeInto(out);
|
||||
this.destroy();
|
||||
return out;
|
||||
}
|
||||
digest() {
|
||||
return this.digestInto(new Uint8Array(this.outputLen));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* BLAKE3 hash function. Can be used as MAC and KDF.
|
||||
* @param msg - message that would be hashed
|
||||
* @param opts - `dkLen` for output length, `key` for MAC mode, `context` for KDF mode
|
||||
* @example
|
||||
* const data = new Uint8Array(32);
|
||||
* const hash = blake3(data);
|
||||
* const mac = blake3(data, { key: new Uint8Array(32) });
|
||||
* const kdf = blake3(data, { context: 'application name' });
|
||||
*/
|
||||
export const blake3 = /* @__PURE__ */ createXOFer((opts) => new BLAKE3(opts));
|
||||
//# sourceMappingURL=blake3.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+2
@@ -0,0 +1,2 @@
|
||||
export declare const crypto: any;
|
||||
//# sourceMappingURL=crypto.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,MAAM,EAAE,GACqE,CAAC"}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
export const crypto = typeof globalThis === 'object' && 'crypto' in globalThis ? globalThis.crypto : undefined;
|
||||
//# sourceMappingURL=crypto.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,MAAM,MAAM,GACjB,OAAO,UAAU,KAAK,QAAQ,IAAI,QAAQ,IAAI,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC"}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
export declare const crypto: any;
|
||||
//# sourceMappingURL=cryptoNode.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"cryptoNode.d.ts","sourceRoot":"","sources":["../src/cryptoNode.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,MAAM,EAAE,GAKJ,CAAC"}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Internal webcrypto alias.
|
||||
* We prefer WebCrypto aka globalThis.crypto, which exists in node.js 16+.
|
||||
* Falls back to Node.js built-in crypto for Node.js <=v14.
|
||||
* See utils.ts for details.
|
||||
* @module
|
||||
*/
|
||||
// @ts-ignore
|
||||
import * as nc from 'node:crypto';
|
||||
export const crypto = nc && typeof nc === 'object' && 'webcrypto' in nc
|
||||
? nc.webcrypto
|
||||
: nc && typeof nc === 'object' && 'randomBytes' in nc
|
||||
? nc
|
||||
: undefined;
|
||||
//# sourceMappingURL=cryptoNode.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"cryptoNode.js","sourceRoot":"","sources":["../src/cryptoNode.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,aAAa;AACb,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAClC,MAAM,CAAC,MAAM,MAAM,GACjB,EAAE,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,WAAW,IAAI,EAAE;IAC/C,CAAC,CAAE,EAAE,CAAC,SAAiB;IACvB,CAAC,CAAC,EAAE,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,aAAa,IAAI,EAAE;QACnD,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC,SAAS,CAAC"}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
export declare function scrypt(password: string, salt: string): Uint8Array;
|
||||
export declare function pbkdf2(password: string, salt: string): Uint8Array;
|
||||
/**
|
||||
* Derives main seed. Takes a lot of time. Prefer `eskdf` method instead.
|
||||
*/
|
||||
export declare function deriveMainSeed(username: string, password: string): Uint8Array;
|
||||
type AccountID = number | string;
|
||||
type OptsLength = {
|
||||
keyLength: number;
|
||||
};
|
||||
type OptsMod = {
|
||||
modulus: bigint;
|
||||
};
|
||||
type KeyOpts = undefined | OptsLength | OptsMod;
|
||||
export interface ESKDF {
|
||||
/**
|
||||
* Derives a child key. Child key will not be associated with any
|
||||
* other child key because of properties of underlying KDF.
|
||||
*
|
||||
* @param protocol - 3-15 character protocol name
|
||||
* @param accountId - numeric identifier of account
|
||||
* @param options - `keyLength: 64` or `modulus: 41920438n`
|
||||
* @example deriveChildKey('aes', 0)
|
||||
*/
|
||||
deriveChildKey: (protocol: string, accountId: AccountID, options?: KeyOpts) => Uint8Array;
|
||||
/**
|
||||
* Deletes the main seed from eskdf instance
|
||||
*/
|
||||
expire: () => void;
|
||||
/**
|
||||
* Account fingerprint
|
||||
*/
|
||||
fingerprint: string;
|
||||
}
|
||||
/**
|
||||
* ESKDF
|
||||
* @param username - username, email, or identifier, min: 8 characters, should have enough entropy
|
||||
* @param password - password, min: 8 characters, should have enough entropy
|
||||
* @example
|
||||
* const kdf = await eskdf('example-university', 'beginning-new-example');
|
||||
* const key = kdf.deriveChildKey('aes', 0);
|
||||
* console.log(kdf.fingerprint);
|
||||
* kdf.expire();
|
||||
*/
|
||||
export declare function eskdf(username: string, password: string): Promise<ESKDF>;
|
||||
export {};
|
||||
//# sourceMappingURL=eskdf.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"eskdf.d.ts","sourceRoot":"","sources":["../src/eskdf.ts"],"names":[],"mappings":"AAiBA,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,CAEjE;AAGD,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,CAEjE;AAiBD;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,CAY7E;AAED,KAAK,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;AAgCjC,KAAK,UAAU,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AACxC,KAAK,OAAO,GAAG;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AACnC,KAAK,OAAO,GAAG,SAAS,GAAG,UAAU,GAAG,OAAO,CAAC;AAwChD,MAAM,WAAW,KAAK;IACpB;;;;;;;;OAQG;IACH,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,UAAU,CAAC;IAC1F;;OAEG;IACH,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;GASG;AACH,wBAAsB,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAuB9E"}
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
/**
|
||||
* Experimental KDF for AES.
|
||||
*/
|
||||
import { hkdf } from "./hkdf.js";
|
||||
import { pbkdf2 as _pbkdf2 } from "./pbkdf2.js";
|
||||
import { scrypt as _scrypt } from "./scrypt.js";
|
||||
import { sha256 } from "./sha256.js";
|
||||
import { abytes, bytesToHex, clean, createView, hexToBytes, kdfInputToBytes } from "./utils.js";
|
||||
// A tiny KDF for various applications like AES key-gen.
|
||||
// Uses HKDF in a non-standard way, so it's not "KDF-secure", only "PRF-secure".
|
||||
// Which is good enough: assume sha2-256 retained preimage resistance.
|
||||
const SCRYPT_FACTOR = 2 ** 19;
|
||||
const PBKDF2_FACTOR = 2 ** 17;
|
||||
// Scrypt KDF
|
||||
export function scrypt(password, salt) {
|
||||
return _scrypt(password, salt, { N: SCRYPT_FACTOR, r: 8, p: 1, dkLen: 32 });
|
||||
}
|
||||
// PBKDF2-HMAC-SHA256
|
||||
export function pbkdf2(password, salt) {
|
||||
return _pbkdf2(sha256, password, salt, { c: PBKDF2_FACTOR, dkLen: 32 });
|
||||
}
|
||||
// Combines two 32-byte byte arrays
|
||||
function xor32(a, b) {
|
||||
abytes(a, 32);
|
||||
abytes(b, 32);
|
||||
const arr = new Uint8Array(32);
|
||||
for (let i = 0; i < 32; i++) {
|
||||
arr[i] = a[i] ^ b[i];
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
function strHasLength(str, min, max) {
|
||||
return typeof str === 'string' && str.length >= min && str.length <= max;
|
||||
}
|
||||
/**
|
||||
* Derives main seed. Takes a lot of time. Prefer `eskdf` method instead.
|
||||
*/
|
||||
export function deriveMainSeed(username, password) {
|
||||
if (!strHasLength(username, 8, 255))
|
||||
throw new Error('invalid username');
|
||||
if (!strHasLength(password, 8, 255))
|
||||
throw new Error('invalid password');
|
||||
// Declared like this to throw off minifiers which auto-convert .fromCharCode(1) to actual string.
|
||||
// String with non-ascii may be problematic in some envs
|
||||
const codes = { _1: 1, _2: 2 };
|
||||
const sep = { s: String.fromCharCode(codes._1), p: String.fromCharCode(codes._2) };
|
||||
const scr = scrypt(password + sep.s, username + sep.s);
|
||||
const pbk = pbkdf2(password + sep.p, username + sep.p);
|
||||
const res = xor32(scr, pbk);
|
||||
clean(scr, pbk);
|
||||
return res;
|
||||
}
|
||||
/**
|
||||
* Converts protocol & accountId pair to HKDF salt & info params.
|
||||
*/
|
||||
function getSaltInfo(protocol, accountId = 0) {
|
||||
// Note that length here also repeats two lines below
|
||||
// We do an additional length check here to reduce the scope of DoS attacks
|
||||
if (!(strHasLength(protocol, 3, 15) && /^[a-z0-9]{3,15}$/.test(protocol))) {
|
||||
throw new Error('invalid protocol');
|
||||
}
|
||||
// Allow string account ids for some protocols
|
||||
const allowsStr = /^password\d{0,3}|ssh|tor|file$/.test(protocol);
|
||||
let salt; // Extract salt. Default is undefined.
|
||||
if (typeof accountId === 'string') {
|
||||
if (!allowsStr)
|
||||
throw new Error('accountId must be a number');
|
||||
if (!strHasLength(accountId, 1, 255))
|
||||
throw new Error('accountId must be string of length 1..255');
|
||||
salt = kdfInputToBytes(accountId);
|
||||
}
|
||||
else if (Number.isSafeInteger(accountId)) {
|
||||
if (accountId < 0 || accountId > Math.pow(2, 32) - 1)
|
||||
throw new Error('invalid accountId');
|
||||
// Convert to Big Endian Uint32
|
||||
salt = new Uint8Array(4);
|
||||
createView(salt).setUint32(0, accountId, false);
|
||||
}
|
||||
else {
|
||||
throw new Error('accountId must be a number' + (allowsStr ? ' or string' : ''));
|
||||
}
|
||||
const info = kdfInputToBytes(protocol);
|
||||
return { salt, info };
|
||||
}
|
||||
function countBytes(num) {
|
||||
if (typeof num !== 'bigint' || num <= BigInt(128))
|
||||
throw new Error('invalid number');
|
||||
return Math.ceil(num.toString(2).length / 8);
|
||||
}
|
||||
/**
|
||||
* Parses keyLength and modulus options to extract length of result key.
|
||||
* If modulus is used, adds 64 bits to it as per FIPS 186 B.4.1 to combat modulo bias.
|
||||
*/
|
||||
function getKeyLength(options) {
|
||||
if (!options || typeof options !== 'object')
|
||||
return 32;
|
||||
const hasLen = 'keyLength' in options;
|
||||
const hasMod = 'modulus' in options;
|
||||
if (hasLen && hasMod)
|
||||
throw new Error('cannot combine keyLength and modulus options');
|
||||
if (!hasLen && !hasMod)
|
||||
throw new Error('must have either keyLength or modulus option');
|
||||
// FIPS 186 B.4.1 requires at least 64 more bits
|
||||
const l = hasMod ? countBytes(options.modulus) + 8 : options.keyLength;
|
||||
if (!(typeof l === 'number' && l >= 16 && l <= 8192))
|
||||
throw new Error('invalid keyLength');
|
||||
return l;
|
||||
}
|
||||
/**
|
||||
* Converts key to bigint and divides it by modulus. Big Endian.
|
||||
* Implements FIPS 186 B.4.1, which removes 0 and modulo bias from output.
|
||||
*/
|
||||
function modReduceKey(key, modulus) {
|
||||
const _1 = BigInt(1);
|
||||
const num = BigInt('0x' + bytesToHex(key)); // check for ui8a, then bytesToNumber()
|
||||
const res = (num % (modulus - _1)) + _1; // Remove 0 from output
|
||||
if (res < _1)
|
||||
throw new Error('expected positive number'); // Guard against bad values
|
||||
const len = key.length - 8; // FIPS requires 64 more bits = 8 bytes
|
||||
const hex = res.toString(16).padStart(len * 2, '0'); // numberToHex()
|
||||
const bytes = hexToBytes(hex);
|
||||
if (bytes.length !== len)
|
||||
throw new Error('invalid length of result key');
|
||||
return bytes;
|
||||
}
|
||||
/**
|
||||
* ESKDF
|
||||
* @param username - username, email, or identifier, min: 8 characters, should have enough entropy
|
||||
* @param password - password, min: 8 characters, should have enough entropy
|
||||
* @example
|
||||
* const kdf = await eskdf('example-university', 'beginning-new-example');
|
||||
* const key = kdf.deriveChildKey('aes', 0);
|
||||
* console.log(kdf.fingerprint);
|
||||
* kdf.expire();
|
||||
*/
|
||||
export async function eskdf(username, password) {
|
||||
// We are using closure + object instead of class because
|
||||
// we want to make `seed` non-accessible for any external function.
|
||||
let seed = deriveMainSeed(username, password);
|
||||
function deriveCK(protocol, accountId = 0, options) {
|
||||
abytes(seed, 32);
|
||||
const { salt, info } = getSaltInfo(protocol, accountId); // validate protocol & accountId
|
||||
const keyLength = getKeyLength(options); // validate options
|
||||
const key = hkdf(sha256, seed, salt, info, keyLength);
|
||||
// Modulus has already been validated
|
||||
return options && 'modulus' in options ? modReduceKey(key, options.modulus) : key;
|
||||
}
|
||||
function expire() {
|
||||
if (seed)
|
||||
seed.fill(1);
|
||||
seed = undefined;
|
||||
}
|
||||
// prettier-ignore
|
||||
const fingerprint = Array.from(deriveCK('fingerprint', 0))
|
||||
.slice(0, 6)
|
||||
.map((char) => char.toString(16).padStart(2, '0').toUpperCase())
|
||||
.join(':');
|
||||
return Object.freeze({ deriveChildKey: deriveCK, expire, fingerprint });
|
||||
}
|
||||
//# sourceMappingURL=eskdf.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+36
@@ -0,0 +1,36 @@
|
||||
import { type CHash, type Input } from './utils.ts';
|
||||
/**
|
||||
* HKDF-extract from spec. Less important part. `HKDF-Extract(IKM, salt) -> PRK`
|
||||
* Arguments position differs from spec (IKM is first one, since it is not optional)
|
||||
* @param hash - hash function that would be used (e.g. sha256)
|
||||
* @param ikm - input keying material, the initial key
|
||||
* @param salt - optional salt value (a non-secret random value)
|
||||
*/
|
||||
export declare function extract(hash: CHash, ikm: Input, salt?: Input): Uint8Array;
|
||||
/**
|
||||
* HKDF-expand from the spec. The most important part. `HKDF-Expand(PRK, info, L) -> OKM`
|
||||
* @param hash - hash function that would be used (e.g. sha256)
|
||||
* @param prk - a pseudorandom key of at least HashLen octets (usually, the output from the extract step)
|
||||
* @param info - optional context and application specific information (can be a zero-length string)
|
||||
* @param length - length of output keying material in bytes
|
||||
*/
|
||||
export declare function expand(hash: CHash, prk: Input, info?: Input, length?: number): Uint8Array;
|
||||
/**
|
||||
* HKDF (RFC 5869): derive keys from an initial input.
|
||||
* Combines hkdf_extract + hkdf_expand in one step
|
||||
* @param hash - hash function that would be used (e.g. sha256)
|
||||
* @param ikm - input keying material, the initial key
|
||||
* @param salt - optional salt value (a non-secret random value)
|
||||
* @param info - optional context and application specific information (can be a zero-length string)
|
||||
* @param length - length of output keying material in bytes
|
||||
* @example
|
||||
* import { hkdf } from '@noble/hashes/hkdf';
|
||||
* import { sha256 } from '@noble/hashes/sha2';
|
||||
* import { randomBytes } from '@noble/hashes/utils';
|
||||
* const inputKey = randomBytes(32);
|
||||
* const salt = randomBytes(32);
|
||||
* const info = 'application-key';
|
||||
* const hk1 = hkdf(sha256, inputKey, salt, info, 32);
|
||||
*/
|
||||
export declare const hkdf: (hash: CHash, ikm: Input, salt: Input | undefined, info: Input | undefined, length: number) => Uint8Array;
|
||||
//# sourceMappingURL=hkdf.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"hkdf.d.ts","sourceRoot":"","sources":["../src/hkdf.ts"],"names":[],"mappings":"AAMA,OAAO,EAAkB,KAAK,KAAK,EAAS,KAAK,KAAK,EAAW,MAAM,YAAY,CAAC;AAEpF;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,KAAK,GAAG,UAAU,CAOzE;AAKD;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,GAAE,MAAW,GAAG,UAAU,CA4B7F;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,IAAI,GACf,MAAM,KAAK,EACX,KAAK,KAAK,EACV,MAAM,KAAK,GAAG,SAAS,EACvB,MAAM,KAAK,GAAG,SAAS,EACvB,QAAQ,MAAM,KACb,UAAkE,CAAC"}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* HKDF (RFC 5869): extract + expand in one step.
|
||||
* See https://soatok.blog/2021/11/17/understanding-hkdf/.
|
||||
* @module
|
||||
*/
|
||||
import { hmac } from "./hmac.js";
|
||||
import { ahash, anumber, clean, toBytes } from "./utils.js";
|
||||
/**
|
||||
* HKDF-extract from spec. Less important part. `HKDF-Extract(IKM, salt) -> PRK`
|
||||
* Arguments position differs from spec (IKM is first one, since it is not optional)
|
||||
* @param hash - hash function that would be used (e.g. sha256)
|
||||
* @param ikm - input keying material, the initial key
|
||||
* @param salt - optional salt value (a non-secret random value)
|
||||
*/
|
||||
export function extract(hash, ikm, salt) {
|
||||
ahash(hash);
|
||||
// NOTE: some libraries treat zero-length array as 'not provided';
|
||||
// we don't, since we have undefined as 'not provided'
|
||||
// https://github.com/RustCrypto/KDFs/issues/15
|
||||
if (salt === undefined)
|
||||
salt = new Uint8Array(hash.outputLen);
|
||||
return hmac(hash, toBytes(salt), toBytes(ikm));
|
||||
}
|
||||
const HKDF_COUNTER = /* @__PURE__ */ Uint8Array.from([0]);
|
||||
const EMPTY_BUFFER = /* @__PURE__ */ Uint8Array.of();
|
||||
/**
|
||||
* HKDF-expand from the spec. The most important part. `HKDF-Expand(PRK, info, L) -> OKM`
|
||||
* @param hash - hash function that would be used (e.g. sha256)
|
||||
* @param prk - a pseudorandom key of at least HashLen octets (usually, the output from the extract step)
|
||||
* @param info - optional context and application specific information (can be a zero-length string)
|
||||
* @param length - length of output keying material in bytes
|
||||
*/
|
||||
export function expand(hash, prk, info, length = 32) {
|
||||
ahash(hash);
|
||||
anumber(length);
|
||||
const olen = hash.outputLen;
|
||||
if (length > 255 * olen)
|
||||
throw new Error('Length should be <= 255*HashLen');
|
||||
const blocks = Math.ceil(length / olen);
|
||||
if (info === undefined)
|
||||
info = EMPTY_BUFFER;
|
||||
// first L(ength) octets of T
|
||||
const okm = new Uint8Array(blocks * olen);
|
||||
// Re-use HMAC instance between blocks
|
||||
const HMAC = hmac.create(hash, prk);
|
||||
const HMACTmp = HMAC._cloneInto();
|
||||
const T = new Uint8Array(HMAC.outputLen);
|
||||
for (let counter = 0; counter < blocks; counter++) {
|
||||
HKDF_COUNTER[0] = counter + 1;
|
||||
// T(0) = empty string (zero length)
|
||||
// T(N) = HMAC-Hash(PRK, T(N-1) | info | N)
|
||||
HMACTmp.update(counter === 0 ? EMPTY_BUFFER : T)
|
||||
.update(info)
|
||||
.update(HKDF_COUNTER)
|
||||
.digestInto(T);
|
||||
okm.set(T, olen * counter);
|
||||
HMAC._cloneInto(HMACTmp);
|
||||
}
|
||||
HMAC.destroy();
|
||||
HMACTmp.destroy();
|
||||
clean(T, HKDF_COUNTER);
|
||||
return okm.slice(0, length);
|
||||
}
|
||||
/**
|
||||
* HKDF (RFC 5869): derive keys from an initial input.
|
||||
* Combines hkdf_extract + hkdf_expand in one step
|
||||
* @param hash - hash function that would be used (e.g. sha256)
|
||||
* @param ikm - input keying material, the initial key
|
||||
* @param salt - optional salt value (a non-secret random value)
|
||||
* @param info - optional context and application specific information (can be a zero-length string)
|
||||
* @param length - length of output keying material in bytes
|
||||
* @example
|
||||
* import { hkdf } from '@noble/hashes/hkdf';
|
||||
* import { sha256 } from '@noble/hashes/sha2';
|
||||
* import { randomBytes } from '@noble/hashes/utils';
|
||||
* const inputKey = randomBytes(32);
|
||||
* const salt = randomBytes(32);
|
||||
* const info = 'application-key';
|
||||
* const hk1 = hkdf(sha256, inputKey, salt, info, 32);
|
||||
*/
|
||||
export const hkdf = (hash, ikm, salt, info, length) => expand(hash, extract(hash, ikm, salt), info, length);
|
||||
//# sourceMappingURL=hkdf.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"hkdf.js","sourceRoot":"","sources":["../src/hkdf.ts"],"names":[],"mappings":"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"}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* HMAC: RFC2104 message authentication code.
|
||||
* @module
|
||||
*/
|
||||
import { Hash, type CHash, type Input } from './utils.ts';
|
||||
export declare class HMAC<T extends Hash<T>> extends Hash<HMAC<T>> {
|
||||
oHash: T;
|
||||
iHash: T;
|
||||
blockLen: number;
|
||||
outputLen: number;
|
||||
private finished;
|
||||
private destroyed;
|
||||
constructor(hash: CHash, _key: Input);
|
||||
update(buf: Input): this;
|
||||
digestInto(out: Uint8Array): void;
|
||||
digest(): Uint8Array;
|
||||
_cloneInto(to?: HMAC<T>): HMAC<T>;
|
||||
clone(): HMAC<T>;
|
||||
destroy(): void;
|
||||
}
|
||||
/**
|
||||
* HMAC: RFC2104 message authentication code.
|
||||
* @param hash - function that would be used e.g. sha256
|
||||
* @param key - message key
|
||||
* @param message - message data
|
||||
* @example
|
||||
* import { hmac } from '@noble/hashes/hmac';
|
||||
* import { sha256 } from '@noble/hashes/sha2';
|
||||
* const mac1 = hmac(sha256, 'key', 'message');
|
||||
*/
|
||||
export declare const hmac: {
|
||||
(hash: CHash, key: Input, message: Input): Uint8Array;
|
||||
create(hash: CHash, key: Input): HMAC<any>;
|
||||
};
|
||||
//# sourceMappingURL=hmac.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"hmac.d.ts","sourceRoot":"","sources":["../src/hmac.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAiC,IAAI,EAAW,KAAK,KAAK,EAAE,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AAElG,qBAAa,IAAI,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,CAAE,SAAQ,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACxD,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,CAAC,CAAC;IACT,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAS;gBAEd,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK;IAsBpC,MAAM,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI;IAKxB,UAAU,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI;IASjC,MAAM,IAAI,UAAU;IAKpB,UAAU,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;IAajC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC;IAGhB,OAAO,IAAI,IAAI;CAKhB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,IAAI,EAAE;IACjB,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,GAAG,UAAU,CAAC;IACtD,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;CAEM,CAAC"}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* HMAC: RFC2104 message authentication code.
|
||||
* @module
|
||||
*/
|
||||
import { abytes, aexists, ahash, clean, Hash, toBytes } from "./utils.js";
|
||||
export class HMAC extends Hash {
|
||||
constructor(hash, _key) {
|
||||
super();
|
||||
this.finished = false;
|
||||
this.destroyed = false;
|
||||
ahash(hash);
|
||||
const key = toBytes(_key);
|
||||
this.iHash = hash.create();
|
||||
if (typeof this.iHash.update !== 'function')
|
||||
throw new Error('Expected instance of class which extends utils.Hash');
|
||||
this.blockLen = this.iHash.blockLen;
|
||||
this.outputLen = this.iHash.outputLen;
|
||||
const blockLen = this.blockLen;
|
||||
const pad = new Uint8Array(blockLen);
|
||||
// blockLen can be bigger than outputLen
|
||||
pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);
|
||||
for (let i = 0; i < pad.length; i++)
|
||||
pad[i] ^= 0x36;
|
||||
this.iHash.update(pad);
|
||||
// By doing update (processing of first block) of outer hash here we can re-use it between multiple calls via clone
|
||||
this.oHash = hash.create();
|
||||
// Undo internal XOR && apply outer XOR
|
||||
for (let i = 0; i < pad.length; i++)
|
||||
pad[i] ^= 0x36 ^ 0x5c;
|
||||
this.oHash.update(pad);
|
||||
clean(pad);
|
||||
}
|
||||
update(buf) {
|
||||
aexists(this);
|
||||
this.iHash.update(buf);
|
||||
return this;
|
||||
}
|
||||
digestInto(out) {
|
||||
aexists(this);
|
||||
abytes(out, this.outputLen);
|
||||
this.finished = true;
|
||||
this.iHash.digestInto(out);
|
||||
this.oHash.update(out);
|
||||
this.oHash.digestInto(out);
|
||||
this.destroy();
|
||||
}
|
||||
digest() {
|
||||
const out = new Uint8Array(this.oHash.outputLen);
|
||||
this.digestInto(out);
|
||||
return out;
|
||||
}
|
||||
_cloneInto(to) {
|
||||
// Create new instance without calling constructor since key already in state and we don't know it.
|
||||
to || (to = Object.create(Object.getPrototypeOf(this), {}));
|
||||
const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
|
||||
to = to;
|
||||
to.finished = finished;
|
||||
to.destroyed = destroyed;
|
||||
to.blockLen = blockLen;
|
||||
to.outputLen = outputLen;
|
||||
to.oHash = oHash._cloneInto(to.oHash);
|
||||
to.iHash = iHash._cloneInto(to.iHash);
|
||||
return to;
|
||||
}
|
||||
clone() {
|
||||
return this._cloneInto();
|
||||
}
|
||||
destroy() {
|
||||
this.destroyed = true;
|
||||
this.oHash.destroy();
|
||||
this.iHash.destroy();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* HMAC: RFC2104 message authentication code.
|
||||
* @param hash - function that would be used e.g. sha256
|
||||
* @param key - message key
|
||||
* @param message - message data
|
||||
* @example
|
||||
* import { hmac } from '@noble/hashes/hmac';
|
||||
* import { sha256 } from '@noble/hashes/sha2';
|
||||
* const mac1 = hmac(sha256, 'key', 'message');
|
||||
*/
|
||||
export const hmac = (hash, key, message) => new HMAC(hash, key).update(message).digest();
|
||||
hmac.create = (hash, key) => new HMAC(hash, key);
|
||||
//# sourceMappingURL=hmac.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"hmac.js","sourceRoot":"","sources":["../src/hmac.ts"],"names":[],"mappings":"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"}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
export {};
|
||||
//# sourceMappingURL=index.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Audited & minimal JS implementation of hash functions, MACs and KDFs. Check out individual modules.
|
||||
* @module
|
||||
* @example
|
||||
```js
|
||||
import {
|
||||
sha256, sha384, sha512, sha224, sha512_224, sha512_256
|
||||
} from '@noble/hashes/sha2';
|
||||
import {
|
||||
sha3_224, sha3_256, sha3_384, sha3_512,
|
||||
keccak_224, keccak_256, keccak_384, keccak_512,
|
||||
shake128, shake256
|
||||
} from '@noble/hashes/sha3';
|
||||
import {
|
||||
cshake128, cshake256,
|
||||
turboshake128, turboshake256,
|
||||
kmac128, kmac256,
|
||||
tuplehash256, parallelhash256,
|
||||
k12, m14, keccakprg
|
||||
} from '@noble/hashes/sha3-addons';
|
||||
import { blake3 } from '@noble/hashes/blake3';
|
||||
import { blake2b, blake2s } from '@noble/hashes/blake2';
|
||||
import { hmac } from '@noble/hashes/hmac';
|
||||
import { hkdf } from '@noble/hashes/hkdf';
|
||||
import { pbkdf2, pbkdf2Async } from '@noble/hashes/pbkdf2';
|
||||
import { scrypt, scryptAsync } from '@noble/hashes/scrypt';
|
||||
import { md5, ripemd160, sha1 } from '@noble/hashes/legacy';
|
||||
import * as utils from '@noble/hashes/utils';
|
||||
```
|
||||
*/
|
||||
throw new Error('root module cannot be imported: import submodules instead. Check out README');
|
||||
export {};
|
||||
//# sourceMappingURL=index.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,IAAI,KAAK,CAAC,6EAA6E,CAAC,CAAC"}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
|
||||
SHA1 (RFC 3174), MD5 (RFC 1321) and RIPEMD160 (RFC 2286) legacy, weak hash functions.
|
||||
Don't use them in a new protocol. What "weak" means:
|
||||
|
||||
- Collisions can be made with 2^18 effort in MD5, 2^60 in SHA1, 2^80 in RIPEMD160.
|
||||
- No practical pre-image attacks (only theoretical, 2^123.4)
|
||||
- HMAC seems kinda ok: https://datatracker.ietf.org/doc/html/rfc6151
|
||||
* @module
|
||||
*/
|
||||
import { HashMD } from './_md.ts';
|
||||
import { type CHash } from './utils.ts';
|
||||
/** SHA1 legacy hash class. */
|
||||
export declare class SHA1 extends HashMD<SHA1> {
|
||||
private A;
|
||||
private B;
|
||||
private C;
|
||||
private D;
|
||||
private E;
|
||||
constructor();
|
||||
protected get(): [number, number, number, number, number];
|
||||
protected set(A: number, B: number, C: number, D: number, E: number): void;
|
||||
protected process(view: DataView, offset: number): void;
|
||||
protected roundClean(): void;
|
||||
destroy(): void;
|
||||
}
|
||||
/** SHA1 (RFC 3174) legacy hash function. It was cryptographically broken. */
|
||||
export declare const sha1: CHash;
|
||||
/** MD5 legacy hash class. */
|
||||
export declare class MD5 extends HashMD<MD5> {
|
||||
private A;
|
||||
private B;
|
||||
private C;
|
||||
private D;
|
||||
constructor();
|
||||
protected get(): [number, number, number, number];
|
||||
protected set(A: number, B: number, C: number, D: number): void;
|
||||
protected process(view: DataView, offset: number): void;
|
||||
protected roundClean(): void;
|
||||
destroy(): void;
|
||||
}
|
||||
/**
|
||||
* MD5 (RFC 1321) legacy hash function. It was cryptographically broken.
|
||||
* MD5 architecture is similar to SHA1, with some differences:
|
||||
* - Reduced output length: 16 bytes (128 bit) instead of 20
|
||||
* - 64 rounds, instead of 80
|
||||
* - Little-endian: could be faster, but will require more code
|
||||
* - Non-linear index selection: huge speed-up for unroll
|
||||
* - Per round constants: more memory accesses, additional speed-up for unroll
|
||||
*/
|
||||
export declare const md5: CHash;
|
||||
export declare class RIPEMD160 extends HashMD<RIPEMD160> {
|
||||
private h0;
|
||||
private h1;
|
||||
private h2;
|
||||
private h3;
|
||||
private h4;
|
||||
constructor();
|
||||
protected get(): [number, number, number, number, number];
|
||||
protected set(h0: number, h1: number, h2: number, h3: number, h4: number): void;
|
||||
protected process(view: DataView, offset: number): void;
|
||||
protected roundClean(): void;
|
||||
destroy(): void;
|
||||
}
|
||||
/**
|
||||
* RIPEMD-160 - a legacy hash function from 1990s.
|
||||
* * https://homes.esat.kuleuven.be/~bosselae/ripemd160.html
|
||||
* * https://homes.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf
|
||||
*/
|
||||
export declare const ripemd160: CHash;
|
||||
//# sourceMappingURL=legacy.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"legacy.d.ts","sourceRoot":"","sources":["../src/legacy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAO,MAAM,EAAO,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,KAAK,KAAK,EAA6B,MAAM,YAAY,CAAC;AAUnE,8BAA8B;AAC9B,qBAAa,IAAK,SAAQ,MAAM,CAAC,IAAI,CAAC;IACpC,OAAO,CAAC,CAAC,CAAkB;IAC3B,OAAO,CAAC,CAAC,CAAkB;IAC3B,OAAO,CAAC,CAAC,CAAkB;IAC3B,OAAO,CAAC,CAAC,CAAkB;IAC3B,OAAO,CAAC,CAAC,CAAkB;;IAK3B,SAAS,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;IAIzD,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IAO1E,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAoCvD,SAAS,CAAC,UAAU,IAAI,IAAI;IAG5B,OAAO,IAAI,IAAI;CAIhB;AAED,6EAA6E;AAC7E,eAAO,MAAM,IAAI,EAAE,KAAsD,CAAC;AAa1E,6BAA6B;AAC7B,qBAAa,GAAI,SAAQ,MAAM,CAAC,GAAG,CAAC;IAClC,OAAO,CAAC,CAAC,CAAiB;IAC1B,OAAO,CAAC,CAAC,CAAiB;IAC1B,OAAO,CAAC,CAAC,CAAiB;IAC1B,OAAO,CAAC,CAAC,CAAiB;;IAK1B,SAAS,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;IAIjD,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IAM/D,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAoCvD,SAAS,CAAC,UAAU,IAAI,IAAI;IAG5B,OAAO,IAAI,IAAI;CAIhB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,GAAG,EAAE,KAAqD,CAAC;AA6CxE,qBAAa,SAAU,SAAQ,MAAM,CAAC,SAAS,CAAC;IAC9C,OAAO,CAAC,EAAE,CAAkB;IAC5B,OAAO,CAAC,EAAE,CAAkB;IAC5B,OAAO,CAAC,EAAE,CAAkB;IAC5B,OAAO,CAAC,EAAE,CAAkB;IAC5B,OAAO,CAAC,EAAE,CAAkB;;IAK5B,SAAS,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;IAIzD,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAO/E,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAmCvD,SAAS,CAAC,UAAU,IAAI,IAAI;IAG5B,OAAO,IAAI,IAAI;CAKhB;AAED;;;;GAIG;AACH,eAAO,MAAM,SAAS,EAAE,KAA2D,CAAC"}
|
||||
+281
@@ -0,0 +1,281 @@
|
||||
/**
|
||||
|
||||
SHA1 (RFC 3174), MD5 (RFC 1321) and RIPEMD160 (RFC 2286) legacy, weak hash functions.
|
||||
Don't use them in a new protocol. What "weak" means:
|
||||
|
||||
- Collisions can be made with 2^18 effort in MD5, 2^60 in SHA1, 2^80 in RIPEMD160.
|
||||
- No practical pre-image attacks (only theoretical, 2^123.4)
|
||||
- HMAC seems kinda ok: https://datatracker.ietf.org/doc/html/rfc6151
|
||||
* @module
|
||||
*/
|
||||
import { Chi, HashMD, Maj } from "./_md.js";
|
||||
import { clean, createHasher, rotl } from "./utils.js";
|
||||
/** Initial SHA1 state */
|
||||
const SHA1_IV = /* @__PURE__ */ Uint32Array.from([
|
||||
0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0,
|
||||
]);
|
||||
// Reusable temporary buffer
|
||||
const SHA1_W = /* @__PURE__ */ new Uint32Array(80);
|
||||
/** SHA1 legacy hash class. */
|
||||
export class SHA1 extends HashMD {
|
||||
constructor() {
|
||||
super(64, 20, 8, false);
|
||||
this.A = SHA1_IV[0] | 0;
|
||||
this.B = SHA1_IV[1] | 0;
|
||||
this.C = SHA1_IV[2] | 0;
|
||||
this.D = SHA1_IV[3] | 0;
|
||||
this.E = SHA1_IV[4] | 0;
|
||||
}
|
||||
get() {
|
||||
const { A, B, C, D, E } = this;
|
||||
return [A, B, C, D, E];
|
||||
}
|
||||
set(A, B, C, D, E) {
|
||||
this.A = A | 0;
|
||||
this.B = B | 0;
|
||||
this.C = C | 0;
|
||||
this.D = D | 0;
|
||||
this.E = E | 0;
|
||||
}
|
||||
process(view, offset) {
|
||||
for (let i = 0; i < 16; i++, offset += 4)
|
||||
SHA1_W[i] = view.getUint32(offset, false);
|
||||
for (let i = 16; i < 80; i++)
|
||||
SHA1_W[i] = rotl(SHA1_W[i - 3] ^ SHA1_W[i - 8] ^ SHA1_W[i - 14] ^ SHA1_W[i - 16], 1);
|
||||
// Compression function main loop, 80 rounds
|
||||
let { A, B, C, D, E } = this;
|
||||
for (let i = 0; i < 80; i++) {
|
||||
let F, K;
|
||||
if (i < 20) {
|
||||
F = Chi(B, C, D);
|
||||
K = 0x5a827999;
|
||||
}
|
||||
else if (i < 40) {
|
||||
F = B ^ C ^ D;
|
||||
K = 0x6ed9eba1;
|
||||
}
|
||||
else if (i < 60) {
|
||||
F = Maj(B, C, D);
|
||||
K = 0x8f1bbcdc;
|
||||
}
|
||||
else {
|
||||
F = B ^ C ^ D;
|
||||
K = 0xca62c1d6;
|
||||
}
|
||||
const T = (rotl(A, 5) + F + E + K + SHA1_W[i]) | 0;
|
||||
E = D;
|
||||
D = C;
|
||||
C = rotl(B, 30);
|
||||
B = A;
|
||||
A = T;
|
||||
}
|
||||
// Add the compressed chunk to the current hash value
|
||||
A = (A + this.A) | 0;
|
||||
B = (B + this.B) | 0;
|
||||
C = (C + this.C) | 0;
|
||||
D = (D + this.D) | 0;
|
||||
E = (E + this.E) | 0;
|
||||
this.set(A, B, C, D, E);
|
||||
}
|
||||
roundClean() {
|
||||
clean(SHA1_W);
|
||||
}
|
||||
destroy() {
|
||||
this.set(0, 0, 0, 0, 0);
|
||||
clean(this.buffer);
|
||||
}
|
||||
}
|
||||
/** SHA1 (RFC 3174) legacy hash function. It was cryptographically broken. */
|
||||
export const sha1 = /* @__PURE__ */ createHasher(() => new SHA1());
|
||||
/** Per-round constants */
|
||||
const p32 = /* @__PURE__ */ Math.pow(2, 32);
|
||||
const K = /* @__PURE__ */ Array.from({ length: 64 }, (_, i) => Math.floor(p32 * Math.abs(Math.sin(i + 1))));
|
||||
/** md5 initial state: same as sha1, but 4 u32 instead of 5. */
|
||||
const MD5_IV = /* @__PURE__ */ SHA1_IV.slice(0, 4);
|
||||
// Reusable temporary buffer
|
||||
const MD5_W = /* @__PURE__ */ new Uint32Array(16);
|
||||
/** MD5 legacy hash class. */
|
||||
export class MD5 extends HashMD {
|
||||
constructor() {
|
||||
super(64, 16, 8, true);
|
||||
this.A = MD5_IV[0] | 0;
|
||||
this.B = MD5_IV[1] | 0;
|
||||
this.C = MD5_IV[2] | 0;
|
||||
this.D = MD5_IV[3] | 0;
|
||||
}
|
||||
get() {
|
||||
const { A, B, C, D } = this;
|
||||
return [A, B, C, D];
|
||||
}
|
||||
set(A, B, C, D) {
|
||||
this.A = A | 0;
|
||||
this.B = B | 0;
|
||||
this.C = C | 0;
|
||||
this.D = D | 0;
|
||||
}
|
||||
process(view, offset) {
|
||||
for (let i = 0; i < 16; i++, offset += 4)
|
||||
MD5_W[i] = view.getUint32(offset, true);
|
||||
// Compression function main loop, 64 rounds
|
||||
let { A, B, C, D } = this;
|
||||
for (let i = 0; i < 64; i++) {
|
||||
let F, g, s;
|
||||
if (i < 16) {
|
||||
F = Chi(B, C, D);
|
||||
g = i;
|
||||
s = [7, 12, 17, 22];
|
||||
}
|
||||
else if (i < 32) {
|
||||
F = Chi(D, B, C);
|
||||
g = (5 * i + 1) % 16;
|
||||
s = [5, 9, 14, 20];
|
||||
}
|
||||
else if (i < 48) {
|
||||
F = B ^ C ^ D;
|
||||
g = (3 * i + 5) % 16;
|
||||
s = [4, 11, 16, 23];
|
||||
}
|
||||
else {
|
||||
F = C ^ (B | ~D);
|
||||
g = (7 * i) % 16;
|
||||
s = [6, 10, 15, 21];
|
||||
}
|
||||
F = F + A + K[i] + MD5_W[g];
|
||||
A = D;
|
||||
D = C;
|
||||
C = B;
|
||||
B = B + rotl(F, s[i % 4]);
|
||||
}
|
||||
// Add the compressed chunk to the current hash value
|
||||
A = (A + this.A) | 0;
|
||||
B = (B + this.B) | 0;
|
||||
C = (C + this.C) | 0;
|
||||
D = (D + this.D) | 0;
|
||||
this.set(A, B, C, D);
|
||||
}
|
||||
roundClean() {
|
||||
clean(MD5_W);
|
||||
}
|
||||
destroy() {
|
||||
this.set(0, 0, 0, 0);
|
||||
clean(this.buffer);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* MD5 (RFC 1321) legacy hash function. It was cryptographically broken.
|
||||
* MD5 architecture is similar to SHA1, with some differences:
|
||||
* - Reduced output length: 16 bytes (128 bit) instead of 20
|
||||
* - 64 rounds, instead of 80
|
||||
* - Little-endian: could be faster, but will require more code
|
||||
* - Non-linear index selection: huge speed-up for unroll
|
||||
* - Per round constants: more memory accesses, additional speed-up for unroll
|
||||
*/
|
||||
export const md5 = /* @__PURE__ */ createHasher(() => new MD5());
|
||||
// RIPEMD-160
|
||||
const Rho160 = /* @__PURE__ */ Uint8Array.from([
|
||||
7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
|
||||
]);
|
||||
const Id160 = /* @__PURE__ */ (() => Uint8Array.from(new Array(16).fill(0).map((_, i) => i)))();
|
||||
const Pi160 = /* @__PURE__ */ (() => Id160.map((i) => (9 * i + 5) % 16))();
|
||||
const idxLR = /* @__PURE__ */ (() => {
|
||||
const L = [Id160];
|
||||
const R = [Pi160];
|
||||
const res = [L, R];
|
||||
for (let i = 0; i < 4; i++)
|
||||
for (let j of res)
|
||||
j.push(j[i].map((k) => Rho160[k]));
|
||||
return res;
|
||||
})();
|
||||
const idxL = /* @__PURE__ */ (() => idxLR[0])();
|
||||
const idxR = /* @__PURE__ */ (() => idxLR[1])();
|
||||
// const [idxL, idxR] = idxLR;
|
||||
const shifts160 = /* @__PURE__ */ [
|
||||
[11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8],
|
||||
[12, 13, 11, 15, 6, 9, 9, 7, 12, 15, 11, 13, 7, 8, 7, 7],
|
||||
[13, 15, 14, 11, 7, 7, 6, 8, 13, 14, 13, 12, 5, 5, 6, 9],
|
||||
[14, 11, 12, 14, 8, 6, 5, 5, 15, 12, 15, 14, 9, 9, 8, 6],
|
||||
[15, 12, 13, 13, 9, 5, 8, 6, 14, 11, 12, 11, 8, 6, 5, 5],
|
||||
].map((i) => Uint8Array.from(i));
|
||||
const shiftsL160 = /* @__PURE__ */ idxL.map((idx, i) => idx.map((j) => shifts160[i][j]));
|
||||
const shiftsR160 = /* @__PURE__ */ idxR.map((idx, i) => idx.map((j) => shifts160[i][j]));
|
||||
const Kl160 = /* @__PURE__ */ Uint32Array.from([
|
||||
0x00000000, 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xa953fd4e,
|
||||
]);
|
||||
const Kr160 = /* @__PURE__ */ Uint32Array.from([
|
||||
0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x7a6d76e9, 0x00000000,
|
||||
]);
|
||||
// It's called f() in spec.
|
||||
function ripemd_f(group, x, y, z) {
|
||||
if (group === 0)
|
||||
return x ^ y ^ z;
|
||||
if (group === 1)
|
||||
return (x & y) | (~x & z);
|
||||
if (group === 2)
|
||||
return (x | ~y) ^ z;
|
||||
if (group === 3)
|
||||
return (x & z) | (y & ~z);
|
||||
return x ^ (y | ~z);
|
||||
}
|
||||
// Reusable temporary buffer
|
||||
const BUF_160 = /* @__PURE__ */ new Uint32Array(16);
|
||||
export class RIPEMD160 extends HashMD {
|
||||
constructor() {
|
||||
super(64, 20, 8, true);
|
||||
this.h0 = 0x67452301 | 0;
|
||||
this.h1 = 0xefcdab89 | 0;
|
||||
this.h2 = 0x98badcfe | 0;
|
||||
this.h3 = 0x10325476 | 0;
|
||||
this.h4 = 0xc3d2e1f0 | 0;
|
||||
}
|
||||
get() {
|
||||
const { h0, h1, h2, h3, h4 } = this;
|
||||
return [h0, h1, h2, h3, h4];
|
||||
}
|
||||
set(h0, h1, h2, h3, h4) {
|
||||
this.h0 = h0 | 0;
|
||||
this.h1 = h1 | 0;
|
||||
this.h2 = h2 | 0;
|
||||
this.h3 = h3 | 0;
|
||||
this.h4 = h4 | 0;
|
||||
}
|
||||
process(view, offset) {
|
||||
for (let i = 0; i < 16; i++, offset += 4)
|
||||
BUF_160[i] = view.getUint32(offset, true);
|
||||
// prettier-ignore
|
||||
let al = this.h0 | 0, ar = al, bl = this.h1 | 0, br = bl, cl = this.h2 | 0, cr = cl, dl = this.h3 | 0, dr = dl, el = this.h4 | 0, er = el;
|
||||
// Instead of iterating 0 to 80, we split it into 5 groups
|
||||
// And use the groups in constants, functions, etc. Much simpler
|
||||
for (let group = 0; group < 5; group++) {
|
||||
const rGroup = 4 - group;
|
||||
const hbl = Kl160[group], hbr = Kr160[group]; // prettier-ignore
|
||||
const rl = idxL[group], rr = idxR[group]; // prettier-ignore
|
||||
const sl = shiftsL160[group], sr = shiftsR160[group]; // prettier-ignore
|
||||
for (let i = 0; i < 16; i++) {
|
||||
const tl = (rotl(al + ripemd_f(group, bl, cl, dl) + BUF_160[rl[i]] + hbl, sl[i]) + el) | 0;
|
||||
al = el, el = dl, dl = rotl(cl, 10) | 0, cl = bl, bl = tl; // prettier-ignore
|
||||
}
|
||||
// 2 loops are 10% faster
|
||||
for (let i = 0; i < 16; i++) {
|
||||
const tr = (rotl(ar + ripemd_f(rGroup, br, cr, dr) + BUF_160[rr[i]] + hbr, sr[i]) + er) | 0;
|
||||
ar = er, er = dr, dr = rotl(cr, 10) | 0, cr = br, br = tr; // prettier-ignore
|
||||
}
|
||||
}
|
||||
// Add the compressed chunk to the current hash value
|
||||
this.set((this.h1 + cl + dr) | 0, (this.h2 + dl + er) | 0, (this.h3 + el + ar) | 0, (this.h4 + al + br) | 0, (this.h0 + bl + cr) | 0);
|
||||
}
|
||||
roundClean() {
|
||||
clean(BUF_160);
|
||||
}
|
||||
destroy() {
|
||||
this.destroyed = true;
|
||||
clean(this.buffer);
|
||||
this.set(0, 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* RIPEMD-160 - a legacy hash function from 1990s.
|
||||
* * https://homes.esat.kuleuven.be/~bosselae/ripemd160.html
|
||||
* * https://homes.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf
|
||||
*/
|
||||
export const ripemd160 = /* @__PURE__ */ createHasher(() => new RIPEMD160());
|
||||
//# sourceMappingURL=legacy.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
"browser": {
|
||||
"node:crypto": false
|
||||
},
|
||||
"node": {
|
||||
"./crypto": "./esm/cryptoNode.js"
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import { type CHash, type KDFInput } from './utils.ts';
|
||||
export type Pbkdf2Opt = {
|
||||
c: number;
|
||||
dkLen?: number;
|
||||
asyncTick?: number;
|
||||
};
|
||||
/**
|
||||
* PBKDF2-HMAC: RFC 2898 key derivation function
|
||||
* @param hash - hash function that would be used e.g. sha256
|
||||
* @param password - password from which a derived key is generated
|
||||
* @param salt - cryptographic salt
|
||||
* @param opts - {c, dkLen} where c is work factor and dkLen is output message size
|
||||
* @example
|
||||
* const key = pbkdf2(sha256, 'password', 'salt', { dkLen: 32, c: Math.pow(2, 18) });
|
||||
*/
|
||||
export declare function pbkdf2(hash: CHash, password: KDFInput, salt: KDFInput, opts: Pbkdf2Opt): Uint8Array;
|
||||
/**
|
||||
* PBKDF2-HMAC: RFC 2898 key derivation function. Async version.
|
||||
* @example
|
||||
* await pbkdf2Async(sha256, 'password', 'salt', { dkLen: 32, c: 500_000 });
|
||||
*/
|
||||
export declare function pbkdf2Async(hash: CHash, password: KDFInput, salt: KDFInput, opts: Pbkdf2Opt): Promise<Uint8Array>;
|
||||
//# sourceMappingURL=pbkdf2.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"pbkdf2.d.ts","sourceRoot":"","sources":["../src/pbkdf2.ts"],"names":[],"mappings":"AAMA,OAAO,EAGL,KAAK,KAAK,EACV,KAAK,QAAQ,EACd,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,SAAS,GAAG;IACtB,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAkCF;;;;;;;;GAQG;AACH,wBAAgB,MAAM,CACpB,IAAI,EAAE,KAAK,EACX,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,SAAS,GACd,UAAU,CAsBZ;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,KAAK,EACX,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,SAAS,GACd,OAAO,CAAC,UAAU,CAAC,CAsBrB"}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* PBKDF (RFC 2898). Can be used to create a key from password and salt.
|
||||
* @module
|
||||
*/
|
||||
import { hmac } from "./hmac.js";
|
||||
// prettier-ignore
|
||||
import { ahash, anumber, asyncLoop, checkOpts, clean, createView, Hash, kdfInputToBytes } from "./utils.js";
|
||||
// Common prologue and epilogue for sync/async functions
|
||||
function pbkdf2Init(hash, _password, _salt, _opts) {
|
||||
ahash(hash);
|
||||
const opts = checkOpts({ dkLen: 32, asyncTick: 10 }, _opts);
|
||||
const { c, dkLen, asyncTick } = opts;
|
||||
anumber(c);
|
||||
anumber(dkLen);
|
||||
anumber(asyncTick);
|
||||
if (c < 1)
|
||||
throw new Error('iterations (c) should be >= 1');
|
||||
const password = kdfInputToBytes(_password);
|
||||
const salt = kdfInputToBytes(_salt);
|
||||
// DK = PBKDF2(PRF, Password, Salt, c, dkLen);
|
||||
const DK = new Uint8Array(dkLen);
|
||||
// U1 = PRF(Password, Salt + INT_32_BE(i))
|
||||
const PRF = hmac.create(hash, password);
|
||||
const PRFSalt = PRF._cloneInto().update(salt);
|
||||
return { c, dkLen, asyncTick, DK, PRF, PRFSalt };
|
||||
}
|
||||
function pbkdf2Output(PRF, PRFSalt, DK, prfW, u) {
|
||||
PRF.destroy();
|
||||
PRFSalt.destroy();
|
||||
if (prfW)
|
||||
prfW.destroy();
|
||||
clean(u);
|
||||
return DK;
|
||||
}
|
||||
/**
|
||||
* PBKDF2-HMAC: RFC 2898 key derivation function
|
||||
* @param hash - hash function that would be used e.g. sha256
|
||||
* @param password - password from which a derived key is generated
|
||||
* @param salt - cryptographic salt
|
||||
* @param opts - {c, dkLen} where c is work factor and dkLen is output message size
|
||||
* @example
|
||||
* const key = pbkdf2(sha256, 'password', 'salt', { dkLen: 32, c: Math.pow(2, 18) });
|
||||
*/
|
||||
export function pbkdf2(hash, password, salt, opts) {
|
||||
const { c, dkLen, DK, PRF, PRFSalt } = pbkdf2Init(hash, password, salt, opts);
|
||||
let prfW; // Working copy
|
||||
const arr = new Uint8Array(4);
|
||||
const view = createView(arr);
|
||||
const u = new Uint8Array(PRF.outputLen);
|
||||
// DK = T1 + T2 + ⋯ + Tdklen/hlen
|
||||
for (let ti = 1, pos = 0; pos < dkLen; ti++, pos += PRF.outputLen) {
|
||||
// Ti = F(Password, Salt, c, i)
|
||||
const Ti = DK.subarray(pos, pos + PRF.outputLen);
|
||||
view.setInt32(0, ti, false);
|
||||
// F(Password, Salt, c, i) = U1 ^ U2 ^ ⋯ ^ Uc
|
||||
// U1 = PRF(Password, Salt + INT_32_BE(i))
|
||||
(prfW = PRFSalt._cloneInto(prfW)).update(arr).digestInto(u);
|
||||
Ti.set(u.subarray(0, Ti.length));
|
||||
for (let ui = 1; ui < c; ui++) {
|
||||
// Uc = PRF(Password, Uc−1)
|
||||
PRF._cloneInto(prfW).update(u).digestInto(u);
|
||||
for (let i = 0; i < Ti.length; i++)
|
||||
Ti[i] ^= u[i];
|
||||
}
|
||||
}
|
||||
return pbkdf2Output(PRF, PRFSalt, DK, prfW, u);
|
||||
}
|
||||
/**
|
||||
* PBKDF2-HMAC: RFC 2898 key derivation function. Async version.
|
||||
* @example
|
||||
* await pbkdf2Async(sha256, 'password', 'salt', { dkLen: 32, c: 500_000 });
|
||||
*/
|
||||
export async function pbkdf2Async(hash, password, salt, opts) {
|
||||
const { c, dkLen, asyncTick, DK, PRF, PRFSalt } = pbkdf2Init(hash, password, salt, opts);
|
||||
let prfW; // Working copy
|
||||
const arr = new Uint8Array(4);
|
||||
const view = createView(arr);
|
||||
const u = new Uint8Array(PRF.outputLen);
|
||||
// DK = T1 + T2 + ⋯ + Tdklen/hlen
|
||||
for (let ti = 1, pos = 0; pos < dkLen; ti++, pos += PRF.outputLen) {
|
||||
// Ti = F(Password, Salt, c, i)
|
||||
const Ti = DK.subarray(pos, pos + PRF.outputLen);
|
||||
view.setInt32(0, ti, false);
|
||||
// F(Password, Salt, c, i) = U1 ^ U2 ^ ⋯ ^ Uc
|
||||
// U1 = PRF(Password, Salt + INT_32_BE(i))
|
||||
(prfW = PRFSalt._cloneInto(prfW)).update(arr).digestInto(u);
|
||||
Ti.set(u.subarray(0, Ti.length));
|
||||
await asyncLoop(c - 1, asyncTick, () => {
|
||||
// Uc = PRF(Password, Uc−1)
|
||||
PRF._cloneInto(prfW).update(u).digestInto(u);
|
||||
for (let i = 0; i < Ti.length; i++)
|
||||
Ti[i] ^= u[i];
|
||||
});
|
||||
}
|
||||
return pbkdf2Output(PRF, PRFSalt, DK, prfW, u);
|
||||
}
|
||||
//# sourceMappingURL=pbkdf2.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"pbkdf2.js","sourceRoot":"","sources":["../src/pbkdf2.ts"],"names":[],"mappings":"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"}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* RIPEMD-160 legacy hash function.
|
||||
* https://homes.esat.kuleuven.be/~bosselae/ripemd160.html
|
||||
* https://homes.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf
|
||||
* @module
|
||||
* @deprecated
|
||||
*/
|
||||
import { RIPEMD160 as RIPEMD160n, ripemd160 as ripemd160n } from './legacy.ts';
|
||||
/** @deprecated Use import from `noble/hashes/legacy` module */
|
||||
export declare const RIPEMD160: typeof RIPEMD160n;
|
||||
/** @deprecated Use import from `noble/hashes/legacy` module */
|
||||
export declare const ripemd160: typeof ripemd160n;
|
||||
//# sourceMappingURL=ripemd160.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"ripemd160.d.ts","sourceRoot":"","sources":["../src/ripemd160.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,SAAS,IAAI,UAAU,EAAE,SAAS,IAAI,UAAU,EAAE,MAAM,aAAa,CAAC;AAC/E,+DAA+D;AAC/D,eAAO,MAAM,SAAS,EAAE,OAAO,UAAuB,CAAC;AACvD,+DAA+D;AAC/D,eAAO,MAAM,SAAS,EAAE,OAAO,UAAuB,CAAC"}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* RIPEMD-160 legacy hash function.
|
||||
* https://homes.esat.kuleuven.be/~bosselae/ripemd160.html
|
||||
* https://homes.esat.kuleuven.be/~bosselae/ripemd160/pdf/AB-9601/AB-9601.pdf
|
||||
* @module
|
||||
* @deprecated
|
||||
*/
|
||||
import { RIPEMD160 as RIPEMD160n, ripemd160 as ripemd160n } from "./legacy.js";
|
||||
/** @deprecated Use import from `noble/hashes/legacy` module */
|
||||
export const RIPEMD160 = RIPEMD160n;
|
||||
/** @deprecated Use import from `noble/hashes/legacy` module */
|
||||
export const ripemd160 = ripemd160n;
|
||||
//# sourceMappingURL=ripemd160.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"ripemd160.js","sourceRoot":"","sources":["../src/ripemd160.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,SAAS,IAAI,UAAU,EAAE,SAAS,IAAI,UAAU,EAAE,MAAM,aAAa,CAAC;AAC/E,+DAA+D;AAC/D,MAAM,CAAC,MAAM,SAAS,GAAsB,UAAU,CAAC;AACvD,+DAA+D;AAC/D,MAAM,CAAC,MAAM,SAAS,GAAsB,UAAU,CAAC"}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
import { type KDFInput } from './utils.ts';
|
||||
export type ScryptOpts = {
|
||||
N: number;
|
||||
r: number;
|
||||
p: number;
|
||||
dkLen?: number;
|
||||
asyncTick?: number;
|
||||
maxmem?: number;
|
||||
onProgress?: (progress: number) => void;
|
||||
};
|
||||
/**
|
||||
* Scrypt KDF from RFC 7914.
|
||||
* @param password - pass
|
||||
* @param salt - salt
|
||||
* @param opts - parameters
|
||||
* - `N` is cpu/mem work factor (power of 2 e.g. 2**18)
|
||||
* - `r` is block size (8 is common), fine-tunes sequential memory read size and performance
|
||||
* - `p` is parallelization factor (1 is common)
|
||||
* - `dkLen` is output key length in bytes e.g. 32.
|
||||
* - `asyncTick` - (default: 10) max time in ms for which async function can block execution
|
||||
* - `maxmem` - (default: `1024 ** 3 + 1024` aka 1GB+1KB). A limit that the app could use for scrypt
|
||||
* - `onProgress` - callback function that would be executed for progress report
|
||||
* @returns Derived key
|
||||
* @example
|
||||
* scrypt('password', 'salt', { N: 2**18, r: 8, p: 1, dkLen: 32 });
|
||||
*/
|
||||
export declare function scrypt(password: KDFInput, salt: KDFInput, opts: ScryptOpts): Uint8Array;
|
||||
/**
|
||||
* Scrypt KDF from RFC 7914. Async version.
|
||||
* @example
|
||||
* await scryptAsync('password', 'salt', { N: 2**18, r: 8, p: 1, dkLen: 32 });
|
||||
*/
|
||||
export declare function scryptAsync(password: KDFInput, salt: KDFInput, opts: ScryptOpts): Promise<Uint8Array>;
|
||||
//# sourceMappingURL=scrypt.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"scrypt.d.ts","sourceRoot":"","sources":["../src/scrypt.ts"],"names":[],"mappings":"AAOA,OAAO,EAGL,KAAK,QAAQ,EAGd,MAAM,YAAY,CAAC;AAuEpB,MAAM,MAAM,UAAU,GAAG;IACvB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC,CAAC;AAoFF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,GAAG,UAAU,CA0BvF;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,UAAU,CAAC,CA2BrB"}
|
||||
+228
@@ -0,0 +1,228 @@
|
||||
/**
|
||||
* RFC 7914 Scrypt KDF. Can be used to create a key from password and salt.
|
||||
* @module
|
||||
*/
|
||||
import { pbkdf2 } from "./pbkdf2.js";
|
||||
import { sha256 } from "./sha2.js";
|
||||
// prettier-ignore
|
||||
import { anumber, asyncLoop, checkOpts, clean, rotl, swap32IfBE, u32 } from "./utils.js";
|
||||
// The main Scrypt loop: uses Salsa extensively.
|
||||
// Six versions of the function were tried, this is the fastest one.
|
||||
// prettier-ignore
|
||||
function XorAndSalsa(prev, pi, input, ii, out, oi) {
|
||||
// Based on https://cr.yp.to/salsa20.html
|
||||
// Xor blocks
|
||||
let y00 = prev[pi++] ^ input[ii++], y01 = prev[pi++] ^ input[ii++];
|
||||
let y02 = prev[pi++] ^ input[ii++], y03 = prev[pi++] ^ input[ii++];
|
||||
let y04 = prev[pi++] ^ input[ii++], y05 = prev[pi++] ^ input[ii++];
|
||||
let y06 = prev[pi++] ^ input[ii++], y07 = prev[pi++] ^ input[ii++];
|
||||
let y08 = prev[pi++] ^ input[ii++], y09 = prev[pi++] ^ input[ii++];
|
||||
let y10 = prev[pi++] ^ input[ii++], y11 = prev[pi++] ^ input[ii++];
|
||||
let y12 = prev[pi++] ^ input[ii++], y13 = prev[pi++] ^ input[ii++];
|
||||
let y14 = prev[pi++] ^ input[ii++], y15 = prev[pi++] ^ input[ii++];
|
||||
// Save state to temporary variables (salsa)
|
||||
let x00 = y00, x01 = y01, x02 = y02, x03 = y03, x04 = y04, x05 = y05, x06 = y06, x07 = y07, x08 = y08, x09 = y09, x10 = y10, x11 = y11, x12 = y12, x13 = y13, x14 = y14, x15 = y15;
|
||||
// Main loop (salsa)
|
||||
for (let i = 0; i < 8; i += 2) {
|
||||
x04 ^= rotl(x00 + x12 | 0, 7);
|
||||
x08 ^= rotl(x04 + x00 | 0, 9);
|
||||
x12 ^= rotl(x08 + x04 | 0, 13);
|
||||
x00 ^= rotl(x12 + x08 | 0, 18);
|
||||
x09 ^= rotl(x05 + x01 | 0, 7);
|
||||
x13 ^= rotl(x09 + x05 | 0, 9);
|
||||
x01 ^= rotl(x13 + x09 | 0, 13);
|
||||
x05 ^= rotl(x01 + x13 | 0, 18);
|
||||
x14 ^= rotl(x10 + x06 | 0, 7);
|
||||
x02 ^= rotl(x14 + x10 | 0, 9);
|
||||
x06 ^= rotl(x02 + x14 | 0, 13);
|
||||
x10 ^= rotl(x06 + x02 | 0, 18);
|
||||
x03 ^= rotl(x15 + x11 | 0, 7);
|
||||
x07 ^= rotl(x03 + x15 | 0, 9);
|
||||
x11 ^= rotl(x07 + x03 | 0, 13);
|
||||
x15 ^= rotl(x11 + x07 | 0, 18);
|
||||
x01 ^= rotl(x00 + x03 | 0, 7);
|
||||
x02 ^= rotl(x01 + x00 | 0, 9);
|
||||
x03 ^= rotl(x02 + x01 | 0, 13);
|
||||
x00 ^= rotl(x03 + x02 | 0, 18);
|
||||
x06 ^= rotl(x05 + x04 | 0, 7);
|
||||
x07 ^= rotl(x06 + x05 | 0, 9);
|
||||
x04 ^= rotl(x07 + x06 | 0, 13);
|
||||
x05 ^= rotl(x04 + x07 | 0, 18);
|
||||
x11 ^= rotl(x10 + x09 | 0, 7);
|
||||
x08 ^= rotl(x11 + x10 | 0, 9);
|
||||
x09 ^= rotl(x08 + x11 | 0, 13);
|
||||
x10 ^= rotl(x09 + x08 | 0, 18);
|
||||
x12 ^= rotl(x15 + x14 | 0, 7);
|
||||
x13 ^= rotl(x12 + x15 | 0, 9);
|
||||
x14 ^= rotl(x13 + x12 | 0, 13);
|
||||
x15 ^= rotl(x14 + x13 | 0, 18);
|
||||
}
|
||||
// Write output (salsa)
|
||||
out[oi++] = (y00 + x00) | 0;
|
||||
out[oi++] = (y01 + x01) | 0;
|
||||
out[oi++] = (y02 + x02) | 0;
|
||||
out[oi++] = (y03 + x03) | 0;
|
||||
out[oi++] = (y04 + x04) | 0;
|
||||
out[oi++] = (y05 + x05) | 0;
|
||||
out[oi++] = (y06 + x06) | 0;
|
||||
out[oi++] = (y07 + x07) | 0;
|
||||
out[oi++] = (y08 + x08) | 0;
|
||||
out[oi++] = (y09 + x09) | 0;
|
||||
out[oi++] = (y10 + x10) | 0;
|
||||
out[oi++] = (y11 + x11) | 0;
|
||||
out[oi++] = (y12 + x12) | 0;
|
||||
out[oi++] = (y13 + x13) | 0;
|
||||
out[oi++] = (y14 + x14) | 0;
|
||||
out[oi++] = (y15 + x15) | 0;
|
||||
}
|
||||
function BlockMix(input, ii, out, oi, r) {
|
||||
// The block B is r 128-byte chunks (which is equivalent of 2r 64-byte chunks)
|
||||
let head = oi + 0;
|
||||
let tail = oi + 16 * r;
|
||||
for (let i = 0; i < 16; i++)
|
||||
out[tail + i] = input[ii + (2 * r - 1) * 16 + i]; // X ← B[2r−1]
|
||||
for (let i = 0; i < r; i++, head += 16, ii += 16) {
|
||||
// We write odd & even Yi at same time. Even: 0bXXXXX0 Odd: 0bXXXXX1
|
||||
XorAndSalsa(out, tail, input, ii, out, head); // head[i] = Salsa(blockIn[2*i] ^ tail[i-1])
|
||||
if (i > 0)
|
||||
tail += 16; // First iteration overwrites tmp value in tail
|
||||
XorAndSalsa(out, head, input, (ii += 16), out, tail); // tail[i] = Salsa(blockIn[2*i+1] ^ head[i])
|
||||
}
|
||||
}
|
||||
// Common prologue and epilogue for sync/async functions
|
||||
function scryptInit(password, salt, _opts) {
|
||||
// Maxmem - 1GB+1KB by default
|
||||
const opts = checkOpts({
|
||||
dkLen: 32,
|
||||
asyncTick: 10,
|
||||
maxmem: 1024 ** 3 + 1024,
|
||||
}, _opts);
|
||||
const { N, r, p, dkLen, asyncTick, maxmem, onProgress } = opts;
|
||||
anumber(N);
|
||||
anumber(r);
|
||||
anumber(p);
|
||||
anumber(dkLen);
|
||||
anumber(asyncTick);
|
||||
anumber(maxmem);
|
||||
if (onProgress !== undefined && typeof onProgress !== 'function')
|
||||
throw new Error('progressCb should be function');
|
||||
const blockSize = 128 * r;
|
||||
const blockSize32 = blockSize / 4;
|
||||
// Max N is 2^32 (Integrify is 32-bit). Real limit is 2^22: JS engines Uint8Array limit is 4GB in 2024.
|
||||
// Spec check `N >= 2^(blockSize / 8)` is not done for compat with popular libs,
|
||||
// which used incorrect r: 1, p: 8. Also, the check seems to be a spec error:
|
||||
// https://www.rfc-editor.org/errata_search.php?rfc=7914
|
||||
const pow32 = Math.pow(2, 32);
|
||||
if (N <= 1 || (N & (N - 1)) !== 0 || N > pow32) {
|
||||
throw new Error('Scrypt: N must be larger than 1, a power of 2, and less than 2^32');
|
||||
}
|
||||
if (p < 0 || p > ((pow32 - 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 > (pow32 - 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: memused is bigger than maxMem. Expected 128 * r * (N + p) > maxmem of ' + maxmem);
|
||||
}
|
||||
// [B0...Bp−1] ← PBKDF2HMAC-SHA256(Passphrase, Salt, 1, blockSize*ParallelizationFactor)
|
||||
// Since it has only one iteration there is no reason to use async variant
|
||||
const B = pbkdf2(sha256, password, salt, { c: 1, dkLen: blockSize * p });
|
||||
const B32 = u32(B);
|
||||
// Re-used between parallel iterations. Array(iterations) of B
|
||||
const V = u32(new Uint8Array(blockSize * N));
|
||||
const tmp = u32(new Uint8Array(blockSize));
|
||||
let blockMixCb = () => { };
|
||||
if (onProgress) {
|
||||
const totalBlockMix = 2 * N * p;
|
||||
// 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(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 };
|
||||
}
|
||||
function scryptOutput(password, dkLen, B, V, tmp) {
|
||||
const res = pbkdf2(sha256, password, B, { c: 1, dkLen });
|
||||
clean(B, V, tmp);
|
||||
return res;
|
||||
}
|
||||
/**
|
||||
* Scrypt KDF from RFC 7914.
|
||||
* @param password - pass
|
||||
* @param salt - salt
|
||||
* @param opts - parameters
|
||||
* - `N` is cpu/mem work factor (power of 2 e.g. 2**18)
|
||||
* - `r` is block size (8 is common), fine-tunes sequential memory read size and performance
|
||||
* - `p` is parallelization factor (1 is common)
|
||||
* - `dkLen` is output key length in bytes e.g. 32.
|
||||
* - `asyncTick` - (default: 10) max time in ms for which async function can block execution
|
||||
* - `maxmem` - (default: `1024 ** 3 + 1024` aka 1GB+1KB). A limit that the app could use for scrypt
|
||||
* - `onProgress` - callback function that would be executed for progress report
|
||||
* @returns Derived key
|
||||
* @example
|
||||
* scrypt('password', 'salt', { N: 2**18, r: 8, p: 1, dkLen: 32 });
|
||||
*/
|
||||
export function scrypt(password, salt, opts) {
|
||||
const { N, r, p, dkLen, blockSize32, V, B32, B, tmp, blockMixCb } = scryptInit(password, salt, opts);
|
||||
swap32IfBE(B32);
|
||||
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]);
|
||||
blockMixCb();
|
||||
}
|
||||
BlockMix(V, (N - 1) * blockSize32, B32, Pi, r); // Process last element
|
||||
blockMixCb();
|
||||
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])
|
||||
blockMixCb();
|
||||
}
|
||||
}
|
||||
swap32IfBE(B32);
|
||||
return scryptOutput(password, dkLen, B, V, tmp);
|
||||
}
|
||||
/**
|
||||
* Scrypt KDF from RFC 7914. Async version.
|
||||
* @example
|
||||
* await scryptAsync('password', 'salt', { N: 2**18, r: 8, p: 1, dkLen: 32 });
|
||||
*/
|
||||
export async function scryptAsync(password, salt, opts) {
|
||||
const { N, r, p, dkLen, blockSize32, V, B32, B, tmp, blockMixCb, asyncTick } = scryptInit(password, salt, opts);
|
||||
swap32IfBE(B32);
|
||||
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, () => {
|
||||
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, () => {
|
||||
// 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();
|
||||
});
|
||||
}
|
||||
swap32IfBE(B32);
|
||||
return scryptOutput(password, dkLen, B, V, tmp);
|
||||
}
|
||||
//# sourceMappingURL=scrypt.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
+11
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* SHA1 (RFC 3174) legacy hash function.
|
||||
* @module
|
||||
* @deprecated
|
||||
*/
|
||||
import { SHA1 as SHA1n, sha1 as sha1n } from './legacy.ts';
|
||||
/** @deprecated Use import from `noble/hashes/legacy` module */
|
||||
export declare const SHA1: typeof SHA1n;
|
||||
/** @deprecated Use import from `noble/hashes/legacy` module */
|
||||
export declare const sha1: typeof sha1n;
|
||||
//# sourceMappingURL=sha1.d.ts.map
|
||||
Reference in New Issue
Block a user