mirror of
https://github.com/Instadapp/Swap-Aggregator-Subgraph.git
synced 2024-07-29 21:57:12 +00:00
288 lines
10 KiB
JavaScript
Executable File
288 lines
10 KiB
JavaScript
Executable File
import { IllegalArgumentError, IllegalStateError, SecurityError } from '../other/errors';
|
|
import { _heap_write } from '../other/utils';
|
|
import { AES } from './aes';
|
|
import { AES_asm } from './aes.asm';
|
|
const _AES_GCM_data_maxLength = 68719476704; // 2^36 - 2^5
|
|
export class AES_GCM extends AES {
|
|
constructor(key, nonce, adata, tagSize = 16) {
|
|
super(key, undefined, false, 'CTR');
|
|
this.tagSize = tagSize;
|
|
this.gamma0 = 0;
|
|
this.counter = 1;
|
|
// Init GCM
|
|
this.asm.gcm_init();
|
|
// Tag size
|
|
if (this.tagSize < 4 || this.tagSize > 16)
|
|
throw new IllegalArgumentError('illegal tagSize value');
|
|
// Nonce
|
|
const noncelen = nonce.length || 0;
|
|
const noncebuf = new Uint8Array(16);
|
|
if (noncelen !== 12) {
|
|
this._gcm_mac_process(nonce);
|
|
this.heap[0] = 0;
|
|
this.heap[1] = 0;
|
|
this.heap[2] = 0;
|
|
this.heap[3] = 0;
|
|
this.heap[4] = 0;
|
|
this.heap[5] = 0;
|
|
this.heap[6] = 0;
|
|
this.heap[7] = 0;
|
|
this.heap[8] = 0;
|
|
this.heap[9] = 0;
|
|
this.heap[10] = 0;
|
|
this.heap[11] = noncelen >>> 29;
|
|
this.heap[12] = (noncelen >>> 21) & 255;
|
|
this.heap[13] = (noncelen >>> 13) & 255;
|
|
this.heap[14] = (noncelen >>> 5) & 255;
|
|
this.heap[15] = (noncelen << 3) & 255;
|
|
this.asm.mac(AES_asm.MAC.GCM, AES_asm.HEAP_DATA, 16);
|
|
this.asm.get_iv(AES_asm.HEAP_DATA);
|
|
this.asm.set_iv(0, 0, 0, 0);
|
|
noncebuf.set(this.heap.subarray(0, 16));
|
|
}
|
|
else {
|
|
noncebuf.set(nonce);
|
|
noncebuf[15] = 1;
|
|
}
|
|
const nonceview = new DataView(noncebuf.buffer);
|
|
this.gamma0 = nonceview.getUint32(12);
|
|
this.asm.set_nonce(nonceview.getUint32(0), nonceview.getUint32(4), nonceview.getUint32(8), 0);
|
|
this.asm.set_mask(0, 0, 0, 0xffffffff);
|
|
// Associated data
|
|
if (adata !== undefined) {
|
|
if (adata.length > _AES_GCM_data_maxLength)
|
|
throw new IllegalArgumentError('illegal adata length');
|
|
if (adata.length) {
|
|
this.adata = adata;
|
|
this._gcm_mac_process(adata);
|
|
}
|
|
else {
|
|
this.adata = undefined;
|
|
}
|
|
}
|
|
else {
|
|
this.adata = undefined;
|
|
}
|
|
// Counter
|
|
if (this.counter < 1 || this.counter > 0xffffffff)
|
|
throw new RangeError('counter must be a positive 32-bit integer');
|
|
this.asm.set_counter(0, 0, 0, (this.gamma0 + this.counter) | 0);
|
|
}
|
|
static encrypt(cleartext, key, nonce, adata, tagsize) {
|
|
return new AES_GCM(key, nonce, adata, tagsize).encrypt(cleartext);
|
|
}
|
|
static decrypt(ciphertext, key, nonce, adata, tagsize) {
|
|
return new AES_GCM(key, nonce, adata, tagsize).decrypt(ciphertext);
|
|
}
|
|
encrypt(data) {
|
|
return this.AES_GCM_encrypt(data);
|
|
}
|
|
decrypt(data) {
|
|
return this.AES_GCM_decrypt(data);
|
|
}
|
|
AES_GCM_Encrypt_process(data) {
|
|
let dpos = 0;
|
|
let dlen = data.length || 0;
|
|
let asm = this.asm;
|
|
let heap = this.heap;
|
|
let counter = this.counter;
|
|
let pos = this.pos;
|
|
let len = this.len;
|
|
let rpos = 0;
|
|
let rlen = (len + dlen) & -16;
|
|
let wlen = 0;
|
|
if (((counter - 1) << 4) + len + dlen > _AES_GCM_data_maxLength)
|
|
throw new RangeError('counter overflow');
|
|
const 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(AES_asm.ENC.CTR, AES_asm.HEAP_DATA + pos, len);
|
|
wlen = asm.mac(AES_asm.MAC.GCM, 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.pos = pos;
|
|
this.len = len;
|
|
return result;
|
|
}
|
|
AES_GCM_Encrypt_finish() {
|
|
let asm = this.asm;
|
|
let heap = this.heap;
|
|
let counter = this.counter;
|
|
let tagSize = this.tagSize;
|
|
let adata = this.adata;
|
|
let pos = this.pos;
|
|
let len = this.len;
|
|
const result = new Uint8Array(len + tagSize);
|
|
asm.cipher(AES_asm.ENC.CTR, AES_asm.HEAP_DATA + pos, (len + 15) & -16);
|
|
if (len)
|
|
result.set(heap.subarray(pos, pos + len));
|
|
let i = len;
|
|
for (; i & 15; i++)
|
|
heap[pos + i] = 0;
|
|
asm.mac(AES_asm.MAC.GCM, AES_asm.HEAP_DATA + pos, i);
|
|
const alen = adata !== undefined ? adata.length : 0;
|
|
const clen = ((counter - 1) << 4) + len;
|
|
heap[0] = 0;
|
|
heap[1] = 0;
|
|
heap[2] = 0;
|
|
heap[3] = alen >>> 29;
|
|
heap[4] = alen >>> 21;
|
|
heap[5] = (alen >>> 13) & 255;
|
|
heap[6] = (alen >>> 5) & 255;
|
|
heap[7] = (alen << 3) & 255;
|
|
heap[8] = heap[9] = heap[10] = 0;
|
|
heap[11] = clen >>> 29;
|
|
heap[12] = (clen >>> 21) & 255;
|
|
heap[13] = (clen >>> 13) & 255;
|
|
heap[14] = (clen >>> 5) & 255;
|
|
heap[15] = (clen << 3) & 255;
|
|
asm.mac(AES_asm.MAC.GCM, AES_asm.HEAP_DATA, 16);
|
|
asm.get_iv(AES_asm.HEAP_DATA);
|
|
asm.set_counter(0, 0, 0, this.gamma0);
|
|
asm.cipher(AES_asm.ENC.CTR, AES_asm.HEAP_DATA, 16);
|
|
result.set(heap.subarray(0, tagSize), len);
|
|
this.counter = 1;
|
|
this.pos = 0;
|
|
this.len = 0;
|
|
return result;
|
|
}
|
|
AES_GCM_Decrypt_process(data) {
|
|
let dpos = 0;
|
|
let dlen = data.length || 0;
|
|
let asm = this.asm;
|
|
let heap = this.heap;
|
|
let counter = this.counter;
|
|
let tagSize = this.tagSize;
|
|
let pos = this.pos;
|
|
let len = this.len;
|
|
let rpos = 0;
|
|
let rlen = len + dlen > tagSize ? (len + dlen - tagSize) & -16 : 0;
|
|
let tlen = len + dlen - rlen;
|
|
let wlen = 0;
|
|
if (((counter - 1) << 4) + len + dlen > _AES_GCM_data_maxLength)
|
|
throw new RangeError('counter overflow');
|
|
const result = new Uint8Array(rlen);
|
|
while (dlen > tlen) {
|
|
wlen = _heap_write(heap, pos + len, data, dpos, dlen - tlen);
|
|
len += wlen;
|
|
dpos += wlen;
|
|
dlen -= wlen;
|
|
wlen = asm.mac(AES_asm.MAC.GCM, AES_asm.HEAP_DATA + pos, wlen);
|
|
wlen = asm.cipher(AES_asm.DEC.CTR, AES_asm.HEAP_DATA + pos, wlen);
|
|
if (wlen)
|
|
result.set(heap.subarray(pos, pos + wlen), rpos);
|
|
counter += wlen >>> 4;
|
|
rpos += wlen;
|
|
pos = 0;
|
|
len = 0;
|
|
}
|
|
if (dlen > 0) {
|
|
len += _heap_write(heap, 0, data, dpos, dlen);
|
|
}
|
|
this.counter = counter;
|
|
this.pos = pos;
|
|
this.len = len;
|
|
return result;
|
|
}
|
|
AES_GCM_Decrypt_finish() {
|
|
let asm = this.asm;
|
|
let heap = this.heap;
|
|
let tagSize = this.tagSize;
|
|
let adata = this.adata;
|
|
let counter = this.counter;
|
|
let pos = this.pos;
|
|
let len = this.len;
|
|
let rlen = len - tagSize;
|
|
if (len < tagSize)
|
|
throw new IllegalStateError('authentication tag not found');
|
|
const result = new Uint8Array(rlen);
|
|
const atag = new Uint8Array(heap.subarray(pos + rlen, pos + len));
|
|
let i = rlen;
|
|
for (; i & 15; i++)
|
|
heap[pos + i] = 0;
|
|
asm.mac(AES_asm.MAC.GCM, AES_asm.HEAP_DATA + pos, i);
|
|
asm.cipher(AES_asm.DEC.CTR, AES_asm.HEAP_DATA + pos, i);
|
|
if (rlen)
|
|
result.set(heap.subarray(pos, pos + rlen));
|
|
const alen = adata !== undefined ? adata.length : 0;
|
|
const clen = ((counter - 1) << 4) + len - tagSize;
|
|
heap[0] = 0;
|
|
heap[1] = 0;
|
|
heap[2] = 0;
|
|
heap[3] = alen >>> 29;
|
|
heap[4] = alen >>> 21;
|
|
heap[5] = (alen >>> 13) & 255;
|
|
heap[6] = (alen >>> 5) & 255;
|
|
heap[7] = (alen << 3) & 255;
|
|
heap[8] = heap[9] = heap[10] = 0;
|
|
heap[11] = clen >>> 29;
|
|
heap[12] = (clen >>> 21) & 255;
|
|
heap[13] = (clen >>> 13) & 255;
|
|
heap[14] = (clen >>> 5) & 255;
|
|
heap[15] = (clen << 3) & 255;
|
|
asm.mac(AES_asm.MAC.GCM, AES_asm.HEAP_DATA, 16);
|
|
asm.get_iv(AES_asm.HEAP_DATA);
|
|
asm.set_counter(0, 0, 0, this.gamma0);
|
|
asm.cipher(AES_asm.ENC.CTR, AES_asm.HEAP_DATA, 16);
|
|
let acheck = 0;
|
|
for (let i = 0; i < tagSize; ++i)
|
|
acheck |= atag[i] ^ heap[i];
|
|
if (acheck)
|
|
throw new SecurityError('data integrity check failed');
|
|
this.counter = 1;
|
|
this.pos = 0;
|
|
this.len = 0;
|
|
return result;
|
|
}
|
|
AES_GCM_decrypt(data) {
|
|
const result1 = this.AES_GCM_Decrypt_process(data);
|
|
const result2 = this.AES_GCM_Decrypt_finish();
|
|
const result = new Uint8Array(result1.length + result2.length);
|
|
if (result1.length)
|
|
result.set(result1);
|
|
if (result2.length)
|
|
result.set(result2, result1.length);
|
|
return result;
|
|
}
|
|
AES_GCM_encrypt(data) {
|
|
const result1 = this.AES_GCM_Encrypt_process(data);
|
|
const result2 = this.AES_GCM_Encrypt_finish();
|
|
const result = new Uint8Array(result1.length + result2.length);
|
|
if (result1.length)
|
|
result.set(result1);
|
|
if (result2.length)
|
|
result.set(result2, result1.length);
|
|
return result;
|
|
}
|
|
_gcm_mac_process(data) {
|
|
const heap = this.heap;
|
|
const asm = this.asm;
|
|
let dpos = 0;
|
|
let dlen = data.length || 0;
|
|
let wlen = 0;
|
|
while (dlen > 0) {
|
|
wlen = _heap_write(heap, 0, data, dpos, dlen);
|
|
dpos += wlen;
|
|
dlen -= wlen;
|
|
while (wlen & 15)
|
|
heap[wlen++] = 0;
|
|
asm.mac(AES_asm.MAC.GCM, AES_asm.HEAP_DATA, wlen);
|
|
}
|
|
}
|
|
}
|