@hackbg/miscreant-esm
Version:
(ESM port) Misuse resistant symmetric encryption library providing AES-SIV (RFC 5297), AES-PMAC-SIV, and STREAM constructions
75 lines (74 loc) • 2.08 kB
JavaScript
import Block from "../internals/block.dist.mjs";
import {xor} from "../internals/xor.dist.mjs";
export class CMAC {
_cipher;
_subkey1;
_subkey2;
static async importKey(provider, keyData) {
const cipher = await provider.importBlockCipherKey(keyData);
const subkey1 = new Block();
await cipher.encryptBlock(subkey1);
subkey1.dbl();
const subkey2 = subkey1.clone();
subkey2.dbl();
return new CMAC(cipher, subkey1, subkey2);
}
_buffer;
_bufferPos = 0;
_finished = false;
constructor(_cipher, _subkey1, _subkey2) {
this._cipher = _cipher;
this._subkey1 = _subkey1;
this._subkey2 = _subkey2;
this._buffer = new Block();
}
reset() {
this._buffer.clear();
this._bufferPos = 0;
this._finished = false;
return this;
}
clear() {
this.reset();
this._subkey1.clear();
this._subkey2.clear();
}
async update(data) {
const left = Block.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;
await this._cipher.encryptBlock(this._buffer);
this._bufferPos = 0;
}
while (dataLength > Block.SIZE) {
for (let i = 0; i < Block.SIZE; i++) {
this._buffer.data[i] ^= data[dataPos + i];
}
dataLength -= Block.SIZE;
dataPos += Block.SIZE;
await this._cipher.encryptBlock(this._buffer);
}
for (let i = 0; i < dataLength; i++) {
this._buffer.data[this._bufferPos++] ^= data[dataPos + i];
}
return this;
}
async finish() {
if (!this._finished) {
const subkey = this._bufferPos < Block.SIZE ? this._subkey2 : this._subkey1;
xor(this._buffer.data, subkey.data);
if (this._bufferPos < Block.SIZE) {
this._buffer.data[this._bufferPos] ^= 0x80;
}
await this._cipher.encryptBlock(this._buffer);
this._finished = true;
}
return this._buffer.clone().data;
}
}