aead-stream
Version:
Authenticated encryption on arbitrary large files
49 lines (48 loc) • 1.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.webEncrypt = void 0;
const chunkify_1 = require("../chunkify");
const util_1 = require("./util");
const profiles = { "AES-GCM": 1 };
const defaultOptions = {
profile: "AES-GCM",
chunkSize: 64 * 1024, // 64K
};
async function* webEncrypt(key, plaintext, options = defaultOptions) {
var _a;
// magic number
yield new TextEncoder().encode("aead");
switch ((_a = options.profile) !== null && _a !== void 0 ? _a : "AES-GCM") {
case "AES-GCM":
yield* aesGcmEncrypt(key, plaintext, options);
return;
default:
throw new Error("unsupported profile: " + options.profile);
}
}
exports.webEncrypt = webEncrypt;
async function* aesGcmEncrypt(key, plaintext, options = defaultOptions) {
var _a;
const nonceLength = 12;
const authTagLength = 16;
const cipherTextChunkSize = (_a = options.chunkSize) !== null && _a !== void 0 ? _a : defaultOptions.chunkSize;
const chunkSize = cipherTextChunkSize - nonceLength - authTagLength;
yield Uint8Array.of(profiles["AES-GCM"], ...(0, util_1.encodeUint32)(cipherTextChunkSize));
const crypto = await (0, util_1.webcrypto)();
let chunkIndex = 0;
for await (const chunk of (0, chunkify_1.chunkify)(chunkSize, plaintext)) {
const nonce = new Uint8Array(nonceLength);
crypto.getRandomValues(nonce);
let aad = (0, util_1.encodeUint32)(chunkIndex++);
if (options.associatedData) {
aad = (0, util_1.concat)(aad, options.associatedData);
}
const ciphertext = await crypto.subtle.encrypt({
name: "AES-GCM",
iv: nonce,
additionalData: aad,
tagLength: authTagLength * 8,
}, key, chunk);
yield (0, util_1.concat)(nonce, new Uint8Array(ciphertext));
}
}