UNPKG

@hackbg/miscreant-esm

Version:

(ESM port) Misuse resistant symmetric encryption library providing AES-SIV (RFC 5297), AES-PMAC-SIV, and STREAM constructions

153 lines (152 loc) 5.34 kB
"use strict"; var __awaiter = this && this.__awaiter || (function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }); Object.defineProperty(exports, "__esModule", { value: true }); exports.SIV = exports.MAX_ASSOCIATED_DATA = void 0; const constant_time_1 = require("./internals/constant-time.dist.cjs"); const wipe_1 = require("./internals/wipe.dist.cjs"); const xor_1 = require("./internals/xor.dist.cjs"); const exceptions_1 = require("./exceptions.dist.cjs"); const block_1 = require("./internals/block.dist.cjs"); const cmac_1 = require("./mac/cmac.dist.cjs"); const pmac_1 = require("./mac/pmac.dist.cjs"); const webcrypto_1 = require("./providers/webcrypto.dist.cjs"); exports.MAX_ASSOCIATED_DATA = 126; class SIV { static importKey(keyData, alg, provider = new webcrypto_1.WebCryptoProvider()) { return __awaiter(this, void 0, void 0, function* () { if (keyData.length !== 32 && keyData.length !== 64) { throw new Error(`AES-SIV: key must be 32 or 64-bytes (got ${keyData.length}`); } const macKey = keyData.subarray(0, keyData.length / 2 | 0); const encKey = keyData.subarray(keyData.length / 2 | 0); let mac; switch (alg) { case "AES-SIV": mac = yield cmac_1.CMAC.importKey(provider, macKey); break; case "AES-CMAC-SIV": mac = yield cmac_1.CMAC.importKey(provider, macKey); break; case "AES-PMAC-SIV": mac = yield pmac_1.PMAC.importKey(provider, macKey); break; default: throw new exceptions_1.NotImplementedError(`Miscreant: algorithm not supported: ${alg}`); } const ctr = yield provider.importCTRKey(encKey); return new SIV(mac, ctr); }); } constructor(mac, ctr) { this._mac = mac; this._ctr = ctr; this._tmp1 = new block_1.default(); this._tmp2 = new block_1.default(); } seal(plaintext, associatedData) { return __awaiter(this, void 0, void 0, function* () { if (associatedData.length > exports.MAX_ASSOCIATED_DATA) { throw new Error("AES-SIV: too many associated data items"); } const resultLength = block_1.default.SIZE + plaintext.length; const result = new Uint8Array(resultLength); const iv = yield this._s2v(associatedData, plaintext); result.set(iv); zeroIVBits(iv); result.set(yield this._ctr.encryptCtr(iv, plaintext), iv.length); return result; }); } open(sealed, associatedData) { return __awaiter(this, void 0, void 0, function* () { if (associatedData.length > exports.MAX_ASSOCIATED_DATA) { throw new Error("AES-SIV: too many associated data items"); } if (sealed.length < block_1.default.SIZE) { throw new exceptions_1.IntegrityError("AES-SIV: ciphertext is truncated"); } const tag = sealed.subarray(0, block_1.default.SIZE); const iv = this._tmp1.data; iv.set(tag); zeroIVBits(iv); const result = yield this._ctr.encryptCtr(iv, sealed.subarray(block_1.default.SIZE)); const expectedTag = yield this._s2v(associatedData, result); if (!(0, constant_time_1.equal)(expectedTag, tag)) { (0, wipe_1.wipe)(result); throw new exceptions_1.IntegrityError("AES-SIV: ciphertext verification failure!"); } return result; }); } clear() { this._tmp1.clear(); this._tmp2.clear(); this._ctr.clear(); this._mac.clear(); return this; } _s2v(associated_data, plaintext) { return __awaiter(this, void 0, void 0, function* () { this._mac.reset(); this._tmp1.clear(); yield this._mac.update(this._tmp1.data); this._tmp2.clear(); this._tmp2.data.set(yield this._mac.finish()); this._mac.reset(); for (const ad of associated_data) { yield this._mac.update(ad); this._tmp1.clear(); this._tmp1.data.set(yield this._mac.finish()); this._mac.reset(); this._tmp2.dbl(); (0, xor_1.xor)(this._tmp2.data, this._tmp1.data); } this._tmp1.clear(); if (plaintext.length >= block_1.default.SIZE) { const n = plaintext.length - block_1.default.SIZE; this._tmp1.data.set(plaintext.subarray(n)); yield this._mac.update(plaintext.subarray(0, n)); } else { this._tmp1.data.set(plaintext); this._tmp1.data[plaintext.length] = 0x80; this._tmp2.dbl(); } (0, xor_1.xor)(this._tmp1.data, this._tmp2.data); yield this._mac.update(this._tmp1.data); return this._mac.finish(); }); } } exports.SIV = SIV; function zeroIVBits(iv) { iv[iv.length - 8] &= 0x7f; iv[iv.length - 4] &= 0x7f; }