UNPKG

miscreant

Version:

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

102 lines (101 loc) 4.11 kB
"use strict"; // Copyright (C) 2016-2017 Dmitry Chestnykh, Tony Arcieri // MIT License. See LICENSE file for details. var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const block_1 = require("../internals/block"); const xor_1 = require("../internals/xor"); /** * The AES-CMAC message authentication code */ class CMAC { constructor(_cipher, _subkey1, _subkey2) { this._cipher = _cipher; this._subkey1 = _subkey1; this._subkey2 = _subkey2; this._bufferPos = 0; this._finished = false; this._buffer = new block_1.default(); } /** Create a new CMAC instance from the given key */ static importKey(provider, keyData) { return __awaiter(this, void 0, void 0, function* () { const cipher = yield provider.importBlockCipherKey(keyData); // Generate subkeys. const subkey1 = new block_1.default(); yield cipher.encryptBlock(subkey1); subkey1.dbl(); const subkey2 = subkey1.clone(); subkey2.dbl(); return new CMAC(cipher, subkey1, subkey2); }); } reset() { this._buffer.clear(); this._bufferPos = 0; this._finished = false; return this; } clear() { this.reset(); this._subkey1.clear(); this._subkey2.clear(); } update(data) { return __awaiter(this, void 0, void 0, function* () { const left = block_1.default.SIZE - this._bufferPos; let dataPos = 0; let dataLength = data.length; if (dataLength > left) { for (let i = 0; i < left; i++) { this._buffer.data[this._bufferPos + i] ^= data[i]; } dataLength -= left; dataPos += left; yield this._cipher.encryptBlock(this._buffer); this._bufferPos = 0; } // TODO: use AES-CBC with a span of multiple blocks instead of encryptBlock // to encrypt many blocks in a single call to the WebCrypto API while (dataLength > block_1.default.SIZE) { for (let i = 0; i < block_1.default.SIZE; i++) { this._buffer.data[i] ^= data[dataPos + i]; } dataLength -= block_1.default.SIZE; dataPos += block_1.default.SIZE; yield this._cipher.encryptBlock(this._buffer); } for (let i = 0; i < dataLength; i++) { this._buffer.data[this._bufferPos++] ^= data[dataPos + i]; } return this; }); } finish() { return __awaiter(this, void 0, void 0, function* () { if (!this._finished) { // Select which subkey to use. const subkey = (this._bufferPos < block_1.default.SIZE) ? this._subkey2 : this._subkey1; // XOR in the subkey. xor_1.xor(this._buffer.data, subkey.data); // Pad if needed. if (this._bufferPos < block_1.default.SIZE) { this._buffer.data[this._bufferPos] ^= 0x80; } // Encrypt buffer to get the final digest. yield this._cipher.encryptBlock(this._buffer); // Set finished flag. this._finished = true; } return this._buffer.clone().data; }); } } exports.CMAC = CMAC;