include node_modules so release .zip is deployable

This commit is contained in:
2023-11-24 17:44:25 -05:00
parent 6c86cfe5d2
commit 8b11c41267
8963 changed files with 874175 additions and 1 deletions
+31
View File
@@ -0,0 +1,31 @@
export declare const aes_128_ctr: (key: Uint8Array, nonce: Uint8Array) => {
keyLength: number;
encrypt(plaintext: Uint8Array): Promise<Uint8Array>;
decrypt(ciphertext: Uint8Array): Promise<Uint8Array>;
};
export declare const aes_256_ctr: (key: Uint8Array, nonce: Uint8Array) => {
keyLength: number;
encrypt(plaintext: Uint8Array): Promise<Uint8Array>;
decrypt(ciphertext: Uint8Array): Promise<Uint8Array>;
};
export declare const aes_128_cbc: (key: Uint8Array, nonce: Uint8Array) => {
keyLength: number;
encrypt(plaintext: Uint8Array): Promise<Uint8Array>;
decrypt(ciphertext: Uint8Array): Promise<Uint8Array>;
};
export declare const aes_256_cbc: (key: Uint8Array, nonce: Uint8Array) => {
keyLength: number;
encrypt(plaintext: Uint8Array): Promise<Uint8Array>;
decrypt(ciphertext: Uint8Array): Promise<Uint8Array>;
};
export declare const aes_128_gcm: (key: Uint8Array, nonce: Uint8Array) => {
keyLength: number;
encrypt(plaintext: Uint8Array): Promise<Uint8Array>;
decrypt(ciphertext: Uint8Array): Promise<Uint8Array>;
};
export declare const aes_256_gcm: (key: Uint8Array, nonce: Uint8Array) => {
keyLength: number;
encrypt(plaintext: Uint8Array): Promise<Uint8Array>;
decrypt(ciphertext: Uint8Array): Promise<Uint8Array>;
};
//# sourceMappingURL=aes.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"aes.d.ts","sourceRoot":"","sources":["../src/webcrypto/aes.ts"],"names":[],"mappings":"AAwCA,eAAO,MAAM,WAAW,QA/BT,UAAU,SAAS,UAAU;;uBAYb,UAAU,GAAG,QAAQ,UAAU,CAAC;wBAQ/B,UAAU,GAAG,QAAQ,UAAU,CAAC;CAWb,CAAC;AACpD,eAAO,MAAM,WAAW,QAhCT,UAAU,SAAS,UAAU;;uBAYb,UAAU,GAAG,QAAQ,UAAU,CAAC;wBAQ/B,UAAU,GAAG,QAAQ,UAAU,CAAC;CAYb,CAAC;AAEpD,eAAO,MAAM,WAAW,QAlCT,UAAU,SAAS,UAAU;;uBAYb,UAAU,GAAG,QAAQ,UAAU,CAAC;wBAQ/B,UAAU,GAAG,QAAQ,UAAU,CAAC;CAcb,CAAC;AACpD,eAAO,MAAM,WAAW,QAnCT,UAAU,SAAS,UAAU;;uBAYb,UAAU,GAAG,QAAQ,UAAU,CAAC;wBAQ/B,UAAU,GAAG,QAAQ,UAAU,CAAC;CAeb,CAAC;AAEpD,eAAO,MAAM,WAAW,QArCT,UAAU,SAAS,UAAU;;uBAYb,UAAU,GAAG,QAAQ,UAAU,CAAC;wBAQ/B,UAAU,GAAG,QAAQ,UAAU,CAAC;CAiBb,CAAC;AACpD,eAAO,MAAM,WAAW,QAtCT,UAAU,SAAS,UAAU;;uBAYb,UAAU,GAAG,QAAQ,UAAU,CAAC;wBAQ/B,UAAU,GAAG,QAAQ,UAAU,CAAC;CAkBb,CAAC"}
+45
View File
@@ -0,0 +1,45 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.aes_256_gcm = exports.aes_128_gcm = exports.aes_256_cbc = exports.aes_128_cbc = exports.aes_256_ctr = exports.aes_128_ctr = void 0;
const utils_js_1 = require("../utils.js");
const utils_js_2 = require("./utils.js");
function generate(algo, length) {
const keyLength = length / 8;
const keyParams = { name: algo, length };
const cryptParams = { name: algo };
// const params: Record<string, any> = ({ e: algo, i: { name: algo, length } });
return (key, nonce) => {
(0, utils_js_1.ensureBytes)(key, keyLength);
if (algo === 'AES-CTR') {
cryptParams.counter = nonce;
cryptParams.length = 64;
}
else {
cryptParams.iv = nonce;
}
return {
keyLength,
async encrypt(plaintext) {
(0, utils_js_1.ensureBytes)(plaintext);
const cr = (0, utils_js_2.getWebcryptoSubtle)();
const iKey = await cr.importKey('raw', key, keyParams, true, ['encrypt']);
const cipher = await cr.encrypt(cryptParams, iKey, plaintext);
return new Uint8Array(cipher);
},
async decrypt(ciphertext) {
(0, utils_js_1.ensureBytes)(ciphertext);
const cr = (0, utils_js_2.getWebcryptoSubtle)();
const iKey = await cr.importKey('raw', key, keyParams, true, ['decrypt']);
const plaintext = await cr.decrypt(cryptParams, iKey, ciphertext);
return new Uint8Array(plaintext);
},
};
};
}
exports.aes_128_ctr = generate('AES-CTR', 128);
exports.aes_256_ctr = generate('AES-CTR', 256);
exports.aes_128_cbc = generate('AES-CBC', 128);
exports.aes_256_cbc = generate('AES-CBC', 256);
exports.aes_128_gcm = generate('AES-GCM', 128);
exports.aes_256_gcm = generate('AES-GCM', 256);
//# sourceMappingURL=aes.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"aes.js","sourceRoot":"","sources":["../src/webcrypto/aes.ts"],"names":[],"mappings":";;;AAAA,0CAA0C;AAC1C,yCAAgD;AAEhD,SAAS,QAAQ,CAAC,IAAY,EAAE,MAAc;IAC5C,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,CAAC;IAC7B,MAAM,SAAS,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IACzC,MAAM,WAAW,GAAwB,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACxD,gFAAgF;IAEhF,OAAO,CAAC,GAAe,EAAE,KAAiB,EAAE,EAAE;QAC5C,IAAA,sBAAW,EAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC5B,IAAI,IAAI,KAAK,SAAS,EAAE;YACtB,WAAW,CAAC,OAAO,GAAG,KAAK,CAAC;YAC5B,WAAW,CAAC,MAAM,GAAG,EAAE,CAAC;SACzB;aAAM;YACL,WAAW,CAAC,EAAE,GAAG,KAAK,CAAC;SACxB;QAED,OAAO;YACL,SAAS;YAET,KAAK,CAAC,OAAO,CAAC,SAAqB;gBACjC,IAAA,sBAAW,EAAC,SAAS,CAAC,CAAC;gBACvB,MAAM,EAAE,GAAG,IAAA,6BAAkB,GAAE,CAAC;gBAChC,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;gBAC1E,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;gBAC9D,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;YAChC,CAAC;YAED,KAAK,CAAC,OAAO,CAAC,UAAsB;gBAClC,IAAA,sBAAW,EAAC,UAAU,CAAC,CAAC;gBACxB,MAAM,EAAE,GAAG,IAAA,6BAAkB,GAAE,CAAC;gBAChC,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;gBAC1E,MAAM,SAAS,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;gBAClE,OAAO,IAAI,UAAU,CAAC,SAAS,CAAC,CAAC;YACnC,CAAC;SACF,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC;AAEY,QAAA,WAAW,GAAG,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;AACvC,QAAA,WAAW,GAAG,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;AAEvC,QAAA,WAAW,GAAG,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;AACvC,QAAA,WAAW,GAAG,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;AAEvC,QAAA,WAAW,GAAG,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;AACvC,QAAA,WAAW,GAAG,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC"}
+2
View File
@@ -0,0 +1,2 @@
export declare const crypto: any;
//# sourceMappingURL=crypto.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/webcrypto/crypto.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,MAAM,KACuE,CAAC"}
+5
View File
@@ -0,0 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.crypto = void 0;
exports.crypto = typeof globalThis === 'object' && 'crypto' in globalThis ? globalThis.crypto : undefined;
//# sourceMappingURL=crypto.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/webcrypto/crypto.ts"],"names":[],"mappings":";;;AAGa,QAAA,MAAM,GACjB,OAAO,UAAU,KAAK,QAAQ,IAAI,QAAQ,IAAI,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC"}
+2
View File
@@ -0,0 +1,2 @@
export declare const crypto: any;
//# sourceMappingURL=cryptoNode.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"cryptoNode.d.ts","sourceRoot":"","sources":["../src/webcrypto/cryptoNode.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,MAAM,KACoE,CAAC"}
+10
View File
@@ -0,0 +1,10 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.crypto = void 0;
// We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.
// See utils.ts for details.
// The file will throw on node.js 14 and earlier.
// @ts-ignore
const nc = require("node:crypto");
exports.crypto = nc && typeof nc === 'object' && 'webcrypto' in nc ? nc.webcrypto : undefined;
//# sourceMappingURL=cryptoNode.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"cryptoNode.js","sourceRoot":"","sources":["../src/webcrypto/cryptoNode.ts"],"names":[],"mappings":";;;AAAA,oFAAoF;AACpF,4BAA4B;AAC5B,iDAAiD;AACjD,aAAa;AACb,kCAAkC;AACrB,QAAA,MAAM,GACjB,EAAE,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,WAAW,IAAI,EAAE,CAAC,CAAC,CAAE,EAAE,CAAC,SAAiB,CAAC,CAAC,CAAC,SAAS,CAAC"}
+8
View File
@@ -0,0 +1,8 @@
import type { AsyncCipher } from '../utils.js';
export declare function encryptBlock(msg: Uint8Array, key: Uint8Array): Promise<Uint8Array>;
export declare function FF1(radix: number, key: Uint8Array, tweak?: Uint8Array): {
encrypt(x: number[]): Promise<number[]>;
decrypt(x: number[]): Promise<number[]>;
};
export declare function BinaryFF1(key: Uint8Array, tweak?: Uint8Array): AsyncCipher;
//# sourceMappingURL=ff1.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"ff1.d.ts","sourceRoot":"","sources":["../src/webcrypto/ff1.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAmC/C,wBAAsB,YAAY,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAOxF;AAsED,wBAAgB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,GAAE,UAAsB;eAG5D,MAAM,EAAE;eAUR,MAAM,EAAE;EAgB5B;AAqBD,wBAAgB,SAAS,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,GAAE,UAAsB,GAAG,WAAW,CAMrF"}
+177
View File
@@ -0,0 +1,177 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BinaryFF1 = exports.FF1 = exports.encryptBlock = void 0;
const utils_js_1 = require("./utils.js");
// Format-preserving encryption algorithm (FPE-FF1) specified in NIST Special Publication 800-38G.
// https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38G.pdf
// Utils
function toBytesBE(num, length) {
let hex = num.toString(16);
hex = hex.length & 1 ? `0${hex}` : hex;
if (length)
hex = hex.padStart(length * 2, '00');
const len = hex.length / 2;
const u8 = new Uint8Array(len);
for (let j = 0, i = 0; i < hex.length && i < len * 2; i += 2, j++)
u8[j] = parseInt(hex[i] + hex[i + 1], 16);
return u8;
}
function fromBytesBE(bytes) {
let value = 0n;
for (let i = bytes.length - 1, j = 0; i >= 0; i--, j++)
value += (BigInt(bytes[i]) & 255n) << (8n * BigInt(j));
return value;
}
function mod(a, b) {
const result = a % b;
return result >= 0 ? result : b + result;
}
// AES stuff
const BLOCK_LEN = 16;
const IV = new Uint8Array(BLOCK_LEN);
async function encryptBlock(msg, key) {
if (key.length !== 16 && key.length !== 32)
throw new Error('Invalid key length');
const cr = (0, utils_js_1.getWebcryptoSubtle)();
const mode = { name: `AES-CBC`, length: key.length * 8 };
const wKey = await cr.importKey('raw', key, mode, true, ['encrypt']);
const cipher = await cr.encrypt({ name: `aes-cbc`, iv: IV, counter: IV, length: 64 }, wKey, msg);
return new Uint8Array(cipher).subarray(0, 16);
}
exports.encryptBlock = encryptBlock;
function NUMradix(radix, data) {
let res = 0n;
for (let i of data)
res = res * BigInt(radix) + BigInt(i);
return res;
}
async function getRound(radix, key, tweak, x) {
if (radix > 2 ** 16 - 1)
throw new Error(`Invalid radix: ${radix}`);
// radix**minlen ≥ 100
const minLen = Math.ceil(Math.log(100) / Math.log(radix));
const maxLen = 2 ** 32 - 1;
// 2 ≤ minlen ≤ maxlen < 2**32
if (2 > minLen || minLen > maxLen || maxLen >= 2 ** 32)
throw new Error('Invalid radix: 2 ≤ minlen ≤ maxlen < 2**32');
if (x.length < minLen || x.length > maxLen)
throw new Error('X is outside minLen..maxLen bounds');
const u = Math.floor(x.length / 2);
const v = x.length - u;
const b = Math.ceil(Math.ceil(v * Math.log2(radix)) / 8);
const d = 4 * Math.ceil(b / 4) + 4;
const padding = mod(-tweak.length - b - 1, 16);
// P = [1]1 || [2]1 || [1]1 || [radix]3 || [10]1 || [u mod 256]1 || [n]4 || [t]4.
const P = new Uint8Array([1, 2, 1, 0, 0, 0, 10, u, 0, 0, 0, 0, 0, 0, 0, 0]);
const view = new DataView(P.buffer);
view.setUint16(4, radix, false);
view.setUint32(8, x.length, false);
view.setUint32(12, tweak.length, false);
// Q = T || [0](tb1) mod 16 || [i]1 || [NUMradix(B)]b.
const PQ = new Uint8Array(P.length + tweak.length + padding + 1 + b);
PQ.set(P);
P.fill(0);
PQ.set(tweak, P.length);
const round = async (A, B, i, decrypt = false) => {
// Q = ... || [i]1 || [NUMradix(B)]b.
PQ[PQ.length - b - 1] = i;
if (b)
PQ.set(toBytesBE(NUMradix(radix, B), b), PQ.length - b);
// PRF
let r = new Uint8Array(16);
for (let j = 0; j < PQ.length / BLOCK_LEN; j++) {
for (let i = 0; i < BLOCK_LEN; i++)
r[i] ^= PQ[j * BLOCK_LEN + i];
r.set(await encryptBlock(r, key));
}
// Let S be the first d bytes of the following string of ⎡d/16⎤ blocks:
// R || CIPHK(R ⊕[1]16) || CIPHK(R ⊕[2]16) ...CIPHK(R ⊕[⎡d / 16⎤ 1]16).
let s = Array.from(r);
for (let j = 1; s.length < d; j++) {
const block = toBytesBE(BigInt(j), 16);
for (let k = 0; k < BLOCK_LEN; k++)
block[k] ^= r[k];
s.push(...Array.from(await encryptBlock(block, key)));
}
let y = fromBytesBE(Uint8Array.from(s.slice(0, d)));
s.fill(0);
if (decrypt)
y = -y;
const m = i % 2 === 0 ? u : v;
let c = mod(NUMradix(radix, A) + y, BigInt(radix) ** BigInt(m));
// STR(radix, m, c)
const C = Array(m).fill(0);
for (let i = 0; i < m; i++, c /= BigInt(radix))
C[m - 1 - i] = Number(c % BigInt(radix));
A.fill(0);
A = B;
B = C;
return [A, B];
};
const destroy = () => PQ.fill(0);
return { u, round, destroy };
}
const EMPTY_BUF = new Uint8Array([]);
function FF1(radix, key, tweak = EMPTY_BUF) {
const PQ = getRound.bind(null, radix, key, tweak);
return {
async encrypt(x) {
const { u, round, destroy } = await PQ(x);
let [A, B] = [x.slice(0, u), x.slice(u)];
for (let i = 0; i < 10; i++)
[A, B] = await round(A, B, i);
destroy();
const res = A.concat(B);
A.fill(0);
B.fill(0);
return res;
},
async decrypt(x) {
const { u, round, destroy } = await PQ(x);
// The FF1.Decrypt algorithm is similar to the FF1.Encrypt algorithm;
// the differences are in Step 6, where:
// 1) the order of the indices is reversed,
// 2) the roles of A and B are swapped
// 3) modular addition is replaced by modular subtraction, in Step 6vi.
let [B, A] = [x.slice(0, u), x.slice(u)];
for (let i = 9; i >= 0; i--)
[A, B] = await round(A, B, i, true);
destroy();
const res = B.concat(A);
A.fill(0);
B.fill(0);
return res;
},
};
}
exports.FF1 = FF1;
// Binary string which encodes each byte in little-endian byte order
const binLE = {
encode(bytes) {
const x = [];
for (let i = 0; i < bytes.length; i++) {
for (let j = 0, tmp = bytes[i]; j < 8; j++, tmp >>= 1)
x.push(tmp & 1);
}
return x;
},
decode(b) {
if (b.length % 8)
throw new Error('Invalid binary string');
const res = new Uint8Array(b.length / 8);
for (let i = 0, j = 0; i < res.length; i++) {
res[i] = b[j++] | (b[j++] << 1) | (b[j++] << 2) | (b[j++] << 3);
res[i] |= (b[j++] << 4) | (b[j++] << 5) | (b[j++] << 6) | (b[j++] << 7);
}
return res;
},
};
function BinaryFF1(key, tweak = EMPTY_BUF) {
const ff1 = FF1(2, key, tweak);
return {
encrypt: async (x) => binLE.decode(await ff1.encrypt(binLE.encode(x))),
decrypt: async (x) => binLE.decode(await ff1.decrypt(binLE.encode(x))),
};
}
exports.BinaryFF1 = BinaryFF1;
//# sourceMappingURL=ff1.js.map
File diff suppressed because one or more lines are too long
+7
View File
@@ -0,0 +1,7 @@
import { AsyncCipher } from '../utils.js';
export declare function deriveKeys(key: Uint8Array, nonce: Uint8Array): Promise<{
authKey: Uint8Array;
encKey: Uint8Array;
}>;
export declare function aes_256_gcm_siv(key: Uint8Array, nonce: Uint8Array, AAD: Uint8Array): Promise<AsyncCipher>;
//# sourceMappingURL=siv.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"siv.d.ts","sourceRoot":"","sources":["../src/webcrypto/siv.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA4B,MAAM,aAAa,CAAC;AA0DpE,wBAAsB,UAAU,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU;;;GAmBlE;AAED,wBAAsB,eAAe,CACnC,GAAG,EAAE,UAAU,EACf,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE,UAAU,GACd,OAAO,CAAC,WAAW,CAAC,CAyCtB"}
+127
View File
@@ -0,0 +1,127 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.aes_256_gcm_siv = exports.deriveKeys = void 0;
const utils_js_1 = require("../utils.js");
const _polyval_js_1 = require("../_polyval.js");
const utils_js_2 = require("./utils.js");
/**
* AES-GCM-SIV: classic AES-GCM with nonce-misuse resistance.
* RFC 8452, https://datatracker.ietf.org/doc/html/rfc8452
*/
// AES stuff (same as ff1)
const BLOCK_LEN = 16;
const IV = new Uint8Array(BLOCK_LEN);
async function encryptBlock(msg, key) {
if (key.length !== 16 && key.length !== 32)
throw new Error('Invalid key length');
const mode = { name: `AES-CBC`, length: key.length * 8 };
const cr = (0, utils_js_2.getWebcryptoSubtle)();
const wKey = await cr.importKey('raw', key, mode, true, ['encrypt']);
const cipher = await cr.encrypt({ name: `aes-cbc`, iv: IV, counter: IV, length: 64 }, wKey, msg);
return new Uint8Array(cipher).subarray(0, 16);
}
// Kinda constant-time equality
function equalBytes(a, b) {
// Should not happen
if (a.length !== b.length)
throw new Error('equalBytes: Different size of Uint8Arrays');
let flag = true;
for (let i = 0; i < a.length; i++)
if (a[i] !== b[i])
flag && (flag = false);
return flag;
}
// Wrap position so it will be in padded to blockSize
const wrapPos = (pos, blockSize) => Math.ceil(pos / blockSize) * blockSize;
const limit = (name, min, max) => (value) => {
if (!Number.isSafeInteger(value) || min > value || value > max)
throw new Error(`${name}: invalid value=${value}, must be [${min}..${max}]`);
};
// From RFC 8452: Section 6
const AAD_LIMIT = limit('AAD', 0, 2 ** 36);
const PLAIN_LIMIT = limit('Plaintext', 0, 2 ** 36);
const NONCE_LIMIT = limit('Nonce', 12, 12);
const CIPHER_LIMIT = limit('Ciphertext', 16, 2 ** 36 + 16);
// nodejs api doesn't support 32bit counters, browser does
async function ctr(key, tag, input) {
// The initial counter block is the tag with the most significant bit of the last byte set to one.
let block = tag.slice();
block[15] |= 0x80;
let view = (0, utils_js_1.createView)(block);
let output = new Uint8Array(input.length);
for (let pos = 0; pos < input.length;) {
const encryptedBlock = await encryptBlock(block, key);
view.setUint32(0, view.getUint32(0, true) + 1, true);
const take = Math.min(input.length, encryptedBlock.length);
for (let j = 0; j < take; j++, pos++)
output[pos] = encryptedBlock[j] ^ input[pos];
}
return new Uint8Array(output);
}
async function deriveKeys(key, nonce) {
NONCE_LIMIT(nonce.length);
const len = key.length;
if (len !== 16 && len !== 32)
throw new Error(`key length must be 16 or 32 bytes, got: ${len} bytes`);
const encKey = new Uint8Array(len);
const authKey = new Uint8Array(16);
let counter = 0;
const deriveBlock = new Uint8Array(nonce.length + 4);
deriveBlock.set(nonce, 4);
const view = (0, utils_js_1.createView)(deriveBlock);
for (const derivedKey of [authKey, encKey]) {
for (let i = 0; i < derivedKey.length; i += 8) {
view.setUint32(0, counter++, true);
const block = await encryptBlock(deriveBlock, key);
derivedKey.set(block.subarray(0, 8), i);
}
}
return { authKey, encKey };
}
exports.deriveKeys = deriveKeys;
async function aes_256_gcm_siv(key, nonce, AAD) {
const { encKey, authKey } = await deriveKeys(key, nonce);
const computeTag = async (data, AAD) => {
const dataPos = wrapPos(AAD.length, 16);
const lenPos = wrapPos(dataPos + data.length, 16);
const block = new Uint8Array(lenPos + 16);
const view = (0, utils_js_1.createView)(block);
block.set(AAD);
block.set(data, dataPos);
(0, utils_js_1.setBigUint64)(view, lenPos, BigInt(AAD.length * 8), true);
(0, utils_js_1.setBigUint64)(view, lenPos + 8, BigInt(data.length * 8), true);
// Compute the expected tag by XORing S_s and the nonce, clearing the
// most significant bit of the last byte and encrypting with the
// message-encryption key.
const tag = (0, _polyval_js_1.polyval)(authKey, block);
for (let i = 0; i < 12; i++)
tag[i] ^= nonce[i];
// Clear the highest bit
tag[15] &= 0x7f;
return await encryptBlock(tag, encKey);
};
return {
// computeTag,
encrypt: async (plaintext) => {
AAD_LIMIT(AAD.length);
PLAIN_LIMIT(plaintext.length);
const tag = await computeTag(plaintext, AAD);
const out = new Uint8Array(plaintext.length + 16);
out.set(tag, plaintext.length);
out.set(await ctr(encKey, tag, plaintext));
return out;
},
decrypt: async (ciphertext) => {
CIPHER_LIMIT(ciphertext.length);
AAD_LIMIT(AAD.length);
const tag = ciphertext.subarray(-16);
const plaintext = await ctr(encKey, tag, ciphertext.subarray(0, -16));
const expectedTag = await computeTag(plaintext, AAD);
if (!equalBytes(tag, expectedTag))
throw new Error('invalid poly1305 tag');
return plaintext;
},
};
}
exports.aes_256_gcm_siv = aes_256_gcm_siv;
//# sourceMappingURL=siv.js.map
File diff suppressed because one or more lines are too long
+6
View File
@@ -0,0 +1,6 @@
/**
* Secure PRNG. Uses `crypto.getRandomValues`, which defers to OS.
*/
export declare function randomBytes(bytesLength?: number): Uint8Array;
export declare function getWebcryptoSubtle(): any;
//# sourceMappingURL=utils.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/webcrypto/utils.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,wBAAgB,WAAW,CAAC,WAAW,SAAK,GAAG,UAAU,CAKxD;AAED,wBAAgB,kBAAkB,QAKjC"}
+28
View File
@@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getWebcryptoSubtle = exports.randomBytes = void 0;
// We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.
// node.js versions earlier than v19 don't declare it in global scope.
// For node.js, package.js on#exports field mapping rewrites import
// from `crypto` to `cryptoNode`, which imports native module.
// Makes the utils un-importable in browsers without a bundler.
// Once node.js 18 is deprecated, we can just drop the import.
const crypto_1 = require("@noble/ciphers/webcrypto/crypto");
/**
* Secure PRNG. Uses `crypto.getRandomValues`, which defers to OS.
*/
function randomBytes(bytesLength = 32) {
if (crypto_1.crypto && typeof crypto_1.crypto.getRandomValues === 'function') {
return crypto_1.crypto.getRandomValues(new Uint8Array(bytesLength));
}
throw new Error('crypto.getRandomValues must be defined');
}
exports.randomBytes = randomBytes;
function getWebcryptoSubtle() {
if (crypto_1.crypto && typeof crypto_1.crypto.subtle === 'object' && crypto_1.crypto.subtle != null) {
return crypto_1.crypto.subtle;
}
throw new Error('crypto.subtle must be defined');
}
exports.getWebcryptoSubtle = getWebcryptoSubtle;
//# sourceMappingURL=utils.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/webcrypto/utils.ts"],"names":[],"mappings":";;;AAAA,oFAAoF;AACpF,sEAAsE;AACtE,mEAAmE;AACnE,8DAA8D;AAC9D,+DAA+D;AAC/D,8DAA8D;AAC9D,4DAAyD;AAEzD;;GAEG;AACH,SAAgB,WAAW,CAAC,WAAW,GAAG,EAAE;IAC1C,IAAI,eAAM,IAAI,OAAO,eAAM,CAAC,eAAe,KAAK,UAAU,EAAE;QAC1D,OAAO,eAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC;KAC5D;IACD,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;AAC5D,CAAC;AALD,kCAKC;AAED,SAAgB,kBAAkB;IAChC,IAAI,eAAM,IAAI,OAAO,eAAM,CAAC,MAAM,KAAK,QAAQ,IAAI,eAAM,CAAC,MAAM,IAAI,IAAI,EAAE;QACxE,OAAO,eAAM,CAAC,MAAM,CAAC;KACtB;IACD,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;AACnD,CAAC;AALD,gDAKC"}