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
JavaScript
"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;