miijs
Version:
Read, Edit, Write, and make Special Miis from a Wiimote binary file or 3DS QR Code to a binary file or QR code
1,426 lines (1,298 loc) • 177 kB
JavaScript
'use strict';
function string_to_bytes(str, utf8) {
if (utf8 === void 0) { utf8 = false; }
var len = str.length, bytes = new Uint8Array(utf8 ? 4 * len : len);
for (var i = 0, j = 0; i < len; i++) {
var c = str.charCodeAt(i);
if (utf8 && 0xd800 <= c && c <= 0xdbff) {
if (++i >= len)
throw new Error('Malformed string, low surrogate expected at position ' + i);
c = ((c ^ 0xd800) << 10) | 0x10000 | (str.charCodeAt(i) ^ 0xdc00);
}
else if (!utf8 && c >>> 8) {
throw new Error('Wide characters are not allowed.');
}
if (!utf8 || c <= 0x7f) {
bytes[j++] = c;
}
else if (c <= 0x7ff) {
bytes[j++] = 0xc0 | (c >> 6);
bytes[j++] = 0x80 | (c & 0x3f);
}
else if (c <= 0xffff) {
bytes[j++] = 0xe0 | (c >> 12);
bytes[j++] = 0x80 | ((c >> 6) & 0x3f);
bytes[j++] = 0x80 | (c & 0x3f);
}
else {
bytes[j++] = 0xf0 | (c >> 18);
bytes[j++] = 0x80 | ((c >> 12) & 0x3f);
bytes[j++] = 0x80 | ((c >> 6) & 0x3f);
bytes[j++] = 0x80 | (c & 0x3f);
}
}
return bytes.subarray(0, j);
}
function is_bytes(a) {
return a instanceof Uint8Array;
}
function _heap_init(heap, heapSize) {
var size = heap ? heap.byteLength : heapSize || 65536;
if (size & 0xfff || size <= 0)
throw new Error('heap size must be a positive integer and a multiple of 4096');
heap = heap || new Uint8Array(new ArrayBuffer(size));
return heap;
}
function _heap_write(heap, hpos, data, dpos, dlen) {
var hlen = heap.length - hpos;
var wlen = hlen < dlen ? hlen : dlen;
heap.set(data.subarray(dpos, dpos + wlen), hpos);
return wlen;
}
/**
* Util exports
*/
var __extends = (undefined && undefined.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var IllegalStateError = /** @class */ (function (_super) {
__extends(IllegalStateError, _super);
function IllegalStateError() {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var _this = _super.apply(this, args) || this;
return _this;
}
return IllegalStateError;
}(Error));
var IllegalArgumentError = /** @class */ (function (_super) {
__extends(IllegalArgumentError, _super);
function IllegalArgumentError() {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var _this = _super.apply(this, args) || this;
return _this;
}
return IllegalArgumentError;
}(Error));
var SecurityError = /** @class */ (function (_super) {
__extends(SecurityError, _super);
function SecurityError() {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var _this = _super.apply(this, args) || this;
return _this;
}
return SecurityError;
}(Error));
/**
* @file {@link http://asmjs.org Asm.js} implementation of the {@link https://en.wikipedia.org/wiki/Advanced_Encryption_Standard Advanced Encryption Standard}.
* @author Artem S Vybornov <vybornov@gmail.com>
* @license MIT
*/
var AES_asm = function () {
/**
* Galois Field stuff init flag
*/
var ginit_done = false;
/**
* Galois Field exponentiation and logarithm tables for 3 (the generator)
*/
var gexp3, glog3;
/**
* Init Galois Field tables
*/
function ginit() {
gexp3 = [],
glog3 = [];
var a = 1, c, d;
for (c = 0; c < 255; c++) {
gexp3[c] = a;
// Multiply by three
d = a & 0x80, a <<= 1, a &= 255;
if (d === 0x80) a ^= 0x1b;
a ^= gexp3[c];
// Set the log table value
glog3[gexp3[c]] = c;
}
gexp3[255] = gexp3[0];
glog3[0] = 0;
ginit_done = true;
}
/**
* Galois Field multiplication
* @param {number} a
* @param {number} b
* @return {number}
*/
function gmul(a, b) {
var c = gexp3[(glog3[a] + glog3[b]) % 255];
if (a === 0 || b === 0) c = 0;
return c;
}
/**
* Galois Field reciprocal
* @param {number} a
* @return {number}
*/
function ginv(a) {
var i = gexp3[255 - glog3[a]];
if (a === 0) i = 0;
return i;
}
/**
* AES stuff init flag
*/
var aes_init_done = false;
/**
* Encryption, Decryption, S-Box and KeyTransform tables
*
* @type {number[]}
*/
var aes_sbox;
/**
* @type {number[]}
*/
var aes_sinv;
/**
* @type {number[][]}
*/
var aes_enc;
/**
* @type {number[][]}
*/
var aes_dec;
/**
* Init AES tables
*/
function aes_init() {
if (!ginit_done) ginit();
// Calculates AES S-Box value
function _s(a) {
var c, s, x;
s = x = ginv(a);
for (c = 0; c < 4; c++) {
s = ((s << 1) | (s >>> 7)) & 255;
x ^= s;
}
x ^= 99;
return x;
}
// Tables
aes_sbox = [],
aes_sinv = [],
aes_enc = [[], [], [], []],
aes_dec = [[], [], [], []];
for (var i = 0; i < 256; i++) {
var s = _s(i);
// S-Box and its inverse
aes_sbox[i] = s;
aes_sinv[s] = i;
// Ecryption and Decryption tables
aes_enc[0][i] = (gmul(2, s) << 24) | (s << 16) | (s << 8) | gmul(3, s);
aes_dec[0][s] = (gmul(14, i) << 24) | (gmul(9, i) << 16) | (gmul(13, i) << 8) | gmul(11, i);
// Rotate tables
for (var t = 1; t < 4; t++) {
aes_enc[t][i] = (aes_enc[t - 1][i] >>> 8) | (aes_enc[t - 1][i] << 24);
aes_dec[t][s] = (aes_dec[t - 1][s] >>> 8) | (aes_dec[t - 1][s] << 24);
}
}
aes_init_done = true;
}
/**
* Asm.js module constructor.
*
* <p>
* Heap buffer layout by offset:
* <pre>
* 0x0000 encryption key schedule
* 0x0400 decryption key schedule
* 0x0800 sbox
* 0x0c00 inv sbox
* 0x1000 encryption tables
* 0x2000 decryption tables
* 0x3000 reserved (future GCM multiplication lookup table)
* 0x4000 data
* </pre>
* Don't touch anything before <code>0x400</code>.
* </p>
*
* @alias AES_asm
* @class
* @param foreign - <i>ignored</i>
* @param buffer - heap buffer to link with
*/
var wrapper = function (foreign, buffer) {
// Init AES stuff for the first time
if (!aes_init_done) aes_init();
// Fill up AES tables
var heap = new Uint32Array(buffer);
heap.set(aes_sbox, 0x0800 >> 2);
heap.set(aes_sinv, 0x0c00 >> 2);
for (var i = 0; i < 4; i++) {
heap.set(aes_enc[i], (0x1000 + 0x400 * i) >> 2);
heap.set(aes_dec[i], (0x2000 + 0x400 * i) >> 2);
}
/**
* Calculate AES key schedules.
* @instance
* @memberof AES_asm
* @param {number} ks - key size, 4/6/8 (for 128/192/256-bit key correspondingly)
* @param {number} k0 - key vector components
* @param {number} k1 - key vector components
* @param {number} k2 - key vector components
* @param {number} k3 - key vector components
* @param {number} k4 - key vector components
* @param {number} k5 - key vector components
* @param {number} k6 - key vector components
* @param {number} k7 - key vector components
*/
function set_key(ks, k0, k1, k2, k3, k4, k5, k6, k7) {
var ekeys = heap.subarray(0x000, 60),
dkeys = heap.subarray(0x100, 0x100 + 60);
// Encryption key schedule
ekeys.set([k0, k1, k2, k3, k4, k5, k6, k7]);
for (var i = ks, rcon = 1; i < 4 * ks + 28; i++) {
var k = ekeys[i - 1];
if ((i % ks === 0) || (ks === 8 && i % ks === 4)) {
k = aes_sbox[k >>> 24] << 24 ^ aes_sbox[k >>> 16 & 255] << 16 ^ aes_sbox[k >>> 8 & 255] << 8 ^ aes_sbox[k & 255];
}
if (i % ks === 0) {
k = (k << 8) ^ (k >>> 24) ^ (rcon << 24);
rcon = (rcon << 1) ^ ((rcon & 0x80) ? 0x1b : 0);
}
ekeys[i] = ekeys[i - ks] ^ k;
}
// Decryption key schedule
for (var j = 0; j < i; j += 4) {
for (var jj = 0; jj < 4; jj++) {
var k = ekeys[i - (4 + j) + (4 - jj) % 4];
if (j < 4 || j >= i - 4) {
dkeys[j + jj] = k;
} else {
dkeys[j + jj] = aes_dec[0][aes_sbox[k >>> 24]]
^ aes_dec[1][aes_sbox[k >>> 16 & 255]]
^ aes_dec[2][aes_sbox[k >>> 8 & 255]]
^ aes_dec[3][aes_sbox[k & 255]];
}
}
}
// Set rounds number
asm.set_rounds(ks + 5);
}
// create library object with necessary properties
var stdlib = { Uint8Array: Uint8Array, Uint32Array: Uint32Array };
var asm = function (stdlib, foreign, buffer) {
"use asm";
var S0 = 0, S1 = 0, S2 = 0, S3 = 0,
I0 = 0, I1 = 0, I2 = 0, I3 = 0,
N0 = 0, N1 = 0, N2 = 0, N3 = 0,
M0 = 0, M1 = 0, M2 = 0, M3 = 0,
H0 = 0, H1 = 0, H2 = 0, H3 = 0,
R = 0;
var HEAP = new stdlib.Uint32Array(buffer),
DATA = new stdlib.Uint8Array(buffer);
/**
* AES core
* @param {number} k - precomputed key schedule offset
* @param {number} s - precomputed sbox table offset
* @param {number} t - precomputed round table offset
* @param {number} r - number of inner rounds to perform
* @param {number} x0 - 128-bit input block vector
* @param {number} x1 - 128-bit input block vector
* @param {number} x2 - 128-bit input block vector
* @param {number} x3 - 128-bit input block vector
*/
function _core(k, s, t, r, x0, x1, x2, x3) {
k = k | 0;
s = s | 0;
t = t | 0;
r = r | 0;
x0 = x0 | 0;
x1 = x1 | 0;
x2 = x2 | 0;
x3 = x3 | 0;
var t1 = 0, t2 = 0, t3 = 0,
y0 = 0, y1 = 0, y2 = 0, y3 = 0,
i = 0;
t1 = t | 0x400, t2 = t | 0x800, t3 = t | 0xc00;
// round 0
x0 = x0 ^ HEAP[(k | 0) >> 2],
x1 = x1 ^ HEAP[(k | 4) >> 2],
x2 = x2 ^ HEAP[(k | 8) >> 2],
x3 = x3 ^ HEAP[(k | 12) >> 2];
// round 1..r
for (i = 16; (i | 0) <= (r << 4); i = (i + 16) | 0) {
y0 = HEAP[(t | x0 >> 22 & 1020) >> 2] ^ HEAP[(t1 | x1 >> 14 & 1020) >> 2] ^ HEAP[(t2 | x2 >> 6 & 1020) >> 2] ^ HEAP[(t3 | x3 << 2 & 1020) >> 2] ^ HEAP[(k | i | 0) >> 2],
y1 = HEAP[(t | x1 >> 22 & 1020) >> 2] ^ HEAP[(t1 | x2 >> 14 & 1020) >> 2] ^ HEAP[(t2 | x3 >> 6 & 1020) >> 2] ^ HEAP[(t3 | x0 << 2 & 1020) >> 2] ^ HEAP[(k | i | 4) >> 2],
y2 = HEAP[(t | x2 >> 22 & 1020) >> 2] ^ HEAP[(t1 | x3 >> 14 & 1020) >> 2] ^ HEAP[(t2 | x0 >> 6 & 1020) >> 2] ^ HEAP[(t3 | x1 << 2 & 1020) >> 2] ^ HEAP[(k | i | 8) >> 2],
y3 = HEAP[(t | x3 >> 22 & 1020) >> 2] ^ HEAP[(t1 | x0 >> 14 & 1020) >> 2] ^ HEAP[(t2 | x1 >> 6 & 1020) >> 2] ^ HEAP[(t3 | x2 << 2 & 1020) >> 2] ^ HEAP[(k | i | 12) >> 2];
x0 = y0, x1 = y1, x2 = y2, x3 = y3;
}
// final round
S0 = HEAP[(s | x0 >> 22 & 1020) >> 2] << 24 ^ HEAP[(s | x1 >> 14 & 1020) >> 2] << 16 ^ HEAP[(s | x2 >> 6 & 1020) >> 2] << 8 ^ HEAP[(s | x3 << 2 & 1020) >> 2] ^ HEAP[(k | i | 0) >> 2],
S1 = HEAP[(s | x1 >> 22 & 1020) >> 2] << 24 ^ HEAP[(s | x2 >> 14 & 1020) >> 2] << 16 ^ HEAP[(s | x3 >> 6 & 1020) >> 2] << 8 ^ HEAP[(s | x0 << 2 & 1020) >> 2] ^ HEAP[(k | i | 4) >> 2],
S2 = HEAP[(s | x2 >> 22 & 1020) >> 2] << 24 ^ HEAP[(s | x3 >> 14 & 1020) >> 2] << 16 ^ HEAP[(s | x0 >> 6 & 1020) >> 2] << 8 ^ HEAP[(s | x1 << 2 & 1020) >> 2] ^ HEAP[(k | i | 8) >> 2],
S3 = HEAP[(s | x3 >> 22 & 1020) >> 2] << 24 ^ HEAP[(s | x0 >> 14 & 1020) >> 2] << 16 ^ HEAP[(s | x1 >> 6 & 1020) >> 2] << 8 ^ HEAP[(s | x2 << 2 & 1020) >> 2] ^ HEAP[(k | i | 12) >> 2];
}
/**
* ECB mode encryption
* @param {number} x0 - 128-bit input block vector
* @param {number} x1 - 128-bit input block vector
* @param {number} x2 - 128-bit input block vector
* @param {number} x3 - 128-bit input block vector
*/
function _ecb_enc(x0, x1, x2, x3) {
x0 = x0 | 0;
x1 = x1 | 0;
x2 = x2 | 0;
x3 = x3 | 0;
_core(
0x0000, 0x0800, 0x1000,
R,
x0,
x1,
x2,
x3
);
}
/**
* ECB mode decryption
* @param {number} x0 - 128-bit input block vector
* @param {number} x1 - 128-bit input block vector
* @param {number} x2 - 128-bit input block vector
* @param {number} x3 - 128-bit input block vector
*/
function _ecb_dec(x0, x1, x2, x3) {
x0 = x0 | 0;
x1 = x1 | 0;
x2 = x2 | 0;
x3 = x3 | 0;
var t = 0;
_core(
0x0400, 0x0c00, 0x2000,
R,
x0,
x3,
x2,
x1
);
t = S1, S1 = S3, S3 = t;
}
/**
* CBC mode encryption
* @param {number} x0 - 128-bit input block vector
* @param {number} x1 - 128-bit input block vector
* @param {number} x2 - 128-bit input block vector
* @param {number} x3 - 128-bit input block vector
*/
function _cbc_enc(x0, x1, x2, x3) {
x0 = x0 | 0;
x1 = x1 | 0;
x2 = x2 | 0;
x3 = x3 | 0;
_core(
0x0000, 0x0800, 0x1000,
R,
I0 ^ x0,
I1 ^ x1,
I2 ^ x2,
I3 ^ x3
);
I0 = S0,
I1 = S1,
I2 = S2,
I3 = S3;
}
/**
* CBC mode decryption
* @param {number} x0 - 128-bit input block vector
* @param {number} x1 - 128-bit input block vector
* @param {number} x2 - 128-bit input block vector
* @param {number} x3 - 128-bit input block vector
*/
function _cbc_dec(x0, x1, x2, x3) {
x0 = x0 | 0;
x1 = x1 | 0;
x2 = x2 | 0;
x3 = x3 | 0;
var t = 0;
_core(
0x0400, 0x0c00, 0x2000,
R,
x0,
x3,
x2,
x1
);
t = S1, S1 = S3, S3 = t;
S0 = S0 ^ I0,
S1 = S1 ^ I1,
S2 = S2 ^ I2,
S3 = S3 ^ I3;
I0 = x0,
I1 = x1,
I2 = x2,
I3 = x3;
}
/**
* CFB mode encryption
* @param {number} x0 - 128-bit input block vector
* @param {number} x1 - 128-bit input block vector
* @param {number} x2 - 128-bit input block vector
* @param {number} x3 - 128-bit input block vector
*/
function _cfb_enc(x0, x1, x2, x3) {
x0 = x0 | 0;
x1 = x1 | 0;
x2 = x2 | 0;
x3 = x3 | 0;
_core(
0x0000, 0x0800, 0x1000,
R,
I0,
I1,
I2,
I3
);
I0 = S0 = S0 ^ x0,
I1 = S1 = S1 ^ x1,
I2 = S2 = S2 ^ x2,
I3 = S3 = S3 ^ x3;
}
/**
* CFB mode decryption
* @param {number} x0 - 128-bit input block vector
* @param {number} x1 - 128-bit input block vector
* @param {number} x2 - 128-bit input block vector
* @param {number} x3 - 128-bit input block vector
*/
function _cfb_dec(x0, x1, x2, x3) {
x0 = x0 | 0;
x1 = x1 | 0;
x2 = x2 | 0;
x3 = x3 | 0;
_core(
0x0000, 0x0800, 0x1000,
R,
I0,
I1,
I2,
I3
);
S0 = S0 ^ x0,
S1 = S1 ^ x1,
S2 = S2 ^ x2,
S3 = S3 ^ x3;
I0 = x0,
I1 = x1,
I2 = x2,
I3 = x3;
}
/**
* OFB mode encryption / decryption
* @param {number} x0 - 128-bit input block vector
* @param {number} x1 - 128-bit input block vector
* @param {number} x2 - 128-bit input block vector
* @param {number} x3 - 128-bit input block vector
*/
function _ofb(x0, x1, x2, x3) {
x0 = x0 | 0;
x1 = x1 | 0;
x2 = x2 | 0;
x3 = x3 | 0;
_core(
0x0000, 0x0800, 0x1000,
R,
I0,
I1,
I2,
I3
);
I0 = S0,
I1 = S1,
I2 = S2,
I3 = S3;
S0 = S0 ^ x0,
S1 = S1 ^ x1,
S2 = S2 ^ x2,
S3 = S3 ^ x3;
}
/**
* CTR mode encryption / decryption
* @param {number} x0 - 128-bit input block vector
* @param {number} x1 - 128-bit input block vector
* @param {number} x2 - 128-bit input block vector
* @param {number} x3 - 128-bit input block vector
*/
function _ctr(x0, x1, x2, x3) {
x0 = x0 | 0;
x1 = x1 | 0;
x2 = x2 | 0;
x3 = x3 | 0;
_core(
0x0000, 0x0800, 0x1000,
R,
N0,
N1,
N2,
N3
);
N3 = (~M3 & N3) | M3 & (N3 + 1);
N2 = (~M2 & N2) | M2 & (N2 + ((N3 | 0) == 0));
N1 = (~M1 & N1) | M1 & (N1 + ((N2 | 0) == 0));
N0 = (~M0 & N0) | M0 & (N0 + ((N1 | 0) == 0));
S0 = S0 ^ x0;
S1 = S1 ^ x1;
S2 = S2 ^ x2;
S3 = S3 ^ x3;
}
/**
* GCM mode MAC calculation
* @param {number} x0 - 128-bit input block vector
* @param {number} x1 - 128-bit input block vector
* @param {number} x2 - 128-bit input block vector
* @param {number} x3 - 128-bit input block vector
*/
function _gcm_mac(x0, x1, x2, x3) {
x0 = x0 | 0;
x1 = x1 | 0;
x2 = x2 | 0;
x3 = x3 | 0;
var y0 = 0, y1 = 0, y2 = 0, y3 = 0,
z0 = 0, z1 = 0, z2 = 0, z3 = 0,
i = 0, c = 0;
x0 = x0 ^ I0,
x1 = x1 ^ I1,
x2 = x2 ^ I2,
x3 = x3 ^ I3;
y0 = H0 | 0,
y1 = H1 | 0,
y2 = H2 | 0,
y3 = H3 | 0;
for (; (i | 0) < 128; i = (i + 1) | 0) {
if (y0 >>> 31) {
z0 = z0 ^ x0,
z1 = z1 ^ x1,
z2 = z2 ^ x2,
z3 = z3 ^ x3;
}
y0 = (y0 << 1) | (y1 >>> 31),
y1 = (y1 << 1) | (y2 >>> 31),
y2 = (y2 << 1) | (y3 >>> 31),
y3 = (y3 << 1);
c = x3 & 1;
x3 = (x3 >>> 1) | (x2 << 31),
x2 = (x2 >>> 1) | (x1 << 31),
x1 = (x1 >>> 1) | (x0 << 31),
x0 = (x0 >>> 1);
if (c) x0 = x0 ^ 0xe1000000;
}
I0 = z0,
I1 = z1,
I2 = z2,
I3 = z3;
}
/**
* Set the internal rounds number.
* @instance
* @memberof AES_asm
* @param {number} r - number if inner AES rounds
*/
function set_rounds(r) {
r = r | 0;
R = r;
}
/**
* Populate the internal state of the module.
* @instance
* @memberof AES_asm
* @param {number} s0 - state vector
* @param {number} s1 - state vector
* @param {number} s2 - state vector
* @param {number} s3 - state vector
*/
function set_state(s0, s1, s2, s3) {
s0 = s0 | 0;
s1 = s1 | 0;
s2 = s2 | 0;
s3 = s3 | 0;
S0 = s0,
S1 = s1,
S2 = s2,
S3 = s3;
}
/**
* Populate the internal iv of the module.
* @instance
* @memberof AES_asm
* @param {number} i0 - iv vector
* @param {number} i1 - iv vector
* @param {number} i2 - iv vector
* @param {number} i3 - iv vector
*/
function set_iv(i0, i1, i2, i3) {
i0 = i0 | 0;
i1 = i1 | 0;
i2 = i2 | 0;
i3 = i3 | 0;
I0 = i0,
I1 = i1,
I2 = i2,
I3 = i3;
}
/**
* Set nonce for CTR-family modes.
* @instance
* @memberof AES_asm
* @param {number} n0 - nonce vector
* @param {number} n1 - nonce vector
* @param {number} n2 - nonce vector
* @param {number} n3 - nonce vector
*/
function set_nonce(n0, n1, n2, n3) {
n0 = n0 | 0;
n1 = n1 | 0;
n2 = n2 | 0;
n3 = n3 | 0;
N0 = n0,
N1 = n1,
N2 = n2,
N3 = n3;
}
/**
* Set counter mask for CTR-family modes.
* @instance
* @memberof AES_asm
* @param {number} m0 - counter mask vector
* @param {number} m1 - counter mask vector
* @param {number} m2 - counter mask vector
* @param {number} m3 - counter mask vector
*/
function set_mask(m0, m1, m2, m3) {
m0 = m0 | 0;
m1 = m1 | 0;
m2 = m2 | 0;
m3 = m3 | 0;
M0 = m0,
M1 = m1,
M2 = m2,
M3 = m3;
}
/**
* Set counter for CTR-family modes.
* @instance
* @memberof AES_asm
* @param {number} c0 - counter vector
* @param {number} c1 - counter vector
* @param {number} c2 - counter vector
* @param {number} c3 - counter vector
*/
function set_counter(c0, c1, c2, c3) {
c0 = c0 | 0;
c1 = c1 | 0;
c2 = c2 | 0;
c3 = c3 | 0;
N3 = (~M3 & N3) | M3 & c3,
N2 = (~M2 & N2) | M2 & c2,
N1 = (~M1 & N1) | M1 & c1,
N0 = (~M0 & N0) | M0 & c0;
}
/**
* Store the internal state vector into the heap.
* @instance
* @memberof AES_asm
* @param {number} pos - offset where to put the data
* @return {number} The number of bytes have been written into the heap, always 16.
*/
function get_state(pos) {
pos = pos | 0;
if (pos & 15) return -1;
DATA[pos | 0] = S0 >>> 24,
DATA[pos | 1] = S0 >>> 16 & 255,
DATA[pos | 2] = S0 >>> 8 & 255,
DATA[pos | 3] = S0 & 255,
DATA[pos | 4] = S1 >>> 24,
DATA[pos | 5] = S1 >>> 16 & 255,
DATA[pos | 6] = S1 >>> 8 & 255,
DATA[pos | 7] = S1 & 255,
DATA[pos | 8] = S2 >>> 24,
DATA[pos | 9] = S2 >>> 16 & 255,
DATA[pos | 10] = S2 >>> 8 & 255,
DATA[pos | 11] = S2 & 255,
DATA[pos | 12] = S3 >>> 24,
DATA[pos | 13] = S3 >>> 16 & 255,
DATA[pos | 14] = S3 >>> 8 & 255,
DATA[pos | 15] = S3 & 255;
return 16;
}
/**
* Store the internal iv vector into the heap.
* @instance
* @memberof AES_asm
* @param {number} pos - offset where to put the data
* @return {number} The number of bytes have been written into the heap, always 16.
*/
function get_iv(pos) {
pos = pos | 0;
if (pos & 15) return -1;
DATA[pos | 0] = I0 >>> 24,
DATA[pos | 1] = I0 >>> 16 & 255,
DATA[pos | 2] = I0 >>> 8 & 255,
DATA[pos | 3] = I0 & 255,
DATA[pos | 4] = I1 >>> 24,
DATA[pos | 5] = I1 >>> 16 & 255,
DATA[pos | 6] = I1 >>> 8 & 255,
DATA[pos | 7] = I1 & 255,
DATA[pos | 8] = I2 >>> 24,
DATA[pos | 9] = I2 >>> 16 & 255,
DATA[pos | 10] = I2 >>> 8 & 255,
DATA[pos | 11] = I2 & 255,
DATA[pos | 12] = I3 >>> 24,
DATA[pos | 13] = I3 >>> 16 & 255,
DATA[pos | 14] = I3 >>> 8 & 255,
DATA[pos | 15] = I3 & 255;
return 16;
}
/**
* GCM initialization.
* @instance
* @memberof AES_asm
*/
function gcm_init() {
_ecb_enc(0, 0, 0, 0);
H0 = S0,
H1 = S1,
H2 = S2,
H3 = S3;
}
/**
* Perform ciphering operation on the supplied data.
* @instance
* @memberof AES_asm
* @param {number} mode - block cipher mode (see {@link AES_asm} mode constants)
* @param {number} pos - offset of the data being processed
* @param {number} len - length of the data being processed
* @return {number} Actual amount of data have been processed.
*/
function cipher(mode, pos, len) {
mode = mode | 0;
pos = pos | 0;
len = len | 0;
var ret = 0;
if (pos & 15) return -1;
while ((len | 0) >= 16) {
_cipher_modes[mode & 7](
DATA[pos | 0] << 24 | DATA[pos | 1] << 16 | DATA[pos | 2] << 8 | DATA[pos | 3],
DATA[pos | 4] << 24 | DATA[pos | 5] << 16 | DATA[pos | 6] << 8 | DATA[pos | 7],
DATA[pos | 8] << 24 | DATA[pos | 9] << 16 | DATA[pos | 10] << 8 | DATA[pos | 11],
DATA[pos | 12] << 24 | DATA[pos | 13] << 16 | DATA[pos | 14] << 8 | DATA[pos | 15]
);
DATA[pos | 0] = S0 >>> 24,
DATA[pos | 1] = S0 >>> 16 & 255,
DATA[pos | 2] = S0 >>> 8 & 255,
DATA[pos | 3] = S0 & 255,
DATA[pos | 4] = S1 >>> 24,
DATA[pos | 5] = S1 >>> 16 & 255,
DATA[pos | 6] = S1 >>> 8 & 255,
DATA[pos | 7] = S1 & 255,
DATA[pos | 8] = S2 >>> 24,
DATA[pos | 9] = S2 >>> 16 & 255,
DATA[pos | 10] = S2 >>> 8 & 255,
DATA[pos | 11] = S2 & 255,
DATA[pos | 12] = S3 >>> 24,
DATA[pos | 13] = S3 >>> 16 & 255,
DATA[pos | 14] = S3 >>> 8 & 255,
DATA[pos | 15] = S3 & 255;
ret = (ret + 16) | 0,
pos = (pos + 16) | 0,
len = (len - 16) | 0;
}
return ret | 0;
}
/**
* Calculates MAC of the supplied data.
* @instance
* @memberof AES_asm
* @param {number} mode - block cipher mode (see {@link AES_asm} mode constants)
* @param {number} pos - offset of the data being processed
* @param {number} len - length of the data being processed
* @return {number} Actual amount of data have been processed.
*/
function mac(mode, pos, len) {
mode = mode | 0;
pos = pos | 0;
len = len | 0;
var ret = 0;
if (pos & 15) return -1;
while ((len | 0) >= 16) {
_mac_modes[mode & 1](
DATA[pos | 0] << 24 | DATA[pos | 1] << 16 | DATA[pos | 2] << 8 | DATA[pos | 3],
DATA[pos | 4] << 24 | DATA[pos | 5] << 16 | DATA[pos | 6] << 8 | DATA[pos | 7],
DATA[pos | 8] << 24 | DATA[pos | 9] << 16 | DATA[pos | 10] << 8 | DATA[pos | 11],
DATA[pos | 12] << 24 | DATA[pos | 13] << 16 | DATA[pos | 14] << 8 | DATA[pos | 15]
);
ret = (ret + 16) | 0,
pos = (pos + 16) | 0,
len = (len - 16) | 0;
}
return ret | 0;
}
/**
* AES cipher modes table (virual methods)
*/
var _cipher_modes = [_ecb_enc, _ecb_dec, _cbc_enc, _cbc_dec, _cfb_enc, _cfb_dec, _ofb, _ctr];
/**
* AES MAC modes table (virual methods)
*/
var _mac_modes = [_cbc_enc, _gcm_mac];
/**
* Asm.js module exports
*/
return {
set_rounds: set_rounds,
set_state: set_state,
set_iv: set_iv,
set_nonce: set_nonce,
set_mask: set_mask,
set_counter: set_counter,
get_state: get_state,
get_iv: get_iv,
gcm_init: gcm_init,
cipher: cipher,
mac: mac,
};
}(stdlib, foreign, buffer);
asm.set_key = set_key;
return asm;
};
/**
* AES enciphering mode constants
* @enum {number}
* @const
*/
wrapper.ENC = {
ECB: 0,
CBC: 2,
CFB: 4,
OFB: 6,
CTR: 7,
},
/**
* AES deciphering mode constants
* @enum {number}
* @const
*/
wrapper.DEC = {
ECB: 1,
CBC: 3,
CFB: 5,
OFB: 6,
CTR: 7,
},
/**
* AES MAC mode constants
* @enum {number}
* @const
*/
wrapper.MAC = {
CBC: 0,
GCM: 1,
};
/**
* Heap data offset
* @type {number}
* @const
*/
wrapper.HEAP_DATA = 0x4000;
return wrapper;
}();
var AES = /** @class */ (function () {
function AES(key, iv, padding, mode, heap, asm) {
if (padding === void 0) { padding = true; }
this.pos = 0;
this.len = 0;
this.mode = mode;
// The AES "worker"
this.heap = heap ? heap : _heap_init().subarray(AES_asm.HEAP_DATA);
this.asm = asm ? asm : new AES_asm(null, this.heap.buffer);
// The AES object state
this.pos = 0;
this.len = 0;
// Key
var keylen = key.length;
if (keylen !== 16 && keylen !== 24 && keylen !== 32)
throw new IllegalArgumentError('illegal key size');
var keyview = new DataView(key.buffer, key.byteOffset, key.byteLength);
this.asm.set_key(keylen >> 2, keyview.getUint32(0), keyview.getUint32(4), keyview.getUint32(8), keyview.getUint32(12), keylen > 16 ? keyview.getUint32(16) : 0, keylen > 16 ? keyview.getUint32(20) : 0, keylen > 24 ? keyview.getUint32(24) : 0, keylen > 24 ? keyview.getUint32(28) : 0);
// IV
if (iv !== undefined) {
if (iv.length !== 16)
throw new IllegalArgumentError('illegal iv size');
var ivview = new DataView(iv.buffer, iv.byteOffset, iv.byteLength);
this.asm.set_iv(ivview.getUint32(0), ivview.getUint32(4), ivview.getUint32(8), ivview.getUint32(12));
}
else {
this.asm.set_iv(0, 0, 0, 0);
}
this.padding = padding;
}
AES.prototype.AES_Encrypt_process = function (data) {
if (!is_bytes(data))
throw new TypeError("data isn't of expected type");
var asm = this.asm;
var heap = this.heap;
var amode = AES_asm.ENC[this.mode];
var hpos = AES_asm.HEAP_DATA;
var pos = this.pos;
var len = this.len;
var dpos = 0;
var dlen = data.length || 0;
var rpos = 0;
var rlen = (len + dlen) & -16;
var wlen = 0;
var result = new Uint8Array(rlen);
while (dlen > 0) {
wlen = _heap_write(heap, pos + len, data, dpos, dlen);
len += wlen;
dpos += wlen;
dlen -= wlen;
wlen = asm.cipher(amode, hpos + pos, len);
if (wlen)
result.set(heap.subarray(pos, pos + wlen), rpos);
rpos += wlen;
if (wlen < len) {
pos += wlen;
len -= wlen;
}
else {
pos = 0;
len = 0;
}
}
this.pos = pos;
this.len = len;
return result;
};
AES.prototype.AES_Encrypt_finish = function () {
var asm = this.asm;
var heap = this.heap;
var amode = AES_asm.ENC[this.mode];
var hpos = AES_asm.HEAP_DATA;
var pos = this.pos;
var len = this.len;
var plen = 16 - (len % 16);
var rlen = len;
if (this.hasOwnProperty('padding')) {
if (this.padding) {
for (var p = 0; p < plen; ++p) {
heap[pos + len + p] = plen;
}
len += plen;
rlen = len;
}
else if (len % 16) {
throw new IllegalArgumentError('data length must be a multiple of the block size');
}
}
else {
len += plen;
}
var result = new Uint8Array(rlen);
if (len)
asm.cipher(amode, hpos + pos, len);
if (rlen)
result.set(heap.subarray(pos, pos + rlen));
this.pos = 0;
this.len = 0;
return result;
};
AES.prototype.AES_Decrypt_process = function (data) {
if (!is_bytes(data))
throw new TypeError("data isn't of expected type");
var asm = this.asm;
var heap = this.heap;
var amode = AES_asm.DEC[this.mode];
var hpos = AES_asm.HEAP_DATA;
var pos = this.pos;
var len = this.len;
var dpos = 0;
var dlen = data.length || 0;
var rpos = 0;
var rlen = (len + dlen) & -16;
var plen = 0;
var wlen = 0;
if (this.padding) {
plen = len + dlen - rlen || 16;
rlen -= plen;
}
var result = new Uint8Array(rlen);
while (dlen > 0) {
wlen = _heap_write(heap, pos + len, data, dpos, dlen);
len += wlen;
dpos += wlen;
dlen -= wlen;
wlen = asm.cipher(amode, hpos + pos, len - (!dlen ? plen : 0));
if (wlen)
result.set(heap.subarray(pos, pos + wlen), rpos);
rpos += wlen;
if (wlen < len) {
pos += wlen;
len -= wlen;
}
else {
pos = 0;
len = 0;
}
}
this.pos = pos;
this.len = len;
return result;
};
AES.prototype.AES_Decrypt_finish = function () {
var asm = this.asm;
var heap = this.heap;
var amode = AES_asm.DEC[this.mode];
var hpos = AES_asm.HEAP_DATA;
var pos = this.pos;
var len = this.len;
var rlen = len;
if (len > 0) {
if (len % 16) {
if (this.hasOwnProperty('padding')) {
throw new IllegalArgumentError('data length must be a multiple of the block size');
}
else {
len += 16 - (len % 16);
}
}
asm.cipher(amode, hpos + pos, len);
if (this.hasOwnProperty('padding') && this.padding) {
var pad = heap[pos + rlen - 1];
if (pad < 1 || pad > 16 || pad > rlen)
throw new SecurityError('bad padding');
var pcheck = 0;
for (var i = pad; i > 1; i--)
pcheck |= pad ^ heap[pos + rlen - i];
if (pcheck)
throw new SecurityError('bad padding');
rlen -= pad;
}
}
var result = new Uint8Array(rlen);
if (rlen > 0) {
result.set(heap.subarray(pos, pos + rlen));
}
this.pos = 0;
this.len = 0;
return result;
};
return AES;
}());
/**
* Counter with CBC-MAC (CCM)
*
* Due to JS limitations (52 bits of Number precision) maximum encrypted message length
* is limited to ~4 PiB ( 2^52 - 16 ) per `nonce`-`key` pair.
* That also limits `lengthSize` parameter maximum value to 7 (not 8 as described in RFC3610).
*
* Additional authenticated data `adata` maximum length is chosen to be no more than 65279 bytes ( 2^16 - 2^8 ),
* which is considered enough for the most of use-cases.
*
* And one more important thing: in case of progressive ciphering of a data stream (in other
* words when data can't be held in-memory at a whole and are ciphered chunk-by-chunk)
* you have to know the `dataLength` in advance and pass that value to the cipher options.
*/
var _AES_CCM_adata_maxLength = 65279; // 2^16 - 2^8
var _AES_CCM_data_maxLength = 4503599627370480; // 2^52 - 2^4
var AES_CCM = /** @class */ (function () {
function AES_CCM(key, nonce, adata, tagSize, dataLength, aes) {
if (tagSize === void 0) { tagSize = 16; }
this.counter = 1;
this.dataLength = -1;
this.aes = aes ? aes : new AES(key, undefined, undefined, 'CCM');
// Tag size
if (tagSize < 4 || tagSize > 16 || tagSize & 1)
throw new IllegalArgumentError('illegal tagSize value');
this.tagSize = tagSize;
// Nonce
this.nonce = nonce;
if (nonce.length < 8 || nonce.length > 13)
throw new IllegalArgumentError('illegal nonce length');
this.lengthSize = 15 - nonce.length;
nonce = new Uint8Array(nonce.length + 1);
nonce[0] = this.lengthSize - 1;
nonce.set(this.nonce, 1);
if (dataLength < 0 || dataLength > _AES_CCM_data_maxLength || dataLength > Math.pow(2, 8 * this.lengthSize) - 16)
throw new IllegalArgumentError('illegal dataLength value');
if (adata !== undefined) {
if (adata.length > _AES_CCM_adata_maxLength)
throw new IllegalArgumentError('illegal adata length');
this.adata = adata.length ? adata : undefined;
}
this.dataLength = dataLength;
this.counter = 1;
this.AES_CCM_calculate_iv();
this.AES_CTR_set_options(nonce, this.counter, 8 * this.lengthSize);
}
AES_CCM.encrypt = function (clear, key, nonce, adata, tagsize) {
if (tagsize === void 0) { tagsize = 16; }
return new AES_CCM(key, nonce, adata, tagsize, clear.length).encrypt(clear);
};
AES_CCM.decrypt = function (cipher, key, nonce, adata, tagsize) {
if (tagsize === void 0) { tagsize = 16; }
return new AES_CCM(key, nonce, adata, tagsize, cipher.length - tagsize).decrypt(cipher);
};
AES_CCM.prototype.encrypt = function (data) {
this.dataLength = data.length || 0;
var result1 = this.AES_CCM_Encrypt_process(data);
var result2 = this.AES_CCM_Encrypt_finish();
var result = new Uint8Array(result1.length + result2.length);
if (result1.length)
result.set(result1);
if (result2.length)
result.set(result2, result1.length);
return result;
};
AES_CCM.prototype.decrypt = function (data) {
this.dataLength = data.length || 0;
var result1 = this.AES_CCM_Decrypt_process(data);
var result2 = this.AES_CCM_Decrypt_finish();
var result = new Uint8Array(result1.length + result2.length);
if (result1.length)
result.set(result1);
if (result2.length)
result.set(result2, result1.length);
return result;
};
AES_CCM.prototype.AES_CCM_calculate_iv = function () {
var nonce = this.nonce;
var adata = this.adata;
var tagSize = this.tagSize;
var lengthSize = this.lengthSize;
var dataLength = this.dataLength;
var data = new Uint8Array(16 + (adata ? 2 + adata.length : 0));
// B0: flags(adata?, M', L'), nonce, len(data)
data[0] = (adata ? 64 : 0) | ((tagSize - 2) << 2) | (lengthSize - 1);
data.set(nonce, 1);
if (lengthSize > 6)
data[9] = ((dataLength / 0x100000000) >>> 16) & 15;
if (lengthSize > 5)
data[10] = ((dataLength / 0x100000000) >>> 8) & 255;
if (lengthSize > 4)
data[11] = (dataLength / 0x100000000) & 255;
if (lengthSize > 3)
data[12] = dataLength >>> 24;
if (lengthSize > 2)
data[13] = (dataLength >>> 16) & 255;
data[14] = (dataLength >>> 8) & 255;
data[15] = dataLength & 255;
// B*: len(adata), adata
if (adata) {
data[16] = (adata.length >>> 8) & 255;
data[17] = adata.length & 255;
data.set(adata, 18);
}
this._cbc_mac_process(data);
this.aes.asm.get_state(AES_asm.HEAP_DATA);
var iv = new Uint8Array(this.aes.heap.subarray(0, 16));
var ivview = new DataView(iv.buffer, iv.byteOffset, iv.byteLength);
this.aes.asm.set_iv(ivview.getUint32(0), ivview.getUint32(4), ivview.getUint32(8), ivview.getUint32(12));
};
AES_CCM.prototype._cbc_mac_process = function (data) {
var heap = this.aes.heap;
var asm = this.aes.asm;
var dpos = 0;
var dlen = data.length || 0;
var wlen = 0;
while (dlen > 0) {
wlen = _heap_write(heap, 0, data, dpos, dlen);
while (wlen & 15)
heap[wlen++] = 0;
dpos += wlen;
dlen -= wlen;
asm.mac(AES_asm.MAC.CBC, AES_asm.HEAP_DATA, wlen);
}
};
AES_CCM.prototype.AES_CCM_Encrypt_process = function (data) {
var asm = this.aes.asm;
var heap = this.aes.heap;
var dpos = 0;
var dlen = data.length || 0;
var counter = this.counter;
var pos = this.aes.pos;
var len = this.aes.len;
var rlen = (len + dlen) & -16;
var rpos = 0;
var wlen = 0;
if (((counter - 1) << 4) + len + dlen > _AES_CCM_data_maxLength)
// ??? should check against lengthSize
throw new RangeError('counter overflow');
var result = new Uint8Array(rlen);
while (dlen > 0) {
wlen = _heap_write(heap, pos + len, data, dpos, dlen);
len += wlen;
dpos += wlen;
dlen -= wlen;
wlen = asm.mac(AES_asm.MAC.CBC, AES_asm.HEAP_DATA + pos, len);
wlen = asm.cipher(AES_asm.ENC.CTR, AES_asm.HEAP_DATA + pos, wlen);
if (wlen)
result.set(heap.subarray(pos, pos + wlen), rpos);
counter += wlen >>> 4;
rpos += wlen;
if (wlen < len) {
pos += wlen;
len -= wlen;
}
else {
pos = 0;
len = 0;
}
}
this.counter = counter;
this.aes.pos = pos;
this.aes.len = len;
return result;
};
AES_CCM.prototype.AES_CCM_Encrypt_finish = function () {
var asm = this.aes.asm;
var heap = this.aes.heap;
var tagSize = this.tagSize;
var pos = this.aes.pos;
var len = this.aes.len;
var result = new Uint8Array(len + tagSize);
var i = len;
for (; i & 15; i++)
heap[pos + i] = 0;
asm.mac(AES_asm.MAC.CBC, AES_asm.HEAP_DATA + pos, i);
asm.cipher(AES_asm.ENC.CTR, AES_asm.HEAP_DATA + pos, i);
if (len)
result.set(heap.subarray(pos, pos + len));
asm.set_counter(0, 0, 0, 0);
asm.get_iv(AES_asm.HEAP_DATA);
asm.cipher(AES_asm.ENC.CTR, AES_asm.HEAP_DATA, 16);
result.set(heap.subarray(0, tagSize), len);
this.counter = 1;
this.aes.pos = 0;
this.aes.len = 0;
return result;
};
AES_CCM.prototype.AES_CCM_Decrypt_process = function (data) {
var dpos = 0;
var dlen = data.length |