aead-stream
Version:
Authenticated encryption on arbitrary large files
44 lines (43 loc) • 1.66 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.webDecrypt = void 0;
const chunkify_1 = require("../chunkify");
const util_1 = require("./util");
const profiles = { "AES-GCM": 1 };
const defaultOptions = {};
async function* webDecrypt(key, ciphertext, options = defaultOptions) {
const [header, chunkStream] = await (0, util_1.shift)(9, ciphertext);
if (new TextDecoder().decode(header.slice(0, 4)) !== "aead") {
throw new Error("invalid input: magic number mismatch");
}
const profile = header[4];
const chunksize = (0, util_1.decodeUint32)(header.slice(5));
switch (profile) {
case profiles["AES-GCM"]:
yield* aesGcmDecrypt(key, (0, chunkify_1.chunkify)(chunksize, chunkStream), options);
return;
default:
throw new Error("unsupported profile: " + profile);
}
}
exports.webDecrypt = webDecrypt;
async function* aesGcmDecrypt(key, ciphertext, options) {
const nonceLength = 12;
const authTagLength = 16;
const crypto = await (0, util_1.webcrypto)();
let chunkIndex = 0;
for await (const chunk of ciphertext) {
let aad = (0, util_1.encodeUint32)(chunkIndex++);
if (options.associatedData) {
aad = (0, util_1.concat)(aad, options.associatedData);
}
const nonce = chunk.slice(0, nonceLength);
const ciphertext = await crypto.subtle.decrypt({
name: "AES-GCM",
iv: nonce,
additionalData: aad,
tagLength: authTagLength * 8,
}, key, chunk.slice(nonceLength));
yield new Uint8Array(ciphertext);
}
}