miscreant
Version:
Misuse resistant symmetric encryption library providing AES-SIV (RFC 5297), AES-PMAC-SIV, and STREAM constructions
72 lines (71 loc) • 2.97 kB
JavaScript
;
// Copyright (C) 2016 Dmitry Chestnykh
// 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");
/**
* Polyfill for the AES-CTR (counter) mode of operation.
*
* Uses a non-constant-time (lookup table-based) AES polyfill.
* See polyfill/aes.ts for more information on the security impact.
*
* Note that CTR mode is malleable and generally should not be used without
* authentication. Instead, use an authenticated encryption mode, like AES-SIV!
*/
class PolyfillAesCtr {
constructor(cipher) {
// Set cipher.
this._cipher = cipher;
// Allocate space for counter.
this._counter = new block_1.default();
// Allocate buffer for encrypted block.
this._buffer = new block_1.default();
}
clear() {
this._buffer.clear();
this._counter.clear();
this._cipher.clear();
return this;
}
encryptCtr(iv, plaintext) {
return __awaiter(this, void 0, void 0, function* () {
if (iv.length !== block_1.default.SIZE) {
throw new Error("CTR: iv length must be equal to cipher block size");
}
// Copy IV to counter, overwriting it.
this._counter.data.set(iv);
// Set buffer position to length of buffer
// so that the first cipher block is generated.
let bufferPos = block_1.default.SIZE;
const result = new Uint8Array(plaintext.length);
for (let i = 0; i < plaintext.length; i++) {
if (bufferPos === block_1.default.SIZE) {
this._buffer.copy(this._counter);
this._cipher.encryptBlock(this._buffer);
bufferPos = 0;
incrementCounter(this._counter);
}
result[i] = plaintext[i] ^ this._buffer.data[bufferPos++];
}
return result;
});
}
}
exports.default = PolyfillAesCtr;
// Increment an AES-CTR mode counter, intentionally wrapping/overflowing
function incrementCounter(counter) {
let carry = 1;
for (let i = block_1.default.SIZE - 1; i >= 0; i--) {
carry += (counter.data[i] & 0xff) | 0;
counter.data[i] = carry & 0xff;
carry >>>= 8;
}
}