/*! OpenPGP.js v5.8.0 - 2023-08-14 - this is LGPL licensed code, see LICENSE/our website https://openpgpjs.org/ for more information. */
const globalThis = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
const doneWritingPromise = Symbol('doneWritingPromise');
const doneWritingResolve = Symbol('doneWritingResolve');
const doneWritingReject = Symbol('doneWritingReject');
const readingIndex = Symbol('readingIndex');
class ArrayStream extends Array {
constructor() {
super();
this[doneWritingPromise] = new Promise((resolve, reject) => {
this[doneWritingResolve] = resolve;
this[doneWritingReject] = reject;
});
this[doneWritingPromise].catch(() => {});
}
}
ArrayStream.prototype.getReader = function() {
if (this[readingIndex] === undefined) {
this[readingIndex] = 0;
}
return {
read: async () => {
await this[doneWritingPromise];
if (this[readingIndex] === this.length) {
return { value: undefined, done: true };
}
return { value: this[this[readingIndex]++], done: false };
}
};
};
ArrayStream.prototype.readToEnd = async function(join) {
await this[doneWritingPromise];
const result = join(this.slice(this[readingIndex]));
this.length = 0;
return result;
};
ArrayStream.prototype.clone = function() {
const clone = new ArrayStream();
clone[doneWritingPromise] = this[doneWritingPromise].then(() => {
clone.push(...this);
});
return clone;
};
/**
* Check whether data is an ArrayStream
* @param {Any} input data to check
* @returns {boolean}
*/
function isArrayStream(input) {
return input && input.getReader && Array.isArray(input);
}
/**
* A wrapper class over the native WritableStreamDefaultWriter.
* It also lets you "write data to" array streams instead of streams.
* @class
*/
function Writer(input) {
if (!isArrayStream(input)) {
const writer = input.getWriter();
const releaseLock = writer.releaseLock;
writer.releaseLock = () => {
writer.closed.catch(function() {});
releaseLock.call(writer);
};
return writer;
}
this.stream = input;
}
/**
* Write a chunk of data.
* @returns {Promise}
* @async
*/
Writer.prototype.write = async function(chunk) {
this.stream.push(chunk);
};
/**
* Close the stream.
* @returns {Promise}
* @async
*/
Writer.prototype.close = async function() {
this.stream[doneWritingResolve]();
};
/**
* Error the stream.
* @returns {Promise
*
* @alias AES_asm
* @class
* @param foreign - ignored
* @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;
}();
function is_bytes(a) {
return a instanceof Uint8Array;
}
function _heap_init(heap, heapSize) {
const 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) {
const hlen = heap.length - hpos;
const wlen = hlen < dlen ? hlen : dlen;
heap.set(data.subarray(dpos, dpos + wlen), hpos);
return wlen;
}
function joinBytes(...arg) {
const totalLenght = arg.reduce((sum, curr) => sum + curr.length, 0);
const ret = new Uint8Array(totalLenght);
let cursor = 0;
for (let i = 0; i < arg.length; i++) {
ret.set(arg[i], cursor);
cursor += arg[i].length;
}
return ret;
}
class IllegalStateError extends Error {
constructor(...args) {
super(...args);
}
}
class IllegalArgumentError extends Error {
constructor(...args) {
super(...args);
}
}
class SecurityError extends Error {
constructor(...args) {
super(...args);
}
}
const heap_pool = [];
const asm_pool = [];
class AES {
constructor(key, iv, padding = true, mode, heap, asm) {
this.pos = 0;
this.len = 0;
this.mode = mode;
// The AES object state
this.pos = 0;
this.len = 0;
this.key = key;
this.iv = iv;
this.padding = padding;
// The AES "worker"
this.acquire_asm(heap, asm);
}
acquire_asm(heap, asm) {
if (this.heap === undefined || this.asm === undefined) {
this.heap = heap || heap_pool.pop() || _heap_init().subarray(AES_asm.HEAP_DATA);
this.asm = asm || asm_pool.pop() || new AES_asm(null, this.heap.buffer);
this.reset(this.key, this.iv);
}
return { heap: this.heap, asm: this.asm };
}
release_asm() {
if (this.heap !== undefined && this.asm !== undefined) {
heap_pool.push(this.heap);
asm_pool.push(this.asm);
}
this.heap = undefined;
this.asm = undefined;
}
reset(key, iv) {
const { asm } = this.acquire_asm();
// Key
const keylen = key.length;
if (keylen !== 16 && keylen !== 24 && keylen !== 32)
throw new IllegalArgumentError('illegal key size');
const keyview = new DataView(key.buffer, key.byteOffset, key.byteLength);
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');
let ivview = new DataView(iv.buffer, iv.byteOffset, iv.byteLength);
asm.set_iv(ivview.getUint32(0), ivview.getUint32(4), ivview.getUint32(8), ivview.getUint32(12));
}
else {
asm.set_iv(0, 0, 0, 0);
}
}
AES_Encrypt_process(data) {
if (!is_bytes(data))
throw new TypeError("data isn't of expected type");
let { heap, asm } = this.acquire_asm();
let amode = AES_asm.ENC[this.mode];
let hpos = AES_asm.HEAP_DATA;
let pos = this.pos;
let len = this.len;
let dpos = 0;
let dlen = data.length || 0;
let rpos = 0;
let rlen = (len + dlen) & -16;
let wlen = 0;
let 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_Encrypt_finish() {
let { heap, asm } = this.acquire_asm();
let amode = AES_asm.ENC[this.mode];
let hpos = AES_asm.HEAP_DATA;
let pos = this.pos;
let len = this.len;
let plen = 16 - (len % 16);
let rlen = len;
if (this.hasOwnProperty('padding')) {
if (this.padding) {
for (let 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;
}
const 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;
this.release_asm();
return result;
}
AES_Decrypt_process(data) {
if (!is_bytes(data))
throw new TypeError("data isn't of expected type");
let { heap, asm } = this.acquire_asm();
let amode = AES_asm.DEC[this.mode];
let hpos = AES_asm.HEAP_DATA;
let pos = this.pos;
let len = this.len;
let dpos = 0;
let dlen = data.length || 0;
let rpos = 0;
let rlen = (len + dlen) & -16;
let plen = 0;
let wlen = 0;
if (this.padding) {
plen = len + dlen - rlen || 16;
rlen -= plen;
}
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(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_Decrypt_finish() {
let { heap, asm } = this.acquire_asm();
let amode = AES_asm.DEC[this.mode];
let hpos = AES_asm.HEAP_DATA;
let pos = this.pos;
let len = this.len;
let 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) {
let pad = heap[pos + rlen - 1];
if (pad < 1 || pad > 16 || pad > rlen)
throw new SecurityError('bad padding');
let pcheck = 0;
for (let i = pad; i > 1; i--)
pcheck |= pad ^ heap[pos + rlen - i];
if (pcheck)
throw new SecurityError('bad padding');
rlen -= pad;
}
}
const result = new Uint8Array(rlen);
if (rlen > 0) {
result.set(heap.subarray(pos, pos + rlen));
}
this.pos = 0;
this.len = 0;
this.release_asm();
return result;
}
}
class AES_ECB {
static encrypt(data, key, padding = false) {
return new AES_ECB(key, padding).encrypt(data);
}
static decrypt(data, key, padding = false) {
return new AES_ECB(key, padding).decrypt(data);
}
constructor(key, padding = false, aes) {
this.aes = aes ? aes : new AES(key, undefined, padding, 'ECB');
}
encrypt(data) {
const r1 = this.aes.AES_Encrypt_process(data);
const r2 = this.aes.AES_Encrypt_finish();
return joinBytes(r1, r2);
}
decrypt(data) {
const r1 = this.aes.AES_Decrypt_process(data);
const r2 = this.aes.AES_Decrypt_finish();
return joinBytes(r1, r2);
}
}
/**
* Javascript AES implementation.
* This is used as fallback if the native Crypto APIs are not available.
*/
function aes(length) {
const C = function(key) {
const aesECB = new AES_ECB(key);
this.encrypt = function(block) {
return aesECB.encrypt(block);
};
this.decrypt = function(block) {
return aesECB.decrypt(block);
};
};
C.blockSize = C.prototype.blockSize = 16;
C.keySize = C.prototype.keySize = length / 8;
return C;
}
//Paul Tero, July 2001
//http://www.tero.co.uk/des/
//
//Optimised for performance with large blocks by Michael Hayworth, November 2001
//http://www.netdealing.com
//
// Modified by Recurity Labs GmbH
//THIS SOFTWARE IS PROVIDED "AS IS" AND
//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
//IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
//ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
//FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
//DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
//OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
//HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
//OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
//SUCH DAMAGE.
//des
//this takes the key, the message, and whether to encrypt or decrypt
function des(keys, message, encrypt, mode, iv, padding) {
//declaring this locally speeds things up a bit
const spfunction1 = [
0x1010400, 0, 0x10000, 0x1010404, 0x1010004, 0x10404, 0x4, 0x10000, 0x400, 0x1010400,
0x1010404, 0x400, 0x1000404, 0x1010004, 0x1000000, 0x4, 0x404, 0x1000400, 0x1000400, 0x10400, 0x10400, 0x1010000,
0x1010000, 0x1000404, 0x10004, 0x1000004, 0x1000004, 0x10004, 0, 0x404, 0x10404, 0x1000000, 0x10000, 0x1010404, 0x4,
0x1010000, 0x1010400, 0x1000000, 0x1000000, 0x400, 0x1010004, 0x10000, 0x10400, 0x1000004, 0x400, 0x4, 0x1000404,
0x10404, 0x1010404, 0x10004, 0x1010000, 0x1000404, 0x1000004, 0x404, 0x10404, 0x1010400, 0x404, 0x1000400,
0x1000400, 0, 0x10004, 0x10400, 0, 0x1010004
];
const spfunction2 = [
-0x7fef7fe0, -0x7fff8000, 0x8000, 0x108020, 0x100000, 0x20, -0x7fefffe0, -0x7fff7fe0,
-0x7fffffe0, -0x7fef7fe0, -0x7fef8000, -0x80000000, -0x7fff8000, 0x100000, 0x20, -0x7fefffe0, 0x108000, 0x100020,
-0x7fff7fe0, 0, -0x80000000, 0x8000, 0x108020, -0x7ff00000, 0x100020, -0x7fffffe0, 0, 0x108000, 0x8020, -0x7fef8000,
-0x7ff00000, 0x8020, 0, 0x108020, -0x7fefffe0, 0x100000, -0x7fff7fe0, -0x7ff00000, -0x7fef8000, 0x8000, -0x7ff00000,
-0x7fff8000, 0x20, -0x7fef7fe0, 0x108020, 0x20, 0x8000, -0x80000000, 0x8020, -0x7fef8000, 0x100000, -0x7fffffe0,
0x100020, -0x7fff7fe0, -0x7fffffe0, 0x100020, 0x108000, 0, -0x7fff8000, 0x8020, -0x80000000, -0x7fefffe0,
-0x7fef7fe0, 0x108000
];
const spfunction3 = [
0x208, 0x8020200, 0, 0x8020008, 0x8000200, 0, 0x20208, 0x8000200, 0x20008, 0x8000008,
0x8000008, 0x20000, 0x8020208, 0x20008, 0x8020000, 0x208, 0x8000000, 0x8, 0x8020200, 0x200, 0x20200, 0x8020000,
0x8020008, 0x20208, 0x8000208, 0x20200, 0x20000, 0x8000208, 0x8, 0x8020208, 0x200, 0x8000000, 0x8020200, 0x8000000,
0x20008, 0x208, 0x20000, 0x8020200, 0x8000200, 0, 0x200, 0x20008, 0x8020208, 0x8000200, 0x8000008, 0x200, 0,
0x8020008, 0x8000208, 0x20000, 0x8000000, 0x8020208, 0x8, 0x20208, 0x20200, 0x8000008, 0x8020000, 0x8000208, 0x208,
0x8020000, 0x20208, 0x8, 0x8020008, 0x20200
];
const spfunction4 = [
0x802001, 0x2081, 0x2081, 0x80, 0x802080, 0x800081, 0x800001, 0x2001, 0, 0x802000,
0x802000, 0x802081, 0x81, 0, 0x800080, 0x800001, 0x1, 0x2000, 0x800000, 0x802001, 0x80, 0x800000, 0x2001, 0x2080,
0x800081, 0x1, 0x2080, 0x800080, 0x2000, 0x802080, 0x802081, 0x81, 0x800080, 0x800001, 0x802000, 0x802081, 0x81, 0,
0, 0x802000, 0x2080, 0x800080, 0x800081, 0x1, 0x802001, 0x2081, 0x2081, 0x80, 0x802081, 0x81, 0x1, 0x2000, 0x800001,
0x2001, 0x802080, 0x800081, 0x2001, 0x2080, 0x800000, 0x802001, 0x80, 0x800000, 0x2000, 0x802080
];
const spfunction5 = [
0x100, 0x2080100, 0x2080000, 0x42000100, 0x80000, 0x100, 0x40000000, 0x2080000,
0x40080100, 0x80000, 0x2000100, 0x40080100, 0x42000100, 0x42080000, 0x80100, 0x40000000, 0x2000000, 0x40080000,
0x40080000, 0, 0x40000100, 0x42080100, 0x42080100, 0x2000100, 0x42080000, 0x40000100, 0, 0x42000000, 0x2080100,
0x2000000, 0x42000000, 0x80100, 0x80000, 0x42000100, 0x100, 0x2000000, 0x40000000, 0x2080000, 0x42000100,
0x40080100, 0x2000100, 0x40000000, 0x42080000, 0x2080100, 0x40080100, 0x100, 0x2000000, 0x42080000, 0x42080100,
0x80100, 0x42000000, 0x42080100, 0x2080000, 0, 0x40080000, 0x42000000, 0x80100, 0x2000100, 0x40000100, 0x80000, 0,
0x40080000, 0x2080100, 0x40000100
];
const spfunction6 = [
0x20000010, 0x20400000, 0x4000, 0x20404010, 0x20400000, 0x10, 0x20404010, 0x400000,
0x20004000, 0x404010, 0x400000, 0x20000010, 0x400010, 0x20004000, 0x20000000, 0x4010, 0, 0x400010, 0x20004010,
0x4000, 0x404000, 0x20004010, 0x10, 0x20400010, 0x20400010, 0, 0x404010, 0x20404000, 0x4010, 0x404000, 0x20404000,
0x20000000, 0x20004000, 0x10, 0x20400010, 0x404000, 0x20404010, 0x400000, 0x4010, 0x20000010, 0x400000, 0x20004000,
0x20000000, 0x4010, 0x20000010, 0x20404010, 0x404000, 0x20400000, 0x404010, 0x20404000, 0, 0x20400010, 0x10, 0x4000,
0x20400000, 0x404010, 0x4000, 0x400010, 0x20004010, 0, 0x20404000, 0x20000000, 0x400010, 0x20004010
];
const spfunction7 = [
0x200000, 0x4200002, 0x4000802, 0, 0x800, 0x4000802, 0x200802, 0x4200800, 0x4200802,
0x200000, 0, 0x4000002, 0x2, 0x4000000, 0x4200002, 0x802, 0x4000800, 0x200802, 0x200002, 0x4000800, 0x4000002,
0x4200000, 0x4200800, 0x200002, 0x4200000, 0x800, 0x802, 0x4200802, 0x200800, 0x2, 0x4000000, 0x200800, 0x4000000,
0x200800, 0x200000, 0x4000802, 0x4000802, 0x4200002, 0x4200002, 0x2, 0x200002, 0x4000000, 0x4000800, 0x200000,
0x4200800, 0x802, 0x200802, 0x4200800, 0x802, 0x4000002, 0x4200802, 0x4200000, 0x200800, 0, 0x2, 0x4200802, 0,
0x200802, 0x4200000, 0x800, 0x4000002, 0x4000800, 0x800, 0x200002
];
const spfunction8 = [
0x10001040, 0x1000, 0x40000, 0x10041040, 0x10000000, 0x10001040, 0x40, 0x10000000,
0x40040, 0x10040000, 0x10041040, 0x41000, 0x10041000, 0x41040, 0x1000, 0x40, 0x10040000, 0x10000040, 0x10001000,
0x1040, 0x41000, 0x40040, 0x10040040, 0x10041000, 0x1040, 0, 0, 0x10040040, 0x10000040, 0x10001000, 0x41040,
0x40000, 0x41040, 0x40000, 0x10041000, 0x1000, 0x40, 0x10040040, 0x1000, 0x41040, 0x10001000, 0x40, 0x10000040,
0x10040000, 0x10040040, 0x10000000, 0x40000, 0x10001040, 0, 0x10041040, 0x40040, 0x10000040, 0x10040000, 0x10001000,
0x10001040, 0, 0x10041040, 0x41000, 0x41000, 0x1040, 0x1040, 0x40040, 0x10000000, 0x10041000
];
//create the 16 or 48 subkeys we will need
let m = 0;
let i;
let j;
let temp;
let right1;
let right2;
let left;
let right;
let looping;
let cbcleft;
let cbcleft2;
let cbcright;
let cbcright2;
let endloop;
let loopinc;
let len = message.length;
//set up the loops for single and triple des
const iterations = keys.length === 32 ? 3 : 9; //single or triple des
if (iterations === 3) {
looping = encrypt ? [0, 32, 2] : [30, -2, -2];
} else {
looping = encrypt ? [0, 32, 2, 62, 30, -2, 64, 96, 2] : [94, 62, -2, 32, 64, 2, 30, -2, -2];
}
//pad the message depending on the padding parameter
//only add padding if encrypting - note that you need to use the same padding option for both encrypt and decrypt
if (encrypt) {
message = desAddPadding(message, padding);
len = message.length;
}
//store the result here
let result = new Uint8Array(len);
let k = 0;
if (mode === 1) { //CBC mode
cbcleft = (iv[m++] << 24) | (iv[m++] << 16) | (iv[m++] << 8) | iv[m++];
cbcright = (iv[m++] << 24) | (iv[m++] << 16) | (iv[m++] << 8) | iv[m++];
m = 0;
}
//loop through each 64 bit chunk of the message
while (m < len) {
left = (message[m++] << 24) | (message[m++] << 16) | (message[m++] << 8) | message[m++];
right = (message[m++] << 24) | (message[m++] << 16) | (message[m++] << 8) | message[m++];
//for Cipher Block Chaining mode, xor the message with the previous result
if (mode === 1) {
if (encrypt) {
left ^= cbcleft;
right ^= cbcright;
} else {
cbcleft2 = cbcleft;
cbcright2 = cbcright;
cbcleft = left;
cbcright = right;
}
}
//first each 64 but chunk of the message must be permuted according to IP
temp = ((left >>> 4) ^ right) & 0x0f0f0f0f;
right ^= temp;
left ^= (temp << 4);
temp = ((left >>> 16) ^ right) & 0x0000ffff;
right ^= temp;
left ^= (temp << 16);
temp = ((right >>> 2) ^ left) & 0x33333333;
left ^= temp;
right ^= (temp << 2);
temp = ((right >>> 8) ^ left) & 0x00ff00ff;
left ^= temp;
right ^= (temp << 8);
temp = ((left >>> 1) ^ right) & 0x55555555;
right ^= temp;
left ^= (temp << 1);
left = ((left << 1) | (left >>> 31));
right = ((right << 1) | (right >>> 31));
//do this either 1 or 3 times for each chunk of the message
for (j = 0; j < iterations; j += 3) {
endloop = looping[j + 1];
loopinc = looping[j + 2];
//now go through and perform the encryption or decryption
for (i = looping[j]; i !== endloop; i += loopinc) { //for efficiency
right1 = right ^ keys[i];
right2 = ((right >>> 4) | (right << 28)) ^ keys[i + 1];
//the result is attained by passing these bytes through the S selection functions
temp = left;
left = right;
right = temp ^ (spfunction2[(right1 >>> 24) & 0x3f] | spfunction4[(right1 >>> 16) & 0x3f] | spfunction6[(right1 >>>
8) & 0x3f] | spfunction8[right1 & 0x3f] | spfunction1[(right2 >>> 24) & 0x3f] | spfunction3[(right2 >>> 16) &
0x3f] | spfunction5[(right2 >>> 8) & 0x3f] | spfunction7[right2 & 0x3f]);
}
temp = left;
left = right;
right = temp; //unreverse left and right
} //for either 1 or 3 iterations
//move then each one bit to the right
left = ((left >>> 1) | (left << 31));
right = ((right >>> 1) | (right << 31));
//now perform IP-1, which is IP in the opposite direction
temp = ((left >>> 1) ^ right) & 0x55555555;
right ^= temp;
left ^= (temp << 1);
temp = ((right >>> 8) ^ left) & 0x00ff00ff;
left ^= temp;
right ^= (temp << 8);
temp = ((right >>> 2) ^ left) & 0x33333333;
left ^= temp;
right ^= (temp << 2);
temp = ((left >>> 16) ^ right) & 0x0000ffff;
right ^= temp;
left ^= (temp << 16);
temp = ((left >>> 4) ^ right) & 0x0f0f0f0f;
right ^= temp;
left ^= (temp << 4);
//for Cipher Block Chaining mode, xor the message with the previous result
if (mode === 1) {
if (encrypt) {
cbcleft = left;
cbcright = right;
} else {
left ^= cbcleft2;
right ^= cbcright2;
}
}
result[k++] = (left >>> 24);
result[k++] = ((left >>> 16) & 0xff);
result[k++] = ((left >>> 8) & 0xff);
result[k++] = (left & 0xff);
result[k++] = (right >>> 24);
result[k++] = ((right >>> 16) & 0xff);
result[k++] = ((right >>> 8) & 0xff);
result[k++] = (right & 0xff);
} //for every 8 characters, or 64 bits in the message
//only remove padding if decrypting - note that you need to use the same padding option for both encrypt and decrypt
if (!encrypt) {
result = desRemovePadding(result, padding);
}
return result;
} //end of des
//desCreateKeys
//this takes as input a 64 bit key (even though only 56 bits are used)
//as an array of 2 integers, and returns 16 48 bit keys
function desCreateKeys(key) {
//declaring this locally speeds things up a bit
const pc2bytes0 = [
0, 0x4, 0x20000000, 0x20000004, 0x10000, 0x10004, 0x20010000, 0x20010004, 0x200, 0x204,
0x20000200, 0x20000204, 0x10200, 0x10204, 0x20010200, 0x20010204
];
const pc2bytes1 = [
0, 0x1, 0x100000, 0x100001, 0x4000000, 0x4000001, 0x4100000, 0x4100001, 0x100, 0x101, 0x100100,
0x100101, 0x4000100, 0x4000101, 0x4100100, 0x4100101
];
const pc2bytes2 = [
0, 0x8, 0x800, 0x808, 0x1000000, 0x1000008, 0x1000800, 0x1000808, 0, 0x8, 0x800, 0x808,
0x1000000, 0x1000008, 0x1000800, 0x1000808
];
const pc2bytes3 = [
0, 0x200000, 0x8000000, 0x8200000, 0x2000, 0x202000, 0x8002000, 0x8202000, 0x20000, 0x220000,
0x8020000, 0x8220000, 0x22000, 0x222000, 0x8022000, 0x8222000
];
const pc2bytes4 = [
0, 0x40000, 0x10, 0x40010, 0, 0x40000, 0x10, 0x40010, 0x1000, 0x41000, 0x1010, 0x41010, 0x1000,
0x41000, 0x1010, 0x41010
];
const pc2bytes5 = [
0, 0x400, 0x20, 0x420, 0, 0x400, 0x20, 0x420, 0x2000000, 0x2000400, 0x2000020, 0x2000420,
0x2000000, 0x2000400, 0x2000020, 0x2000420
];
const pc2bytes6 = [
0, 0x10000000, 0x80000, 0x10080000, 0x2, 0x10000002, 0x80002, 0x10080002, 0, 0x10000000,
0x80000, 0x10080000, 0x2, 0x10000002, 0x80002, 0x10080002
];
const pc2bytes7 = [
0, 0x10000, 0x800, 0x10800, 0x20000000, 0x20010000, 0x20000800, 0x20010800, 0x20000, 0x30000,
0x20800, 0x30800, 0x20020000, 0x20030000, 0x20020800, 0x20030800
];
const pc2bytes8 = [
0, 0x40000, 0, 0x40000, 0x2, 0x40002, 0x2, 0x40002, 0x2000000, 0x2040000, 0x2000000, 0x2040000,
0x2000002, 0x2040002, 0x2000002, 0x2040002
];
const pc2bytes9 = [
0, 0x10000000, 0x8, 0x10000008, 0, 0x10000000, 0x8, 0x10000008, 0x400, 0x10000400, 0x408,
0x10000408, 0x400, 0x10000400, 0x408, 0x10000408
];
const pc2bytes10 = [
0, 0x20, 0, 0x20, 0x100000, 0x100020, 0x100000, 0x100020, 0x2000, 0x2020, 0x2000, 0x2020,
0x102000, 0x102020, 0x102000, 0x102020
];
const pc2bytes11 = [
0, 0x1000000, 0x200, 0x1000200, 0x200000, 0x1200000, 0x200200, 0x1200200, 0x4000000, 0x5000000,
0x4000200, 0x5000200, 0x4200000, 0x5200000, 0x4200200, 0x5200200
];
const pc2bytes12 = [
0, 0x1000, 0x8000000, 0x8001000, 0x80000, 0x81000, 0x8080000, 0x8081000, 0x10, 0x1010,
0x8000010, 0x8001010, 0x80010, 0x81010, 0x8080010, 0x8081010
];
const pc2bytes13 = [0, 0x4, 0x100, 0x104, 0, 0x4, 0x100, 0x104, 0x1, 0x5, 0x101, 0x105, 0x1, 0x5, 0x101, 0x105];
//how many iterations (1 for des, 3 for triple des)
const iterations = key.length > 8 ? 3 : 1; //changed by Paul 16/6/2007 to use Triple DES for 9+ byte keys
//stores the return keys
const keys = new Array(32 * iterations);
//now define the left shifts which need to be done
const shifts = [0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0];
//other variables
let lefttemp;
let righttemp;
let m = 0;
let n = 0;
let temp;
for (let j = 0; j < iterations; j++) { //either 1 or 3 iterations
let left = (key[m++] << 24) | (key[m++] << 16) | (key[m++] << 8) | key[m++];
let right = (key[m++] << 24) | (key[m++] << 16) | (key[m++] << 8) | key[m++];
temp = ((left >>> 4) ^ right) & 0x0f0f0f0f;
right ^= temp;
left ^= (temp << 4);
temp = ((right >>> -16) ^ left) & 0x0000ffff;
left ^= temp;
right ^= (temp << -16);
temp = ((left >>> 2) ^ right) & 0x33333333;
right ^= temp;
left ^= (temp << 2);
temp = ((right >>> -16) ^ left) & 0x0000ffff;
left ^= temp;
right ^= (temp << -16);
temp = ((left >>> 1) ^ right) & 0x55555555;
right ^= temp;
left ^= (temp << 1);
temp = ((right >>> 8) ^ left) & 0x00ff00ff;
left ^= temp;
right ^= (temp << 8);
temp = ((left >>> 1) ^ right) & 0x55555555;
right ^= temp;
left ^= (temp << 1);
//the right side needs to be shifted and to get the last four bits of the left side
temp = (left << 8) | ((right >>> 20) & 0x000000f0);
//left needs to be put upside down
left = (right << 24) | ((right << 8) & 0xff0000) | ((right >>> 8) & 0xff00) | ((right >>> 24) & 0xf0);
right = temp;
//now go through and perform these shifts on the left and right keys
for (let i = 0; i < shifts.length; i++) {
//shift the keys either one or two bits to the left
if (shifts[i]) {
left = (left << 2) | (left >>> 26);
right = (right << 2) | (right >>> 26);
} else {
left = (left << 1) | (left >>> 27);
right = (right << 1) | (right >>> 27);
}
left &= -0xf;
right &= -0xf;
//now apply PC-2, in such a way that E is easier when encrypting or decrypting
//this conversion will look like PC-2 except only the last 6 bits of each byte are used
//rather than 48 consecutive bits and the order of lines will be according to
//how the S selection functions will be applied: S2, S4, S6, S8, S1, S3, S5, S7
lefttemp = pc2bytes0[left >>> 28] | pc2bytes1[(left >>> 24) & 0xf] | pc2bytes2[(left >>> 20) & 0xf] | pc2bytes3[(
left >>> 16) & 0xf] | pc2bytes4[(left >>> 12) & 0xf] | pc2bytes5[(left >>> 8) & 0xf] | pc2bytes6[(left >>> 4) &
0xf];
righttemp = pc2bytes7[right >>> 28] | pc2bytes8[(right >>> 24) & 0xf] | pc2bytes9[(right >>> 20) & 0xf] |
pc2bytes10[(right >>> 16) & 0xf] | pc2bytes11[(right >>> 12) & 0xf] | pc2bytes12[(right >>> 8) & 0xf] |
pc2bytes13[(right >>> 4) & 0xf];
temp = ((righttemp >>> 16) ^ lefttemp) & 0x0000ffff;
keys[n++] = lefttemp ^ temp;
keys[n++] = righttemp ^ (temp << 16);
}
} //for each iterations
//return the keys we've created
return keys;
} //end of desCreateKeys
function desAddPadding(message, padding) {
const padLength = 8 - (message.length % 8);
let pad;
if (padding === 2 && (padLength < 8)) { //pad the message with spaces
pad = ' '.charCodeAt(0);
} else if (padding === 1) { //PKCS7 padding
pad = padLength;
} else if (!padding && (padLength < 8)) { //pad the message out with null bytes
pad = 0;
} else if (padLength === 8) {
return message;
} else {
throw new Error('des: invalid padding');
}
const paddedMessage = new Uint8Array(message.length + padLength);
for (let i = 0; i < message.length; i++) {
paddedMessage[i] = message[i];
}
for (let j = 0; j < padLength; j++) {
paddedMessage[message.length + j] = pad;
}
return paddedMessage;
}
function desRemovePadding(message, padding) {
let padLength = null;
let pad;
if (padding === 2) { // space padded
pad = ' '.charCodeAt(0);
} else if (padding === 1) { // PKCS7
padLength = message[message.length - 1];
} else if (!padding) { // null padding
pad = 0;
} else {
throw new Error('des: invalid padding');
}
if (!padLength) {
padLength = 1;
while (message[message.length - padLength] === pad) {
padLength++;
}
padLength--;
}
return message.subarray(0, message.length - padLength);
}
// added by Recurity Labs
function TripleDES(key) {
this.key = [];
for (let i = 0; i < 3; i++) {
this.key.push(new Uint8Array(key.subarray(i * 8, (i * 8) + 8)));
}
this.encrypt = function(block) {
return des(
desCreateKeys(this.key[2]),
des(
desCreateKeys(this.key[1]),
des(
desCreateKeys(this.key[0]),
block, true, 0, null, null
),
false, 0, null, null
), true, 0, null, null
);
};
}
TripleDES.keySize = TripleDES.prototype.keySize = 24;
TripleDES.blockSize = TripleDES.prototype.blockSize = 8;
// This is "original" DES
function DES(key) {
this.key = key;
this.encrypt = function(block, padding) {
const keys = desCreateKeys(this.key);
return des(keys, block, true, 0, null, padding);
};
this.decrypt = function(block, padding) {
const keys = desCreateKeys(this.key);
return des(keys, block, false, 0, null, padding);
};
}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Copyright 2010 pjacobs@xeekr.com . All rights reserved.
// Modified by Recurity Labs GmbH
// fixed/modified by Herbert Hanewinkel, www.haneWIN.de
// check www.haneWIN.de for the latest version
// cast5.js is a Javascript implementation of CAST-128, as defined in RFC 2144.
// CAST-128 is a common OpenPGP cipher.
// CAST5 constructor
function OpenPGPSymEncCAST5() {
this.BlockSize = 8;
this.KeySize = 16;
this.setKey = function(key) {
this.masking = new Array(16);
this.rotate = new Array(16);
this.reset();
if (key.length === this.KeySize) {
this.keySchedule(key);
} else {
throw new Error('CAST-128: keys must be 16 bytes');
}
return true;
};
this.reset = function() {
for (let i = 0; i < 16; i++) {
this.masking[i] = 0;
this.rotate[i] = 0;
}
};
this.getBlockSize = function() {
return this.BlockSize;
};
this.encrypt = function(src) {
const dst = new Array(src.length);
for (let i = 0; i < src.length; i += 8) {
let l = (src[i] << 24) | (src[i + 1] << 16) | (src[i + 2] << 8) | src[i + 3];
let r = (src[i + 4] << 24) | (src[i + 5] << 16) | (src[i + 6] << 8) | src[i + 7];
let t;
t = r;
r = l ^ f1(r, this.masking[0], this.rotate[0]);
l = t;
t = r;
r = l ^ f2(r, this.masking[1], this.rotate[1]);
l = t;
t = r;
r = l ^ f3(r, this.masking[2], this.rotate[2]);
l = t;
t = r;
r = l ^ f1(r, this.masking[3], this.rotate[3]);
l = t;
t = r;
r = l ^ f2(r, this.masking[4], this.rotate[4]);
l = t;
t = r;
r = l ^ f3(r, this.masking[5], this.rotate[5]);
l = t;
t = r;
r = l ^ f1(r, this.masking[6], this.rotate[6]);
l = t;
t = r;
r = l ^ f2(r, this.masking[7], this.rotate[7]);
l = t;
t = r;
r = l ^ f3(r, this.masking[8], this.rotate[8]);
l = t;
t = r;
r = l ^ f1(r, this.masking[9], this.rotate[9]);
l = t;
t = r;
r = l ^ f2(r, this.masking[10], this.rotate[10]);
l = t;
t = r;
r = l ^ f3(r, this.masking[11], this.rotate[11]);
l = t;
t = r;
r = l ^ f1(r, this.masking[12], this.rotate[12]);
l = t;
t = r;
r = l ^ f2(r, this.masking[13], this.rotate[13]);
l = t;
t = r;
r = l ^ f3(r, this.masking[14], this.rotate[14]);
l = t;
t = r;
r = l ^ f1(r, this.masking[15], this.rotate[15]);
l = t;
dst[i] = (r >>> 24) & 255;
dst[i + 1] = (r >>> 16) & 255;
dst[i + 2] = (r >>> 8) & 255;
dst[i + 3] = r & 255;
dst[i + 4] = (l >>> 24) & 255;
dst[i + 5] = (l >>> 16) & 255;
dst[i + 6] = (l >>> 8) & 255;
dst[i + 7] = l & 255;
}
return dst;
};
this.decrypt = function(src) {
const dst = new Array(src.length);
for (let i = 0; i < src.length; i += 8) {
let l = (src[i] << 24) | (src[i + 1] << 16) | (src[i + 2] << 8) | src[i + 3];
let r = (src[i + 4] << 24) | (src[i + 5] << 16) | (src[i + 6] << 8) | src[i + 7];
let t;
t = r;
r = l ^ f1(r, this.masking[15], this.rotate[15]);
l = t;
t = r;
r = l ^ f3(r, this.masking[14], this.rotate[14]);
l = t;
t = r;
r = l ^ f2(r, this.masking[13], this.rotate[13]);
l = t;
t = r;
r = l ^ f1(r, this.masking[12], this.rotate[12]);
l = t;
t = r;
r = l ^ f3(r, this.masking[11], this.rotate[11]);
l = t;
t = r;
r = l ^ f2(r, this.masking[10], this.rotate[10]);
l = t;
t = r;
r = l ^ f1(r, this.masking[9], this.rotate[9]);
l = t;
t = r;
r = l ^ f3(r, this.masking[8], this.rotate[8]);
l = t;
t = r;
r = l ^ f2(r, this.masking[7], this.rotate[7]);
l = t;
t = r;
r = l ^ f1(r, this.masking[6], this.rotate[6]);
l = t;
t = r;
r = l ^ f3(r, this.masking[5], this.rotate[5]);
l = t;
t = r;
r = l ^ f2(r, this.masking[4], this.rotate[4]);
l = t;
t = r;
r = l ^ f1(r, this.masking[3], this.rotate[3]);
l = t;
t = r;
r = l ^ f3(r, this.masking[2], this.rotate[2]);
l = t;
t = r;
r = l ^ f2(r, this.masking[1], this.rotate[1]);
l = t;
t = r;
r = l ^ f1(r, this.masking[0], this.rotate[0]);
l = t;
dst[i] = (r >>> 24) & 255;
dst[i + 1] = (r >>> 16) & 255;
dst[i + 2] = (r >>> 8) & 255;
dst[i + 3] = r & 255;
dst[i + 4] = (l >>> 24) & 255;
dst[i + 5] = (l >> 16) & 255;
dst[i + 6] = (l >> 8) & 255;
dst[i + 7] = l & 255;
}
return dst;
};
const scheduleA = new Array(4);
scheduleA[0] = new Array(4);
scheduleA[0][0] = [4, 0, 0xd, 0xf, 0xc, 0xe, 0x8];
scheduleA[0][1] = [5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa];
scheduleA[0][2] = [6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9];
scheduleA[0][3] = [7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb];
scheduleA[1] = new Array(4);
scheduleA[1][0] = [0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0];
scheduleA[1][1] = [1, 4, 0, 2, 1, 3, 16 + 2];
scheduleA[1][2] = [2, 5, 7, 6, 5, 4, 16 + 1];
scheduleA[1][3] = [3, 7, 0xa, 9, 0xb, 8, 16 + 3];
scheduleA[2] = new Array(4);
scheduleA[2][0] = [4, 0, 0xd, 0xf, 0xc, 0xe, 8];
scheduleA[2][1] = [5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa];
scheduleA[2][2] = [6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9];
scheduleA[2][3] = [7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb];
scheduleA[3] = new Array(4);
scheduleA[3][0] = [0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0];
scheduleA[3][1] = [1, 4, 0, 2, 1, 3, 16 + 2];
scheduleA[3][2] = [2, 5, 7, 6, 5, 4, 16 + 1];
scheduleA[3][3] = [3, 7, 0xa, 9, 0xb, 8, 16 + 3];
const scheduleB = new Array(4);
scheduleB[0] = new Array(4);
scheduleB[0][0] = [16 + 8, 16 + 9, 16 + 7, 16 + 6, 16 + 2];
scheduleB[0][1] = [16 + 0xa, 16 + 0xb, 16 + 5, 16 + 4, 16 + 6];
scheduleB[0][2] = [16 + 0xc, 16 + 0xd, 16 + 3, 16 + 2, 16 + 9];
scheduleB[0][3] = [16 + 0xe, 16 + 0xf, 16 + 1, 16 + 0, 16 + 0xc];
scheduleB[1] = new Array(4);
scheduleB[1][0] = [3, 2, 0xc, 0xd, 8];
scheduleB[1][1] = [1, 0, 0xe, 0xf, 0xd];
scheduleB[1][2] = [7, 6, 8, 9, 3];
scheduleB[1][3] = [5, 4, 0xa, 0xb, 7];
scheduleB[2] = new Array(4);
scheduleB[2][0] = [16 + 3, 16 + 2, 16 + 0xc, 16 + 0xd, 16 + 9];
scheduleB[2][1] = [16 + 1, 16 + 0, 16 + 0xe, 16 + 0xf, 16 + 0xc];
scheduleB[2][2] = [16 + 7, 16 + 6, 16 + 8, 16 + 9, 16 + 2];
scheduleB[2][3] = [16 + 5, 16 + 4, 16 + 0xa, 16 + 0xb, 16 + 6];
scheduleB[3] = new Array(4);
scheduleB[3][0] = [8, 9, 7, 6, 3];
scheduleB[3][1] = [0xa, 0xb, 5, 4, 7];
scheduleB[3][2] = [0xc, 0xd, 3, 2, 8];
scheduleB[3][3] = [0xe, 0xf, 1, 0, 0xd];
// changed 'in' to 'inn' (in javascript 'in' is a reserved word)
this.keySchedule = function(inn) {
const t = new Array(8);
const k = new Array(32);
let j;
for (let i = 0; i < 4; i++) {
j = i * 4;
t[i] = (inn[j] << 24) | (inn[j + 1] << 16) | (inn[j + 2] << 8) | inn[j + 3];
}
const x = [6, 7, 4, 5];
let ki = 0;
let w;
for (let half = 0; half < 2; half++) {
for (let round = 0; round < 4; round++) {
for (j = 0; j < 4; j++) {
const a = scheduleA[round][j];
w = t[a[1]];
w ^= sBox[4][(t[a[2] >>> 2] >>> (24 - 8 * (a[2] & 3))) & 0xff];
w ^= sBox[5][(t[a[3] >>> 2] >>> (24 - 8 * (a[3] & 3))) & 0xff];
w ^= sBox[6][(t[a[4] >>> 2] >>> (24 - 8 * (a[4] & 3))) & 0xff];
w ^= sBox[7][(t[a[5] >>> 2] >>> (24 - 8 * (a[5] & 3))) & 0xff];
w ^= sBox[x[j]][(t[a[6] >>> 2] >>> (24 - 8 * (a[6] & 3))) & 0xff];
t[a[0]] = w;
}
for (j = 0; j < 4; j++) {
const b = scheduleB[round][j];
w = sBox[4][(t[b[0] >>> 2] >>> (24 - 8 * (b[0] & 3))) & 0xff];
w ^= sBox[5][(t[b[1] >>> 2] >>> (24 - 8 * (b[1] & 3))) & 0xff];
w ^= sBox[6][(t[b[2] >>> 2] >>> (24 - 8 * (b[2] & 3))) & 0xff];
w ^= sBox[7][(t[b[3] >>> 2] >>> (24 - 8 * (b[3] & 3))) & 0xff];
w ^= sBox[4 + j][(t[b[4] >>> 2] >>> (24 - 8 * (b[4] & 3))) & 0xff];
k[ki] = w;
ki++;
}
}
}
for (let i = 0; i < 16; i++) {
this.masking[i] = k[i];
this.rotate[i] = k[16 + i] & 0x1f;
}
};
// These are the three 'f' functions. See RFC 2144, section 2.2.
function f1(d, m, r) {
const t = m + d;
const I = (t << r) | (t >>> (32 - r));
return ((sBox[0][I >>> 24] ^ sBox[1][(I >>> 16) & 255]) - sBox[2][(I >>> 8) & 255]) + sBox[3][I & 255];
}
function f2(d, m, r) {
const t = m ^ d;
const I = (t << r) | (t >>> (32 - r));
return ((sBox[0][I >>> 24] - sBox[1][(I >>> 16) & 255]) + sBox[2][(I >>> 8) & 255]) ^ sBox[3][I & 255];
}
function f3(d, m, r) {
const t = m - d;
const I = (t << r) | (t >>> (32 - r));
return ((sBox[0][I >>> 24] + sBox[1][(I >>> 16) & 255]) ^ sBox[2][(I >>> 8) & 255]) - sBox[3][I & 255];
}
const sBox = new Array(8);
sBox[0] = [
0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949,
0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e,
0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0,
0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7,
0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935,
0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d,
0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50,
0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe,
0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3,
0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167,
0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291,
0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779,
0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2,
0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511,
0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d,
0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5,
0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324,
0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c,
0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc,
0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d,
0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96,
0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a,
0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd,
0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6,
0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872,
0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c,
0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e,
0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9,
0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf
];
sBox[1] = [
0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651,
0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3,
0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb,
0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806,
0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b,
0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359,
0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b,
0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c,
0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34,
0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb,
0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd,
0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860,
0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b,
0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304,
0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b,
0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf,
0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c,
0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13,
0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f,
0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6,
0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6,
0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58,
0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906,
0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6,
0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4,
0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6,
0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f,
0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249,
0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9,
0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1
];
sBox[2] = [
0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90,
0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5,
0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e,
0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240,
0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5,
0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71,
0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04,
0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15,
0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2,
0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176,
0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148,
0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc,
0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e,
0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51,
0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f,
0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a,
0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b,
0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5,
0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45,
0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536,
0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc,
0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0,
0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69,
0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2,
0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49,
0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d,
0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a,
0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783
];
sBox[3] = [
0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1,
0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf,
0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15,
0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121,
0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25,
0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb,
0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5,
0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d,
0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6,
0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23,
0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003,
0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6,
0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119,
0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a,
0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79,
0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df,
0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26,
0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab,
0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7,
0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417,
0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2,
0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2,
0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a,
0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919,
0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876,
0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab,
0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04,
0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282,
0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2
];
sBox[4] = [
0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f,
0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a,
0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff,
0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02,
0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a,
0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7,
0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9,
0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981,
0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774,
0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655,
0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2,
0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910,
0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1,
0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da,
0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049,
0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f,
0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba,
0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be,
0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3,
0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840,
0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4,
0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2,
0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7,
0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5,
0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e,
0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e,
0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801,
0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad,
0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0,
0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20,
0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8,
0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4
];
sBox[5] = [
0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac,
0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138,
0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367,
0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98,
0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072,
0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3,
0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd,
0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8,
0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9,
0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54,
0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387,
0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc,
0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf,
0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf,
0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f,
0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289,
0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950,
0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f,
0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b,
0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be,
0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13,
0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976,
0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0,
0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891,
0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da,
0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc,
0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084,
0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25,
0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121,
0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5,
0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd,
0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f
];
sBox[6] = [
0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f,
0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de,
0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43,
0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19,
0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2,
0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516,
0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88,
0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816,
0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756,
0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a,
0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264,
0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688,
0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28,
0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3,
0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7,
0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06,
0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033,
0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a,
0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566,
0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509,
0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962,
0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e,
0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c,
0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c,
0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285,
0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301,
0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be,
0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767,
0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647,
0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914,
0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c,
0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3
];
sBox[7] = [
0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5,
0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc,
0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd,
0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d,
0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2,
0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862,
0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc,
0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c,
0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e,
0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039,
0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8,
0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42,
0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5,
0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472,
0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225,
0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c,
0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb,
0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054,
0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70,
0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc,
0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c,
0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3,
0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4,
0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101,
0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f,
0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e,
0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a,
0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c,
0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384,
0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c,
0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82,
0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e
];
}
function CAST5(key) {
this.cast5 = new OpenPGPSymEncCAST5();
this.cast5.setKey(key);
this.encrypt = function(block) {
return this.cast5.encrypt(block);
};
}
CAST5.blockSize = CAST5.prototype.blockSize = 8;
CAST5.keySize = CAST5.prototype.keySize = 16;
/* eslint-disable no-mixed-operators, no-fallthrough */
/* Modified by Recurity Labs GmbH
*
* Cipher.js
* A block-cipher algorithm implementation on JavaScript
* See Cipher.readme.txt for further information.
*
* Copyright(c) 2009 Atsushi Oka [ http://oka.nu/ ]
* This script file is distributed under the LGPL
*
* ACKNOWLEDGMENT
*
* The main subroutines are written by Michiel van Everdingen.
*
* Michiel van Everdingen
* http://home.versatel.nl/MAvanEverdingen/index.html
*
* All rights for these routines are reserved to Michiel van Everdingen.
*
*/
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Math
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const MAXINT = 0xFFFFFFFF;
function rotw(w, n) {
return (w << n | w >>> (32 - n)) & MAXINT;
}
function getW(a, i) {
return a[i] | a[i + 1] << 8 | a[i + 2] << 16 | a[i + 3] << 24;
}
function setW(a, i, w) {
a.splice(i, 4, w & 0xFF, (w >>> 8) & 0xFF, (w >>> 16) & 0xFF, (w >>> 24) & 0xFF);
}
function getB(x, n) {
return (x >>> (n * 8)) & 0xFF;
}
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Twofish
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function createTwofish() {
//
let keyBytes = null;
let dataBytes = null;
let dataOffset = -1;
// var dataLength = -1;
// var idx2 = -1;
//
let tfsKey = [];
let tfsM = [
[],
[],
[],
[]
];
function tfsInit(key) {
keyBytes = key;
let i;
let a;
let b;
let c;
let d;
const meKey = [];
const moKey = [];
const inKey = [];
let kLen;
const sKey = [];
let f01;
let f5b;
let fef;
const q0 = [
[8, 1, 7, 13, 6, 15, 3, 2, 0, 11, 5, 9, 14, 12, 10, 4],
[2, 8, 11, 13, 15, 7, 6, 14, 3, 1, 9, 4, 0, 10, 12, 5]
];
const q1 = [
[14, 12, 11, 8, 1, 2, 3, 5, 15, 4, 10, 6, 7, 0, 9, 13],
[1, 14, 2, 11, 4, 12, 3, 7, 6, 13, 10, 5, 15, 9, 0, 8]
];
const q2 = [
[11, 10, 5, 14, 6, 13, 9, 0, 12, 8, 15, 3, 2, 4, 7, 1],
[4, 12, 7, 5, 1, 6, 9, 10, 0, 14, 13, 8, 2, 11, 3, 15]
];
const q3 = [
[13, 7, 15, 4, 1, 2, 6, 14, 9, 11, 3, 0, 8, 5, 12, 10],
[11, 9, 5, 1, 12, 3, 13, 14, 6, 4, 7, 15, 2, 0, 8, 10]
];
const ror4 = [0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15];
const ashx = [0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 5, 14, 7];
const q = [
[],
[]
];
const m = [
[],
[],
[],
[]
];
function ffm5b(x) {
return x ^ (x >> 2) ^ [0, 90, 180, 238][x & 3];
}
function ffmEf(x) {
return x ^ (x >> 1) ^ (x >> 2) ^ [0, 238, 180, 90][x & 3];
}
function mdsRem(p, q) {
let i;
let t;
let u;
for (i = 0; i < 8; i++) {
t = q >>> 24;
q = ((q << 8) & MAXINT) | p >>> 24;
p = (p << 8) & MAXINT;
u = t << 1;
if (t & 128) {
u ^= 333;
}
q ^= t ^ (u << 16);
u ^= t >>> 1;
if (t & 1) {
u ^= 166;
}
q ^= u << 24 | u << 8;
}
return q;
}
function qp(n, x) {
const a = x >> 4;
const b = x & 15;
const c = q0[n][a ^ b];
const d = q1[n][ror4[b] ^ ashx[a]];
return q3[n][ror4[d] ^ ashx[c]] << 4 | q2[n][c ^ d];
}
function hFun(x, key) {
let a = getB(x, 0);
let b = getB(x, 1);
let c = getB(x, 2);
let d = getB(x, 3);
switch (kLen) {
case 4:
a = q[1][a] ^ getB(key[3], 0);
b = q[0][b] ^ getB(key[3], 1);
c = q[0][c] ^ getB(key[3], 2);
d = q[1][d] ^ getB(key[3], 3);
case 3:
a = q[1][a] ^ getB(key[2], 0);
b = q[1][b] ^ getB(key[2], 1);
c = q[0][c] ^ getB(key[2], 2);
d = q[0][d] ^ getB(key[2], 3);
case 2:
a = q[0][q[0][a] ^ getB(key[1], 0)] ^ getB(key[0], 0);
b = q[0][q[1][b] ^ getB(key[1], 1)] ^ getB(key[0], 1);
c = q[1][q[0][c] ^ getB(key[1], 2)] ^ getB(key[0], 2);
d = q[1][q[1][d] ^ getB(key[1], 3)] ^ getB(key[0], 3);
}
return m[0][a] ^ m[1][b] ^ m[2][c] ^ m[3][d];
}
keyBytes = keyBytes.slice(0, 32);
i = keyBytes.length;
while (i !== 16 && i !== 24 && i !== 32) {
keyBytes[i++] = 0;
}
for (i = 0; i < keyBytes.length; i += 4) {
inKey[i >> 2] = getW(keyBytes, i);
}
for (i = 0; i < 256; i++) {
q[0][i] = qp(0, i);
q[1][i] = qp(1, i);
}
for (i = 0; i < 256; i++) {
f01 = q[1][i];
f5b = ffm5b(f01);
fef = ffmEf(f01);
m[0][i] = f01 + (f5b << 8) + (fef << 16) + (fef << 24);
m[2][i] = f5b + (fef << 8) + (f01 << 16) + (fef << 24);
f01 = q[0][i];
f5b = ffm5b(f01);
fef = ffmEf(f01);
m[1][i] = fef + (fef << 8) + (f5b << 16) + (f01 << 24);
m[3][i] = f5b + (f01 << 8) + (fef << 16) + (f5b << 24);
}
kLen = inKey.length / 2;
for (i = 0; i < kLen; i++) {
a = inKey[i + i];
meKey[i] = a;
b = inKey[i + i + 1];
moKey[i] = b;
sKey[kLen - i - 1] = mdsRem(a, b);
}
for (i = 0; i < 40; i += 2) {
a = 0x1010101 * i;
b = a + 0x1010101;
a = hFun(a, meKey);
b = rotw(hFun(b, moKey), 8);
tfsKey[i] = (a + b) & MAXINT;
tfsKey[i + 1] = rotw(a + 2 * b, 9);
}
for (i = 0; i < 256; i++) {
a = b = c = d = i;
switch (kLen) {
case 4:
a = q[1][a] ^ getB(sKey[3], 0);
b = q[0][b] ^ getB(sKey[3], 1);
c = q[0][c] ^ getB(sKey[3], 2);
d = q[1][d] ^ getB(sKey[3], 3);
case 3:
a = q[1][a] ^ getB(sKey[2], 0);
b = q[1][b] ^ getB(sKey[2], 1);
c = q[0][c] ^ getB(sKey[2], 2);
d = q[0][d] ^ getB(sKey[2], 3);
case 2:
tfsM[0][i] = m[0][q[0][q[0][a] ^ getB(sKey[1], 0)] ^ getB(sKey[0], 0)];
tfsM[1][i] = m[1][q[0][q[1][b] ^ getB(sKey[1], 1)] ^ getB(sKey[0], 1)];
tfsM[2][i] = m[2][q[1][q[0][c] ^ getB(sKey[1], 2)] ^ getB(sKey[0], 2)];
tfsM[3][i] = m[3][q[1][q[1][d] ^ getB(sKey[1], 3)] ^ getB(sKey[0], 3)];
}
}
}
function tfsG0(x) {
return tfsM[0][getB(x, 0)] ^ tfsM[1][getB(x, 1)] ^ tfsM[2][getB(x, 2)] ^ tfsM[3][getB(x, 3)];
}
function tfsG1(x) {
return tfsM[0][getB(x, 3)] ^ tfsM[1][getB(x, 0)] ^ tfsM[2][getB(x, 1)] ^ tfsM[3][getB(x, 2)];
}
function tfsFrnd(r, blk) {
let a = tfsG0(blk[0]);
let b = tfsG1(blk[1]);
blk[2] = rotw(blk[2] ^ (a + b + tfsKey[4 * r + 8]) & MAXINT, 31);
blk[3] = rotw(blk[3], 1) ^ (a + 2 * b + tfsKey[4 * r + 9]) & MAXINT;
a = tfsG0(blk[2]);
b = tfsG1(blk[3]);
blk[0] = rotw(blk[0] ^ (a + b + tfsKey[4 * r + 10]) & MAXINT, 31);
blk[1] = rotw(blk[1], 1) ^ (a + 2 * b + tfsKey[4 * r + 11]) & MAXINT;
}
function tfsIrnd(i, blk) {
let a = tfsG0(blk[0]);
let b = tfsG1(blk[1]);
blk[2] = rotw(blk[2], 1) ^ (a + b + tfsKey[4 * i + 10]) & MAXINT;
blk[3] = rotw(blk[3] ^ (a + 2 * b + tfsKey[4 * i + 11]) & MAXINT, 31);
a = tfsG0(blk[2]);
b = tfsG1(blk[3]);
blk[0] = rotw(blk[0], 1) ^ (a + b + tfsKey[4 * i + 8]) & MAXINT;
blk[1] = rotw(blk[1] ^ (a + 2 * b + tfsKey[4 * i + 9]) & MAXINT, 31);
}
function tfsClose() {
tfsKey = [];
tfsM = [
[],
[],
[],
[]
];
}
function tfsEncrypt(data, offset) {
dataBytes = data;
dataOffset = offset;
const blk = [getW(dataBytes, dataOffset) ^ tfsKey[0],
getW(dataBytes, dataOffset + 4) ^ tfsKey[1],
getW(dataBytes, dataOffset + 8) ^ tfsKey[2],
getW(dataBytes, dataOffset + 12) ^ tfsKey[3]];
for (let j = 0; j < 8; j++) {
tfsFrnd(j, blk);
}
setW(dataBytes, dataOffset, blk[2] ^ tfsKey[4]);
setW(dataBytes, dataOffset + 4, blk[3] ^ tfsKey[5]);
setW(dataBytes, dataOffset + 8, blk[0] ^ tfsKey[6]);
setW(dataBytes, dataOffset + 12, blk[1] ^ tfsKey[7]);
dataOffset += 16;
return dataBytes;
}
function tfsDecrypt(data, offset) {
dataBytes = data;
dataOffset = offset;
const blk = [getW(dataBytes, dataOffset) ^ tfsKey[4],
getW(dataBytes, dataOffset + 4) ^ tfsKey[5],
getW(dataBytes, dataOffset + 8) ^ tfsKey[6],
getW(dataBytes, dataOffset + 12) ^ tfsKey[7]];
for (let j = 7; j >= 0; j--) {
tfsIrnd(j, blk);
}
setW(dataBytes, dataOffset, blk[2] ^ tfsKey[0]);
setW(dataBytes, dataOffset + 4, blk[3] ^ tfsKey[1]);
setW(dataBytes, dataOffset + 8, blk[0] ^ tfsKey[2]);
setW(dataBytes, dataOffset + 12, blk[1] ^ tfsKey[3]);
dataOffset += 16;
}
// added by Recurity Labs
function tfsFinal() {
return dataBytes;
}
return {
name: 'twofish',
blocksize: 128 / 8,
open: tfsInit,
close: tfsClose,
encrypt: tfsEncrypt,
decrypt: tfsDecrypt,
// added by Recurity Labs
finalize: tfsFinal
};
}
// added by Recurity Labs
function TF(key) {
this.tf = createTwofish();
this.tf.open(Array.from(key), 0);
this.encrypt = function(block) {
return this.tf.encrypt(Array.from(block), 0);
};
}
TF.keySize = TF.prototype.keySize = 32;
TF.blockSize = TF.prototype.blockSize = 16;
/* Modified by Recurity Labs GmbH
*
* Originally written by nklein software (nklein.com)
*/
/*
* Javascript implementation based on Bruce Schneier's reference implementation.
*
*
* The constructor doesn't do much of anything. It's just here
* so we can start defining properties and methods and such.
*/
function Blowfish() {}
/*
* Declare the block size so that protocols know what size
* Initialization Vector (IV) they will need.
*/
Blowfish.prototype.BLOCKSIZE = 8;
/*
* These are the default SBOXES.
*/
Blowfish.prototype.SBOXES = [
[
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
],
[
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d,
0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65,
0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9,
0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d,
0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc,
0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908,
0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908,
0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b,
0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa,
0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d,
0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5,
0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96,
0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca,
0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77,
0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054,
0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea,
0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646,
0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea,
0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd,
0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
],
[
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7,
0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af,
0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4,
0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec,
0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332,
0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58,
0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60,
0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99,
0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74,
0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3,
0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979,
0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa,
0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086,
0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24,
0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84,
0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09,
0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe,
0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0,
0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8,
0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
],
[
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
]
];
//*
//* This is the default PARRAY
//*
Blowfish.prototype.PARRAY = [
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b
];
//*
//* This is the number of rounds the cipher will go
//*
Blowfish.prototype.NN = 16;
//*
//* This function is needed to get rid of problems
//* with the high-bit getting set. If we don't do
//* this, then sometimes ( aa & 0x00FFFFFFFF ) is not
//* equal to ( bb & 0x00FFFFFFFF ) even when they
//* agree bit-for-bit for the first 32 bits.
//*
Blowfish.prototype._clean = function(xx) {
if (xx < 0) {
const yy = xx & 0x7FFFFFFF;
xx = yy + 0x80000000;
}
return xx;
};
//*
//* This is the mixing function that uses the sboxes
//*
Blowfish.prototype._F = function(xx) {
let yy;
const dd = xx & 0x00FF;
xx >>>= 8;
const cc = xx & 0x00FF;
xx >>>= 8;
const bb = xx & 0x00FF;
xx >>>= 8;
const aa = xx & 0x00FF;
yy = this.sboxes[0][aa] + this.sboxes[1][bb];
yy ^= this.sboxes[2][cc];
yy += this.sboxes[3][dd];
return yy;
};
//*
//* This method takes an array with two values, left and right
//* and does NN rounds of Blowfish on them.
//*
Blowfish.prototype._encryptBlock = function(vals) {
let dataL = vals[0];
let dataR = vals[1];
let ii;
for (ii = 0; ii < this.NN; ++ii) {
dataL ^= this.parray[ii];
dataR = this._F(dataL) ^ dataR;
const tmp = dataL;
dataL = dataR;
dataR = tmp;
}
dataL ^= this.parray[this.NN + 0];
dataR ^= this.parray[this.NN + 1];
vals[0] = this._clean(dataR);
vals[1] = this._clean(dataL);
};
//*
//* This method takes a vector of numbers and turns them
//* into long words so that they can be processed by the
//* real algorithm.
//*
//* Maybe I should make the real algorithm above take a vector
//* instead. That will involve more looping, but it won't require
//* the F() method to deconstruct the vector.
//*
Blowfish.prototype.encryptBlock = function(vector) {
let ii;
const vals = [0, 0];
const off = this.BLOCKSIZE / 2;
for (ii = 0; ii < this.BLOCKSIZE / 2; ++ii) {
vals[0] = (vals[0] << 8) | (vector[ii + 0] & 0x00FF);
vals[1] = (vals[1] << 8) | (vector[ii + off] & 0x00FF);
}
this._encryptBlock(vals);
const ret = [];
for (ii = 0; ii < this.BLOCKSIZE / 2; ++ii) {
ret[ii + 0] = ((vals[0] >>> (24 - 8 * (ii))) & 0x00FF);
ret[ii + off] = ((vals[1] >>> (24 - 8 * (ii))) & 0x00FF);
// vals[ 0 ] = ( vals[ 0 ] >>> 8 );
// vals[ 1 ] = ( vals[ 1 ] >>> 8 );
}
return ret;
};
//*
//* This method takes an array with two values, left and right
//* and undoes NN rounds of Blowfish on them.
//*
Blowfish.prototype._decryptBlock = function(vals) {
let dataL = vals[0];
let dataR = vals[1];
let ii;
for (ii = this.NN + 1; ii > 1; --ii) {
dataL ^= this.parray[ii];
dataR = this._F(dataL) ^ dataR;
const tmp = dataL;
dataL = dataR;
dataR = tmp;
}
dataL ^= this.parray[1];
dataR ^= this.parray[0];
vals[0] = this._clean(dataR);
vals[1] = this._clean(dataL);
};
//*
//* This method takes a key array and initializes the
//* sboxes and parray for this encryption.
//*
Blowfish.prototype.init = function(key) {
let ii;
let jj = 0;
this.parray = [];
for (ii = 0; ii < this.NN + 2; ++ii) {
let data = 0x00000000;
for (let kk = 0; kk < 4; ++kk) {
data = (data << 8) | (key[jj] & 0x00FF);
if (++jj >= key.length) {
jj = 0;
}
}
this.parray[ii] = this.PARRAY[ii] ^ data;
}
this.sboxes = [];
for (ii = 0; ii < 4; ++ii) {
this.sboxes[ii] = [];
for (jj = 0; jj < 256; ++jj) {
this.sboxes[ii][jj] = this.SBOXES[ii][jj];
}
}
const vals = [0x00000000, 0x00000000];
for (ii = 0; ii < this.NN + 2; ii += 2) {
this._encryptBlock(vals);
this.parray[ii + 0] = vals[0];
this.parray[ii + 1] = vals[1];
}
for (ii = 0; ii < 4; ++ii) {
for (jj = 0; jj < 256; jj += 2) {
this._encryptBlock(vals);
this.sboxes[ii][jj + 0] = vals[0];
this.sboxes[ii][jj + 1] = vals[1];
}
}
};
// added by Recurity Labs
function BF(key) {
this.bf = new Blowfish();
this.bf.init(key);
this.encrypt = function(block) {
return this.bf.encryptBlock(block);
};
}
BF.keySize = BF.prototype.keySize = 16;
BF.blockSize = BF.prototype.blockSize = 8;
/**
* @fileoverview Symmetric cryptography functions
* @module crypto/cipher
* @private
*/
/**
* AES-128 encryption and decryption (ID 7)
* @function
* @param {String} key - 128-bit key
* @see {@link https://github.com/asmcrypto/asmcrypto.js|asmCrypto}
* @see {@link https://csrc.nist.gov/publications/fips/fips197/fips-197.pdf|NIST FIPS-197}
* @returns {Object}
*/
const aes128 = aes(128);
/**
* AES-128 Block Cipher (ID 8)
* @function
* @param {String} key - 192-bit key
* @see {@link https://github.com/asmcrypto/asmcrypto.js|asmCrypto}
* @see {@link https://csrc.nist.gov/publications/fips/fips197/fips-197.pdf|NIST FIPS-197}
* @returns {Object}
*/
const aes192 = aes(192);
/**
* AES-128 Block Cipher (ID 9)
* @function
* @param {String} key - 256-bit key
* @see {@link https://github.com/asmcrypto/asmcrypto.js|asmCrypto}
* @see {@link https://csrc.nist.gov/publications/fips/fips197/fips-197.pdf|NIST FIPS-197}
* @returns {Object}
*/
const aes256 = aes(256);
// Not in OpenPGP specifications
const des$1 = DES;
/**
* Triple DES Block Cipher (ID 2)
* @function
* @param {String} key - 192-bit key
* @see {@link https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-67r2.pdf|NIST SP 800-67}
* @returns {Object}
*/
const tripledes = TripleDES;
/**
* CAST-128 Block Cipher (ID 3)
* @function
* @param {String} key - 128-bit key
* @see {@link https://tools.ietf.org/html/rfc2144|The CAST-128 Encryption Algorithm}
* @returns {Object}
*/
const cast5 = CAST5;
/**
* Twofish Block Cipher (ID 10)
* @function
* @param {String} key - 256-bit key
* @see {@link https://tools.ietf.org/html/rfc4880#ref-TWOFISH|TWOFISH}
* @returns {Object}
*/
const twofish = TF;
/**
* Blowfish Block Cipher (ID 4)
* @function
* @param {String} key - 128-bit key
* @see {@link https://tools.ietf.org/html/rfc4880#ref-BLOWFISH|BLOWFISH}
* @returns {Object}
*/
const blowfish = BF;
/**
* Not implemented
* @function
* @throws {Error}
*/
const idea = function() {
throw new Error('IDEA symmetric-key algorithm not implemented');
};
var cipher = /*#__PURE__*/Object.freeze({
__proto__: null,
aes128: aes128,
aes192: aes192,
aes256: aes256,
des: des$1,
tripledes: tripledes,
cast5: cast5,
twofish: twofish,
blowfish: blowfish,
idea: idea
});
var sha1_asm = function ( stdlib, foreign, buffer ) {
"use asm";
// SHA256 state
var H0 = 0, H1 = 0, H2 = 0, H3 = 0, H4 = 0,
TOTAL0 = 0, TOTAL1 = 0;
// HMAC state
var I0 = 0, I1 = 0, I2 = 0, I3 = 0, I4 = 0,
O0 = 0, O1 = 0, O2 = 0, O3 = 0, O4 = 0;
// I/O buffer
var HEAP = new stdlib.Uint8Array(buffer);
function _core ( w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15 ) {
w0 = w0|0;
w1 = w1|0;
w2 = w2|0;
w3 = w3|0;
w4 = w4|0;
w5 = w5|0;
w6 = w6|0;
w7 = w7|0;
w8 = w8|0;
w9 = w9|0;
w10 = w10|0;
w11 = w11|0;
w12 = w12|0;
w13 = w13|0;
w14 = w14|0;
w15 = w15|0;
var a = 0, b = 0, c = 0, d = 0, e = 0, n = 0, t = 0,
w16 = 0, w17 = 0, w18 = 0, w19 = 0,
w20 = 0, w21 = 0, w22 = 0, w23 = 0, w24 = 0, w25 = 0, w26 = 0, w27 = 0, w28 = 0, w29 = 0,
w30 = 0, w31 = 0, w32 = 0, w33 = 0, w34 = 0, w35 = 0, w36 = 0, w37 = 0, w38 = 0, w39 = 0,
w40 = 0, w41 = 0, w42 = 0, w43 = 0, w44 = 0, w45 = 0, w46 = 0, w47 = 0, w48 = 0, w49 = 0,
w50 = 0, w51 = 0, w52 = 0, w53 = 0, w54 = 0, w55 = 0, w56 = 0, w57 = 0, w58 = 0, w59 = 0,
w60 = 0, w61 = 0, w62 = 0, w63 = 0, w64 = 0, w65 = 0, w66 = 0, w67 = 0, w68 = 0, w69 = 0,
w70 = 0, w71 = 0, w72 = 0, w73 = 0, w74 = 0, w75 = 0, w76 = 0, w77 = 0, w78 = 0, w79 = 0;
a = H0;
b = H1;
c = H2;
d = H3;
e = H4;
// 0
t = ( w0 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (~b & d)) + 0x5a827999 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 1
t = ( w1 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (~b & d)) + 0x5a827999 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 2
t = ( w2 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (~b & d)) + 0x5a827999 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 3
t = ( w3 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (~b & d)) + 0x5a827999 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 4
t = ( w4 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (~b & d)) + 0x5a827999 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 5
t = ( w5 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (~b & d)) + 0x5a827999 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 6
t = ( w6 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (~b & d)) + 0x5a827999 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 7
t = ( w7 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (~b & d)) + 0x5a827999 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 8
t = ( w8 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (~b & d)) + 0x5a827999 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 9
t = ( w9 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (~b & d)) + 0x5a827999 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 10
t = ( w10 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (~b & d)) + 0x5a827999 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 11
t = ( w11 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (~b & d)) + 0x5a827999 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 12
t = ( w12 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (~b & d)) + 0x5a827999 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 13
t = ( w13 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (~b & d)) + 0x5a827999 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 14
t = ( w14 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (~b & d)) + 0x5a827999 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 15
t = ( w15 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (~b & d)) + 0x5a827999 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 16
n = w13 ^ w8 ^ w2 ^ w0;
w16 = (n << 1) | (n >>> 31);
t = (w16 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (~b & d)) + 0x5a827999 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 17
n = w14 ^ w9 ^ w3 ^ w1;
w17 = (n << 1) | (n >>> 31);
t = (w17 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (~b & d)) + 0x5a827999 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 18
n = w15 ^ w10 ^ w4 ^ w2;
w18 = (n << 1) | (n >>> 31);
t = (w18 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (~b & d)) + 0x5a827999 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 19
n = w16 ^ w11 ^ w5 ^ w3;
w19 = (n << 1) | (n >>> 31);
t = (w19 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (~b & d)) + 0x5a827999 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 20
n = w17 ^ w12 ^ w6 ^ w4;
w20 = (n << 1) | (n >>> 31);
t = (w20 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) + 0x6ed9eba1 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 21
n = w18 ^ w13 ^ w7 ^ w5;
w21 = (n << 1) | (n >>> 31);
t = (w21 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) + 0x6ed9eba1 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 22
n = w19 ^ w14 ^ w8 ^ w6;
w22 = (n << 1) | (n >>> 31);
t = (w22 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) + 0x6ed9eba1 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 23
n = w20 ^ w15 ^ w9 ^ w7;
w23 = (n << 1) | (n >>> 31);
t = (w23 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) + 0x6ed9eba1 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 24
n = w21 ^ w16 ^ w10 ^ w8;
w24 = (n << 1) | (n >>> 31);
t = (w24 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) + 0x6ed9eba1 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 25
n = w22 ^ w17 ^ w11 ^ w9;
w25 = (n << 1) | (n >>> 31);
t = (w25 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) + 0x6ed9eba1 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 26
n = w23 ^ w18 ^ w12 ^ w10;
w26 = (n << 1) | (n >>> 31);
t = (w26 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) + 0x6ed9eba1 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 27
n = w24 ^ w19 ^ w13 ^ w11;
w27 = (n << 1) | (n >>> 31);
t = (w27 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) + 0x6ed9eba1 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 28
n = w25 ^ w20 ^ w14 ^ w12;
w28 = (n << 1) | (n >>> 31);
t = (w28 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) + 0x6ed9eba1 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 29
n = w26 ^ w21 ^ w15 ^ w13;
w29 = (n << 1) | (n >>> 31);
t = (w29 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) + 0x6ed9eba1 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 30
n = w27 ^ w22 ^ w16 ^ w14;
w30 = (n << 1) | (n >>> 31);
t = (w30 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) + 0x6ed9eba1 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 31
n = w28 ^ w23 ^ w17 ^ w15;
w31 = (n << 1) | (n >>> 31);
t = (w31 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) + 0x6ed9eba1 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 32
n = w29 ^ w24 ^ w18 ^ w16;
w32 = (n << 1) | (n >>> 31);
t = (w32 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) + 0x6ed9eba1 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 33
n = w30 ^ w25 ^ w19 ^ w17;
w33 = (n << 1) | (n >>> 31);
t = (w33 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) + 0x6ed9eba1 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 34
n = w31 ^ w26 ^ w20 ^ w18;
w34 = (n << 1) | (n >>> 31);
t = (w34 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) + 0x6ed9eba1 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 35
n = w32 ^ w27 ^ w21 ^ w19;
w35 = (n << 1) | (n >>> 31);
t = (w35 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) + 0x6ed9eba1 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 36
n = w33 ^ w28 ^ w22 ^ w20;
w36 = (n << 1) | (n >>> 31);
t = (w36 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) + 0x6ed9eba1 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 37
n = w34 ^ w29 ^ w23 ^ w21;
w37 = (n << 1) | (n >>> 31);
t = (w37 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) + 0x6ed9eba1 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 38
n = w35 ^ w30 ^ w24 ^ w22;
w38 = (n << 1) | (n >>> 31);
t = (w38 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) + 0x6ed9eba1 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 39
n = w36 ^ w31 ^ w25 ^ w23;
w39 = (n << 1) | (n >>> 31);
t = (w39 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) + 0x6ed9eba1 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 40
n = w37 ^ w32 ^ w26 ^ w24;
w40 = (n << 1) | (n >>> 31);
t = (w40 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (b & d) | (c & d)) - 0x70e44324 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 41
n = w38 ^ w33 ^ w27 ^ w25;
w41 = (n << 1) | (n >>> 31);
t = (w41 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (b & d) | (c & d)) - 0x70e44324 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 42
n = w39 ^ w34 ^ w28 ^ w26;
w42 = (n << 1) | (n >>> 31);
t = (w42 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (b & d) | (c & d)) - 0x70e44324 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 43
n = w40 ^ w35 ^ w29 ^ w27;
w43 = (n << 1) | (n >>> 31);
t = (w43 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (b & d) | (c & d)) - 0x70e44324 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 44
n = w41 ^ w36 ^ w30 ^ w28;
w44 = (n << 1) | (n >>> 31);
t = (w44 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (b & d) | (c & d)) - 0x70e44324 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 45
n = w42 ^ w37 ^ w31 ^ w29;
w45 = (n << 1) | (n >>> 31);
t = (w45 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (b & d) | (c & d)) - 0x70e44324 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 46
n = w43 ^ w38 ^ w32 ^ w30;
w46 = (n << 1) | (n >>> 31);
t = (w46 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (b & d) | (c & d)) - 0x70e44324 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 47
n = w44 ^ w39 ^ w33 ^ w31;
w47 = (n << 1) | (n >>> 31);
t = (w47 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (b & d) | (c & d)) - 0x70e44324 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 48
n = w45 ^ w40 ^ w34 ^ w32;
w48 = (n << 1) | (n >>> 31);
t = (w48 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (b & d) | (c & d)) - 0x70e44324 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 49
n = w46 ^ w41 ^ w35 ^ w33;
w49 = (n << 1) | (n >>> 31);
t = (w49 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (b & d) | (c & d)) - 0x70e44324 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 50
n = w47 ^ w42 ^ w36 ^ w34;
w50 = (n << 1) | (n >>> 31);
t = (w50 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (b & d) | (c & d)) - 0x70e44324 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 51
n = w48 ^ w43 ^ w37 ^ w35;
w51 = (n << 1) | (n >>> 31);
t = (w51 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (b & d) | (c & d)) - 0x70e44324 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 52
n = w49 ^ w44 ^ w38 ^ w36;
w52 = (n << 1) | (n >>> 31);
t = (w52 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (b & d) | (c & d)) - 0x70e44324 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 53
n = w50 ^ w45 ^ w39 ^ w37;
w53 = (n << 1) | (n >>> 31);
t = (w53 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (b & d) | (c & d)) - 0x70e44324 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 54
n = w51 ^ w46 ^ w40 ^ w38;
w54 = (n << 1) | (n >>> 31);
t = (w54 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (b & d) | (c & d)) - 0x70e44324 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 55
n = w52 ^ w47 ^ w41 ^ w39;
w55 = (n << 1) | (n >>> 31);
t = (w55 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (b & d) | (c & d)) - 0x70e44324 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 56
n = w53 ^ w48 ^ w42 ^ w40;
w56 = (n << 1) | (n >>> 31);
t = (w56 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (b & d) | (c & d)) - 0x70e44324 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 57
n = w54 ^ w49 ^ w43 ^ w41;
w57 = (n << 1) | (n >>> 31);
t = (w57 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (b & d) | (c & d)) - 0x70e44324 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 58
n = w55 ^ w50 ^ w44 ^ w42;
w58 = (n << 1) | (n >>> 31);
t = (w58 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (b & d) | (c & d)) - 0x70e44324 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 59
n = w56 ^ w51 ^ w45 ^ w43;
w59 = (n << 1) | (n >>> 31);
t = (w59 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (b & d) | (c & d)) - 0x70e44324 )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 60
n = w57 ^ w52 ^ w46 ^ w44;
w60 = (n << 1) | (n >>> 31);
t = (w60 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) - 0x359d3e2a )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 61
n = w58 ^ w53 ^ w47 ^ w45;
w61 = (n << 1) | (n >>> 31);
t = (w61 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) - 0x359d3e2a )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 62
n = w59 ^ w54 ^ w48 ^ w46;
w62 = (n << 1) | (n >>> 31);
t = (w62 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) - 0x359d3e2a )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 63
n = w60 ^ w55 ^ w49 ^ w47;
w63 = (n << 1) | (n >>> 31);
t = (w63 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) - 0x359d3e2a )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 64
n = w61 ^ w56 ^ w50 ^ w48;
w64 = (n << 1) | (n >>> 31);
t = (w64 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) - 0x359d3e2a )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 65
n = w62 ^ w57 ^ w51 ^ w49;
w65 = (n << 1) | (n >>> 31);
t = (w65 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) - 0x359d3e2a )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 66
n = w63 ^ w58 ^ w52 ^ w50;
w66 = (n << 1) | (n >>> 31);
t = (w66 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) - 0x359d3e2a )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 67
n = w64 ^ w59 ^ w53 ^ w51;
w67 = (n << 1) | (n >>> 31);
t = (w67 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) - 0x359d3e2a )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 68
n = w65 ^ w60 ^ w54 ^ w52;
w68 = (n << 1) | (n >>> 31);
t = (w68 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) - 0x359d3e2a )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 69
n = w66 ^ w61 ^ w55 ^ w53;
w69 = (n << 1) | (n >>> 31);
t = (w69 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) - 0x359d3e2a )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 70
n = w67 ^ w62 ^ w56 ^ w54;
w70 = (n << 1) | (n >>> 31);
t = (w70 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) - 0x359d3e2a )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 71
n = w68 ^ w63 ^ w57 ^ w55;
w71 = (n << 1) | (n >>> 31);
t = (w71 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) - 0x359d3e2a )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 72
n = w69 ^ w64 ^ w58 ^ w56;
w72 = (n << 1) | (n >>> 31);
t = (w72 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) - 0x359d3e2a )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 73
n = w70 ^ w65 ^ w59 ^ w57;
w73 = (n << 1) | (n >>> 31);
t = (w73 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) - 0x359d3e2a )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 74
n = w71 ^ w66 ^ w60 ^ w58;
w74 = (n << 1) | (n >>> 31);
t = (w74 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) - 0x359d3e2a )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 75
n = w72 ^ w67 ^ w61 ^ w59;
w75 = (n << 1) | (n >>> 31);
t = (w75 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) - 0x359d3e2a )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 76
n = w73 ^ w68 ^ w62 ^ w60;
w76 = (n << 1) | (n >>> 31);
t = (w76 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) - 0x359d3e2a )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 77
n = w74 ^ w69 ^ w63 ^ w61;
w77 = (n << 1) | (n >>> 31);
t = (w77 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) - 0x359d3e2a )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 78
n = w75 ^ w70 ^ w64 ^ w62;
w78 = (n << 1) | (n >>> 31);
t = (w78 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) - 0x359d3e2a )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
// 79
n = w76 ^ w71 ^ w65 ^ w63;
w79 = (n << 1) | (n >>> 31);
t = (w79 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) - 0x359d3e2a )|0;
e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
H0 = ( H0 + a )|0;
H1 = ( H1 + b )|0;
H2 = ( H2 + c )|0;
H3 = ( H3 + d )|0;
H4 = ( H4 + e )|0;
}
function _core_heap ( offset ) {
offset = offset|0;
_core(
HEAP[offset|0]<<24 | HEAP[offset|1]<<16 | HEAP[offset|2]<<8 | HEAP[offset|3],
HEAP[offset|4]<<24 | HEAP[offset|5]<<16 | HEAP[offset|6]<<8 | HEAP[offset|7],
HEAP[offset|8]<<24 | HEAP[offset|9]<<16 | HEAP[offset|10]<<8 | HEAP[offset|11],
HEAP[offset|12]<<24 | HEAP[offset|13]<<16 | HEAP[offset|14]<<8 | HEAP[offset|15],
HEAP[offset|16]<<24 | HEAP[offset|17]<<16 | HEAP[offset|18]<<8 | HEAP[offset|19],
HEAP[offset|20]<<24 | HEAP[offset|21]<<16 | HEAP[offset|22]<<8 | HEAP[offset|23],
HEAP[offset|24]<<24 | HEAP[offset|25]<<16 | HEAP[offset|26]<<8 | HEAP[offset|27],
HEAP[offset|28]<<24 | HEAP[offset|29]<<16 | HEAP[offset|30]<<8 | HEAP[offset|31],
HEAP[offset|32]<<24 | HEAP[offset|33]<<16 | HEAP[offset|34]<<8 | HEAP[offset|35],
HEAP[offset|36]<<24 | HEAP[offset|37]<<16 | HEAP[offset|38]<<8 | HEAP[offset|39],
HEAP[offset|40]<<24 | HEAP[offset|41]<<16 | HEAP[offset|42]<<8 | HEAP[offset|43],
HEAP[offset|44]<<24 | HEAP[offset|45]<<16 | HEAP[offset|46]<<8 | HEAP[offset|47],
HEAP[offset|48]<<24 | HEAP[offset|49]<<16 | HEAP[offset|50]<<8 | HEAP[offset|51],
HEAP[offset|52]<<24 | HEAP[offset|53]<<16 | HEAP[offset|54]<<8 | HEAP[offset|55],
HEAP[offset|56]<<24 | HEAP[offset|57]<<16 | HEAP[offset|58]<<8 | HEAP[offset|59],
HEAP[offset|60]<<24 | HEAP[offset|61]<<16 | HEAP[offset|62]<<8 | HEAP[offset|63]
);
}
// offset — multiple of 32
function _state_to_heap ( output ) {
output = output|0;
HEAP[output|0] = H0>>>24;
HEAP[output|1] = H0>>>16&255;
HEAP[output|2] = H0>>>8&255;
HEAP[output|3] = H0&255;
HEAP[output|4] = H1>>>24;
HEAP[output|5] = H1>>>16&255;
HEAP[output|6] = H1>>>8&255;
HEAP[output|7] = H1&255;
HEAP[output|8] = H2>>>24;
HEAP[output|9] = H2>>>16&255;
HEAP[output|10] = H2>>>8&255;
HEAP[output|11] = H2&255;
HEAP[output|12] = H3>>>24;
HEAP[output|13] = H3>>>16&255;
HEAP[output|14] = H3>>>8&255;
HEAP[output|15] = H3&255;
HEAP[output|16] = H4>>>24;
HEAP[output|17] = H4>>>16&255;
HEAP[output|18] = H4>>>8&255;
HEAP[output|19] = H4&255;
}
function reset () {
H0 = 0x67452301;
H1 = 0xefcdab89;
H2 = 0x98badcfe;
H3 = 0x10325476;
H4 = 0xc3d2e1f0;
TOTAL0 = TOTAL1 = 0;
}
function init ( h0, h1, h2, h3, h4, total0, total1 ) {
h0 = h0|0;
h1 = h1|0;
h2 = h2|0;
h3 = h3|0;
h4 = h4|0;
total0 = total0|0;
total1 = total1|0;
H0 = h0;
H1 = h1;
H2 = h2;
H3 = h3;
H4 = h4;
TOTAL0 = total0;
TOTAL1 = total1;
}
// offset — multiple of 64
function process ( offset, length ) {
offset = offset|0;
length = length|0;
var hashed = 0;
if ( offset & 63 )
return -1;
while ( (length|0) >= 64 ) {
_core_heap(offset);
offset = ( offset + 64 )|0;
length = ( length - 64 )|0;
hashed = ( hashed + 64 )|0;
}
TOTAL0 = ( TOTAL0 + hashed )|0;
if ( TOTAL0>>>0 < hashed>>>0 ) TOTAL1 = ( TOTAL1 + 1 )|0;
return hashed|0;
}
// offset — multiple of 64
// output — multiple of 32
function finish ( offset, length, output ) {
offset = offset|0;
length = length|0;
output = output|0;
var hashed = 0,
i = 0;
if ( offset & 63 )
return -1;
if ( ~output )
if ( output & 31 )
return -1;
if ( (length|0) >= 64 ) {
hashed = process( offset, length )|0;
if ( (hashed|0) == -1 )
return -1;
offset = ( offset + hashed )|0;
length = ( length - hashed )|0;
}
hashed = ( hashed + length )|0;
TOTAL0 = ( TOTAL0 + length )|0;
if ( TOTAL0>>>0 < length>>>0 ) TOTAL1 = (TOTAL1 + 1)|0;
HEAP[offset|length] = 0x80;
if ( (length|0) >= 56 ) {
for ( i = (length+1)|0; (i|0) < 64; i = (i+1)|0 )
HEAP[offset|i] = 0x00;
_core_heap(offset);
length = 0;
HEAP[offset|0] = 0;
}
for ( i = (length+1)|0; (i|0) < 59; i = (i+1)|0 )
HEAP[offset|i] = 0;
HEAP[offset|56] = TOTAL1>>>21&255;
HEAP[offset|57] = TOTAL1>>>13&255;
HEAP[offset|58] = TOTAL1>>>5&255;
HEAP[offset|59] = TOTAL1<<3&255 | TOTAL0>>>29;
HEAP[offset|60] = TOTAL0>>>21&255;
HEAP[offset|61] = TOTAL0>>>13&255;
HEAP[offset|62] = TOTAL0>>>5&255;
HEAP[offset|63] = TOTAL0<<3&255;
_core_heap(offset);
if ( ~output )
_state_to_heap(output);
return hashed|0;
}
function hmac_reset () {
H0 = I0;
H1 = I1;
H2 = I2;
H3 = I3;
H4 = I4;
TOTAL0 = 64;
TOTAL1 = 0;
}
function _hmac_opad () {
H0 = O0;
H1 = O1;
H2 = O2;
H3 = O3;
H4 = O4;
TOTAL0 = 64;
TOTAL1 = 0;
}
function hmac_init ( p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15 ) {
p0 = p0|0;
p1 = p1|0;
p2 = p2|0;
p3 = p3|0;
p4 = p4|0;
p5 = p5|0;
p6 = p6|0;
p7 = p7|0;
p8 = p8|0;
p9 = p9|0;
p10 = p10|0;
p11 = p11|0;
p12 = p12|0;
p13 = p13|0;
p14 = p14|0;
p15 = p15|0;
// opad
reset();
_core(
p0 ^ 0x5c5c5c5c,
p1 ^ 0x5c5c5c5c,
p2 ^ 0x5c5c5c5c,
p3 ^ 0x5c5c5c5c,
p4 ^ 0x5c5c5c5c,
p5 ^ 0x5c5c5c5c,
p6 ^ 0x5c5c5c5c,
p7 ^ 0x5c5c5c5c,
p8 ^ 0x5c5c5c5c,
p9 ^ 0x5c5c5c5c,
p10 ^ 0x5c5c5c5c,
p11 ^ 0x5c5c5c5c,
p12 ^ 0x5c5c5c5c,
p13 ^ 0x5c5c5c5c,
p14 ^ 0x5c5c5c5c,
p15 ^ 0x5c5c5c5c
);
O0 = H0;
O1 = H1;
O2 = H2;
O3 = H3;
O4 = H4;
// ipad
reset();
_core(
p0 ^ 0x36363636,
p1 ^ 0x36363636,
p2 ^ 0x36363636,
p3 ^ 0x36363636,
p4 ^ 0x36363636,
p5 ^ 0x36363636,
p6 ^ 0x36363636,
p7 ^ 0x36363636,
p8 ^ 0x36363636,
p9 ^ 0x36363636,
p10 ^ 0x36363636,
p11 ^ 0x36363636,
p12 ^ 0x36363636,
p13 ^ 0x36363636,
p14 ^ 0x36363636,
p15 ^ 0x36363636
);
I0 = H0;
I1 = H1;
I2 = H2;
I3 = H3;
I4 = H4;
TOTAL0 = 64;
TOTAL1 = 0;
}
// offset — multiple of 64
// output — multiple of 32
function hmac_finish ( offset, length, output ) {
offset = offset|0;
length = length|0;
output = output|0;
var t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, hashed = 0;
if ( offset & 63 )
return -1;
if ( ~output )
if ( output & 31 )
return -1;
hashed = finish( offset, length, -1 )|0;
t0 = H0, t1 = H1, t2 = H2, t3 = H3, t4 = H4;
_hmac_opad();
_core( t0, t1, t2, t3, t4, 0x80000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 672 );
if ( ~output )
_state_to_heap(output);
return hashed|0;
}
// salt is assumed to be already processed
// offset — multiple of 64
// output — multiple of 32
function pbkdf2_generate_block ( offset, length, block, count, output ) {
offset = offset|0;
length = length|0;
block = block|0;
count = count|0;
output = output|0;
var h0 = 0, h1 = 0, h2 = 0, h3 = 0, h4 = 0,
t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0;
if ( offset & 63 )
return -1;
if ( ~output )
if ( output & 31 )
return -1;
// pad block number into heap
// FIXME probable OOB write
HEAP[(offset+length)|0] = block>>>24;
HEAP[(offset+length+1)|0] = block>>>16&255;
HEAP[(offset+length+2)|0] = block>>>8&255;
HEAP[(offset+length+3)|0] = block&255;
// finish first iteration
hmac_finish( offset, (length+4)|0, -1 )|0;
h0 = t0 = H0, h1 = t1 = H1, h2 = t2 = H2, h3 = t3 = H3, h4 = t4 = H4;
count = (count-1)|0;
// perform the rest iterations
while ( (count|0) > 0 ) {
hmac_reset();
_core( t0, t1, t2, t3, t4, 0x80000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 672 );
t0 = H0, t1 = H1, t2 = H2, t3 = H3, t4 = H4;
_hmac_opad();
_core( t0, t1, t2, t3, t4, 0x80000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 672 );
t0 = H0, t1 = H1, t2 = H2, t3 = H3, t4 = H4;
h0 = h0 ^ H0;
h1 = h1 ^ H1;
h2 = h2 ^ H2;
h3 = h3 ^ H3;
h4 = h4 ^ H4;
count = (count-1)|0;
}
H0 = h0;
H1 = h1;
H2 = h2;
H3 = h3;
H4 = h4;
if ( ~output )
_state_to_heap(output);
return 0;
}
return {
// SHA1
reset: reset,
init: init,
process: process,
finish: finish,
// HMAC-SHA1
hmac_reset: hmac_reset,
hmac_init: hmac_init,
hmac_finish: hmac_finish,
// PBKDF2-HMAC-SHA1
pbkdf2_generate_block: pbkdf2_generate_block
}
};
class Hash {
constructor() {
this.pos = 0;
this.len = 0;
}
reset() {
const { asm } = this.acquire_asm();
this.result = null;
this.pos = 0;
this.len = 0;
asm.reset();
return this;
}
process(data) {
if (this.result !== null)
throw new IllegalStateError('state must be reset before processing new data');
const { asm, heap } = this.acquire_asm();
let hpos = this.pos;
let hlen = this.len;
let dpos = 0;
let dlen = data.length;
let wlen = 0;
while (dlen > 0) {
wlen = _heap_write(heap, hpos + hlen, data, dpos, dlen);
hlen += wlen;
dpos += wlen;
dlen -= wlen;
wlen = asm.process(hpos, hlen);
hpos += wlen;
hlen -= wlen;
if (!hlen)
hpos = 0;
}
this.pos = hpos;
this.len = hlen;
return this;
}
finish() {
if (this.result !== null)
throw new IllegalStateError('state must be reset before processing new data');
const { asm, heap } = this.acquire_asm();
asm.finish(this.pos, this.len, 0);
this.result = new Uint8Array(this.HASH_SIZE);
this.result.set(heap.subarray(0, this.HASH_SIZE));
this.pos = 0;
this.len = 0;
this.release_asm();
return this;
}
}
const _sha1_block_size = 64;
const _sha1_hash_size = 20;
const heap_pool$1 = [];
const asm_pool$1 = [];
class Sha1 extends Hash {
constructor() {
super();
this.NAME = 'sha1';
this.BLOCK_SIZE = _sha1_block_size;
this.HASH_SIZE = _sha1_hash_size;
this.acquire_asm();
}
acquire_asm() {
if (this.heap === undefined || this.asm === undefined) {
this.heap = heap_pool$1.pop() || _heap_init();
this.asm = asm_pool$1.pop() || sha1_asm({ Uint8Array: Uint8Array }, null, this.heap.buffer);
this.reset();
}
return { heap: this.heap, asm: this.asm };
}
release_asm() {
if (this.heap !== undefined && this.asm !== undefined) {
heap_pool$1.push(this.heap);
asm_pool$1.push(this.asm);
}
this.heap = undefined;
this.asm = undefined;
}
static bytes(data) {
return new Sha1().process(data).finish().result;
}
}
Sha1.NAME = 'sha1';
Sha1.heap_pool = [];
Sha1.asm_pool = [];
Sha1.asm_function = sha1_asm;
var sha256_asm = function ( stdlib, foreign, buffer ) {
"use asm";
// SHA256 state
var H0 = 0, H1 = 0, H2 = 0, H3 = 0, H4 = 0, H5 = 0, H6 = 0, H7 = 0,
TOTAL0 = 0, TOTAL1 = 0;
// HMAC state
var I0 = 0, I1 = 0, I2 = 0, I3 = 0, I4 = 0, I5 = 0, I6 = 0, I7 = 0,
O0 = 0, O1 = 0, O2 = 0, O3 = 0, O4 = 0, O5 = 0, O6 = 0, O7 = 0;
// I/O buffer
var HEAP = new stdlib.Uint8Array(buffer);
function _core ( w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15 ) {
w0 = w0|0;
w1 = w1|0;
w2 = w2|0;
w3 = w3|0;
w4 = w4|0;
w5 = w5|0;
w6 = w6|0;
w7 = w7|0;
w8 = w8|0;
w9 = w9|0;
w10 = w10|0;
w11 = w11|0;
w12 = w12|0;
w13 = w13|0;
w14 = w14|0;
w15 = w15|0;
var a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0;
a = H0;
b = H1;
c = H2;
d = H3;
e = H4;
f = H5;
g = H6;
h = H7;
// 0
h = ( w0 + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x428a2f98 )|0;
d = ( d + h )|0;
h = ( h + ( (a & b) ^ ( c & (a ^ b) ) ) + ( a>>>2 ^ a>>>13 ^ a>>>22 ^ a<<30 ^ a<<19 ^ a<<10 ) )|0;
// 1
g = ( w1 + g + ( d>>>6 ^ d>>>11 ^ d>>>25 ^ d<<26 ^ d<<21 ^ d<<7 ) + ( f ^ d & (e^f) ) + 0x71374491 )|0;
c = ( c + g )|0;
g = ( g + ( (h & a) ^ ( b & (h ^ a) ) ) + ( h>>>2 ^ h>>>13 ^ h>>>22 ^ h<<30 ^ h<<19 ^ h<<10 ) )|0;
// 2
f = ( w2 + f + ( c>>>6 ^ c>>>11 ^ c>>>25 ^ c<<26 ^ c<<21 ^ c<<7 ) + ( e ^ c & (d^e) ) + 0xb5c0fbcf )|0;
b = ( b + f )|0;
f = ( f + ( (g & h) ^ ( a & (g ^ h) ) ) + ( g>>>2 ^ g>>>13 ^ g>>>22 ^ g<<30 ^ g<<19 ^ g<<10 ) )|0;
// 3
e = ( w3 + e + ( b>>>6 ^ b>>>11 ^ b>>>25 ^ b<<26 ^ b<<21 ^ b<<7 ) + ( d ^ b & (c^d) ) + 0xe9b5dba5 )|0;
a = ( a + e )|0;
e = ( e + ( (f & g) ^ ( h & (f ^ g) ) ) + ( f>>>2 ^ f>>>13 ^ f>>>22 ^ f<<30 ^ f<<19 ^ f<<10 ) )|0;
// 4
d = ( w4 + d + ( a>>>6 ^ a>>>11 ^ a>>>25 ^ a<<26 ^ a<<21 ^ a<<7 ) + ( c ^ a & (b^c) ) + 0x3956c25b )|0;
h = ( h + d )|0;
d = ( d + ( (e & f) ^ ( g & (e ^ f) ) ) + ( e>>>2 ^ e>>>13 ^ e>>>22 ^ e<<30 ^ e<<19 ^ e<<10 ) )|0;
// 5
c = ( w5 + c + ( h>>>6 ^ h>>>11 ^ h>>>25 ^ h<<26 ^ h<<21 ^ h<<7 ) + ( b ^ h & (a^b) ) + 0x59f111f1 )|0;
g = ( g + c )|0;
c = ( c + ( (d & e) ^ ( f & (d ^ e) ) ) + ( d>>>2 ^ d>>>13 ^ d>>>22 ^ d<<30 ^ d<<19 ^ d<<10 ) )|0;
// 6
b = ( w6 + b + ( g>>>6 ^ g>>>11 ^ g>>>25 ^ g<<26 ^ g<<21 ^ g<<7 ) + ( a ^ g & (h^a) ) + 0x923f82a4 )|0;
f = ( f + b )|0;
b = ( b + ( (c & d) ^ ( e & (c ^ d) ) ) + ( c>>>2 ^ c>>>13 ^ c>>>22 ^ c<<30 ^ c<<19 ^ c<<10 ) )|0;
// 7
a = ( w7 + a + ( f>>>6 ^ f>>>11 ^ f>>>25 ^ f<<26 ^ f<<21 ^ f<<7 ) + ( h ^ f & (g^h) ) + 0xab1c5ed5 )|0;
e = ( e + a )|0;
a = ( a + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 8
h = ( w8 + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0xd807aa98 )|0;
d = ( d + h )|0;
h = ( h + ( (a & b) ^ ( c & (a ^ b) ) ) + ( a>>>2 ^ a>>>13 ^ a>>>22 ^ a<<30 ^ a<<19 ^ a<<10 ) )|0;
// 9
g = ( w9 + g + ( d>>>6 ^ d>>>11 ^ d>>>25 ^ d<<26 ^ d<<21 ^ d<<7 ) + ( f ^ d & (e^f) ) + 0x12835b01 )|0;
c = ( c + g )|0;
g = ( g + ( (h & a) ^ ( b & (h ^ a) ) ) + ( h>>>2 ^ h>>>13 ^ h>>>22 ^ h<<30 ^ h<<19 ^ h<<10 ) )|0;
// 10
f = ( w10 + f + ( c>>>6 ^ c>>>11 ^ c>>>25 ^ c<<26 ^ c<<21 ^ c<<7 ) + ( e ^ c & (d^e) ) + 0x243185be )|0;
b = ( b + f )|0;
f = ( f + ( (g & h) ^ ( a & (g ^ h) ) ) + ( g>>>2 ^ g>>>13 ^ g>>>22 ^ g<<30 ^ g<<19 ^ g<<10 ) )|0;
// 11
e = ( w11 + e + ( b>>>6 ^ b>>>11 ^ b>>>25 ^ b<<26 ^ b<<21 ^ b<<7 ) + ( d ^ b & (c^d) ) + 0x550c7dc3 )|0;
a = ( a + e )|0;
e = ( e + ( (f & g) ^ ( h & (f ^ g) ) ) + ( f>>>2 ^ f>>>13 ^ f>>>22 ^ f<<30 ^ f<<19 ^ f<<10 ) )|0;
// 12
d = ( w12 + d + ( a>>>6 ^ a>>>11 ^ a>>>25 ^ a<<26 ^ a<<21 ^ a<<7 ) + ( c ^ a & (b^c) ) + 0x72be5d74 )|0;
h = ( h + d )|0;
d = ( d + ( (e & f) ^ ( g & (e ^ f) ) ) + ( e>>>2 ^ e>>>13 ^ e>>>22 ^ e<<30 ^ e<<19 ^ e<<10 ) )|0;
// 13
c = ( w13 + c + ( h>>>6 ^ h>>>11 ^ h>>>25 ^ h<<26 ^ h<<21 ^ h<<7 ) + ( b ^ h & (a^b) ) + 0x80deb1fe )|0;
g = ( g + c )|0;
c = ( c + ( (d & e) ^ ( f & (d ^ e) ) ) + ( d>>>2 ^ d>>>13 ^ d>>>22 ^ d<<30 ^ d<<19 ^ d<<10 ) )|0;
// 14
b = ( w14 + b + ( g>>>6 ^ g>>>11 ^ g>>>25 ^ g<<26 ^ g<<21 ^ g<<7 ) + ( a ^ g & (h^a) ) + 0x9bdc06a7 )|0;
f = ( f + b )|0;
b = ( b + ( (c & d) ^ ( e & (c ^ d) ) ) + ( c>>>2 ^ c>>>13 ^ c>>>22 ^ c<<30 ^ c<<19 ^ c<<10 ) )|0;
// 15
a = ( w15 + a + ( f>>>6 ^ f>>>11 ^ f>>>25 ^ f<<26 ^ f<<21 ^ f<<7 ) + ( h ^ f & (g^h) ) + 0xc19bf174 )|0;
e = ( e + a )|0;
a = ( a + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 16
w0 = ( ( w1>>>7 ^ w1>>>18 ^ w1>>>3 ^ w1<<25 ^ w1<<14 ) + ( w14>>>17 ^ w14>>>19 ^ w14>>>10 ^ w14<<15 ^ w14<<13 ) + w0 + w9 )|0;
h = ( w0 + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0xe49b69c1 )|0;
d = ( d + h )|0;
h = ( h + ( (a & b) ^ ( c & (a ^ b) ) ) + ( a>>>2 ^ a>>>13 ^ a>>>22 ^ a<<30 ^ a<<19 ^ a<<10 ) )|0;
// 17
w1 = ( ( w2>>>7 ^ w2>>>18 ^ w2>>>3 ^ w2<<25 ^ w2<<14 ) + ( w15>>>17 ^ w15>>>19 ^ w15>>>10 ^ w15<<15 ^ w15<<13 ) + w1 + w10 )|0;
g = ( w1 + g + ( d>>>6 ^ d>>>11 ^ d>>>25 ^ d<<26 ^ d<<21 ^ d<<7 ) + ( f ^ d & (e^f) ) + 0xefbe4786 )|0;
c = ( c + g )|0;
g = ( g + ( (h & a) ^ ( b & (h ^ a) ) ) + ( h>>>2 ^ h>>>13 ^ h>>>22 ^ h<<30 ^ h<<19 ^ h<<10 ) )|0;
// 18
w2 = ( ( w3>>>7 ^ w3>>>18 ^ w3>>>3 ^ w3<<25 ^ w3<<14 ) + ( w0>>>17 ^ w0>>>19 ^ w0>>>10 ^ w0<<15 ^ w0<<13 ) + w2 + w11 )|0;
f = ( w2 + f + ( c>>>6 ^ c>>>11 ^ c>>>25 ^ c<<26 ^ c<<21 ^ c<<7 ) + ( e ^ c & (d^e) ) + 0x0fc19dc6 )|0;
b = ( b + f )|0;
f = ( f + ( (g & h) ^ ( a & (g ^ h) ) ) + ( g>>>2 ^ g>>>13 ^ g>>>22 ^ g<<30 ^ g<<19 ^ g<<10 ) )|0;
// 19
w3 = ( ( w4>>>7 ^ w4>>>18 ^ w4>>>3 ^ w4<<25 ^ w4<<14 ) + ( w1>>>17 ^ w1>>>19 ^ w1>>>10 ^ w1<<15 ^ w1<<13 ) + w3 + w12 )|0;
e = ( w3 + e + ( b>>>6 ^ b>>>11 ^ b>>>25 ^ b<<26 ^ b<<21 ^ b<<7 ) + ( d ^ b & (c^d) ) + 0x240ca1cc )|0;
a = ( a + e )|0;
e = ( e + ( (f & g) ^ ( h & (f ^ g) ) ) + ( f>>>2 ^ f>>>13 ^ f>>>22 ^ f<<30 ^ f<<19 ^ f<<10 ) )|0;
// 20
w4 = ( ( w5>>>7 ^ w5>>>18 ^ w5>>>3 ^ w5<<25 ^ w5<<14 ) + ( w2>>>17 ^ w2>>>19 ^ w2>>>10 ^ w2<<15 ^ w2<<13 ) + w4 + w13 )|0;
d = ( w4 + d + ( a>>>6 ^ a>>>11 ^ a>>>25 ^ a<<26 ^ a<<21 ^ a<<7 ) + ( c ^ a & (b^c) ) + 0x2de92c6f )|0;
h = ( h + d )|0;
d = ( d + ( (e & f) ^ ( g & (e ^ f) ) ) + ( e>>>2 ^ e>>>13 ^ e>>>22 ^ e<<30 ^ e<<19 ^ e<<10 ) )|0;
// 21
w5 = ( ( w6>>>7 ^ w6>>>18 ^ w6>>>3 ^ w6<<25 ^ w6<<14 ) + ( w3>>>17 ^ w3>>>19 ^ w3>>>10 ^ w3<<15 ^ w3<<13 ) + w5 + w14 )|0;
c = ( w5 + c + ( h>>>6 ^ h>>>11 ^ h>>>25 ^ h<<26 ^ h<<21 ^ h<<7 ) + ( b ^ h & (a^b) ) + 0x4a7484aa )|0;
g = ( g + c )|0;
c = ( c + ( (d & e) ^ ( f & (d ^ e) ) ) + ( d>>>2 ^ d>>>13 ^ d>>>22 ^ d<<30 ^ d<<19 ^ d<<10 ) )|0;
// 22
w6 = ( ( w7>>>7 ^ w7>>>18 ^ w7>>>3 ^ w7<<25 ^ w7<<14 ) + ( w4>>>17 ^ w4>>>19 ^ w4>>>10 ^ w4<<15 ^ w4<<13 ) + w6 + w15 )|0;
b = ( w6 + b + ( g>>>6 ^ g>>>11 ^ g>>>25 ^ g<<26 ^ g<<21 ^ g<<7 ) + ( a ^ g & (h^a) ) + 0x5cb0a9dc )|0;
f = ( f + b )|0;
b = ( b + ( (c & d) ^ ( e & (c ^ d) ) ) + ( c>>>2 ^ c>>>13 ^ c>>>22 ^ c<<30 ^ c<<19 ^ c<<10 ) )|0;
// 23
w7 = ( ( w8>>>7 ^ w8>>>18 ^ w8>>>3 ^ w8<<25 ^ w8<<14 ) + ( w5>>>17 ^ w5>>>19 ^ w5>>>10 ^ w5<<15 ^ w5<<13 ) + w7 + w0 )|0;
a = ( w7 + a + ( f>>>6 ^ f>>>11 ^ f>>>25 ^ f<<26 ^ f<<21 ^ f<<7 ) + ( h ^ f & (g^h) ) + 0x76f988da )|0;
e = ( e + a )|0;
a = ( a + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 24
w8 = ( ( w9>>>7 ^ w9>>>18 ^ w9>>>3 ^ w9<<25 ^ w9<<14 ) + ( w6>>>17 ^ w6>>>19 ^ w6>>>10 ^ w6<<15 ^ w6<<13 ) + w8 + w1 )|0;
h = ( w8 + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x983e5152 )|0;
d = ( d + h )|0;
h = ( h + ( (a & b) ^ ( c & (a ^ b) ) ) + ( a>>>2 ^ a>>>13 ^ a>>>22 ^ a<<30 ^ a<<19 ^ a<<10 ) )|0;
// 25
w9 = ( ( w10>>>7 ^ w10>>>18 ^ w10>>>3 ^ w10<<25 ^ w10<<14 ) + ( w7>>>17 ^ w7>>>19 ^ w7>>>10 ^ w7<<15 ^ w7<<13 ) + w9 + w2 )|0;
g = ( w9 + g + ( d>>>6 ^ d>>>11 ^ d>>>25 ^ d<<26 ^ d<<21 ^ d<<7 ) + ( f ^ d & (e^f) ) + 0xa831c66d )|0;
c = ( c + g )|0;
g = ( g + ( (h & a) ^ ( b & (h ^ a) ) ) + ( h>>>2 ^ h>>>13 ^ h>>>22 ^ h<<30 ^ h<<19 ^ h<<10 ) )|0;
// 26
w10 = ( ( w11>>>7 ^ w11>>>18 ^ w11>>>3 ^ w11<<25 ^ w11<<14 ) + ( w8>>>17 ^ w8>>>19 ^ w8>>>10 ^ w8<<15 ^ w8<<13 ) + w10 + w3 )|0;
f = ( w10 + f + ( c>>>6 ^ c>>>11 ^ c>>>25 ^ c<<26 ^ c<<21 ^ c<<7 ) + ( e ^ c & (d^e) ) + 0xb00327c8 )|0;
b = ( b + f )|0;
f = ( f + ( (g & h) ^ ( a & (g ^ h) ) ) + ( g>>>2 ^ g>>>13 ^ g>>>22 ^ g<<30 ^ g<<19 ^ g<<10 ) )|0;
// 27
w11 = ( ( w12>>>7 ^ w12>>>18 ^ w12>>>3 ^ w12<<25 ^ w12<<14 ) + ( w9>>>17 ^ w9>>>19 ^ w9>>>10 ^ w9<<15 ^ w9<<13 ) + w11 + w4 )|0;
e = ( w11 + e + ( b>>>6 ^ b>>>11 ^ b>>>25 ^ b<<26 ^ b<<21 ^ b<<7 ) + ( d ^ b & (c^d) ) + 0xbf597fc7 )|0;
a = ( a + e )|0;
e = ( e + ( (f & g) ^ ( h & (f ^ g) ) ) + ( f>>>2 ^ f>>>13 ^ f>>>22 ^ f<<30 ^ f<<19 ^ f<<10 ) )|0;
// 28
w12 = ( ( w13>>>7 ^ w13>>>18 ^ w13>>>3 ^ w13<<25 ^ w13<<14 ) + ( w10>>>17 ^ w10>>>19 ^ w10>>>10 ^ w10<<15 ^ w10<<13 ) + w12 + w5 )|0;
d = ( w12 + d + ( a>>>6 ^ a>>>11 ^ a>>>25 ^ a<<26 ^ a<<21 ^ a<<7 ) + ( c ^ a & (b^c) ) + 0xc6e00bf3 )|0;
h = ( h + d )|0;
d = ( d + ( (e & f) ^ ( g & (e ^ f) ) ) + ( e>>>2 ^ e>>>13 ^ e>>>22 ^ e<<30 ^ e<<19 ^ e<<10 ) )|0;
// 29
w13 = ( ( w14>>>7 ^ w14>>>18 ^ w14>>>3 ^ w14<<25 ^ w14<<14 ) + ( w11>>>17 ^ w11>>>19 ^ w11>>>10 ^ w11<<15 ^ w11<<13 ) + w13 + w6 )|0;
c = ( w13 + c + ( h>>>6 ^ h>>>11 ^ h>>>25 ^ h<<26 ^ h<<21 ^ h<<7 ) + ( b ^ h & (a^b) ) + 0xd5a79147 )|0;
g = ( g + c )|0;
c = ( c + ( (d & e) ^ ( f & (d ^ e) ) ) + ( d>>>2 ^ d>>>13 ^ d>>>22 ^ d<<30 ^ d<<19 ^ d<<10 ) )|0;
// 30
w14 = ( ( w15>>>7 ^ w15>>>18 ^ w15>>>3 ^ w15<<25 ^ w15<<14 ) + ( w12>>>17 ^ w12>>>19 ^ w12>>>10 ^ w12<<15 ^ w12<<13 ) + w14 + w7 )|0;
b = ( w14 + b + ( g>>>6 ^ g>>>11 ^ g>>>25 ^ g<<26 ^ g<<21 ^ g<<7 ) + ( a ^ g & (h^a) ) + 0x06ca6351 )|0;
f = ( f + b )|0;
b = ( b + ( (c & d) ^ ( e & (c ^ d) ) ) + ( c>>>2 ^ c>>>13 ^ c>>>22 ^ c<<30 ^ c<<19 ^ c<<10 ) )|0;
// 31
w15 = ( ( w0>>>7 ^ w0>>>18 ^ w0>>>3 ^ w0<<25 ^ w0<<14 ) + ( w13>>>17 ^ w13>>>19 ^ w13>>>10 ^ w13<<15 ^ w13<<13 ) + w15 + w8 )|0;
a = ( w15 + a + ( f>>>6 ^ f>>>11 ^ f>>>25 ^ f<<26 ^ f<<21 ^ f<<7 ) + ( h ^ f & (g^h) ) + 0x14292967 )|0;
e = ( e + a )|0;
a = ( a + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 32
w0 = ( ( w1>>>7 ^ w1>>>18 ^ w1>>>3 ^ w1<<25 ^ w1<<14 ) + ( w14>>>17 ^ w14>>>19 ^ w14>>>10 ^ w14<<15 ^ w14<<13 ) + w0 + w9 )|0;
h = ( w0 + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x27b70a85 )|0;
d = ( d + h )|0;
h = ( h + ( (a & b) ^ ( c & (a ^ b) ) ) + ( a>>>2 ^ a>>>13 ^ a>>>22 ^ a<<30 ^ a<<19 ^ a<<10 ) )|0;
// 33
w1 = ( ( w2>>>7 ^ w2>>>18 ^ w2>>>3 ^ w2<<25 ^ w2<<14 ) + ( w15>>>17 ^ w15>>>19 ^ w15>>>10 ^ w15<<15 ^ w15<<13 ) + w1 + w10 )|0;
g = ( w1 + g + ( d>>>6 ^ d>>>11 ^ d>>>25 ^ d<<26 ^ d<<21 ^ d<<7 ) + ( f ^ d & (e^f) ) + 0x2e1b2138 )|0;
c = ( c + g )|0;
g = ( g + ( (h & a) ^ ( b & (h ^ a) ) ) + ( h>>>2 ^ h>>>13 ^ h>>>22 ^ h<<30 ^ h<<19 ^ h<<10 ) )|0;
// 34
w2 = ( ( w3>>>7 ^ w3>>>18 ^ w3>>>3 ^ w3<<25 ^ w3<<14 ) + ( w0>>>17 ^ w0>>>19 ^ w0>>>10 ^ w0<<15 ^ w0<<13 ) + w2 + w11 )|0;
f = ( w2 + f + ( c>>>6 ^ c>>>11 ^ c>>>25 ^ c<<26 ^ c<<21 ^ c<<7 ) + ( e ^ c & (d^e) ) + 0x4d2c6dfc )|0;
b = ( b + f )|0;
f = ( f + ( (g & h) ^ ( a & (g ^ h) ) ) + ( g>>>2 ^ g>>>13 ^ g>>>22 ^ g<<30 ^ g<<19 ^ g<<10 ) )|0;
// 35
w3 = ( ( w4>>>7 ^ w4>>>18 ^ w4>>>3 ^ w4<<25 ^ w4<<14 ) + ( w1>>>17 ^ w1>>>19 ^ w1>>>10 ^ w1<<15 ^ w1<<13 ) + w3 + w12 )|0;
e = ( w3 + e + ( b>>>6 ^ b>>>11 ^ b>>>25 ^ b<<26 ^ b<<21 ^ b<<7 ) + ( d ^ b & (c^d) ) + 0x53380d13 )|0;
a = ( a + e )|0;
e = ( e + ( (f & g) ^ ( h & (f ^ g) ) ) + ( f>>>2 ^ f>>>13 ^ f>>>22 ^ f<<30 ^ f<<19 ^ f<<10 ) )|0;
// 36
w4 = ( ( w5>>>7 ^ w5>>>18 ^ w5>>>3 ^ w5<<25 ^ w5<<14 ) + ( w2>>>17 ^ w2>>>19 ^ w2>>>10 ^ w2<<15 ^ w2<<13 ) + w4 + w13 )|0;
d = ( w4 + d + ( a>>>6 ^ a>>>11 ^ a>>>25 ^ a<<26 ^ a<<21 ^ a<<7 ) + ( c ^ a & (b^c) ) + 0x650a7354 )|0;
h = ( h + d )|0;
d = ( d + ( (e & f) ^ ( g & (e ^ f) ) ) + ( e>>>2 ^ e>>>13 ^ e>>>22 ^ e<<30 ^ e<<19 ^ e<<10 ) )|0;
// 37
w5 = ( ( w6>>>7 ^ w6>>>18 ^ w6>>>3 ^ w6<<25 ^ w6<<14 ) + ( w3>>>17 ^ w3>>>19 ^ w3>>>10 ^ w3<<15 ^ w3<<13 ) + w5 + w14 )|0;
c = ( w5 + c + ( h>>>6 ^ h>>>11 ^ h>>>25 ^ h<<26 ^ h<<21 ^ h<<7 ) + ( b ^ h & (a^b) ) + 0x766a0abb )|0;
g = ( g + c )|0;
c = ( c + ( (d & e) ^ ( f & (d ^ e) ) ) + ( d>>>2 ^ d>>>13 ^ d>>>22 ^ d<<30 ^ d<<19 ^ d<<10 ) )|0;
// 38
w6 = ( ( w7>>>7 ^ w7>>>18 ^ w7>>>3 ^ w7<<25 ^ w7<<14 ) + ( w4>>>17 ^ w4>>>19 ^ w4>>>10 ^ w4<<15 ^ w4<<13 ) + w6 + w15 )|0;
b = ( w6 + b + ( g>>>6 ^ g>>>11 ^ g>>>25 ^ g<<26 ^ g<<21 ^ g<<7 ) + ( a ^ g & (h^a) ) + 0x81c2c92e )|0;
f = ( f + b )|0;
b = ( b + ( (c & d) ^ ( e & (c ^ d) ) ) + ( c>>>2 ^ c>>>13 ^ c>>>22 ^ c<<30 ^ c<<19 ^ c<<10 ) )|0;
// 39
w7 = ( ( w8>>>7 ^ w8>>>18 ^ w8>>>3 ^ w8<<25 ^ w8<<14 ) + ( w5>>>17 ^ w5>>>19 ^ w5>>>10 ^ w5<<15 ^ w5<<13 ) + w7 + w0 )|0;
a = ( w7 + a + ( f>>>6 ^ f>>>11 ^ f>>>25 ^ f<<26 ^ f<<21 ^ f<<7 ) + ( h ^ f & (g^h) ) + 0x92722c85 )|0;
e = ( e + a )|0;
a = ( a + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 40
w8 = ( ( w9>>>7 ^ w9>>>18 ^ w9>>>3 ^ w9<<25 ^ w9<<14 ) + ( w6>>>17 ^ w6>>>19 ^ w6>>>10 ^ w6<<15 ^ w6<<13 ) + w8 + w1 )|0;
h = ( w8 + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0xa2bfe8a1 )|0;
d = ( d + h )|0;
h = ( h + ( (a & b) ^ ( c & (a ^ b) ) ) + ( a>>>2 ^ a>>>13 ^ a>>>22 ^ a<<30 ^ a<<19 ^ a<<10 ) )|0;
// 41
w9 = ( ( w10>>>7 ^ w10>>>18 ^ w10>>>3 ^ w10<<25 ^ w10<<14 ) + ( w7>>>17 ^ w7>>>19 ^ w7>>>10 ^ w7<<15 ^ w7<<13 ) + w9 + w2 )|0;
g = ( w9 + g + ( d>>>6 ^ d>>>11 ^ d>>>25 ^ d<<26 ^ d<<21 ^ d<<7 ) + ( f ^ d & (e^f) ) + 0xa81a664b )|0;
c = ( c + g )|0;
g = ( g + ( (h & a) ^ ( b & (h ^ a) ) ) + ( h>>>2 ^ h>>>13 ^ h>>>22 ^ h<<30 ^ h<<19 ^ h<<10 ) )|0;
// 42
w10 = ( ( w11>>>7 ^ w11>>>18 ^ w11>>>3 ^ w11<<25 ^ w11<<14 ) + ( w8>>>17 ^ w8>>>19 ^ w8>>>10 ^ w8<<15 ^ w8<<13 ) + w10 + w3 )|0;
f = ( w10 + f + ( c>>>6 ^ c>>>11 ^ c>>>25 ^ c<<26 ^ c<<21 ^ c<<7 ) + ( e ^ c & (d^e) ) + 0xc24b8b70 )|0;
b = ( b + f )|0;
f = ( f + ( (g & h) ^ ( a & (g ^ h) ) ) + ( g>>>2 ^ g>>>13 ^ g>>>22 ^ g<<30 ^ g<<19 ^ g<<10 ) )|0;
// 43
w11 = ( ( w12>>>7 ^ w12>>>18 ^ w12>>>3 ^ w12<<25 ^ w12<<14 ) + ( w9>>>17 ^ w9>>>19 ^ w9>>>10 ^ w9<<15 ^ w9<<13 ) + w11 + w4 )|0;
e = ( w11 + e + ( b>>>6 ^ b>>>11 ^ b>>>25 ^ b<<26 ^ b<<21 ^ b<<7 ) + ( d ^ b & (c^d) ) + 0xc76c51a3 )|0;
a = ( a + e )|0;
e = ( e + ( (f & g) ^ ( h & (f ^ g) ) ) + ( f>>>2 ^ f>>>13 ^ f>>>22 ^ f<<30 ^ f<<19 ^ f<<10 ) )|0;
// 44
w12 = ( ( w13>>>7 ^ w13>>>18 ^ w13>>>3 ^ w13<<25 ^ w13<<14 ) + ( w10>>>17 ^ w10>>>19 ^ w10>>>10 ^ w10<<15 ^ w10<<13 ) + w12 + w5 )|0;
d = ( w12 + d + ( a>>>6 ^ a>>>11 ^ a>>>25 ^ a<<26 ^ a<<21 ^ a<<7 ) + ( c ^ a & (b^c) ) + 0xd192e819 )|0;
h = ( h + d )|0;
d = ( d + ( (e & f) ^ ( g & (e ^ f) ) ) + ( e>>>2 ^ e>>>13 ^ e>>>22 ^ e<<30 ^ e<<19 ^ e<<10 ) )|0;
// 45
w13 = ( ( w14>>>7 ^ w14>>>18 ^ w14>>>3 ^ w14<<25 ^ w14<<14 ) + ( w11>>>17 ^ w11>>>19 ^ w11>>>10 ^ w11<<15 ^ w11<<13 ) + w13 + w6 )|0;
c = ( w13 + c + ( h>>>6 ^ h>>>11 ^ h>>>25 ^ h<<26 ^ h<<21 ^ h<<7 ) + ( b ^ h & (a^b) ) + 0xd6990624 )|0;
g = ( g + c )|0;
c = ( c + ( (d & e) ^ ( f & (d ^ e) ) ) + ( d>>>2 ^ d>>>13 ^ d>>>22 ^ d<<30 ^ d<<19 ^ d<<10 ) )|0;
// 46
w14 = ( ( w15>>>7 ^ w15>>>18 ^ w15>>>3 ^ w15<<25 ^ w15<<14 ) + ( w12>>>17 ^ w12>>>19 ^ w12>>>10 ^ w12<<15 ^ w12<<13 ) + w14 + w7 )|0;
b = ( w14 + b + ( g>>>6 ^ g>>>11 ^ g>>>25 ^ g<<26 ^ g<<21 ^ g<<7 ) + ( a ^ g & (h^a) ) + 0xf40e3585 )|0;
f = ( f + b )|0;
b = ( b + ( (c & d) ^ ( e & (c ^ d) ) ) + ( c>>>2 ^ c>>>13 ^ c>>>22 ^ c<<30 ^ c<<19 ^ c<<10 ) )|0;
// 47
w15 = ( ( w0>>>7 ^ w0>>>18 ^ w0>>>3 ^ w0<<25 ^ w0<<14 ) + ( w13>>>17 ^ w13>>>19 ^ w13>>>10 ^ w13<<15 ^ w13<<13 ) + w15 + w8 )|0;
a = ( w15 + a + ( f>>>6 ^ f>>>11 ^ f>>>25 ^ f<<26 ^ f<<21 ^ f<<7 ) + ( h ^ f & (g^h) ) + 0x106aa070 )|0;
e = ( e + a )|0;
a = ( a + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 48
w0 = ( ( w1>>>7 ^ w1>>>18 ^ w1>>>3 ^ w1<<25 ^ w1<<14 ) + ( w14>>>17 ^ w14>>>19 ^ w14>>>10 ^ w14<<15 ^ w14<<13 ) + w0 + w9 )|0;
h = ( w0 + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x19a4c116 )|0;
d = ( d + h )|0;
h = ( h + ( (a & b) ^ ( c & (a ^ b) ) ) + ( a>>>2 ^ a>>>13 ^ a>>>22 ^ a<<30 ^ a<<19 ^ a<<10 ) )|0;
// 49
w1 = ( ( w2>>>7 ^ w2>>>18 ^ w2>>>3 ^ w2<<25 ^ w2<<14 ) + ( w15>>>17 ^ w15>>>19 ^ w15>>>10 ^ w15<<15 ^ w15<<13 ) + w1 + w10 )|0;
g = ( w1 + g + ( d>>>6 ^ d>>>11 ^ d>>>25 ^ d<<26 ^ d<<21 ^ d<<7 ) + ( f ^ d & (e^f) ) + 0x1e376c08 )|0;
c = ( c + g )|0;
g = ( g + ( (h & a) ^ ( b & (h ^ a) ) ) + ( h>>>2 ^ h>>>13 ^ h>>>22 ^ h<<30 ^ h<<19 ^ h<<10 ) )|0;
// 50
w2 = ( ( w3>>>7 ^ w3>>>18 ^ w3>>>3 ^ w3<<25 ^ w3<<14 ) + ( w0>>>17 ^ w0>>>19 ^ w0>>>10 ^ w0<<15 ^ w0<<13 ) + w2 + w11 )|0;
f = ( w2 + f + ( c>>>6 ^ c>>>11 ^ c>>>25 ^ c<<26 ^ c<<21 ^ c<<7 ) + ( e ^ c & (d^e) ) + 0x2748774c )|0;
b = ( b + f )|0;
f = ( f + ( (g & h) ^ ( a & (g ^ h) ) ) + ( g>>>2 ^ g>>>13 ^ g>>>22 ^ g<<30 ^ g<<19 ^ g<<10 ) )|0;
// 51
w3 = ( ( w4>>>7 ^ w4>>>18 ^ w4>>>3 ^ w4<<25 ^ w4<<14 ) + ( w1>>>17 ^ w1>>>19 ^ w1>>>10 ^ w1<<15 ^ w1<<13 ) + w3 + w12 )|0;
e = ( w3 + e + ( b>>>6 ^ b>>>11 ^ b>>>25 ^ b<<26 ^ b<<21 ^ b<<7 ) + ( d ^ b & (c^d) ) + 0x34b0bcb5 )|0;
a = ( a + e )|0;
e = ( e + ( (f & g) ^ ( h & (f ^ g) ) ) + ( f>>>2 ^ f>>>13 ^ f>>>22 ^ f<<30 ^ f<<19 ^ f<<10 ) )|0;
// 52
w4 = ( ( w5>>>7 ^ w5>>>18 ^ w5>>>3 ^ w5<<25 ^ w5<<14 ) + ( w2>>>17 ^ w2>>>19 ^ w2>>>10 ^ w2<<15 ^ w2<<13 ) + w4 + w13 )|0;
d = ( w4 + d + ( a>>>6 ^ a>>>11 ^ a>>>25 ^ a<<26 ^ a<<21 ^ a<<7 ) + ( c ^ a & (b^c) ) + 0x391c0cb3 )|0;
h = ( h + d )|0;
d = ( d + ( (e & f) ^ ( g & (e ^ f) ) ) + ( e>>>2 ^ e>>>13 ^ e>>>22 ^ e<<30 ^ e<<19 ^ e<<10 ) )|0;
// 53
w5 = ( ( w6>>>7 ^ w6>>>18 ^ w6>>>3 ^ w6<<25 ^ w6<<14 ) + ( w3>>>17 ^ w3>>>19 ^ w3>>>10 ^ w3<<15 ^ w3<<13 ) + w5 + w14 )|0;
c = ( w5 + c + ( h>>>6 ^ h>>>11 ^ h>>>25 ^ h<<26 ^ h<<21 ^ h<<7 ) + ( b ^ h & (a^b) ) + 0x4ed8aa4a )|0;
g = ( g + c )|0;
c = ( c + ( (d & e) ^ ( f & (d ^ e) ) ) + ( d>>>2 ^ d>>>13 ^ d>>>22 ^ d<<30 ^ d<<19 ^ d<<10 ) )|0;
// 54
w6 = ( ( w7>>>7 ^ w7>>>18 ^ w7>>>3 ^ w7<<25 ^ w7<<14 ) + ( w4>>>17 ^ w4>>>19 ^ w4>>>10 ^ w4<<15 ^ w4<<13 ) + w6 + w15 )|0;
b = ( w6 + b + ( g>>>6 ^ g>>>11 ^ g>>>25 ^ g<<26 ^ g<<21 ^ g<<7 ) + ( a ^ g & (h^a) ) + 0x5b9cca4f )|0;
f = ( f + b )|0;
b = ( b + ( (c & d) ^ ( e & (c ^ d) ) ) + ( c>>>2 ^ c>>>13 ^ c>>>22 ^ c<<30 ^ c<<19 ^ c<<10 ) )|0;
// 55
w7 = ( ( w8>>>7 ^ w8>>>18 ^ w8>>>3 ^ w8<<25 ^ w8<<14 ) + ( w5>>>17 ^ w5>>>19 ^ w5>>>10 ^ w5<<15 ^ w5<<13 ) + w7 + w0 )|0;
a = ( w7 + a + ( f>>>6 ^ f>>>11 ^ f>>>25 ^ f<<26 ^ f<<21 ^ f<<7 ) + ( h ^ f & (g^h) ) + 0x682e6ff3 )|0;
e = ( e + a )|0;
a = ( a + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
// 56
w8 = ( ( w9>>>7 ^ w9>>>18 ^ w9>>>3 ^ w9<<25 ^ w9<<14 ) + ( w6>>>17 ^ w6>>>19 ^ w6>>>10 ^ w6<<15 ^ w6<<13 ) + w8 + w1 )|0;
h = ( w8 + h + ( e>>>6 ^ e>>>11 ^ e>>>25 ^ e<<26 ^ e<<21 ^ e<<7 ) + ( g ^ e & (f^g) ) + 0x748f82ee )|0;
d = ( d + h )|0;
h = ( h + ( (a & b) ^ ( c & (a ^ b) ) ) + ( a>>>2 ^ a>>>13 ^ a>>>22 ^ a<<30 ^ a<<19 ^ a<<10 ) )|0;
// 57
w9 = ( ( w10>>>7 ^ w10>>>18 ^ w10>>>3 ^ w10<<25 ^ w10<<14 ) + ( w7>>>17 ^ w7>>>19 ^ w7>>>10 ^ w7<<15 ^ w7<<13 ) + w9 + w2 )|0;
g = ( w9 + g + ( d>>>6 ^ d>>>11 ^ d>>>25 ^ d<<26 ^ d<<21 ^ d<<7 ) + ( f ^ d & (e^f) ) + 0x78a5636f )|0;
c = ( c + g )|0;
g = ( g + ( (h & a) ^ ( b & (h ^ a) ) ) + ( h>>>2 ^ h>>>13 ^ h>>>22 ^ h<<30 ^ h<<19 ^ h<<10 ) )|0;
// 58
w10 = ( ( w11>>>7 ^ w11>>>18 ^ w11>>>3 ^ w11<<25 ^ w11<<14 ) + ( w8>>>17 ^ w8>>>19 ^ w8>>>10 ^ w8<<15 ^ w8<<13 ) + w10 + w3 )|0;
f = ( w10 + f + ( c>>>6 ^ c>>>11 ^ c>>>25 ^ c<<26 ^ c<<21 ^ c<<7 ) + ( e ^ c & (d^e) ) + 0x84c87814 )|0;
b = ( b + f )|0;
f = ( f + ( (g & h) ^ ( a & (g ^ h) ) ) + ( g>>>2 ^ g>>>13 ^ g>>>22 ^ g<<30 ^ g<<19 ^ g<<10 ) )|0;
// 59
w11 = ( ( w12>>>7 ^ w12>>>18 ^ w12>>>3 ^ w12<<25 ^ w12<<14 ) + ( w9>>>17 ^ w9>>>19 ^ w9>>>10 ^ w9<<15 ^ w9<<13 ) + w11 + w4 )|0;
e = ( w11 + e + ( b>>>6 ^ b>>>11 ^ b>>>25 ^ b<<26 ^ b<<21 ^ b<<7 ) + ( d ^ b & (c^d) ) + 0x8cc70208 )|0;
a = ( a + e )|0;
e = ( e + ( (f & g) ^ ( h & (f ^ g) ) ) + ( f>>>2 ^ f>>>13 ^ f>>>22 ^ f<<30 ^ f<<19 ^ f<<10 ) )|0;
// 60
w12 = ( ( w13>>>7 ^ w13>>>18 ^ w13>>>3 ^ w13<<25 ^ w13<<14 ) + ( w10>>>17 ^ w10>>>19 ^ w10>>>10 ^ w10<<15 ^ w10<<13 ) + w12 + w5 )|0;
d = ( w12 + d + ( a>>>6 ^ a>>>11 ^ a>>>25 ^ a<<26 ^ a<<21 ^ a<<7 ) + ( c ^ a & (b^c) ) + 0x90befffa )|0;
h = ( h + d )|0;
d = ( d + ( (e & f) ^ ( g & (e ^ f) ) ) + ( e>>>2 ^ e>>>13 ^ e>>>22 ^ e<<30 ^ e<<19 ^ e<<10 ) )|0;
// 61
w13 = ( ( w14>>>7 ^ w14>>>18 ^ w14>>>3 ^ w14<<25 ^ w14<<14 ) + ( w11>>>17 ^ w11>>>19 ^ w11>>>10 ^ w11<<15 ^ w11<<13 ) + w13 + w6 )|0;
c = ( w13 + c + ( h>>>6 ^ h>>>11 ^ h>>>25 ^ h<<26 ^ h<<21 ^ h<<7 ) + ( b ^ h & (a^b) ) + 0xa4506ceb )|0;
g = ( g + c )|0;
c = ( c + ( (d & e) ^ ( f & (d ^ e) ) ) + ( d>>>2 ^ d>>>13 ^ d>>>22 ^ d<<30 ^ d<<19 ^ d<<10 ) )|0;
// 62
w14 = ( ( w15>>>7 ^ w15>>>18 ^ w15>>>3 ^ w15<<25 ^ w15<<14 ) + ( w12>>>17 ^ w12>>>19 ^ w12>>>10 ^ w12<<15 ^ w12<<13 ) + w14 + w7 )|0;
b = ( w14 + b + ( g>>>6 ^ g>>>11 ^ g>>>25 ^ g<<26 ^ g<<21 ^ g<<7 ) + ( a ^ g & (h^a) ) + 0xbef9a3f7 )|0;
f = ( f + b )|0;
b = ( b + ( (c & d) ^ ( e & (c ^ d) ) ) + ( c>>>2 ^ c>>>13 ^ c>>>22 ^ c<<30 ^ c<<19 ^ c<<10 ) )|0;
// 63
w15 = ( ( w0>>>7 ^ w0>>>18 ^ w0>>>3 ^ w0<<25 ^ w0<<14 ) + ( w13>>>17 ^ w13>>>19 ^ w13>>>10 ^ w13<<15 ^ w13<<13 ) + w15 + w8 )|0;
a = ( w15 + a + ( f>>>6 ^ f>>>11 ^ f>>>25 ^ f<<26 ^ f<<21 ^ f<<7 ) + ( h ^ f & (g^h) ) + 0xc67178f2 )|0;
e = ( e + a )|0;
a = ( a + ( (b & c) ^ ( d & (b ^ c) ) ) + ( b>>>2 ^ b>>>13 ^ b>>>22 ^ b<<30 ^ b<<19 ^ b<<10 ) )|0;
H0 = ( H0 + a )|0;
H1 = ( H1 + b )|0;
H2 = ( H2 + c )|0;
H3 = ( H3 + d )|0;
H4 = ( H4 + e )|0;
H5 = ( H5 + f )|0;
H6 = ( H6 + g )|0;
H7 = ( H7 + h )|0;
}
function _core_heap ( offset ) {
offset = offset|0;
_core(
HEAP[offset|0]<<24 | HEAP[offset|1]<<16 | HEAP[offset|2]<<8 | HEAP[offset|3],
HEAP[offset|4]<<24 | HEAP[offset|5]<<16 | HEAP[offset|6]<<8 | HEAP[offset|7],
HEAP[offset|8]<<24 | HEAP[offset|9]<<16 | HEAP[offset|10]<<8 | HEAP[offset|11],
HEAP[offset|12]<<24 | HEAP[offset|13]<<16 | HEAP[offset|14]<<8 | HEAP[offset|15],
HEAP[offset|16]<<24 | HEAP[offset|17]<<16 | HEAP[offset|18]<<8 | HEAP[offset|19],
HEAP[offset|20]<<24 | HEAP[offset|21]<<16 | HEAP[offset|22]<<8 | HEAP[offset|23],
HEAP[offset|24]<<24 | HEAP[offset|25]<<16 | HEAP[offset|26]<<8 | HEAP[offset|27],
HEAP[offset|28]<<24 | HEAP[offset|29]<<16 | HEAP[offset|30]<<8 | HEAP[offset|31],
HEAP[offset|32]<<24 | HEAP[offset|33]<<16 | HEAP[offset|34]<<8 | HEAP[offset|35],
HEAP[offset|36]<<24 | HEAP[offset|37]<<16 | HEAP[offset|38]<<8 | HEAP[offset|39],
HEAP[offset|40]<<24 | HEAP[offset|41]<<16 | HEAP[offset|42]<<8 | HEAP[offset|43],
HEAP[offset|44]<<24 | HEAP[offset|45]<<16 | HEAP[offset|46]<<8 | HEAP[offset|47],
HEAP[offset|48]<<24 | HEAP[offset|49]<<16 | HEAP[offset|50]<<8 | HEAP[offset|51],
HEAP[offset|52]<<24 | HEAP[offset|53]<<16 | HEAP[offset|54]<<8 | HEAP[offset|55],
HEAP[offset|56]<<24 | HEAP[offset|57]<<16 | HEAP[offset|58]<<8 | HEAP[offset|59],
HEAP[offset|60]<<24 | HEAP[offset|61]<<16 | HEAP[offset|62]<<8 | HEAP[offset|63]
);
}
// offset — multiple of 32
function _state_to_heap ( output ) {
output = output|0;
HEAP[output|0] = H0>>>24;
HEAP[output|1] = H0>>>16&255;
HEAP[output|2] = H0>>>8&255;
HEAP[output|3] = H0&255;
HEAP[output|4] = H1>>>24;
HEAP[output|5] = H1>>>16&255;
HEAP[output|6] = H1>>>8&255;
HEAP[output|7] = H1&255;
HEAP[output|8] = H2>>>24;
HEAP[output|9] = H2>>>16&255;
HEAP[output|10] = H2>>>8&255;
HEAP[output|11] = H2&255;
HEAP[output|12] = H3>>>24;
HEAP[output|13] = H3>>>16&255;
HEAP[output|14] = H3>>>8&255;
HEAP[output|15] = H3&255;
HEAP[output|16] = H4>>>24;
HEAP[output|17] = H4>>>16&255;
HEAP[output|18] = H4>>>8&255;
HEAP[output|19] = H4&255;
HEAP[output|20] = H5>>>24;
HEAP[output|21] = H5>>>16&255;
HEAP[output|22] = H5>>>8&255;
HEAP[output|23] = H5&255;
HEAP[output|24] = H6>>>24;
HEAP[output|25] = H6>>>16&255;
HEAP[output|26] = H6>>>8&255;
HEAP[output|27] = H6&255;
HEAP[output|28] = H7>>>24;
HEAP[output|29] = H7>>>16&255;
HEAP[output|30] = H7>>>8&255;
HEAP[output|31] = H7&255;
}
function reset () {
H0 = 0x6a09e667;
H1 = 0xbb67ae85;
H2 = 0x3c6ef372;
H3 = 0xa54ff53a;
H4 = 0x510e527f;
H5 = 0x9b05688c;
H6 = 0x1f83d9ab;
H7 = 0x5be0cd19;
TOTAL0 = TOTAL1 = 0;
}
function init ( h0, h1, h2, h3, h4, h5, h6, h7, total0, total1 ) {
h0 = h0|0;
h1 = h1|0;
h2 = h2|0;
h3 = h3|0;
h4 = h4|0;
h5 = h5|0;
h6 = h6|0;
h7 = h7|0;
total0 = total0|0;
total1 = total1|0;
H0 = h0;
H1 = h1;
H2 = h2;
H3 = h3;
H4 = h4;
H5 = h5;
H6 = h6;
H7 = h7;
TOTAL0 = total0;
TOTAL1 = total1;
}
// offset — multiple of 64
function process ( offset, length ) {
offset = offset|0;
length = length|0;
var hashed = 0;
if ( offset & 63 )
return -1;
while ( (length|0) >= 64 ) {
_core_heap(offset);
offset = ( offset + 64 )|0;
length = ( length - 64 )|0;
hashed = ( hashed + 64 )|0;
}
TOTAL0 = ( TOTAL0 + hashed )|0;
if ( TOTAL0>>>0 < hashed>>>0 ) TOTAL1 = ( TOTAL1 + 1 )|0;
return hashed|0;
}
// offset — multiple of 64
// output — multiple of 32
function finish ( offset, length, output ) {
offset = offset|0;
length = length|0;
output = output|0;
var hashed = 0,
i = 0;
if ( offset & 63 )
return -1;
if ( ~output )
if ( output & 31 )
return -1;
if ( (length|0) >= 64 ) {
hashed = process( offset, length )|0;
if ( (hashed|0) == -1 )
return -1;
offset = ( offset + hashed )|0;
length = ( length - hashed )|0;
}
hashed = ( hashed + length )|0;
TOTAL0 = ( TOTAL0 + length )|0;
if ( TOTAL0>>>0 < length>>>0 ) TOTAL1 = ( TOTAL1 + 1 )|0;
HEAP[offset|length] = 0x80;
if ( (length|0) >= 56 ) {
for ( i = (length+1)|0; (i|0) < 64; i = (i+1)|0 )
HEAP[offset|i] = 0x00;
_core_heap(offset);
length = 0;
HEAP[offset|0] = 0;
}
for ( i = (length+1)|0; (i|0) < 59; i = (i+1)|0 )
HEAP[offset|i] = 0;
HEAP[offset|56] = TOTAL1>>>21&255;
HEAP[offset|57] = TOTAL1>>>13&255;
HEAP[offset|58] = TOTAL1>>>5&255;
HEAP[offset|59] = TOTAL1<<3&255 | TOTAL0>>>29;
HEAP[offset|60] = TOTAL0>>>21&255;
HEAP[offset|61] = TOTAL0>>>13&255;
HEAP[offset|62] = TOTAL0>>>5&255;
HEAP[offset|63] = TOTAL0<<3&255;
_core_heap(offset);
if ( ~output )
_state_to_heap(output);
return hashed|0;
}
function hmac_reset () {
H0 = I0;
H1 = I1;
H2 = I2;
H3 = I3;
H4 = I4;
H5 = I5;
H6 = I6;
H7 = I7;
TOTAL0 = 64;
TOTAL1 = 0;
}
function _hmac_opad () {
H0 = O0;
H1 = O1;
H2 = O2;
H3 = O3;
H4 = O4;
H5 = O5;
H6 = O6;
H7 = O7;
TOTAL0 = 64;
TOTAL1 = 0;
}
function hmac_init ( p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15 ) {
p0 = p0|0;
p1 = p1|0;
p2 = p2|0;
p3 = p3|0;
p4 = p4|0;
p5 = p5|0;
p6 = p6|0;
p7 = p7|0;
p8 = p8|0;
p9 = p9|0;
p10 = p10|0;
p11 = p11|0;
p12 = p12|0;
p13 = p13|0;
p14 = p14|0;
p15 = p15|0;
// opad
reset();
_core(
p0 ^ 0x5c5c5c5c,
p1 ^ 0x5c5c5c5c,
p2 ^ 0x5c5c5c5c,
p3 ^ 0x5c5c5c5c,
p4 ^ 0x5c5c5c5c,
p5 ^ 0x5c5c5c5c,
p6 ^ 0x5c5c5c5c,
p7 ^ 0x5c5c5c5c,
p8 ^ 0x5c5c5c5c,
p9 ^ 0x5c5c5c5c,
p10 ^ 0x5c5c5c5c,
p11 ^ 0x5c5c5c5c,
p12 ^ 0x5c5c5c5c,
p13 ^ 0x5c5c5c5c,
p14 ^ 0x5c5c5c5c,
p15 ^ 0x5c5c5c5c
);
O0 = H0;
O1 = H1;
O2 = H2;
O3 = H3;
O4 = H4;
O5 = H5;
O6 = H6;
O7 = H7;
// ipad
reset();
_core(
p0 ^ 0x36363636,
p1 ^ 0x36363636,
p2 ^ 0x36363636,
p3 ^ 0x36363636,
p4 ^ 0x36363636,
p5 ^ 0x36363636,
p6 ^ 0x36363636,
p7 ^ 0x36363636,
p8 ^ 0x36363636,
p9 ^ 0x36363636,
p10 ^ 0x36363636,
p11 ^ 0x36363636,
p12 ^ 0x36363636,
p13 ^ 0x36363636,
p14 ^ 0x36363636,
p15 ^ 0x36363636
);
I0 = H0;
I1 = H1;
I2 = H2;
I3 = H3;
I4 = H4;
I5 = H5;
I6 = H6;
I7 = H7;
TOTAL0 = 64;
TOTAL1 = 0;
}
// offset — multiple of 64
// output — multiple of 32
function hmac_finish ( offset, length, output ) {
offset = offset|0;
length = length|0;
output = output|0;
var t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0,
hashed = 0;
if ( offset & 63 )
return -1;
if ( ~output )
if ( output & 31 )
return -1;
hashed = finish( offset, length, -1 )|0;
t0 = H0, t1 = H1, t2 = H2, t3 = H3, t4 = H4, t5 = H5, t6 = H6, t7 = H7;
_hmac_opad();
_core( t0, t1, t2, t3, t4, t5, t6, t7, 0x80000000, 0, 0, 0, 0, 0, 0, 768 );
if ( ~output )
_state_to_heap(output);
return hashed|0;
}
// salt is assumed to be already processed
// offset — multiple of 64
// output — multiple of 32
function pbkdf2_generate_block ( offset, length, block, count, output ) {
offset = offset|0;
length = length|0;
block = block|0;
count = count|0;
output = output|0;
var h0 = 0, h1 = 0, h2 = 0, h3 = 0, h4 = 0, h5 = 0, h6 = 0, h7 = 0,
t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0;
if ( offset & 63 )
return -1;
if ( ~output )
if ( output & 31 )
return -1;
// pad block number into heap
// FIXME probable OOB write
HEAP[(offset+length)|0] = block>>>24;
HEAP[(offset+length+1)|0] = block>>>16&255;
HEAP[(offset+length+2)|0] = block>>>8&255;
HEAP[(offset+length+3)|0] = block&255;
// finish first iteration
hmac_finish( offset, (length+4)|0, -1 )|0;
h0 = t0 = H0, h1 = t1 = H1, h2 = t2 = H2, h3 = t3 = H3, h4 = t4 = H4, h5 = t5 = H5, h6 = t6 = H6, h7 = t7 = H7;
count = (count-1)|0;
// perform the rest iterations
while ( (count|0) > 0 ) {
hmac_reset();
_core( t0, t1, t2, t3, t4, t5, t6, t7, 0x80000000, 0, 0, 0, 0, 0, 0, 768 );
t0 = H0, t1 = H1, t2 = H2, t3 = H3, t4 = H4, t5 = H5, t6 = H6, t7 = H7;
_hmac_opad();
_core( t0, t1, t2, t3, t4, t5, t6, t7, 0x80000000, 0, 0, 0, 0, 0, 0, 768 );
t0 = H0, t1 = H1, t2 = H2, t3 = H3, t4 = H4, t5 = H5, t6 = H6, t7 = H7;
h0 = h0 ^ H0;
h1 = h1 ^ H1;
h2 = h2 ^ H2;
h3 = h3 ^ H3;
h4 = h4 ^ H4;
h5 = h5 ^ H5;
h6 = h6 ^ H6;
h7 = h7 ^ H7;
count = (count-1)|0;
}
H0 = h0;
H1 = h1;
H2 = h2;
H3 = h3;
H4 = h4;
H5 = h5;
H6 = h6;
H7 = h7;
if ( ~output )
_state_to_heap(output);
return 0;
}
return {
// SHA256
reset: reset,
init: init,
process: process,
finish: finish,
// HMAC-SHA256
hmac_reset: hmac_reset,
hmac_init: hmac_init,
hmac_finish: hmac_finish,
// PBKDF2-HMAC-SHA256
pbkdf2_generate_block: pbkdf2_generate_block
}
};
const _sha256_block_size = 64;
const _sha256_hash_size = 32;
const heap_pool$2 = [];
const asm_pool$2 = [];
class Sha256 extends Hash {
constructor() {
super();
this.NAME = 'sha256';
this.BLOCK_SIZE = _sha256_block_size;
this.HASH_SIZE = _sha256_hash_size;
this.acquire_asm();
}
acquire_asm() {
if (this.heap === undefined || this.asm === undefined) {
this.heap = heap_pool$2.pop() || _heap_init();
this.asm = asm_pool$2.pop() || sha256_asm({ Uint8Array: Uint8Array }, null, this.heap.buffer);
this.reset();
}
return { heap: this.heap, asm: this.asm };
}
release_asm() {
if (this.heap !== undefined && this.asm !== undefined) {
heap_pool$2.push(this.heap);
asm_pool$2.push(this.asm);
}
this.heap = undefined;
this.asm = undefined;
}
static bytes(data) {
return new Sha256().process(data).finish().result;
}
}
Sha256.NAME = 'sha256';
var minimalisticAssert = assert;
function assert(val, msg) {
if (!val)
throw new Error(msg || 'Assertion failed');
}
assert.equal = function assertEqual(l, r, msg) {
if (l != r)
throw new Error(msg || ('Assertion failed: ' + l + ' != ' + r));
};
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function createCommonjsModule(fn, module) {
return module = { exports: {} }, fn(module, module.exports), module.exports;
}
function commonjsRequire () {
throw new Error('Dynamic requires are not currently supported by @rollup/plugin-commonjs');
}
var inherits_browser = createCommonjsModule(function (module) {
if (typeof Object.create === 'function') {
// implementation from standard node.js 'util' module
module.exports = function inherits(ctor, superCtor) {
ctor.super_ = superCtor;
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
});
};
} else {
// old school shim for old browsers
module.exports = function inherits(ctor, superCtor) {
ctor.super_ = superCtor;
var TempCtor = function () {};
TempCtor.prototype = superCtor.prototype;
ctor.prototype = new TempCtor();
ctor.prototype.constructor = ctor;
};
}
});
var inherits_1 = inherits_browser;
function toArray(msg, enc) {
if (Array.isArray(msg))
return msg.slice();
if (!msg)
return [];
var res = [];
if (typeof msg === 'string') {
if (!enc) {
for (var i = 0; i < msg.length; i++) {
var c = msg.charCodeAt(i);
var hi = c >> 8;
var lo = c & 0xff;
if (hi)
res.push(hi, lo);
else
res.push(lo);
}
} else if (enc === 'hex') {
msg = msg.replace(/[^a-z0-9]+/ig, '');
if (msg.length % 2 !== 0)
msg = '0' + msg;
for (i = 0; i < msg.length; i += 2)
res.push(parseInt(msg[i] + msg[i + 1], 16));
}
} else {
for (i = 0; i < msg.length; i++)
res[i] = msg[i] | 0;
}
return res;
}
var toArray_1 = toArray;
function toHex(msg) {
var res = '';
for (var i = 0; i < msg.length; i++)
res += zero2(msg[i].toString(16));
return res;
}
var toHex_1 = toHex;
function htonl(w) {
var res = (w >>> 24) |
((w >>> 8) & 0xff00) |
((w << 8) & 0xff0000) |
((w & 0xff) << 24);
return res >>> 0;
}
var htonl_1 = htonl;
function toHex32(msg, endian) {
var res = '';
for (var i = 0; i < msg.length; i++) {
var w = msg[i];
if (endian === 'little')
w = htonl(w);
res += zero8(w.toString(16));
}
return res;
}
var toHex32_1 = toHex32;
function zero2(word) {
if (word.length === 1)
return '0' + word;
else
return word;
}
var zero2_1 = zero2;
function zero8(word) {
if (word.length === 7)
return '0' + word;
else if (word.length === 6)
return '00' + word;
else if (word.length === 5)
return '000' + word;
else if (word.length === 4)
return '0000' + word;
else if (word.length === 3)
return '00000' + word;
else if (word.length === 2)
return '000000' + word;
else if (word.length === 1)
return '0000000' + word;
else
return word;
}
var zero8_1 = zero8;
function join32(msg, start, end, endian) {
var len = end - start;
minimalisticAssert(len % 4 === 0);
var res = new Array(len / 4);
for (var i = 0, k = start; i < res.length; i++, k += 4) {
var w;
if (endian === 'big')
w = (msg[k] << 24) | (msg[k + 1] << 16) | (msg[k + 2] << 8) | msg[k + 3];
else
w = (msg[k + 3] << 24) | (msg[k + 2] << 16) | (msg[k + 1] << 8) | msg[k];
res[i] = w >>> 0;
}
return res;
}
var join32_1 = join32;
function split32(msg, endian) {
var res = new Array(msg.length * 4);
for (var i = 0, k = 0; i < msg.length; i++, k += 4) {
var m = msg[i];
if (endian === 'big') {
res[k] = m >>> 24;
res[k + 1] = (m >>> 16) & 0xff;
res[k + 2] = (m >>> 8) & 0xff;
res[k + 3] = m & 0xff;
} else {
res[k + 3] = m >>> 24;
res[k + 2] = (m >>> 16) & 0xff;
res[k + 1] = (m >>> 8) & 0xff;
res[k] = m & 0xff;
}
}
return res;
}
var split32_1 = split32;
function rotr32(w, b) {
return (w >>> b) | (w << (32 - b));
}
var rotr32_1 = rotr32;
function rotl32(w, b) {
return (w << b) | (w >>> (32 - b));
}
var rotl32_1 = rotl32;
function sum32(a, b) {
return (a + b) >>> 0;
}
var sum32_1 = sum32;
function sum32_3(a, b, c) {
return (a + b + c) >>> 0;
}
var sum32_3_1 = sum32_3;
function sum32_4(a, b, c, d) {
return (a + b + c + d) >>> 0;
}
var sum32_4_1 = sum32_4;
function sum32_5(a, b, c, d, e) {
return (a + b + c + d + e) >>> 0;
}
var sum32_5_1 = sum32_5;
function sum64(buf, pos, ah, al) {
var bh = buf[pos];
var bl = buf[pos + 1];
var lo = (al + bl) >>> 0;
var hi = (lo < al ? 1 : 0) + ah + bh;
buf[pos] = hi >>> 0;
buf[pos + 1] = lo;
}
var sum64_1 = sum64;
function sum64_hi(ah, al, bh, bl) {
var lo = (al + bl) >>> 0;
var hi = (lo < al ? 1 : 0) + ah + bh;
return hi >>> 0;
}
var sum64_hi_1 = sum64_hi;
function sum64_lo(ah, al, bh, bl) {
var lo = al + bl;
return lo >>> 0;
}
var sum64_lo_1 = sum64_lo;
function sum64_4_hi(ah, al, bh, bl, ch, cl, dh, dl) {
var carry = 0;
var lo = al;
lo = (lo + bl) >>> 0;
carry += lo < al ? 1 : 0;
lo = (lo + cl) >>> 0;
carry += lo < cl ? 1 : 0;
lo = (lo + dl) >>> 0;
carry += lo < dl ? 1 : 0;
var hi = ah + bh + ch + dh + carry;
return hi >>> 0;
}
var sum64_4_hi_1 = sum64_4_hi;
function sum64_4_lo(ah, al, bh, bl, ch, cl, dh, dl) {
var lo = al + bl + cl + dl;
return lo >>> 0;
}
var sum64_4_lo_1 = sum64_4_lo;
function sum64_5_hi(ah, al, bh, bl, ch, cl, dh, dl, eh, el) {
var carry = 0;
var lo = al;
lo = (lo + bl) >>> 0;
carry += lo < al ? 1 : 0;
lo = (lo + cl) >>> 0;
carry += lo < cl ? 1 : 0;
lo = (lo + dl) >>> 0;
carry += lo < dl ? 1 : 0;
lo = (lo + el) >>> 0;
carry += lo < el ? 1 : 0;
var hi = ah + bh + ch + dh + eh + carry;
return hi >>> 0;
}
var sum64_5_hi_1 = sum64_5_hi;
function sum64_5_lo(ah, al, bh, bl, ch, cl, dh, dl, eh, el) {
var lo = al + bl + cl + dl + el;
return lo >>> 0;
}
var sum64_5_lo_1 = sum64_5_lo;
function rotr64_hi(ah, al, num) {
var r = (al << (32 - num)) | (ah >>> num);
return r >>> 0;
}
var rotr64_hi_1 = rotr64_hi;
function rotr64_lo(ah, al, num) {
var r = (ah << (32 - num)) | (al >>> num);
return r >>> 0;
}
var rotr64_lo_1 = rotr64_lo;
function shr64_hi(ah, al, num) {
return ah >>> num;
}
var shr64_hi_1 = shr64_hi;
function shr64_lo(ah, al, num) {
var r = (ah << (32 - num)) | (al >>> num);
return r >>> 0;
}
var shr64_lo_1 = shr64_lo;
var utils = {
inherits: inherits_1,
toArray: toArray_1,
toHex: toHex_1,
htonl: htonl_1,
toHex32: toHex32_1,
zero2: zero2_1,
zero8: zero8_1,
join32: join32_1,
split32: split32_1,
rotr32: rotr32_1,
rotl32: rotl32_1,
sum32: sum32_1,
sum32_3: sum32_3_1,
sum32_4: sum32_4_1,
sum32_5: sum32_5_1,
sum64: sum64_1,
sum64_hi: sum64_hi_1,
sum64_lo: sum64_lo_1,
sum64_4_hi: sum64_4_hi_1,
sum64_4_lo: sum64_4_lo_1,
sum64_5_hi: sum64_5_hi_1,
sum64_5_lo: sum64_5_lo_1,
rotr64_hi: rotr64_hi_1,
rotr64_lo: rotr64_lo_1,
shr64_hi: shr64_hi_1,
shr64_lo: shr64_lo_1
};
function BlockHash() {
this.pending = null;
this.pendingTotal = 0;
this.blockSize = this.constructor.blockSize;
this.outSize = this.constructor.outSize;
this.hmacStrength = this.constructor.hmacStrength;
this.padLength = this.constructor.padLength / 8;
this.endian = 'big';
this._delta8 = this.blockSize / 8;
this._delta32 = this.blockSize / 32;
}
var BlockHash_1 = BlockHash;
BlockHash.prototype.update = function update(msg, enc) {
// Convert message to array, pad it, and join into 32bit blocks
msg = utils.toArray(msg, enc);
if (!this.pending)
this.pending = msg;
else
this.pending = this.pending.concat(msg);
this.pendingTotal += msg.length;
// Enough data, try updating
if (this.pending.length >= this._delta8) {
msg = this.pending;
// Process pending data in blocks
var r = msg.length % this._delta8;
this.pending = msg.slice(msg.length - r, msg.length);
if (this.pending.length === 0)
this.pending = null;
msg = utils.join32(msg, 0, msg.length - r, this.endian);
for (var i = 0; i < msg.length; i += this._delta32)
this._update(msg, i, i + this._delta32);
}
return this;
};
BlockHash.prototype.digest = function digest(enc) {
this.update(this._pad());
minimalisticAssert(this.pending === null);
return this._digest(enc);
};
BlockHash.prototype._pad = function pad() {
var len = this.pendingTotal;
var bytes = this._delta8;
var k = bytes - ((len + this.padLength) % bytes);
var res = new Array(k + this.padLength);
res[0] = 0x80;
for (var i = 1; i < k; i++)
res[i] = 0;
// Append length
len <<= 3;
if (this.endian === 'big') {
for (var t = 8; t < this.padLength; t++)
res[i++] = 0;
res[i++] = 0;
res[i++] = 0;
res[i++] = 0;
res[i++] = 0;
res[i++] = (len >>> 24) & 0xff;
res[i++] = (len >>> 16) & 0xff;
res[i++] = (len >>> 8) & 0xff;
res[i++] = len & 0xff;
} else {
res[i++] = len & 0xff;
res[i++] = (len >>> 8) & 0xff;
res[i++] = (len >>> 16) & 0xff;
res[i++] = (len >>> 24) & 0xff;
res[i++] = 0;
res[i++] = 0;
res[i++] = 0;
res[i++] = 0;
for (t = 8; t < this.padLength; t++)
res[i++] = 0;
}
return res;
};
var common = {
BlockHash: BlockHash_1
};
var rotr32$1 = utils.rotr32;
function ft_1(s, x, y, z) {
if (s === 0)
return ch32(x, y, z);
if (s === 1 || s === 3)
return p32(x, y, z);
if (s === 2)
return maj32(x, y, z);
}
var ft_1_1 = ft_1;
function ch32(x, y, z) {
return (x & y) ^ ((~x) & z);
}
var ch32_1 = ch32;
function maj32(x, y, z) {
return (x & y) ^ (x & z) ^ (y & z);
}
var maj32_1 = maj32;
function p32(x, y, z) {
return x ^ y ^ z;
}
var p32_1 = p32;
function s0_256(x) {
return rotr32$1(x, 2) ^ rotr32$1(x, 13) ^ rotr32$1(x, 22);
}
var s0_256_1 = s0_256;
function s1_256(x) {
return rotr32$1(x, 6) ^ rotr32$1(x, 11) ^ rotr32$1(x, 25);
}
var s1_256_1 = s1_256;
function g0_256(x) {
return rotr32$1(x, 7) ^ rotr32$1(x, 18) ^ (x >>> 3);
}
var g0_256_1 = g0_256;
function g1_256(x) {
return rotr32$1(x, 17) ^ rotr32$1(x, 19) ^ (x >>> 10);
}
var g1_256_1 = g1_256;
var common$1 = {
ft_1: ft_1_1,
ch32: ch32_1,
maj32: maj32_1,
p32: p32_1,
s0_256: s0_256_1,
s1_256: s1_256_1,
g0_256: g0_256_1,
g1_256: g1_256_1
};
var sum32$1 = utils.sum32;
var sum32_4$1 = utils.sum32_4;
var sum32_5$1 = utils.sum32_5;
var ch32$1 = common$1.ch32;
var maj32$1 = common$1.maj32;
var s0_256$1 = common$1.s0_256;
var s1_256$1 = common$1.s1_256;
var g0_256$1 = common$1.g0_256;
var g1_256$1 = common$1.g1_256;
var BlockHash$1 = common.BlockHash;
var sha256_K = [
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
];
function SHA256() {
if (!(this instanceof SHA256))
return new SHA256();
BlockHash$1.call(this);
this.h = [
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
];
this.k = sha256_K;
this.W = new Array(64);
}
utils.inherits(SHA256, BlockHash$1);
var _256 = SHA256;
SHA256.blockSize = 512;
SHA256.outSize = 256;
SHA256.hmacStrength = 192;
SHA256.padLength = 64;
SHA256.prototype._update = function _update(msg, start) {
var W = this.W;
for (var i = 0; i < 16; i++)
W[i] = msg[start + i];
for (; i < W.length; i++)
W[i] = sum32_4$1(g1_256$1(W[i - 2]), W[i - 7], g0_256$1(W[i - 15]), W[i - 16]);
var a = this.h[0];
var b = this.h[1];
var c = this.h[2];
var d = this.h[3];
var e = this.h[4];
var f = this.h[5];
var g = this.h[6];
var h = this.h[7];
minimalisticAssert(this.k.length === W.length);
for (i = 0; i < W.length; i++) {
var T1 = sum32_5$1(h, s1_256$1(e), ch32$1(e, f, g), this.k[i], W[i]);
var T2 = sum32$1(s0_256$1(a), maj32$1(a, b, c));
h = g;
g = f;
f = e;
e = sum32$1(d, T1);
d = c;
c = b;
b = a;
a = sum32$1(T1, T2);
}
this.h[0] = sum32$1(this.h[0], a);
this.h[1] = sum32$1(this.h[1], b);
this.h[2] = sum32$1(this.h[2], c);
this.h[3] = sum32$1(this.h[3], d);
this.h[4] = sum32$1(this.h[4], e);
this.h[5] = sum32$1(this.h[5], f);
this.h[6] = sum32$1(this.h[6], g);
this.h[7] = sum32$1(this.h[7], h);
};
SHA256.prototype._digest = function digest(enc) {
if (enc === 'hex')
return utils.toHex32(this.h, 'big');
else
return utils.split32(this.h, 'big');
};
function SHA224() {
if (!(this instanceof SHA224))
return new SHA224();
_256.call(this);
this.h = [
0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4 ];
}
utils.inherits(SHA224, _256);
var _224 = SHA224;
SHA224.blockSize = 512;
SHA224.outSize = 224;
SHA224.hmacStrength = 192;
SHA224.padLength = 64;
SHA224.prototype._digest = function digest(enc) {
// Just truncate output
if (enc === 'hex')
return utils.toHex32(this.h.slice(0, 7), 'big');
else
return utils.split32(this.h.slice(0, 7), 'big');
};
var rotr64_hi$1 = utils.rotr64_hi;
var rotr64_lo$1 = utils.rotr64_lo;
var shr64_hi$1 = utils.shr64_hi;
var shr64_lo$1 = utils.shr64_lo;
var sum64$1 = utils.sum64;
var sum64_hi$1 = utils.sum64_hi;
var sum64_lo$1 = utils.sum64_lo;
var sum64_4_hi$1 = utils.sum64_4_hi;
var sum64_4_lo$1 = utils.sum64_4_lo;
var sum64_5_hi$1 = utils.sum64_5_hi;
var sum64_5_lo$1 = utils.sum64_5_lo;
var BlockHash$2 = common.BlockHash;
var sha512_K = [
0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd,
0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc,
0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019,
0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118,
0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe,
0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2,
0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1,
0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694,
0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3,
0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65,
0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483,
0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5,
0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210,
0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4,
0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725,
0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70,
0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926,
0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df,
0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8,
0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b,
0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001,
0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30,
0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910,
0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8,
0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53,
0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8,
0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb,
0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3,
0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60,
0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec,
0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9,
0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b,
0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207,
0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178,
0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6,
0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b,
0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493,
0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c,
0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a,
0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817
];
function SHA512() {
if (!(this instanceof SHA512))
return new SHA512();
BlockHash$2.call(this);
this.h = [
0x6a09e667, 0xf3bcc908,
0xbb67ae85, 0x84caa73b,
0x3c6ef372, 0xfe94f82b,
0xa54ff53a, 0x5f1d36f1,
0x510e527f, 0xade682d1,
0x9b05688c, 0x2b3e6c1f,
0x1f83d9ab, 0xfb41bd6b,
0x5be0cd19, 0x137e2179 ];
this.k = sha512_K;
this.W = new Array(160);
}
utils.inherits(SHA512, BlockHash$2);
var _512 = SHA512;
SHA512.blockSize = 1024;
SHA512.outSize = 512;
SHA512.hmacStrength = 192;
SHA512.padLength = 128;
SHA512.prototype._prepareBlock = function _prepareBlock(msg, start) {
var W = this.W;
// 32 x 32bit words
for (var i = 0; i < 32; i++)
W[i] = msg[start + i];
for (; i < W.length; i += 2) {
var c0_hi = g1_512_hi(W[i - 4], W[i - 3]); // i - 2
var c0_lo = g1_512_lo(W[i - 4], W[i - 3]);
var c1_hi = W[i - 14]; // i - 7
var c1_lo = W[i - 13];
var c2_hi = g0_512_hi(W[i - 30], W[i - 29]); // i - 15
var c2_lo = g0_512_lo(W[i - 30], W[i - 29]);
var c3_hi = W[i - 32]; // i - 16
var c3_lo = W[i - 31];
W[i] = sum64_4_hi$1(
c0_hi, c0_lo,
c1_hi, c1_lo,
c2_hi, c2_lo,
c3_hi, c3_lo);
W[i + 1] = sum64_4_lo$1(
c0_hi, c0_lo,
c1_hi, c1_lo,
c2_hi, c2_lo,
c3_hi, c3_lo);
}
};
SHA512.prototype._update = function _update(msg, start) {
this._prepareBlock(msg, start);
var W = this.W;
var ah = this.h[0];
var al = this.h[1];
var bh = this.h[2];
var bl = this.h[3];
var ch = this.h[4];
var cl = this.h[5];
var dh = this.h[6];
var dl = this.h[7];
var eh = this.h[8];
var el = this.h[9];
var fh = this.h[10];
var fl = this.h[11];
var gh = this.h[12];
var gl = this.h[13];
var hh = this.h[14];
var hl = this.h[15];
minimalisticAssert(this.k.length === W.length);
for (var i = 0; i < W.length; i += 2) {
var c0_hi = hh;
var c0_lo = hl;
var c1_hi = s1_512_hi(eh, el);
var c1_lo = s1_512_lo(eh, el);
var c2_hi = ch64_hi(eh, el, fh, fl, gh);
var c2_lo = ch64_lo(eh, el, fh, fl, gh, gl);
var c3_hi = this.k[i];
var c3_lo = this.k[i + 1];
var c4_hi = W[i];
var c4_lo = W[i + 1];
var T1_hi = sum64_5_hi$1(
c0_hi, c0_lo,
c1_hi, c1_lo,
c2_hi, c2_lo,
c3_hi, c3_lo,
c4_hi, c4_lo);
var T1_lo = sum64_5_lo$1(
c0_hi, c0_lo,
c1_hi, c1_lo,
c2_hi, c2_lo,
c3_hi, c3_lo,
c4_hi, c4_lo);
c0_hi = s0_512_hi(ah, al);
c0_lo = s0_512_lo(ah, al);
c1_hi = maj64_hi(ah, al, bh, bl, ch);
c1_lo = maj64_lo(ah, al, bh, bl, ch, cl);
var T2_hi = sum64_hi$1(c0_hi, c0_lo, c1_hi, c1_lo);
var T2_lo = sum64_lo$1(c0_hi, c0_lo, c1_hi, c1_lo);
hh = gh;
hl = gl;
gh = fh;
gl = fl;
fh = eh;
fl = el;
eh = sum64_hi$1(dh, dl, T1_hi, T1_lo);
el = sum64_lo$1(dl, dl, T1_hi, T1_lo);
dh = ch;
dl = cl;
ch = bh;
cl = bl;
bh = ah;
bl = al;
ah = sum64_hi$1(T1_hi, T1_lo, T2_hi, T2_lo);
al = sum64_lo$1(T1_hi, T1_lo, T2_hi, T2_lo);
}
sum64$1(this.h, 0, ah, al);
sum64$1(this.h, 2, bh, bl);
sum64$1(this.h, 4, ch, cl);
sum64$1(this.h, 6, dh, dl);
sum64$1(this.h, 8, eh, el);
sum64$1(this.h, 10, fh, fl);
sum64$1(this.h, 12, gh, gl);
sum64$1(this.h, 14, hh, hl);
};
SHA512.prototype._digest = function digest(enc) {
if (enc === 'hex')
return utils.toHex32(this.h, 'big');
else
return utils.split32(this.h, 'big');
};
function ch64_hi(xh, xl, yh, yl, zh) {
var r = (xh & yh) ^ ((~xh) & zh);
if (r < 0)
r += 0x100000000;
return r;
}
function ch64_lo(xh, xl, yh, yl, zh, zl) {
var r = (xl & yl) ^ ((~xl) & zl);
if (r < 0)
r += 0x100000000;
return r;
}
function maj64_hi(xh, xl, yh, yl, zh) {
var r = (xh & yh) ^ (xh & zh) ^ (yh & zh);
if (r < 0)
r += 0x100000000;
return r;
}
function maj64_lo(xh, xl, yh, yl, zh, zl) {
var r = (xl & yl) ^ (xl & zl) ^ (yl & zl);
if (r < 0)
r += 0x100000000;
return r;
}
function s0_512_hi(xh, xl) {
var c0_hi = rotr64_hi$1(xh, xl, 28);
var c1_hi = rotr64_hi$1(xl, xh, 2); // 34
var c2_hi = rotr64_hi$1(xl, xh, 7); // 39
var r = c0_hi ^ c1_hi ^ c2_hi;
if (r < 0)
r += 0x100000000;
return r;
}
function s0_512_lo(xh, xl) {
var c0_lo = rotr64_lo$1(xh, xl, 28);
var c1_lo = rotr64_lo$1(xl, xh, 2); // 34
var c2_lo = rotr64_lo$1(xl, xh, 7); // 39
var r = c0_lo ^ c1_lo ^ c2_lo;
if (r < 0)
r += 0x100000000;
return r;
}
function s1_512_hi(xh, xl) {
var c0_hi = rotr64_hi$1(xh, xl, 14);
var c1_hi = rotr64_hi$1(xh, xl, 18);
var c2_hi = rotr64_hi$1(xl, xh, 9); // 41
var r = c0_hi ^ c1_hi ^ c2_hi;
if (r < 0)
r += 0x100000000;
return r;
}
function s1_512_lo(xh, xl) {
var c0_lo = rotr64_lo$1(xh, xl, 14);
var c1_lo = rotr64_lo$1(xh, xl, 18);
var c2_lo = rotr64_lo$1(xl, xh, 9); // 41
var r = c0_lo ^ c1_lo ^ c2_lo;
if (r < 0)
r += 0x100000000;
return r;
}
function g0_512_hi(xh, xl) {
var c0_hi = rotr64_hi$1(xh, xl, 1);
var c1_hi = rotr64_hi$1(xh, xl, 8);
var c2_hi = shr64_hi$1(xh, xl, 7);
var r = c0_hi ^ c1_hi ^ c2_hi;
if (r < 0)
r += 0x100000000;
return r;
}
function g0_512_lo(xh, xl) {
var c0_lo = rotr64_lo$1(xh, xl, 1);
var c1_lo = rotr64_lo$1(xh, xl, 8);
var c2_lo = shr64_lo$1(xh, xl, 7);
var r = c0_lo ^ c1_lo ^ c2_lo;
if (r < 0)
r += 0x100000000;
return r;
}
function g1_512_hi(xh, xl) {
var c0_hi = rotr64_hi$1(xh, xl, 19);
var c1_hi = rotr64_hi$1(xl, xh, 29); // 61
var c2_hi = shr64_hi$1(xh, xl, 6);
var r = c0_hi ^ c1_hi ^ c2_hi;
if (r < 0)
r += 0x100000000;
return r;
}
function g1_512_lo(xh, xl) {
var c0_lo = rotr64_lo$1(xh, xl, 19);
var c1_lo = rotr64_lo$1(xl, xh, 29); // 61
var c2_lo = shr64_lo$1(xh, xl, 6);
var r = c0_lo ^ c1_lo ^ c2_lo;
if (r < 0)
r += 0x100000000;
return r;
}
function SHA384() {
if (!(this instanceof SHA384))
return new SHA384();
_512.call(this);
this.h = [
0xcbbb9d5d, 0xc1059ed8,
0x629a292a, 0x367cd507,
0x9159015a, 0x3070dd17,
0x152fecd8, 0xf70e5939,
0x67332667, 0xffc00b31,
0x8eb44a87, 0x68581511,
0xdb0c2e0d, 0x64f98fa7,
0x47b5481d, 0xbefa4fa4 ];
}
utils.inherits(SHA384, _512);
var _384 = SHA384;
SHA384.blockSize = 1024;
SHA384.outSize = 384;
SHA384.hmacStrength = 192;
SHA384.padLength = 128;
SHA384.prototype._digest = function digest(enc) {
if (enc === 'hex')
return utils.toHex32(this.h.slice(0, 12), 'big');
else
return utils.split32(this.h.slice(0, 12), 'big');
};
var rotl32$1 = utils.rotl32;
var sum32$2 = utils.sum32;
var sum32_3$1 = utils.sum32_3;
var sum32_4$2 = utils.sum32_4;
var BlockHash$3 = common.BlockHash;
function RIPEMD160() {
if (!(this instanceof RIPEMD160))
return new RIPEMD160();
BlockHash$3.call(this);
this.h = [ 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 ];
this.endian = 'little';
}
utils.inherits(RIPEMD160, BlockHash$3);
var ripemd160 = RIPEMD160;
RIPEMD160.blockSize = 512;
RIPEMD160.outSize = 160;
RIPEMD160.hmacStrength = 192;
RIPEMD160.padLength = 64;
RIPEMD160.prototype._update = function update(msg, start) {
var A = this.h[0];
var B = this.h[1];
var C = this.h[2];
var D = this.h[3];
var E = this.h[4];
var Ah = A;
var Bh = B;
var Ch = C;
var Dh = D;
var Eh = E;
for (var j = 0; j < 80; j++) {
var T = sum32$2(
rotl32$1(
sum32_4$2(A, f(j, B, C, D), msg[r[j] + start], K(j)),
s[j]),
E);
A = E;
E = D;
D = rotl32$1(C, 10);
C = B;
B = T;
T = sum32$2(
rotl32$1(
sum32_4$2(Ah, f(79 - j, Bh, Ch, Dh), msg[rh[j] + start], Kh(j)),
sh[j]),
Eh);
Ah = Eh;
Eh = Dh;
Dh = rotl32$1(Ch, 10);
Ch = Bh;
Bh = T;
}
T = sum32_3$1(this.h[1], C, Dh);
this.h[1] = sum32_3$1(this.h[2], D, Eh);
this.h[2] = sum32_3$1(this.h[3], E, Ah);
this.h[3] = sum32_3$1(this.h[4], A, Bh);
this.h[4] = sum32_3$1(this.h[0], B, Ch);
this.h[0] = T;
};
RIPEMD160.prototype._digest = function digest(enc) {
if (enc === 'hex')
return utils.toHex32(this.h, 'little');
else
return utils.split32(this.h, 'little');
};
function f(j, x, y, z) {
if (j <= 15)
return x ^ y ^ z;
else if (j <= 31)
return (x & y) | ((~x) & z);
else if (j <= 47)
return (x | (~y)) ^ z;
else if (j <= 63)
return (x & z) | (y & (~z));
else
return x ^ (y | (~z));
}
function K(j) {
if (j <= 15)
return 0x00000000;
else if (j <= 31)
return 0x5a827999;
else if (j <= 47)
return 0x6ed9eba1;
else if (j <= 63)
return 0x8f1bbcdc;
else
return 0xa953fd4e;
}
function Kh(j) {
if (j <= 15)
return 0x50a28be6;
else if (j <= 31)
return 0x5c4dd124;
else if (j <= 47)
return 0x6d703ef3;
else if (j <= 63)
return 0x7a6d76e9;
else
return 0x00000000;
}
var r = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
];
var rh = [
5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
];
var s = [
11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
];
var sh = [
8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
];
var ripemd = {
ripemd160: ripemd160
};
/**
* A fast MD5 JavaScript implementation
* Copyright (c) 2012 Joseph Myers
* http://www.myersdaily.org/joseph/javascript/md5-text.html
*
* Permission to use, copy, modify, and distribute this software
* and its documentation for any purposes and without
* fee is hereby granted provided that this copyright notice
* appears in all copies.
*
* Of course, this soft is provided "as is" without express or implied
* warranty of any kind.
*/
// MD5 Digest
async function md5(entree) {
const digest = md51(util.uint8ArrayToString(entree));
return util.hexToUint8Array(hex(digest));
}
function md5cycle(x, k) {
let a = x[0];
let b = x[1];
let c = x[2];
let d = x[3];
a = ff(a, b, c, d, k[0], 7, -680876936);
d = ff(d, a, b, c, k[1], 12, -389564586);
c = ff(c, d, a, b, k[2], 17, 606105819);
b = ff(b, c, d, a, k[3], 22, -1044525330);
a = ff(a, b, c, d, k[4], 7, -176418897);
d = ff(d, a, b, c, k[5], 12, 1200080426);
c = ff(c, d, a, b, k[6], 17, -1473231341);
b = ff(b, c, d, a, k[7], 22, -45705983);
a = ff(a, b, c, d, k[8], 7, 1770035416);
d = ff(d, a, b, c, k[9], 12, -1958414417);
c = ff(c, d, a, b, k[10], 17, -42063);
b = ff(b, c, d, a, k[11], 22, -1990404162);
a = ff(a, b, c, d, k[12], 7, 1804603682);
d = ff(d, a, b, c, k[13], 12, -40341101);
c = ff(c, d, a, b, k[14], 17, -1502002290);
b = ff(b, c, d, a, k[15], 22, 1236535329);
a = gg(a, b, c, d, k[1], 5, -165796510);
d = gg(d, a, b, c, k[6], 9, -1069501632);
c = gg(c, d, a, b, k[11], 14, 643717713);
b = gg(b, c, d, a, k[0], 20, -373897302);
a = gg(a, b, c, d, k[5], 5, -701558691);
d = gg(d, a, b, c, k[10], 9, 38016083);
c = gg(c, d, a, b, k[15], 14, -660478335);
b = gg(b, c, d, a, k[4], 20, -405537848);
a = gg(a, b, c, d, k[9], 5, 568446438);
d = gg(d, a, b, c, k[14], 9, -1019803690);
c = gg(c, d, a, b, k[3], 14, -187363961);
b = gg(b, c, d, a, k[8], 20, 1163531501);
a = gg(a, b, c, d, k[13], 5, -1444681467);
d = gg(d, a, b, c, k[2], 9, -51403784);
c = gg(c, d, a, b, k[7], 14, 1735328473);
b = gg(b, c, d, a, k[12], 20, -1926607734);
a = hh(a, b, c, d, k[5], 4, -378558);
d = hh(d, a, b, c, k[8], 11, -2022574463);
c = hh(c, d, a, b, k[11], 16, 1839030562);
b = hh(b, c, d, a, k[14], 23, -35309556);
a = hh(a, b, c, d, k[1], 4, -1530992060);
d = hh(d, a, b, c, k[4], 11, 1272893353);
c = hh(c, d, a, b, k[7], 16, -155497632);
b = hh(b, c, d, a, k[10], 23, -1094730640);
a = hh(a, b, c, d, k[13], 4, 681279174);
d = hh(d, a, b, c, k[0], 11, -358537222);
c = hh(c, d, a, b, k[3], 16, -722521979);
b = hh(b, c, d, a, k[6], 23, 76029189);
a = hh(a, b, c, d, k[9], 4, -640364487);
d = hh(d, a, b, c, k[12], 11, -421815835);
c = hh(c, d, a, b, k[15], 16, 530742520);
b = hh(b, c, d, a, k[2], 23, -995338651);
a = ii(a, b, c, d, k[0], 6, -198630844);
d = ii(d, a, b, c, k[7], 10, 1126891415);
c = ii(c, d, a, b, k[14], 15, -1416354905);
b = ii(b, c, d, a, k[5], 21, -57434055);
a = ii(a, b, c, d, k[12], 6, 1700485571);
d = ii(d, a, b, c, k[3], 10, -1894986606);
c = ii(c, d, a, b, k[10], 15, -1051523);
b = ii(b, c, d, a, k[1], 21, -2054922799);
a = ii(a, b, c, d, k[8], 6, 1873313359);
d = ii(d, a, b, c, k[15], 10, -30611744);
c = ii(c, d, a, b, k[6], 15, -1560198380);
b = ii(b, c, d, a, k[13], 21, 1309151649);
a = ii(a, b, c, d, k[4], 6, -145523070);
d = ii(d, a, b, c, k[11], 10, -1120210379);
c = ii(c, d, a, b, k[2], 15, 718787259);
b = ii(b, c, d, a, k[9], 21, -343485551);
x[0] = add32(a, x[0]);
x[1] = add32(b, x[1]);
x[2] = add32(c, x[2]);
x[3] = add32(d, x[3]);
}
function cmn(q, a, b, x, s, t) {
a = add32(add32(a, q), add32(x, t));
return add32((a << s) | (a >>> (32 - s)), b);
}
function ff(a, b, c, d, x, s, t) {
return cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function gg(a, b, c, d, x, s, t) {
return cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function hh(a, b, c, d, x, s, t) {
return cmn(b ^ c ^ d, a, b, x, s, t);
}
function ii(a, b, c, d, x, s, t) {
return cmn(c ^ (b | (~d)), a, b, x, s, t);
}
function md51(s) {
const n = s.length;
const state = [1732584193, -271733879, -1732584194, 271733878];
let i;
for (i = 64; i <= s.length; i += 64) {
md5cycle(state, md5blk(s.substring(i - 64, i)));
}
s = s.substring(i - 64);
const tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for (i = 0; i < s.length; i++) {
tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3);
}
tail[i >> 2] |= 0x80 << ((i % 4) << 3);
if (i > 55) {
md5cycle(state, tail);
for (i = 0; i < 16; i++) {
tail[i] = 0;
}
}
tail[14] = n * 8;
md5cycle(state, tail);
return state;
}
/* there needs to be support for Unicode here,
* unless we pretend that we can redefine the MD-5
* algorithm for multi-byte characters (perhaps
* by adding every four 16-bit characters and
* shortening the sum to 32 bits). Otherwise
* I suggest performing MD-5 as if every character
* was two bytes--e.g., 0040 0025 = @%--but then
* how will an ordinary MD-5 sum be matched?
* There is no way to standardize text to something
* like UTF-8 before transformation; speed cost is
* utterly prohibitive. The JavaScript standard
* itself needs to look at this: it should start
* providing access to strings as preformed UTF-8
* 8-bit unsigned value arrays.
*/
function md5blk(s) { /* I figured global was faster. */
const md5blks = [];
let i; /* Andy King said do it this way. */
for (i = 0; i < 64; i += 4) {
md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) <<
24);
}
return md5blks;
}
const hex_chr = '0123456789abcdef'.split('');
function rhex(n) {
let s = '';
let j = 0;
for (; j < 4; j++) {
s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] + hex_chr[(n >> (j * 8)) & 0x0F];
}
return s;
}
function hex(x) {
for (let i = 0; i < x.length; i++) {
x[i] = rhex(x[i]);
}
return x.join('');
}
/* this function is much faster,
so if possible we use it. Some IEs
are the only ones I know of that
need the idiotic second function,
generated by an if clause. */
function add32(a, b) {
return (a + b) & 0xFFFFFFFF;
}
/**
* @fileoverview Provides an interface to hashing functions available in Node.js or external libraries.
* @see {@link https://github.com/asmcrypto/asmcrypto.js|asmCrypto}
* @see {@link https://github.com/indutny/hash.js|hash.js}
* @module crypto/hash
* @private
*/
const webCrypto = util.getWebCrypto();
const nodeCrypto = util.getNodeCrypto();
const nodeCryptoHashes = nodeCrypto && nodeCrypto.getHashes();
function nodeHash(type) {
if (!nodeCrypto || !nodeCryptoHashes.includes(type)) {
return;
}
return async function (data) {
const shasum = nodeCrypto.createHash(type);
return transform(data, value => {
shasum.update(value);
}, () => new Uint8Array(shasum.digest()));
};
}
function hashjsHash(hash, webCryptoHash) {
return async function(data, config$1 = config) {
if (isArrayStream(data)) {
data = await readToEnd(data);
}
if (!util.isStream(data) && webCrypto && webCryptoHash && data.length >= config$1.minBytesForWebCrypto) {
return new Uint8Array(await webCrypto.digest(webCryptoHash, data));
}
const hashInstance = hash();
return transform(data, value => {
hashInstance.update(value);
}, () => new Uint8Array(hashInstance.digest()));
};
}
function asmcryptoHash(hash, webCryptoHash) {
return async function(data, config$1 = config) {
if (isArrayStream(data)) {
data = await readToEnd(data);
}
if (util.isStream(data)) {
const hashInstance = new hash();
return transform(data, value => {
hashInstance.process(value);
}, () => hashInstance.finish().result);
} else if (webCrypto && webCryptoHash && data.length >= config$1.minBytesForWebCrypto) {
return new Uint8Array(await webCrypto.digest(webCryptoHash, data));
} else {
return hash.bytes(data);
}
};
}
const hashFunctions = {
md5: nodeHash('md5') || md5,
sha1: nodeHash('sha1') || asmcryptoHash(Sha1, 'SHA-1'),
sha224: nodeHash('sha224') || hashjsHash(_224),
sha256: nodeHash('sha256') || asmcryptoHash(Sha256, 'SHA-256'),
sha384: nodeHash('sha384') || hashjsHash(_384, 'SHA-384'),
sha512: nodeHash('sha512') || hashjsHash(_512, 'SHA-512'), // asmcrypto sha512 is huge.
ripemd: nodeHash('ripemd160') || hashjsHash(ripemd160)
};
var hash = {
/** @see module:md5 */
md5: hashFunctions.md5,
/** @see asmCrypto */
sha1: hashFunctions.sha1,
/** @see hash.js */
sha224: hashFunctions.sha224,
/** @see asmCrypto */
sha256: hashFunctions.sha256,
/** @see hash.js */
sha384: hashFunctions.sha384,
/** @see asmCrypto */
sha512: hashFunctions.sha512,
/** @see hash.js */
ripemd: hashFunctions.ripemd,
/**
* Create a hash on the specified data using the specified algorithm
* @param {module:enums.hash} algo - Hash algorithm type (see {@link https://tools.ietf.org/html/rfc4880#section-9.4|RFC 4880 9.4})
* @param {Uint8Array} data - Data to be hashed
* @returns {Promise} Hash value.
*/
digest: function(algo, data) {
switch (algo) {
case enums.hash.md5:
return this.md5(data);
case enums.hash.sha1:
return this.sha1(data);
case enums.hash.ripemd:
return this.ripemd(data);
case enums.hash.sha256:
return this.sha256(data);
case enums.hash.sha384:
return this.sha384(data);
case enums.hash.sha512:
return this.sha512(data);
case enums.hash.sha224:
return this.sha224(data);
default:
throw new Error('Invalid hash function.');
}
},
/**
* Returns the hash size in bytes of the specified hash algorithm type
* @param {module:enums.hash} algo - Hash algorithm type (See {@link https://tools.ietf.org/html/rfc4880#section-9.4|RFC 4880 9.4})
* @returns {Integer} Size in bytes of the resulting hash.
*/
getHashByteLength: function(algo) {
switch (algo) {
case enums.hash.md5:
return 16;
case enums.hash.sha1:
case enums.hash.ripemd:
return 20;
case enums.hash.sha256:
return 32;
case enums.hash.sha384:
return 48;
case enums.hash.sha512:
return 64;
case enums.hash.sha224:
return 28;
default:
throw new Error('Invalid hash algorithm.');
}
}
};
class AES_CFB {
static encrypt(data, key, iv) {
return new AES_CFB(key, iv).encrypt(data);
}
static decrypt(data, key, iv) {
return new AES_CFB(key, iv).decrypt(data);
}
constructor(key, iv, aes) {
this.aes = aes ? aes : new AES(key, iv, true, 'CFB');
delete this.aes.padding;
}
encrypt(data) {
const r1 = this.aes.AES_Encrypt_process(data);
const r2 = this.aes.AES_Encrypt_finish();
return joinBytes(r1, r2);
}
decrypt(data) {
const r1 = this.aes.AES_Decrypt_process(data);
const r2 = this.aes.AES_Decrypt_finish();
return joinBytes(r1, r2);
}
}
/**
* Get implementation of the given cipher
* @param {enums.symmetric} algo
* @returns {Object}
* @throws {Error} on invalid algo
*/
function getCipher(algo) {
const algoName = enums.read(enums.symmetric, algo);
return cipher[algoName];
}
// Modified by ProtonTech AG
const webCrypto$1 = util.getWebCrypto();
const nodeCrypto$1 = util.getNodeCrypto();
const knownAlgos = nodeCrypto$1 ? nodeCrypto$1.getCiphers() : [];
const nodeAlgos = {
idea: knownAlgos.includes('idea-cfb') ? 'idea-cfb' : undefined, /* Unused, not implemented */
tripledes: knownAlgos.includes('des-ede3-cfb') ? 'des-ede3-cfb' : undefined,
cast5: knownAlgos.includes('cast5-cfb') ? 'cast5-cfb' : undefined,
blowfish: knownAlgos.includes('bf-cfb') ? 'bf-cfb' : undefined,
aes128: knownAlgos.includes('aes-128-cfb') ? 'aes-128-cfb' : undefined,
aes192: knownAlgos.includes('aes-192-cfb') ? 'aes-192-cfb' : undefined,
aes256: knownAlgos.includes('aes-256-cfb') ? 'aes-256-cfb' : undefined
/* twofish is not implemented in OpenSSL */
};
/**
* CFB encryption
* @param {enums.symmetric} algo - block cipher algorithm
* @param {Uint8Array} key
* @param {MaybeStream} plaintext
* @param {Uint8Array} iv
* @param {Object} config - full configuration, defaults to openpgp.config
* @returns MaybeStream
*/
async function encrypt(algo, key, plaintext, iv, config) {
const algoName = enums.read(enums.symmetric, algo);
if (util.getNodeCrypto() && nodeAlgos[algoName]) { // Node crypto library.
return nodeEncrypt(algo, key, plaintext, iv);
}
if (algoName.substr(0, 3) === 'aes') {
return aesEncrypt(algo, key, plaintext, iv, config);
}
const Cipher = getCipher(algo);
const cipherfn = new Cipher(key);
const block_size = cipherfn.blockSize;
const blockc = iv.slice();
let pt = new Uint8Array();
const process = chunk => {
if (chunk) {
pt = util.concatUint8Array([pt, chunk]);
}
const ciphertext = new Uint8Array(pt.length);
let i;
let j = 0;
while (chunk ? pt.length >= block_size : pt.length) {
const encblock = cipherfn.encrypt(blockc);
for (i = 0; i < block_size; i++) {
blockc[i] = pt[i] ^ encblock[i];
ciphertext[j++] = blockc[i];
}
pt = pt.subarray(block_size);
}
return ciphertext.subarray(0, j);
};
return transform(plaintext, process, process);
}
/**
* CFB decryption
* @param {enums.symmetric} algo - block cipher algorithm
* @param {Uint8Array} key
* @param {MaybeStream} ciphertext
* @param {Uint8Array} iv
* @returns MaybeStream
*/
async function decrypt(algo, key, ciphertext, iv) {
const algoName = enums.read(enums.symmetric, algo);
if (util.getNodeCrypto() && nodeAlgos[algoName]) { // Node crypto library.
return nodeDecrypt(algo, key, ciphertext, iv);
}
if (algoName.substr(0, 3) === 'aes') {
return aesDecrypt(algo, key, ciphertext, iv);
}
const Cipher = getCipher(algo);
const cipherfn = new Cipher(key);
const block_size = cipherfn.blockSize;
let blockp = iv;
let ct = new Uint8Array();
const process = chunk => {
if (chunk) {
ct = util.concatUint8Array([ct, chunk]);
}
const plaintext = new Uint8Array(ct.length);
let i;
let j = 0;
while (chunk ? ct.length >= block_size : ct.length) {
const decblock = cipherfn.encrypt(blockp);
blockp = ct;
for (i = 0; i < block_size; i++) {
plaintext[j++] = blockp[i] ^ decblock[i];
}
ct = ct.subarray(block_size);
}
return plaintext.subarray(0, j);
};
return transform(ciphertext, process, process);
}
function aesEncrypt(algo, key, pt, iv, config) {
if (
util.getWebCrypto() &&
key.length !== 24 && // Chrome doesn't support 192 bit keys, see https://www.chromium.org/blink/webcrypto#TOC-AES-support
!util.isStream(pt) &&
pt.length >= 3000 * config.minBytesForWebCrypto // Default to a 3MB minimum. Chrome is pretty slow for small messages, see: https://bugs.chromium.org/p/chromium/issues/detail?id=701188#c2
) { // Web Crypto
return webEncrypt(algo, key, pt, iv);
}
// asm.js fallback
const cfb = new AES_CFB(key, iv);
return transform(pt, value => cfb.aes.AES_Encrypt_process(value), () => cfb.aes.AES_Encrypt_finish());
}
function aesDecrypt(algo, key, ct, iv) {
if (util.isStream(ct)) {
const cfb = new AES_CFB(key, iv);
return transform(ct, value => cfb.aes.AES_Decrypt_process(value), () => cfb.aes.AES_Decrypt_finish());
}
return AES_CFB.decrypt(ct, key, iv);
}
function xorMut(a, b) {
for (let i = 0; i < a.length; i++) {
a[i] = a[i] ^ b[i];
}
}
async function webEncrypt(algo, key, pt, iv) {
const ALGO = 'AES-CBC';
const _key = await webCrypto$1.importKey('raw', key, { name: ALGO }, false, ['encrypt']);
const { blockSize } = getCipher(algo);
const cbc_pt = util.concatUint8Array([new Uint8Array(blockSize), pt]);
const ct = new Uint8Array(await webCrypto$1.encrypt({ name: ALGO, iv }, _key, cbc_pt)).subarray(0, pt.length);
xorMut(ct, pt);
return ct;
}
function nodeEncrypt(algo, key, pt, iv) {
const algoName = enums.read(enums.symmetric, algo);
const cipherObj = new nodeCrypto$1.createCipheriv(nodeAlgos[algoName], key, iv);
return transform(pt, value => new Uint8Array(cipherObj.update(value)));
}
function nodeDecrypt(algo, key, ct, iv) {
const algoName = enums.read(enums.symmetric, algo);
const decipherObj = new nodeCrypto$1.createDecipheriv(nodeAlgos[algoName], key, iv);
return transform(ct, value => new Uint8Array(decipherObj.update(value)));
}
var cfb = /*#__PURE__*/Object.freeze({
__proto__: null,
encrypt: encrypt,
decrypt: decrypt
});
class AES_CTR {
static encrypt(data, key, nonce) {
return new AES_CTR(key, nonce).encrypt(data);
}
static decrypt(data, key, nonce) {
return new AES_CTR(key, nonce).encrypt(data);
}
constructor(key, nonce, aes) {
this.aes = aes ? aes : new AES(key, undefined, false, 'CTR');
delete this.aes.padding;
this.AES_CTR_set_options(nonce);
}
encrypt(data) {
const r1 = this.aes.AES_Encrypt_process(data);
const r2 = this.aes.AES_Encrypt_finish();
return joinBytes(r1, r2);
}
decrypt(data) {
const r1 = this.aes.AES_Encrypt_process(data);
const r2 = this.aes.AES_Encrypt_finish();
return joinBytes(r1, r2);
}
AES_CTR_set_options(nonce, counter, size) {
let { asm } = this.aes.acquire_asm();
if (size !== undefined) {
if (size < 8 || size > 48)
throw new IllegalArgumentError('illegal counter size');
let mask = Math.pow(2, size) - 1;
asm.set_mask(0, 0, (mask / 0x100000000) | 0, mask | 0);
}
else {
size = 48;
asm.set_mask(0, 0, 0xffff, 0xffffffff);
}
if (nonce !== undefined) {
let len = nonce.length;
if (!len || len > 16)
throw new IllegalArgumentError('illegal nonce size');
let view = new DataView(new ArrayBuffer(16));
new Uint8Array(view.buffer).set(nonce);
asm.set_nonce(view.getUint32(0), view.getUint32(4), view.getUint32(8), view.getUint32(12));
}
else {
throw new Error('nonce is required');
}
if (counter !== undefined) {
if (counter < 0 || counter >= Math.pow(2, size))
throw new IllegalArgumentError('illegal counter value');
asm.set_counter(0, 0, (counter / 0x100000000) | 0, counter | 0);
}
}
}
class AES_CBC {
static encrypt(data, key, padding = true, iv) {
return new AES_CBC(key, iv, padding).encrypt(data);
}
static decrypt(data, key, padding = true, iv) {
return new AES_CBC(key, iv, padding).decrypt(data);
}
constructor(key, iv, padding = true, aes) {
this.aes = aes ? aes : new AES(key, iv, padding, 'CBC');
}
encrypt(data) {
const r1 = this.aes.AES_Encrypt_process(data);
const r2 = this.aes.AES_Encrypt_finish();
return joinBytes(r1, r2);
}
decrypt(data) {
const r1 = this.aes.AES_Decrypt_process(data);
const r2 = this.aes.AES_Decrypt_finish();
return joinBytes(r1, r2);
}
}
/**
* @fileoverview This module implements AES-CMAC on top of
* native AES-CBC using either the WebCrypto API or Node.js' crypto API.
* @module crypto/cmac
* @private
*/
const webCrypto$2 = util.getWebCrypto();
const nodeCrypto$2 = util.getNodeCrypto();
/**
* This implementation of CMAC is based on the description of OMAC in
* http://web.cs.ucdavis.edu/~rogaway/papers/eax.pdf. As per that
* document:
*
* We have made a small modification to the OMAC algorithm as it was
* originally presented, changing one of its two constants.
* Specifically, the constant 4 at line 85 was the constant 1/2 (the
* multiplicative inverse of 2) in the original definition of OMAC [14].
* The OMAC authors indicate that they will promulgate this modification
* [15], which slightly simplifies implementations.
*/
const blockLength = 16;
/**
* xor `padding` into the end of `data`. This function implements "the
* operation xor→ [which] xors the shorter string into the end of longer
* one". Since data is always as least as long as padding, we can
* simplify the implementation.
* @param {Uint8Array} data
* @param {Uint8Array} padding
*/
function rightXORMut(data, padding) {
const offset = data.length - blockLength;
for (let i = 0; i < blockLength; i++) {
data[i + offset] ^= padding[i];
}
return data;
}
function pad(data, padding, padding2) {
// if |M| in {n, 2n, 3n, ...}
if (data.length && data.length % blockLength === 0) {
// then return M xor→ B,
return rightXORMut(data, padding);
}
// else return (M || 10^(n−1−(|M| mod n))) xor→ P
const padded = new Uint8Array(data.length + (blockLength - (data.length % blockLength)));
padded.set(data);
padded[data.length] = 0b10000000;
return rightXORMut(padded, padding2);
}
const zeroBlock = new Uint8Array(blockLength);
async function CMAC(key) {
const cbc = await CBC(key);
// L ← E_K(0^n); B ← 2L; P ← 4L
const padding = util.double(await cbc(zeroBlock));
const padding2 = util.double(padding);
return async function(data) {
// return CBC_K(pad(M; B, P))
return (await cbc(pad(data, padding, padding2))).subarray(-blockLength);
};
}
async function CBC(key) {
if (util.getWebCrypto() && key.length !== 24) { // WebCrypto (no 192 bit support) see: https://www.chromium.org/blink/webcrypto#TOC-AES-support
key = await webCrypto$2.importKey('raw', key, { name: 'AES-CBC', length: key.length * 8 }, false, ['encrypt']);
return async function(pt) {
const ct = await webCrypto$2.encrypt({ name: 'AES-CBC', iv: zeroBlock, length: blockLength * 8 }, key, pt);
return new Uint8Array(ct).subarray(0, ct.byteLength - blockLength);
};
}
if (util.getNodeCrypto()) { // Node crypto library
return async function(pt) {
const en = new nodeCrypto$2.createCipheriv('aes-' + (key.length * 8) + '-cbc', key, zeroBlock);
const ct = en.update(pt);
return new Uint8Array(ct);
};
}
// asm.js fallback
return async function(pt) {
return AES_CBC.encrypt(pt, key, false, zeroBlock);
};
}
// OpenPGP.js - An OpenPGP implementation in javascript
const webCrypto$3 = util.getWebCrypto();
const nodeCrypto$3 = util.getNodeCrypto();
const Buffer$1 = util.getNodeBuffer();
const blockLength$1 = 16;
const ivLength = blockLength$1;
const tagLength = blockLength$1;
const zero = new Uint8Array(blockLength$1);
const one = new Uint8Array(blockLength$1); one[blockLength$1 - 1] = 1;
const two = new Uint8Array(blockLength$1); two[blockLength$1 - 1] = 2;
async function OMAC(key) {
const cmac = await CMAC(key);
return function(t, message) {
return cmac(util.concatUint8Array([t, message]));
};
}
async function CTR(key) {
if (
util.getWebCrypto() &&
key.length !== 24 // WebCrypto (no 192 bit support) see: https://www.chromium.org/blink/webcrypto#TOC-AES-support
) {
key = await webCrypto$3.importKey('raw', key, { name: 'AES-CTR', length: key.length * 8 }, false, ['encrypt']);
return async function(pt, iv) {
const ct = await webCrypto$3.encrypt({ name: 'AES-CTR', counter: iv, length: blockLength$1 * 8 }, key, pt);
return new Uint8Array(ct);
};
}
if (util.getNodeCrypto()) { // Node crypto library
return async function(pt, iv) {
const en = new nodeCrypto$3.createCipheriv('aes-' + (key.length * 8) + '-ctr', key, iv);
const ct = Buffer$1.concat([en.update(pt), en.final()]);
return new Uint8Array(ct);
};
}
// asm.js fallback
return async function(pt, iv) {
return AES_CTR.encrypt(pt, key, iv);
};
}
/**
* Class to en/decrypt using EAX mode.
* @param {enums.symmetric} cipher - The symmetric cipher algorithm to use
* @param {Uint8Array} key - The encryption key
*/
async function EAX(cipher, key) {
if (cipher !== enums.symmetric.aes128 &&
cipher !== enums.symmetric.aes192 &&
cipher !== enums.symmetric.aes256) {
throw new Error('EAX mode supports only AES cipher');
}
const [
omac,
ctr
] = await Promise.all([
OMAC(key),
CTR(key)
]);
return {
/**
* Encrypt plaintext input.
* @param {Uint8Array} plaintext - The cleartext input to be encrypted
* @param {Uint8Array} nonce - The nonce (16 bytes)
* @param {Uint8Array} adata - Associated data to sign
* @returns {Promise} The ciphertext output.
*/
encrypt: async function(plaintext, nonce, adata) {
const [
omacNonce,
omacAdata
] = await Promise.all([
omac(zero, nonce),
omac(one, adata)
]);
const ciphered = await ctr(plaintext, omacNonce);
const omacCiphered = await omac(two, ciphered);
const tag = omacCiphered; // Assumes that omac(*).length === tagLength.
for (let i = 0; i < tagLength; i++) {
tag[i] ^= omacAdata[i] ^ omacNonce[i];
}
return util.concatUint8Array([ciphered, tag]);
},
/**
* Decrypt ciphertext input.
* @param {Uint8Array} ciphertext - The ciphertext input to be decrypted
* @param {Uint8Array} nonce - The nonce (16 bytes)
* @param {Uint8Array} adata - Associated data to verify
* @returns {Promise} The plaintext output.
*/
decrypt: async function(ciphertext, nonce, adata) {
if (ciphertext.length < tagLength) throw new Error('Invalid EAX ciphertext');
const ciphered = ciphertext.subarray(0, -tagLength);
const ctTag = ciphertext.subarray(-tagLength);
const [
omacNonce,
omacAdata,
omacCiphered
] = await Promise.all([
omac(zero, nonce),
omac(one, adata),
omac(two, ciphered)
]);
const tag = omacCiphered; // Assumes that omac(*).length === tagLength.
for (let i = 0; i < tagLength; i++) {
tag[i] ^= omacAdata[i] ^ omacNonce[i];
}
if (!util.equalsUint8Array(ctTag, tag)) throw new Error('Authentication tag mismatch');
const plaintext = await ctr(ciphered, omacNonce);
return plaintext;
}
};
}
/**
* Get EAX nonce as defined by {@link https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-04#section-5.16.1|RFC4880bis-04, section 5.16.1}.
* @param {Uint8Array} iv - The initialization vector (16 bytes)
* @param {Uint8Array} chunkIndex - The chunk index (8 bytes)
*/
EAX.getNonce = function(iv, chunkIndex) {
const nonce = iv.slice();
for (let i = 0; i < chunkIndex.length; i++) {
nonce[8 + i] ^= chunkIndex[i];
}
return nonce;
};
EAX.blockLength = blockLength$1;
EAX.ivLength = ivLength;
EAX.tagLength = tagLength;
// OpenPGP.js - An OpenPGP implementation in javascript
const blockLength$2 = 16;
const ivLength$1 = 15;
// https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-04#section-5.16.2:
// While OCB [RFC7253] allows the authentication tag length to be of any
// number up to 128 bits long, this document requires a fixed
// authentication tag length of 128 bits (16 octets) for simplicity.
const tagLength$1 = 16;
function ntz(n) {
let ntz = 0;
for (let i = 1; (n & i) === 0; i <<= 1) {
ntz++;
}
return ntz;
}
function xorMut$1(S, T) {
for (let i = 0; i < S.length; i++) {
S[i] ^= T[i];
}
return S;
}
function xor(S, T) {
return xorMut$1(S.slice(), T);
}
const zeroBlock$1 = new Uint8Array(blockLength$2);
const one$1 = new Uint8Array([1]);
/**
* Class to en/decrypt using OCB mode.
* @param {enums.symmetric} cipher - The symmetric cipher algorithm to use
* @param {Uint8Array} key - The encryption key
*/
async function OCB(cipher$1, key) {
let maxNtz = 0;
let encipher;
let decipher;
let mask;
constructKeyVariables(cipher$1, key);
function constructKeyVariables(cipher$1, key) {
const cipherName = enums.read(enums.symmetric, cipher$1);
const aes = new cipher[cipherName](key);
encipher = aes.encrypt.bind(aes);
decipher = aes.decrypt.bind(aes);
const mask_x = encipher(zeroBlock$1);
const mask_$ = util.double(mask_x);
mask = [];
mask[0] = util.double(mask_$);
mask.x = mask_x;
mask.$ = mask_$;
}
function extendKeyVariables(text, adata) {
const newMaxNtz = util.nbits(Math.max(text.length, adata.length) / blockLength$2 | 0) - 1;
for (let i = maxNtz + 1; i <= newMaxNtz; i++) {
mask[i] = util.double(mask[i - 1]);
}
maxNtz = newMaxNtz;
}
function hash(adata) {
if (!adata.length) {
// Fast path
return zeroBlock$1;
}
//
// Consider A as a sequence of 128-bit blocks
//
const m = adata.length / blockLength$2 | 0;
const offset = new Uint8Array(blockLength$2);
const sum = new Uint8Array(blockLength$2);
for (let i = 0; i < m; i++) {
xorMut$1(offset, mask[ntz(i + 1)]);
xorMut$1(sum, encipher(xor(offset, adata)));
adata = adata.subarray(blockLength$2);
}
//
// Process any final partial block; compute final hash value
//
if (adata.length) {
xorMut$1(offset, mask.x);
const cipherInput = new Uint8Array(blockLength$2);
cipherInput.set(adata, 0);
cipherInput[adata.length] = 0b10000000;
xorMut$1(cipherInput, offset);
xorMut$1(sum, encipher(cipherInput));
}
return sum;
}
/**
* Encrypt/decrypt data.
* @param {encipher|decipher} fn - Encryption/decryption block cipher function
* @param {Uint8Array} text - The cleartext or ciphertext (without tag) input
* @param {Uint8Array} nonce - The nonce (15 bytes)
* @param {Uint8Array} adata - Associated data to sign
* @returns {Promise} The ciphertext or plaintext output, with tag appended in both cases.
*/
function crypt(fn, text, nonce, adata) {
//
// Consider P as a sequence of 128-bit blocks
//
const m = text.length / blockLength$2 | 0;
//
// Key-dependent variables
//
extendKeyVariables(text, adata);
//
// Nonce-dependent and per-encryption variables
//
// Nonce = num2str(TAGLEN mod 128,7) || zeros(120-bitlen(N)) || 1 || N
// Note: We assume here that tagLength mod 16 == 0.
const paddedNonce = util.concatUint8Array([zeroBlock$1.subarray(0, ivLength$1 - nonce.length), one$1, nonce]);
// bottom = str2num(Nonce[123..128])
const bottom = paddedNonce[blockLength$2 - 1] & 0b111111;
// Ktop = ENCIPHER(K, Nonce[1..122] || zeros(6))
paddedNonce[blockLength$2 - 1] &= 0b11000000;
const kTop = encipher(paddedNonce);
// Stretch = Ktop || (Ktop[1..64] xor Ktop[9..72])
const stretched = util.concatUint8Array([kTop, xor(kTop.subarray(0, 8), kTop.subarray(1, 9))]);
// Offset_0 = Stretch[1+bottom..128+bottom]
const offset = util.shiftRight(stretched.subarray(0 + (bottom >> 3), 17 + (bottom >> 3)), 8 - (bottom & 7)).subarray(1);
// Checksum_0 = zeros(128)
const checksum = new Uint8Array(blockLength$2);
const ct = new Uint8Array(text.length + tagLength$1);
//
// Process any whole blocks
//
let i;
let pos = 0;
for (i = 0; i < m; i++) {
// Offset_i = Offset_{i-1} xor L_{ntz(i)}
xorMut$1(offset, mask[ntz(i + 1)]);
// C_i = Offset_i xor ENCIPHER(K, P_i xor Offset_i)
// P_i = Offset_i xor DECIPHER(K, C_i xor Offset_i)
ct.set(xorMut$1(fn(xor(offset, text)), offset), pos);
// Checksum_i = Checksum_{i-1} xor P_i
xorMut$1(checksum, fn === encipher ? text : ct.subarray(pos));
text = text.subarray(blockLength$2);
pos += blockLength$2;
}
//
// Process any final partial block and compute raw tag
//
if (text.length) {
// Offset_* = Offset_m xor L_*
xorMut$1(offset, mask.x);
// Pad = ENCIPHER(K, Offset_*)
const padding = encipher(offset);
// C_* = P_* xor Pad[1..bitlen(P_*)]
ct.set(xor(text, padding), pos);
// Checksum_* = Checksum_m xor (P_* || 1 || new Uint8Array(127-bitlen(P_*)))
const xorInput = new Uint8Array(blockLength$2);
xorInput.set(fn === encipher ? text : ct.subarray(pos, -tagLength$1), 0);
xorInput[text.length] = 0b10000000;
xorMut$1(checksum, xorInput);
pos += text.length;
}
// Tag = ENCIPHER(K, Checksum_* xor Offset_* xor L_$) xor HASH(K,A)
const tag = xorMut$1(encipher(xorMut$1(xorMut$1(checksum, offset), mask.$)), hash(adata));
//
// Assemble ciphertext
//
// C = C_1 || C_2 || ... || C_m || C_* || Tag[1..TAGLEN]
ct.set(tag, pos);
return ct;
}
return {
/**
* Encrypt plaintext input.
* @param {Uint8Array} plaintext - The cleartext input to be encrypted
* @param {Uint8Array} nonce - The nonce (15 bytes)
* @param {Uint8Array} adata - Associated data to sign
* @returns {Promise} The ciphertext output.
*/
encrypt: async function(plaintext, nonce, adata) {
return crypt(encipher, plaintext, nonce, adata);
},
/**
* Decrypt ciphertext input.
* @param {Uint8Array} ciphertext - The ciphertext input to be decrypted
* @param {Uint8Array} nonce - The nonce (15 bytes)
* @param {Uint8Array} adata - Associated data to sign
* @returns {Promise} The ciphertext output.
*/
decrypt: async function(ciphertext, nonce, adata) {
if (ciphertext.length < tagLength$1) throw new Error('Invalid OCB ciphertext');
const tag = ciphertext.subarray(-tagLength$1);
ciphertext = ciphertext.subarray(0, -tagLength$1);
const crypted = crypt(decipher, ciphertext, nonce, adata);
// if (Tag[1..TAGLEN] == T)
if (util.equalsUint8Array(tag, crypted.subarray(-tagLength$1))) {
return crypted.subarray(0, -tagLength$1);
}
throw new Error('Authentication tag mismatch');
}
};
}
/**
* Get OCB nonce as defined by {@link https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-04#section-5.16.2|RFC4880bis-04, section 5.16.2}.
* @param {Uint8Array} iv - The initialization vector (15 bytes)
* @param {Uint8Array} chunkIndex - The chunk index (8 bytes)
*/
OCB.getNonce = function(iv, chunkIndex) {
const nonce = iv.slice();
for (let i = 0; i < chunkIndex.length; i++) {
nonce[7 + i] ^= chunkIndex[i];
}
return nonce;
};
OCB.blockLength = blockLength$2;
OCB.ivLength = ivLength$1;
OCB.tagLength = tagLength$1;
const _AES_GCM_data_maxLength = 68719476704; // 2^36 - 2^5
class AES_GCM {
constructor(key, nonce, adata, tagSize = 16, aes) {
this.tagSize = tagSize;
this.gamma0 = 0;
this.counter = 1;
this.aes = aes ? aes : new AES(key, undefined, false, 'CTR');
let { asm, heap } = this.aes.acquire_asm();
// Init GCM
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);
heap[0] = 0;
heap[1] = 0;
heap[2] = 0;
heap[3] = 0;
heap[4] = 0;
heap[5] = 0;
heap[6] = 0;
heap[7] = 0;
heap[8] = 0;
heap[9] = 0;
heap[10] = 0;
heap[11] = noncelen >>> 29;
heap[12] = (noncelen >>> 21) & 255;
heap[13] = (noncelen >>> 13) & 255;
heap[14] = (noncelen >>> 5) & 255;
heap[15] = (noncelen << 3) & 255;
asm.mac(AES_asm.MAC.GCM, AES_asm.HEAP_DATA, 16);
asm.get_iv(AES_asm.HEAP_DATA);
asm.set_iv(0, 0, 0, 0);
noncebuf.set(heap.subarray(0, 16));
}
else {
noncebuf.set(nonce);
noncebuf[15] = 1;
}
const nonceview = new DataView(noncebuf.buffer);
this.gamma0 = nonceview.getUint32(12);
asm.set_nonce(nonceview.getUint32(0), nonceview.getUint32(4), nonceview.getUint32(8), 0);
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');
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, heap } = this.aes.acquire_asm();
let counter = this.counter;
let pos = this.aes.pos;
let len = this.aes.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.aes.pos = pos;
this.aes.len = len;
return result;
}
AES_GCM_Encrypt_finish() {
let { asm, heap } = this.aes.acquire_asm();
let counter = this.counter;
let tagSize = this.tagSize;
let adata = this.adata;
let pos = this.aes.pos;
let len = this.aes.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.aes.pos = 0;
this.aes.len = 0;
return result;
}
AES_GCM_Decrypt_process(data) {
let dpos = 0;
let dlen = data.length || 0;
let { asm, heap } = this.aes.acquire_asm();
let counter = this.counter;
let tagSize = this.tagSize;
let pos = this.aes.pos;
let len = this.aes.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.aes.pos = pos;
this.aes.len = len;
return result;
}
AES_GCM_Decrypt_finish() {
let { asm, heap } = this.aes.acquire_asm();
let tagSize = this.tagSize;
let adata = this.adata;
let counter = this.counter;
let pos = this.aes.pos;
let len = this.aes.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.aes.pos = 0;
this.aes.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) {
let { asm, heap } = this.aes.acquire_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);
}
}
}
// OpenPGP.js - An OpenPGP implementation in javascript
const webCrypto$4 = util.getWebCrypto();
const nodeCrypto$4 = util.getNodeCrypto();
const Buffer$2 = util.getNodeBuffer();
const blockLength$3 = 16;
const ivLength$2 = 12; // size of the IV in bytes
const tagLength$2 = 16; // size of the tag in bytes
const ALGO = 'AES-GCM';
/**
* Class to en/decrypt using GCM mode.
* @param {enums.symmetric} cipher - The symmetric cipher algorithm to use
* @param {Uint8Array} key - The encryption key
*/
async function GCM(cipher, key) {
if (cipher !== enums.symmetric.aes128 &&
cipher !== enums.symmetric.aes192 &&
cipher !== enums.symmetric.aes256) {
throw new Error('GCM mode supports only AES cipher');
}
if (util.getWebCrypto() && key.length !== 24) { // WebCrypto (no 192 bit support) see: https://www.chromium.org/blink/webcrypto#TOC-AES-support
const _key = await webCrypto$4.importKey('raw', key, { name: ALGO }, false, ['encrypt', 'decrypt']);
return {
encrypt: async function(pt, iv, adata = new Uint8Array()) {
if (!pt.length) { // iOS does not support GCM-en/decrypting empty messages
return AES_GCM.encrypt(pt, key, iv, adata);
}
const ct = await webCrypto$4.encrypt({ name: ALGO, iv, additionalData: adata, tagLength: tagLength$2 * 8 }, _key, pt);
return new Uint8Array(ct);
},
decrypt: async function(ct, iv, adata = new Uint8Array()) {
if (ct.length === tagLength$2) { // iOS does not support GCM-en/decrypting empty messages
return AES_GCM.decrypt(ct, key, iv, adata);
}
const pt = await webCrypto$4.decrypt({ name: ALGO, iv, additionalData: adata, tagLength: tagLength$2 * 8 }, _key, ct);
return new Uint8Array(pt);
}
};
}
if (util.getNodeCrypto()) { // Node crypto library
return {
encrypt: async function(pt, iv, adata = new Uint8Array()) {
const en = new nodeCrypto$4.createCipheriv('aes-' + (key.length * 8) + '-gcm', key, iv);
en.setAAD(adata);
const ct = Buffer$2.concat([en.update(pt), en.final(), en.getAuthTag()]); // append auth tag to ciphertext
return new Uint8Array(ct);
},
decrypt: async function(ct, iv, adata = new Uint8Array()) {
const de = new nodeCrypto$4.createDecipheriv('aes-' + (key.length * 8) + '-gcm', key, iv);
de.setAAD(adata);
de.setAuthTag(ct.slice(ct.length - tagLength$2, ct.length)); // read auth tag at end of ciphertext
const pt = Buffer$2.concat([de.update(ct.slice(0, ct.length - tagLength$2)), de.final()]);
return new Uint8Array(pt);
}
};
}
return {
encrypt: async function(pt, iv, adata) {
return AES_GCM.encrypt(pt, key, iv, adata);
},
decrypt: async function(ct, iv, adata) {
return AES_GCM.decrypt(ct, key, iv, adata);
}
};
}
/**
* Get GCM nonce. Note: this operation is not defined by the standard.
* A future version of the standard may define GCM mode differently,
* hopefully under a different ID (we use Private/Experimental algorithm
* ID 100) so that we can maintain backwards compatibility.
* @param {Uint8Array} iv - The initialization vector (12 bytes)
* @param {Uint8Array} chunkIndex - The chunk index (8 bytes)
*/
GCM.getNonce = function(iv, chunkIndex) {
const nonce = iv.slice();
for (let i = 0; i < chunkIndex.length; i++) {
nonce[4 + i] ^= chunkIndex[i];
}
return nonce;
};
GCM.blockLength = blockLength$3;
GCM.ivLength = ivLength$2;
GCM.tagLength = tagLength$2;
/**
* @fileoverview Cipher modes
* @module crypto/mode
* @private
*/
var mode = {
/** @see module:crypto/mode/cfb */
cfb: cfb,
/** @see module:crypto/mode/gcm */
gcm: GCM,
experimentalGCM: GCM,
/** @see module:crypto/mode/eax */
eax: EAX,
/** @see module:crypto/mode/ocb */
ocb: OCB
};
var naclFastLight = createCommonjsModule(function (module) {
/*jshint bitwise: false*/
(function(nacl) {
// Ported in 2014 by Dmitry Chestnykh and Devi Mandiri.
// Public domain.
//
// Implementation derived from TweetNaCl version 20140427.
// See for details: http://tweetnacl.cr.yp.to/
var gf = function(init) {
var i, r = new Float64Array(16);
if (init) for (i = 0; i < init.length; i++) r[i] = init[i];
return r;
};
// Pluggable, initialized in high-level API below.
var randombytes = function(/* x, n */) { throw new Error('no PRNG'); };
var _9 = new Uint8Array(32); _9[0] = 9;
var gf0 = gf(),
gf1 = gf([1]),
_121665 = gf([0xdb41, 1]),
D = gf([0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203]),
D2 = gf([0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406]),
X = gf([0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169]),
Y = gf([0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666]),
I = gf([0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83]);
function vn(x, xi, y, yi, n) {
var i,d = 0;
for (i = 0; i < n; i++) d |= x[xi+i]^y[yi+i];
return (1 & ((d - 1) >>> 8)) - 1;
}
function crypto_verify_32(x, xi, y, yi) {
return vn(x,xi,y,yi,32);
}
function set25519(r, a) {
var i;
for (i = 0; i < 16; i++) r[i] = a[i]|0;
}
function car25519(o) {
var i, v, c = 1;
for (i = 0; i < 16; i++) {
v = o[i] + c + 65535;
c = Math.floor(v / 65536);
o[i] = v - c * 65536;
}
o[0] += c-1 + 37 * (c-1);
}
function sel25519(p, q, b) {
var t, c = ~(b-1);
for (var i = 0; i < 16; i++) {
t = c & (p[i] ^ q[i]);
p[i] ^= t;
q[i] ^= t;
}
}
function pack25519(o, n) {
var i, j, b;
var m = gf(), t = gf();
for (i = 0; i < 16; i++) t[i] = n[i];
car25519(t);
car25519(t);
car25519(t);
for (j = 0; j < 2; j++) {
m[0] = t[0] - 0xffed;
for (i = 1; i < 15; i++) {
m[i] = t[i] - 0xffff - ((m[i-1]>>16) & 1);
m[i-1] &= 0xffff;
}
m[15] = t[15] - 0x7fff - ((m[14]>>16) & 1);
b = (m[15]>>16) & 1;
m[14] &= 0xffff;
sel25519(t, m, 1-b);
}
for (i = 0; i < 16; i++) {
o[2*i] = t[i] & 0xff;
o[2*i+1] = t[i]>>8;
}
}
function neq25519(a, b) {
var c = new Uint8Array(32), d = new Uint8Array(32);
pack25519(c, a);
pack25519(d, b);
return crypto_verify_32(c, 0, d, 0);
}
function par25519(a) {
var d = new Uint8Array(32);
pack25519(d, a);
return d[0] & 1;
}
function unpack25519(o, n) {
var i;
for (i = 0; i < 16; i++) o[i] = n[2*i] + (n[2*i+1] << 8);
o[15] &= 0x7fff;
}
function A(o, a, b) {
for (var i = 0; i < 16; i++) o[i] = a[i] + b[i];
}
function Z(o, a, b) {
for (var i = 0; i < 16; i++) o[i] = a[i] - b[i];
}
function M(o, a, b) {
var v, c,
t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0,
t8 = 0, t9 = 0, t10 = 0, t11 = 0, t12 = 0, t13 = 0, t14 = 0, t15 = 0,
t16 = 0, t17 = 0, t18 = 0, t19 = 0, t20 = 0, t21 = 0, t22 = 0, t23 = 0,
t24 = 0, t25 = 0, t26 = 0, t27 = 0, t28 = 0, t29 = 0, t30 = 0,
b0 = b[0],
b1 = b[1],
b2 = b[2],
b3 = b[3],
b4 = b[4],
b5 = b[5],
b6 = b[6],
b7 = b[7],
b8 = b[8],
b9 = b[9],
b10 = b[10],
b11 = b[11],
b12 = b[12],
b13 = b[13],
b14 = b[14],
b15 = b[15];
v = a[0];
t0 += v * b0;
t1 += v * b1;
t2 += v * b2;
t3 += v * b3;
t4 += v * b4;
t5 += v * b5;
t6 += v * b6;
t7 += v * b7;
t8 += v * b8;
t9 += v * b9;
t10 += v * b10;
t11 += v * b11;
t12 += v * b12;
t13 += v * b13;
t14 += v * b14;
t15 += v * b15;
v = a[1];
t1 += v * b0;
t2 += v * b1;
t3 += v * b2;
t4 += v * b3;
t5 += v * b4;
t6 += v * b5;
t7 += v * b6;
t8 += v * b7;
t9 += v * b8;
t10 += v * b9;
t11 += v * b10;
t12 += v * b11;
t13 += v * b12;
t14 += v * b13;
t15 += v * b14;
t16 += v * b15;
v = a[2];
t2 += v * b0;
t3 += v * b1;
t4 += v * b2;
t5 += v * b3;
t6 += v * b4;
t7 += v * b5;
t8 += v * b6;
t9 += v * b7;
t10 += v * b8;
t11 += v * b9;
t12 += v * b10;
t13 += v * b11;
t14 += v * b12;
t15 += v * b13;
t16 += v * b14;
t17 += v * b15;
v = a[3];
t3 += v * b0;
t4 += v * b1;
t5 += v * b2;
t6 += v * b3;
t7 += v * b4;
t8 += v * b5;
t9 += v * b6;
t10 += v * b7;
t11 += v * b8;
t12 += v * b9;
t13 += v * b10;
t14 += v * b11;
t15 += v * b12;
t16 += v * b13;
t17 += v * b14;
t18 += v * b15;
v = a[4];
t4 += v * b0;
t5 += v * b1;
t6 += v * b2;
t7 += v * b3;
t8 += v * b4;
t9 += v * b5;
t10 += v * b6;
t11 += v * b7;
t12 += v * b8;
t13 += v * b9;
t14 += v * b10;
t15 += v * b11;
t16 += v * b12;
t17 += v * b13;
t18 += v * b14;
t19 += v * b15;
v = a[5];
t5 += v * b0;
t6 += v * b1;
t7 += v * b2;
t8 += v * b3;
t9 += v * b4;
t10 += v * b5;
t11 += v * b6;
t12 += v * b7;
t13 += v * b8;
t14 += v * b9;
t15 += v * b10;
t16 += v * b11;
t17 += v * b12;
t18 += v * b13;
t19 += v * b14;
t20 += v * b15;
v = a[6];
t6 += v * b0;
t7 += v * b1;
t8 += v * b2;
t9 += v * b3;
t10 += v * b4;
t11 += v * b5;
t12 += v * b6;
t13 += v * b7;
t14 += v * b8;
t15 += v * b9;
t16 += v * b10;
t17 += v * b11;
t18 += v * b12;
t19 += v * b13;
t20 += v * b14;
t21 += v * b15;
v = a[7];
t7 += v * b0;
t8 += v * b1;
t9 += v * b2;
t10 += v * b3;
t11 += v * b4;
t12 += v * b5;
t13 += v * b6;
t14 += v * b7;
t15 += v * b8;
t16 += v * b9;
t17 += v * b10;
t18 += v * b11;
t19 += v * b12;
t20 += v * b13;
t21 += v * b14;
t22 += v * b15;
v = a[8];
t8 += v * b0;
t9 += v * b1;
t10 += v * b2;
t11 += v * b3;
t12 += v * b4;
t13 += v * b5;
t14 += v * b6;
t15 += v * b7;
t16 += v * b8;
t17 += v * b9;
t18 += v * b10;
t19 += v * b11;
t20 += v * b12;
t21 += v * b13;
t22 += v * b14;
t23 += v * b15;
v = a[9];
t9 += v * b0;
t10 += v * b1;
t11 += v * b2;
t12 += v * b3;
t13 += v * b4;
t14 += v * b5;
t15 += v * b6;
t16 += v * b7;
t17 += v * b8;
t18 += v * b9;
t19 += v * b10;
t20 += v * b11;
t21 += v * b12;
t22 += v * b13;
t23 += v * b14;
t24 += v * b15;
v = a[10];
t10 += v * b0;
t11 += v * b1;
t12 += v * b2;
t13 += v * b3;
t14 += v * b4;
t15 += v * b5;
t16 += v * b6;
t17 += v * b7;
t18 += v * b8;
t19 += v * b9;
t20 += v * b10;
t21 += v * b11;
t22 += v * b12;
t23 += v * b13;
t24 += v * b14;
t25 += v * b15;
v = a[11];
t11 += v * b0;
t12 += v * b1;
t13 += v * b2;
t14 += v * b3;
t15 += v * b4;
t16 += v * b5;
t17 += v * b6;
t18 += v * b7;
t19 += v * b8;
t20 += v * b9;
t21 += v * b10;
t22 += v * b11;
t23 += v * b12;
t24 += v * b13;
t25 += v * b14;
t26 += v * b15;
v = a[12];
t12 += v * b0;
t13 += v * b1;
t14 += v * b2;
t15 += v * b3;
t16 += v * b4;
t17 += v * b5;
t18 += v * b6;
t19 += v * b7;
t20 += v * b8;
t21 += v * b9;
t22 += v * b10;
t23 += v * b11;
t24 += v * b12;
t25 += v * b13;
t26 += v * b14;
t27 += v * b15;
v = a[13];
t13 += v * b0;
t14 += v * b1;
t15 += v * b2;
t16 += v * b3;
t17 += v * b4;
t18 += v * b5;
t19 += v * b6;
t20 += v * b7;
t21 += v * b8;
t22 += v * b9;
t23 += v * b10;
t24 += v * b11;
t25 += v * b12;
t26 += v * b13;
t27 += v * b14;
t28 += v * b15;
v = a[14];
t14 += v * b0;
t15 += v * b1;
t16 += v * b2;
t17 += v * b3;
t18 += v * b4;
t19 += v * b5;
t20 += v * b6;
t21 += v * b7;
t22 += v * b8;
t23 += v * b9;
t24 += v * b10;
t25 += v * b11;
t26 += v * b12;
t27 += v * b13;
t28 += v * b14;
t29 += v * b15;
v = a[15];
t15 += v * b0;
t16 += v * b1;
t17 += v * b2;
t18 += v * b3;
t19 += v * b4;
t20 += v * b5;
t21 += v * b6;
t22 += v * b7;
t23 += v * b8;
t24 += v * b9;
t25 += v * b10;
t26 += v * b11;
t27 += v * b12;
t28 += v * b13;
t29 += v * b14;
t30 += v * b15;
t0 += 38 * t16;
t1 += 38 * t17;
t2 += 38 * t18;
t3 += 38 * t19;
t4 += 38 * t20;
t5 += 38 * t21;
t6 += 38 * t22;
t7 += 38 * t23;
t8 += 38 * t24;
t9 += 38 * t25;
t10 += 38 * t26;
t11 += 38 * t27;
t12 += 38 * t28;
t13 += 38 * t29;
t14 += 38 * t30;
// t15 left as is
// first car
c = 1;
v = t0 + c + 65535; c = Math.floor(v / 65536); t0 = v - c * 65536;
v = t1 + c + 65535; c = Math.floor(v / 65536); t1 = v - c * 65536;
v = t2 + c + 65535; c = Math.floor(v / 65536); t2 = v - c * 65536;
v = t3 + c + 65535; c = Math.floor(v / 65536); t3 = v - c * 65536;
v = t4 + c + 65535; c = Math.floor(v / 65536); t4 = v - c * 65536;
v = t5 + c + 65535; c = Math.floor(v / 65536); t5 = v - c * 65536;
v = t6 + c + 65535; c = Math.floor(v / 65536); t6 = v - c * 65536;
v = t7 + c + 65535; c = Math.floor(v / 65536); t7 = v - c * 65536;
v = t8 + c + 65535; c = Math.floor(v / 65536); t8 = v - c * 65536;
v = t9 + c + 65535; c = Math.floor(v / 65536); t9 = v - c * 65536;
v = t10 + c + 65535; c = Math.floor(v / 65536); t10 = v - c * 65536;
v = t11 + c + 65535; c = Math.floor(v / 65536); t11 = v - c * 65536;
v = t12 + c + 65535; c = Math.floor(v / 65536); t12 = v - c * 65536;
v = t13 + c + 65535; c = Math.floor(v / 65536); t13 = v - c * 65536;
v = t14 + c + 65535; c = Math.floor(v / 65536); t14 = v - c * 65536;
v = t15 + c + 65535; c = Math.floor(v / 65536); t15 = v - c * 65536;
t0 += c-1 + 37 * (c-1);
// second car
c = 1;
v = t0 + c + 65535; c = Math.floor(v / 65536); t0 = v - c * 65536;
v = t1 + c + 65535; c = Math.floor(v / 65536); t1 = v - c * 65536;
v = t2 + c + 65535; c = Math.floor(v / 65536); t2 = v - c * 65536;
v = t3 + c + 65535; c = Math.floor(v / 65536); t3 = v - c * 65536;
v = t4 + c + 65535; c = Math.floor(v / 65536); t4 = v - c * 65536;
v = t5 + c + 65535; c = Math.floor(v / 65536); t5 = v - c * 65536;
v = t6 + c + 65535; c = Math.floor(v / 65536); t6 = v - c * 65536;
v = t7 + c + 65535; c = Math.floor(v / 65536); t7 = v - c * 65536;
v = t8 + c + 65535; c = Math.floor(v / 65536); t8 = v - c * 65536;
v = t9 + c + 65535; c = Math.floor(v / 65536); t9 = v - c * 65536;
v = t10 + c + 65535; c = Math.floor(v / 65536); t10 = v - c * 65536;
v = t11 + c + 65535; c = Math.floor(v / 65536); t11 = v - c * 65536;
v = t12 + c + 65535; c = Math.floor(v / 65536); t12 = v - c * 65536;
v = t13 + c + 65535; c = Math.floor(v / 65536); t13 = v - c * 65536;
v = t14 + c + 65535; c = Math.floor(v / 65536); t14 = v - c * 65536;
v = t15 + c + 65535; c = Math.floor(v / 65536); t15 = v - c * 65536;
t0 += c-1 + 37 * (c-1);
o[ 0] = t0;
o[ 1] = t1;
o[ 2] = t2;
o[ 3] = t3;
o[ 4] = t4;
o[ 5] = t5;
o[ 6] = t6;
o[ 7] = t7;
o[ 8] = t8;
o[ 9] = t9;
o[10] = t10;
o[11] = t11;
o[12] = t12;
o[13] = t13;
o[14] = t14;
o[15] = t15;
}
function S(o, a) {
M(o, a, a);
}
function inv25519(o, i) {
var c = gf();
var a;
for (a = 0; a < 16; a++) c[a] = i[a];
for (a = 253; a >= 0; a--) {
S(c, c);
if(a !== 2 && a !== 4) M(c, c, i);
}
for (a = 0; a < 16; a++) o[a] = c[a];
}
function pow2523(o, i) {
var c = gf();
var a;
for (a = 0; a < 16; a++) c[a] = i[a];
for (a = 250; a >= 0; a--) {
S(c, c);
if(a !== 1) M(c, c, i);
}
for (a = 0; a < 16; a++) o[a] = c[a];
}
function crypto_scalarmult(q, n, p) {
var z = new Uint8Array(32);
var x = new Float64Array(80), r, i;
var a = gf(), b = gf(), c = gf(),
d = gf(), e = gf(), f = gf();
for (i = 0; i < 31; i++) z[i] = n[i];
z[31]=(n[31]&127)|64;
z[0]&=248;
unpack25519(x,p);
for (i = 0; i < 16; i++) {
b[i]=x[i];
d[i]=a[i]=c[i]=0;
}
a[0]=d[0]=1;
for (i=254; i>=0; --i) {
r=(z[i>>>3]>>>(i&7))&1;
sel25519(a,b,r);
sel25519(c,d,r);
A(e,a,c);
Z(a,a,c);
A(c,b,d);
Z(b,b,d);
S(d,e);
S(f,a);
M(a,c,a);
M(c,b,e);
A(e,a,c);
Z(a,a,c);
S(b,a);
Z(c,d,f);
M(a,c,_121665);
A(a,a,d);
M(c,c,a);
M(a,d,f);
M(d,b,x);
S(b,e);
sel25519(a,b,r);
sel25519(c,d,r);
}
for (i = 0; i < 16; i++) {
x[i+16]=a[i];
x[i+32]=c[i];
x[i+48]=b[i];
x[i+64]=d[i];
}
var x32 = x.subarray(32);
var x16 = x.subarray(16);
inv25519(x32,x32);
M(x16,x16,x32);
pack25519(q,x16);
return 0;
}
function crypto_scalarmult_base(q, n) {
return crypto_scalarmult(q, n, _9);
}
function crypto_box_keypair(y, x) {
randombytes(x, 32);
return crypto_scalarmult_base(y, x);
}
function add(p, q) {
var a = gf(), b = gf(), c = gf(),
d = gf(), e = gf(), f = gf(),
g = gf(), h = gf(), t = gf();
Z(a, p[1], p[0]);
Z(t, q[1], q[0]);
M(a, a, t);
A(b, p[0], p[1]);
A(t, q[0], q[1]);
M(b, b, t);
M(c, p[3], q[3]);
M(c, c, D2);
M(d, p[2], q[2]);
A(d, d, d);
Z(e, b, a);
Z(f, d, c);
A(g, d, c);
A(h, b, a);
M(p[0], e, f);
M(p[1], h, g);
M(p[2], g, f);
M(p[3], e, h);
}
function cswap(p, q, b) {
var i;
for (i = 0; i < 4; i++) {
sel25519(p[i], q[i], b);
}
}
function pack(r, p) {
var tx = gf(), ty = gf(), zi = gf();
inv25519(zi, p[2]);
M(tx, p[0], zi);
M(ty, p[1], zi);
pack25519(r, ty);
r[31] ^= par25519(tx) << 7;
}
function scalarmult(p, q, s) {
var b, i;
set25519(p[0], gf0);
set25519(p[1], gf1);
set25519(p[2], gf1);
set25519(p[3], gf0);
for (i = 255; i >= 0; --i) {
b = (s[(i/8)|0] >> (i&7)) & 1;
cswap(p, q, b);
add(q, p);
add(p, p);
cswap(p, q, b);
}
}
function scalarbase(p, s) {
var q = [gf(), gf(), gf(), gf()];
set25519(q[0], X);
set25519(q[1], Y);
set25519(q[2], gf1);
M(q[3], X, Y);
scalarmult(p, q, s);
}
function crypto_sign_keypair(pk, sk, seeded) {
var d;
var p = [gf(), gf(), gf(), gf()];
var i;
if (!seeded) randombytes(sk, 32);
d = nacl.hash(sk.subarray(0, 32));
d[0] &= 248;
d[31] &= 127;
d[31] |= 64;
scalarbase(p, d);
pack(pk, p);
for (i = 0; i < 32; i++) sk[i+32] = pk[i];
return 0;
}
var L = new Float64Array([0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10]);
function modL(r, x) {
var carry, i, j, k;
for (i = 63; i >= 32; --i) {
carry = 0;
for (j = i - 32, k = i - 12; j < k; ++j) {
x[j] += carry - 16 * x[i] * L[j - (i - 32)];
carry = Math.floor((x[j] + 128) / 256);
x[j] -= carry * 256;
}
x[j] += carry;
x[i] = 0;
}
carry = 0;
for (j = 0; j < 32; j++) {
x[j] += carry - (x[31] >> 4) * L[j];
carry = x[j] >> 8;
x[j] &= 255;
}
for (j = 0; j < 32; j++) x[j] -= carry * L[j];
for (i = 0; i < 32; i++) {
x[i+1] += x[i] >> 8;
r[i] = x[i] & 255;
}
}
function reduce(r) {
var x = new Float64Array(64), i;
for (i = 0; i < 64; i++) x[i] = r[i];
for (i = 0; i < 64; i++) r[i] = 0;
modL(r, x);
}
// Note: difference from C - smlen returned, not passed as argument.
function crypto_sign(sm, m, n, sk) {
var d, h, r;
var i, j, x = new Float64Array(64);
var p = [gf(), gf(), gf(), gf()];
d = nacl.hash(sk.subarray(0, 32));
d[0] &= 248;
d[31] &= 127;
d[31] |= 64;
var smlen = n + 64;
for (i = 0; i < n; i++) sm[64 + i] = m[i];
for (i = 0; i < 32; i++) sm[32 + i] = d[32 + i];
r = nacl.hash(sm.subarray(32, smlen));
reduce(r);
scalarbase(p, r);
pack(sm, p);
for (i = 32; i < 64; i++) sm[i] = sk[i];
h = nacl.hash(sm.subarray(0, smlen));
reduce(h);
for (i = 0; i < 64; i++) x[i] = 0;
for (i = 0; i < 32; i++) x[i] = r[i];
for (i = 0; i < 32; i++) {
for (j = 0; j < 32; j++) {
x[i+j] += h[i] * d[j];
}
}
modL(sm.subarray(32), x);
return smlen;
}
function unpackneg(r, p) {
var t = gf(), chk = gf(), num = gf(),
den = gf(), den2 = gf(), den4 = gf(),
den6 = gf();
set25519(r[2], gf1);
unpack25519(r[1], p);
S(num, r[1]);
M(den, num, D);
Z(num, num, r[2]);
A(den, r[2], den);
S(den2, den);
S(den4, den2);
M(den6, den4, den2);
M(t, den6, num);
M(t, t, den);
pow2523(t, t);
M(t, t, num);
M(t, t, den);
M(t, t, den);
M(r[0], t, den);
S(chk, r[0]);
M(chk, chk, den);
if (neq25519(chk, num)) M(r[0], r[0], I);
S(chk, r[0]);
M(chk, chk, den);
if (neq25519(chk, num)) return -1;
if (par25519(r[0]) === (p[31]>>7)) Z(r[0], gf0, r[0]);
M(r[3], r[0], r[1]);
return 0;
}
function crypto_sign_open(m, sm, n, pk) {
var i;
var t = new Uint8Array(32), h;
var p = [gf(), gf(), gf(), gf()],
q = [gf(), gf(), gf(), gf()];
if (n < 64) return -1;
if (unpackneg(q, pk)) return -1;
for (i = 0; i < n; i++) m[i] = sm[i];
for (i = 0; i < 32; i++) m[i+32] = pk[i];
h = nacl.hash(m.subarray(0, n));
reduce(h);
scalarmult(p, q, h);
scalarbase(q, sm.subarray(32));
add(p, q);
pack(t, p);
n -= 64;
if (crypto_verify_32(sm, 0, t, 0)) {
for (i = 0; i < n; i++) m[i] = 0;
return -1;
}
for (i = 0; i < n; i++) m[i] = sm[i + 64];
return n;
}
var crypto_scalarmult_BYTES = 32,
crypto_scalarmult_SCALARBYTES = 32,
crypto_box_PUBLICKEYBYTES = 32,
crypto_box_SECRETKEYBYTES = 32,
crypto_sign_BYTES = 64,
crypto_sign_PUBLICKEYBYTES = 32,
crypto_sign_SECRETKEYBYTES = 64,
crypto_sign_SEEDBYTES = 32;
function checkArrayTypes() {
for (var i = 0; i < arguments.length; i++) {
if (!(arguments[i] instanceof Uint8Array))
throw new TypeError('unexpected type, use Uint8Array');
}
}
function cleanup(arr) {
for (var i = 0; i < arr.length; i++) arr[i] = 0;
}
nacl.scalarMult = function(n, p) {
checkArrayTypes(n, p);
if (n.length !== crypto_scalarmult_SCALARBYTES) throw new Error('bad n size');
if (p.length !== crypto_scalarmult_BYTES) throw new Error('bad p size');
var q = new Uint8Array(crypto_scalarmult_BYTES);
crypto_scalarmult(q, n, p);
return q;
};
nacl.box = {};
nacl.box.keyPair = function() {
var pk = new Uint8Array(crypto_box_PUBLICKEYBYTES);
var sk = new Uint8Array(crypto_box_SECRETKEYBYTES);
crypto_box_keypair(pk, sk);
return {publicKey: pk, secretKey: sk};
};
nacl.box.keyPair.fromSecretKey = function(secretKey) {
checkArrayTypes(secretKey);
if (secretKey.length !== crypto_box_SECRETKEYBYTES)
throw new Error('bad secret key size');
var pk = new Uint8Array(crypto_box_PUBLICKEYBYTES);
crypto_scalarmult_base(pk, secretKey);
return {publicKey: pk, secretKey: new Uint8Array(secretKey)};
};
nacl.sign = function(msg, secretKey) {
checkArrayTypes(msg, secretKey);
if (secretKey.length !== crypto_sign_SECRETKEYBYTES)
throw new Error('bad secret key size');
var signedMsg = new Uint8Array(crypto_sign_BYTES+msg.length);
crypto_sign(signedMsg, msg, msg.length, secretKey);
return signedMsg;
};
nacl.sign.detached = function(msg, secretKey) {
var signedMsg = nacl.sign(msg, secretKey);
var sig = new Uint8Array(crypto_sign_BYTES);
for (var i = 0; i < sig.length; i++) sig[i] = signedMsg[i];
return sig;
};
nacl.sign.detached.verify = function(msg, sig, publicKey) {
checkArrayTypes(msg, sig, publicKey);
if (sig.length !== crypto_sign_BYTES)
throw new Error('bad signature size');
if (publicKey.length !== crypto_sign_PUBLICKEYBYTES)
throw new Error('bad public key size');
var sm = new Uint8Array(crypto_sign_BYTES + msg.length);
var m = new Uint8Array(crypto_sign_BYTES + msg.length);
var i;
for (i = 0; i < crypto_sign_BYTES; i++) sm[i] = sig[i];
for (i = 0; i < msg.length; i++) sm[i+crypto_sign_BYTES] = msg[i];
return (crypto_sign_open(m, sm, sm.length, publicKey) >= 0);
};
nacl.sign.keyPair = function() {
var pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES);
var sk = new Uint8Array(crypto_sign_SECRETKEYBYTES);
crypto_sign_keypair(pk, sk);
return {publicKey: pk, secretKey: sk};
};
nacl.sign.keyPair.fromSecretKey = function(secretKey) {
checkArrayTypes(secretKey);
if (secretKey.length !== crypto_sign_SECRETKEYBYTES)
throw new Error('bad secret key size');
var pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES);
for (var i = 0; i < pk.length; i++) pk[i] = secretKey[32+i];
return {publicKey: pk, secretKey: new Uint8Array(secretKey)};
};
nacl.sign.keyPair.fromSeed = function(seed) {
checkArrayTypes(seed);
if (seed.length !== crypto_sign_SEEDBYTES)
throw new Error('bad seed size');
var pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES);
var sk = new Uint8Array(crypto_sign_SECRETKEYBYTES);
for (var i = 0; i < 32; i++) sk[i] = seed[i];
crypto_sign_keypair(pk, sk, true);
return {publicKey: pk, secretKey: sk};
};
nacl.setPRNG = function(fn) {
randombytes = fn;
};
(function() {
// Initialize PRNG if environment provides CSPRNG.
// If not, methods calling randombytes will throw.
var crypto = typeof self !== 'undefined' ? (self.crypto || self.msCrypto) : null;
if (crypto && crypto.getRandomValues) {
// Browsers.
var QUOTA = 65536;
nacl.setPRNG(function(x, n) {
var i, v = new Uint8Array(n);
for (i = 0; i < n; i += QUOTA) {
crypto.getRandomValues(v.subarray(i, i + Math.min(n - i, QUOTA)));
}
for (i = 0; i < n; i++) x[i] = v[i];
cleanup(v);
});
} else if (typeof commonjsRequire !== 'undefined') {
// Node.js.
crypto = void('crypto');
if (crypto && crypto.randomBytes) {
nacl.setPRNG(function(x, n) {
var i, v = crypto.randomBytes(n);
for (i = 0; i < n; i++) x[i] = v[i];
cleanup(v);
});
}
}
})();
})(module.exports ? module.exports : (self.nacl = self.nacl || {}));
});
// GPG4Browsers - An OpenPGP implementation in javascript
const nodeCrypto$5 = util.getNodeCrypto();
/**
* Retrieve secure random byte array of the specified length
* @param {Integer} length - Length in bytes to generate
* @returns {Uint8Array} Random byte array.
*/
function getRandomBytes(length) {
const buf = new Uint8Array(length);
if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
crypto.getRandomValues(buf);
} else if (nodeCrypto$5) {
const bytes = nodeCrypto$5.randomBytes(buf.length);
buf.set(bytes);
} else {
throw new Error('No secure random number generator available.');
}
return buf;
}
/**
* Create a secure random BigInteger that is greater than or equal to min and less than max.
* @param {module:BigInteger} min - Lower bound, included
* @param {module:BigInteger} max - Upper bound, excluded
* @returns {Promise} Random BigInteger.
* @async
*/
async function getRandomBigInteger(min, max) {
const BigInteger = await util.getBigInteger();
if (max.lt(min)) {
throw new Error('Illegal parameter value: max <= min');
}
const modulus = max.sub(min);
const bytes = modulus.byteLength();
// Using a while loop is necessary to avoid bias introduced by the mod operation.
// However, we request 64 extra random bits so that the bias is negligible.
// Section B.1.1 here: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
const r = new BigInteger(await getRandomBytes(bytes + 8));
return r.mod(modulus).add(min);
}
var random = /*#__PURE__*/Object.freeze({
__proto__: null,
getRandomBytes: getRandomBytes,
getRandomBigInteger: getRandomBigInteger
});
// OpenPGP.js - An OpenPGP implementation in javascript
/**
* Generate a probably prime random number
* @param {Integer} bits - Bit length of the prime
* @param {BigInteger} e - Optional RSA exponent to check against the prime
* @param {Integer} k - Optional number of iterations of Miller-Rabin test
* @returns BigInteger
* @async
*/
async function randomProbablePrime(bits, e, k) {
const BigInteger = await util.getBigInteger();
const one = new BigInteger(1);
const min = one.leftShift(new BigInteger(bits - 1));
const thirty = new BigInteger(30);
/*
* We can avoid any multiples of 3 and 5 by looking at n mod 30
* n mod 30 = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
* the next possible prime is mod 30:
* 1 7 7 7 7 7 7 11 11 11 11 13 13 17 17 17 17 19 19 23 23 23 23 29 29 29 29 29 29 1
*/
const adds = [1, 6, 5, 4, 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, 3, 2, 1, 2, 1, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1, 2];
const n = await getRandomBigInteger(min, min.leftShift(one));
let i = n.mod(thirty).toNumber();
do {
n.iadd(new BigInteger(adds[i]));
i = (i + adds[i]) % adds.length;
// If reached the maximum, go back to the minimum.
if (n.bitLength() > bits) {
n.imod(min.leftShift(one)).iadd(min);
i = n.mod(thirty).toNumber();
}
} while (!await isProbablePrime(n, e, k));
return n;
}
/**
* Probabilistic primality testing
* @param {BigInteger} n - Number to test
* @param {BigInteger} e - Optional RSA exponent to check against the prime
* @param {Integer} k - Optional number of iterations of Miller-Rabin test
* @returns {boolean}
* @async
*/
async function isProbablePrime(n, e, k) {
if (e && !n.dec().gcd(e).isOne()) {
return false;
}
if (!await divisionTest(n)) {
return false;
}
if (!await fermat(n)) {
return false;
}
if (!await millerRabin(n, k)) {
return false;
}
// TODO implement the Lucas test
// See Section C.3.3 here: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
return true;
}
/**
* Tests whether n is probably prime or not using Fermat's test with b = 2.
* Fails if b^(n-1) mod n != 1.
* @param {BigInteger} n - Number to test
* @param {BigInteger} b - Optional Fermat test base
* @returns {boolean}
*/
async function fermat(n, b) {
const BigInteger = await util.getBigInteger();
b = b || new BigInteger(2);
return b.modExp(n.dec(), n).isOne();
}
async function divisionTest(n) {
const BigInteger = await util.getBigInteger();
return smallPrimes.every(m => {
return n.mod(new BigInteger(m)) !== 0;
});
}
// https://github.com/gpg/libgcrypt/blob/master/cipher/primegen.c
const smallPrimes = [
7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43,
47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101,
103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
157, 163, 167, 173, 179, 181, 191, 193, 197, 199,
211, 223, 227, 229, 233, 239, 241, 251, 257, 263,
269, 271, 277, 281, 283, 293, 307, 311, 313, 317,
331, 337, 347, 349, 353, 359, 367, 373, 379, 383,
389, 397, 401, 409, 419, 421, 431, 433, 439, 443,
449, 457, 461, 463, 467, 479, 487, 491, 499, 503,
509, 521, 523, 541, 547, 557, 563, 569, 571, 577,
587, 593, 599, 601, 607, 613, 617, 619, 631, 641,
643, 647, 653, 659, 661, 673, 677, 683, 691, 701,
709, 719, 727, 733, 739, 743, 751, 757, 761, 769,
773, 787, 797, 809, 811, 821, 823, 827, 829, 839,
853, 857, 859, 863, 877, 881, 883, 887, 907, 911,
919, 929, 937, 941, 947, 953, 967, 971, 977, 983,
991, 997, 1009, 1013, 1019, 1021, 1031, 1033,
1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091,
1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151,
1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213,
1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277,
1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307,
1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399,
1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451,
1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493,
1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559,
1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609,
1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667,
1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733,
1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789,
1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871,
1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931,
1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997,
1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053,
2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111,
2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161,
2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243,
2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297,
2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357,
2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411,
2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473,
2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551,
2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633,
2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687,
2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729,
2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791,
2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851,
2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917,
2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999,
3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061,
3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137,
3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209,
3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271,
3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331,
3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391,
3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467,
3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533,
3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583,
3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643,
3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709,
3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779,
3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851,
3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917,
3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989,
4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049,
4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111,
4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177,
4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243,
4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297,
4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391,
4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457,
4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519,
4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597,
4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657,
4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729,
4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799,
4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889,
4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951,
4957, 4967, 4969, 4973, 4987, 4993, 4999
];
// Miller-Rabin - Miller Rabin algorithm for primality test
// Copyright Fedor Indutny, 2014.
//
// This software is licensed under the MIT License.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// Adapted on Jan 2018 from version 4.0.1 at https://github.com/indutny/miller-rabin
// Sample syntax for Fixed-Base Miller-Rabin:
// millerRabin(n, k, () => new BN(small_primes[Math.random() * small_primes.length | 0]))
/**
* Tests whether n is probably prime or not using the Miller-Rabin test.
* See HAC Remark 4.28.
* @param {BigInteger} n - Number to test
* @param {Integer} k - Optional number of iterations of Miller-Rabin test
* @param {Function} rand - Optional function to generate potential witnesses
* @returns {boolean}
* @async
*/
async function millerRabin(n, k, rand) {
const BigInteger = await util.getBigInteger();
const len = n.bitLength();
if (!k) {
k = Math.max(1, (len / 48) | 0);
}
const n1 = n.dec(); // n - 1
// Find d and s, (n - 1) = (2 ^ s) * d;
let s = 0;
while (!n1.getBit(s)) { s++; }
const d = n.rightShift(new BigInteger(s));
for (; k > 0; k--) {
const a = rand ? rand() : await getRandomBigInteger(new BigInteger(2), n1);
let x = a.modExp(d, n);
if (x.isOne() || x.equal(n1)) {
continue;
}
let i;
for (i = 1; i < s; i++) {
x = x.mul(x).mod(n);
if (x.isOne()) {
return false;
}
if (x.equal(n1)) {
break;
}
}
if (i === s) {
return false;
}
}
return true;
}
// GPG4Browsers - An OpenPGP implementation in javascript
/**
* ASN1 object identifiers for hashes
* @see {@link https://tools.ietf.org/html/rfc4880#section-5.2.2}
*/
const hash_headers = [];
hash_headers[1] = [0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04,
0x10];
hash_headers[2] = [0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14];
hash_headers[3] = [0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24, 0x03, 0x02, 0x01, 0x05, 0x00, 0x04, 0x14];
hash_headers[8] = [0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00,
0x04, 0x20];
hash_headers[9] = [0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00,
0x04, 0x30];
hash_headers[10] = [0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
0x00, 0x04, 0x40];
hash_headers[11] = [0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05,
0x00, 0x04, 0x1C];
/**
* Create padding with secure random data
* @private
* @param {Integer} length - Length of the padding in bytes
* @returns {Uint8Array} Random padding.
*/
function getPKCS1Padding(length) {
const result = new Uint8Array(length);
let count = 0;
while (count < length) {
const randomBytes = getRandomBytes(length - count);
for (let i = 0; i < randomBytes.length; i++) {
if (randomBytes[i] !== 0) {
result[count++] = randomBytes[i];
}
}
}
return result;
}
/**
* Create a EME-PKCS1-v1_5 padded message
* @see {@link https://tools.ietf.org/html/rfc4880#section-13.1.1|RFC 4880 13.1.1}
* @param {Uint8Array} message - Message to be encoded
* @param {Integer} keyLength - The length in octets of the key modulus
* @returns {Uint8Array} EME-PKCS1 padded message.
*/
function emeEncode(message, keyLength) {
const mLength = message.length;
// length checking
if (mLength > keyLength - 11) {
throw new Error('Message too long');
}
// Generate an octet string PS of length k - mLen - 3 consisting of
// pseudo-randomly generated nonzero octets
const PS = getPKCS1Padding(keyLength - mLength - 3);
// Concatenate PS, the message M, and other padding to form an
// encoded message EM of length k octets as EM = 0x00 || 0x02 || PS || 0x00 || M.
const encoded = new Uint8Array(keyLength);
// 0x00 byte
encoded[1] = 2;
encoded.set(PS, 2);
// 0x00 bytes
encoded.set(message, keyLength - mLength);
return encoded;
}
/**
* Decode a EME-PKCS1-v1_5 padded message
* @see {@link https://tools.ietf.org/html/rfc4880#section-13.1.2|RFC 4880 13.1.2}
* @param {Uint8Array} encoded - Encoded message bytes
* @param {Uint8Array} randomPayload - Data to return in case of decoding error (needed for constant-time processing)
* @returns {Uint8Array} decoded data or `randomPayload` (on error, if given)
* @throws {Error} on decoding failure, unless `randomPayload` is provided
*/
function emeDecode(encoded, randomPayload) {
// encoded format: 0x00 0x02 0x00
let offset = 2;
let separatorNotFound = 1;
for (let j = offset; j < encoded.length; j++) {
separatorNotFound &= encoded[j] !== 0;
offset += separatorNotFound;
}
const psLen = offset - 2;
const payload = encoded.subarray(offset + 1); // discard the 0x00 separator
const isValidPadding = encoded[0] === 0 & encoded[1] === 2 & psLen >= 8 & !separatorNotFound;
if (randomPayload) {
return util.selectUint8Array(isValidPadding, payload, randomPayload);
}
if (isValidPadding) {
return payload;
}
throw new Error('Decryption error');
}
/**
* Create a EMSA-PKCS1-v1_5 padded message
* @see {@link https://tools.ietf.org/html/rfc4880#section-13.1.3|RFC 4880 13.1.3}
* @param {Integer} algo - Hash algorithm type used
* @param {Uint8Array} hashed - Message to be encoded
* @param {Integer} emLen - Intended length in octets of the encoded message
* @returns {Uint8Array} Encoded message.
*/
async function emsaEncode(algo, hashed, emLen) {
let i;
if (hashed.length !== hash.getHashByteLength(algo)) {
throw new Error('Invalid hash length');
}
// produce an ASN.1 DER value for the hash function used.
// Let T be the full hash prefix
const hashPrefix = new Uint8Array(hash_headers[algo].length);
for (i = 0; i < hash_headers[algo].length; i++) {
hashPrefix[i] = hash_headers[algo][i];
}
// and let tLen be the length in octets prefix and hashed data
const tLen = hashPrefix.length + hashed.length;
if (emLen < tLen + 11) {
throw new Error('Intended encoded message length too short');
}
// an octet string PS consisting of emLen - tLen - 3 octets with hexadecimal value 0xFF
// The length of PS will be at least 8 octets
const PS = new Uint8Array(emLen - tLen - 3).fill(0xff);
// Concatenate PS, the hash prefix, hashed data, and other padding to form the
// encoded message EM as EM = 0x00 || 0x01 || PS || 0x00 || prefix || hashed
const EM = new Uint8Array(emLen);
EM[1] = 0x01;
EM.set(PS, 2);
EM.set(hashPrefix, emLen - tLen);
EM.set(hashed, emLen - hashed.length);
return EM;
}
var pkcs1 = /*#__PURE__*/Object.freeze({
__proto__: null,
emeEncode: emeEncode,
emeDecode: emeDecode,
emsaEncode: emsaEncode
});
// GPG4Browsers - An OpenPGP implementation in javascript
const webCrypto$5 = util.getWebCrypto();
const nodeCrypto$6 = util.getNodeCrypto();
const asn1 = nodeCrypto$6 ? void('asn1.js') : undefined;
/* eslint-disable no-invalid-this */
const RSAPrivateKey = nodeCrypto$6 ? asn1.define('RSAPrivateKey', function () {
this.seq().obj( // used for native NodeJS crypto
this.key('version').int(), // 0
this.key('modulus').int(), // n
this.key('publicExponent').int(), // e
this.key('privateExponent').int(), // d
this.key('prime1').int(), // p
this.key('prime2').int(), // q
this.key('exponent1').int(), // dp
this.key('exponent2').int(), // dq
this.key('coefficient').int() // u
);
}) : undefined;
const RSAPublicKey = nodeCrypto$6 ? asn1.define('RSAPubliceKey', function () {
this.seq().obj( // used for native NodeJS crypto
this.key('modulus').int(), // n
this.key('publicExponent').int() // e
);
}) : undefined;
/* eslint-enable no-invalid-this */
/** Create signature
* @param {module:enums.hash} hashAlgo - Hash algorithm
* @param {Uint8Array} data - Message
* @param {Uint8Array} n - RSA public modulus
* @param {Uint8Array} e - RSA public exponent
* @param {Uint8Array} d - RSA private exponent
* @param {Uint8Array} p - RSA private prime p
* @param {Uint8Array} q - RSA private prime q
* @param {Uint8Array} u - RSA private coefficient
* @param {Uint8Array} hashed - Hashed message
* @returns {Promise} RSA Signature.
* @async
*/
async function sign(hashAlgo, data, n, e, d, p, q, u, hashed) {
if (data && !util.isStream(data)) {
if (util.getWebCrypto()) {
try {
return await webSign(enums.read(enums.webHash, hashAlgo), data, n, e, d, p, q, u);
} catch (err) {
util.printDebugError(err);
}
} else if (util.getNodeCrypto()) {
return nodeSign(hashAlgo, data, n, e, d, p, q, u);
}
}
return bnSign(hashAlgo, n, d, hashed);
}
/**
* Verify signature
* @param {module:enums.hash} hashAlgo - Hash algorithm
* @param {Uint8Array} data - Message
* @param {Uint8Array} s - Signature
* @param {Uint8Array} n - RSA public modulus
* @param {Uint8Array} e - RSA public exponent
* @param {Uint8Array} hashed - Hashed message
* @returns {Boolean}
* @async
*/
async function verify(hashAlgo, data, s, n, e, hashed) {
if (data && !util.isStream(data)) {
if (util.getWebCrypto()) {
try {
return await webVerify(enums.read(enums.webHash, hashAlgo), data, s, n, e);
} catch (err) {
util.printDebugError(err);
}
} else if (util.getNodeCrypto()) {
return nodeVerify(hashAlgo, data, s, n, e);
}
}
return bnVerify(hashAlgo, s, n, e, hashed);
}
/**
* Encrypt message
* @param {Uint8Array} data - Message
* @param {Uint8Array} n - RSA public modulus
* @param {Uint8Array} e - RSA public exponent
* @returns {Promise} RSA Ciphertext.
* @async
*/
async function encrypt$1(data, n, e) {
if (util.getNodeCrypto()) {
return nodeEncrypt$1(data, n, e);
}
return bnEncrypt(data, n, e);
}
/**
* Decrypt RSA message
* @param {Uint8Array} m - Message
* @param {Uint8Array} n - RSA public modulus
* @param {Uint8Array} e - RSA public exponent
* @param {Uint8Array} d - RSA private exponent
* @param {Uint8Array} p - RSA private prime p
* @param {Uint8Array} q - RSA private prime q
* @param {Uint8Array} u - RSA private coefficient
* @param {Uint8Array} randomPayload - Data to return on decryption error, instead of throwing
* (needed for constant-time processing)
* @returns {Promise} RSA Plaintext.
* @throws {Error} on decryption error, unless `randomPayload` is given
* @async
*/
async function decrypt$1(data, n, e, d, p, q, u, randomPayload) {
if (util.getNodeCrypto()) {
return nodeDecrypt$1(data, n, e, d, p, q, u, randomPayload);
}
return bnDecrypt(data, n, e, d, p, q, u, randomPayload);
}
/**
* Generate a new random private key B bits long with public exponent E.
*
* When possible, webCrypto or nodeCrypto is used. Otherwise, primes are generated using
* 40 rounds of the Miller-Rabin probabilistic random prime generation algorithm.
* @see module:crypto/public_key/prime
* @param {Integer} bits - RSA bit length
* @param {Integer} e - RSA public exponent
* @returns {{n, e, d,
* p, q ,u: Uint8Array}} RSA public modulus, RSA public exponent, RSA private exponent,
* RSA private prime p, RSA private prime q, u = p ** -1 mod q
* @async
*/
async function generate(bits, e) {
const BigInteger = await util.getBigInteger();
e = new BigInteger(e);
// Native RSA keygen using Web Crypto
if (util.getWebCrypto()) {
const keyGenOpt = {
name: 'RSASSA-PKCS1-v1_5',
modulusLength: bits, // the specified keysize in bits
publicExponent: e.toUint8Array(), // take three bytes (max 65537) for exponent
hash: {
name: 'SHA-1' // not required for actual RSA keys, but for crypto api 'sign' and 'verify'
}
};
const keyPair = await webCrypto$5.generateKey(keyGenOpt, true, ['sign', 'verify']);
// export the generated keys as JsonWebKey (JWK)
// https://tools.ietf.org/html/draft-ietf-jose-json-web-key-33
const jwk = await webCrypto$5.exportKey('jwk', keyPair.privateKey);
// map JWK parameters to corresponding OpenPGP names
return {
n: b64ToUint8Array(jwk.n),
e: e.toUint8Array(),
d: b64ToUint8Array(jwk.d),
// switch p and q
p: b64ToUint8Array(jwk.q),
q: b64ToUint8Array(jwk.p),
// Since p and q are switched in places, u is the inverse of jwk.q
u: b64ToUint8Array(jwk.qi)
};
} else if (util.getNodeCrypto() && nodeCrypto$6.generateKeyPair && RSAPrivateKey) {
const opts = {
modulusLength: bits,
publicExponent: e.toNumber(),
publicKeyEncoding: { type: 'pkcs1', format: 'der' },
privateKeyEncoding: { type: 'pkcs1', format: 'der' }
};
const prv = await new Promise((resolve, reject) => {
nodeCrypto$6.generateKeyPair('rsa', opts, (err, _, der) => {
if (err) {
reject(err);
} else {
resolve(RSAPrivateKey.decode(der, 'der'));
}
});
});
/**
* OpenPGP spec differs from DER spec, DER: `u = (inverse of q) mod p`, OpenPGP: `u = (inverse of p) mod q`.
* @link https://tools.ietf.org/html/rfc3447#section-3.2
* @link https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-08#section-5.6.1
*/
return {
n: prv.modulus.toArrayLike(Uint8Array),
e: prv.publicExponent.toArrayLike(Uint8Array),
d: prv.privateExponent.toArrayLike(Uint8Array),
// switch p and q
p: prv.prime2.toArrayLike(Uint8Array),
q: prv.prime1.toArrayLike(Uint8Array),
// Since p and q are switched in places, we can keep u as defined by DER
u: prv.coefficient.toArrayLike(Uint8Array)
};
}
// RSA keygen fallback using 40 iterations of the Miller-Rabin test
// See https://stackoverflow.com/a/6330138 for justification
// Also see section C.3 here: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST
let p;
let q;
let n;
do {
q = await randomProbablePrime(bits - (bits >> 1), e, 40);
p = await randomProbablePrime(bits >> 1, e, 40);
n = p.mul(q);
} while (n.bitLength() !== bits);
const phi = p.dec().imul(q.dec());
if (q.lt(p)) {
[p, q] = [q, p];
}
return {
n: n.toUint8Array(),
e: e.toUint8Array(),
d: e.modInv(phi).toUint8Array(),
p: p.toUint8Array(),
q: q.toUint8Array(),
// dp: d.mod(p.subn(1)),
// dq: d.mod(q.subn(1)),
u: p.modInv(q).toUint8Array()
};
}
/**
* Validate RSA parameters
* @param {Uint8Array} n - RSA public modulus
* @param {Uint8Array} e - RSA public exponent
* @param {Uint8Array} d - RSA private exponent
* @param {Uint8Array} p - RSA private prime p
* @param {Uint8Array} q - RSA private prime q
* @param {Uint8Array} u - RSA inverse of p w.r.t. q
* @returns {Promise} Whether params are valid.
* @async
*/
async function validateParams(n, e, d, p, q, u) {
const BigInteger = await util.getBigInteger();
n = new BigInteger(n);
p = new BigInteger(p);
q = new BigInteger(q);
// expect pq = n
if (!p.mul(q).equal(n)) {
return false;
}
const two = new BigInteger(2);
// expect p*u = 1 mod q
u = new BigInteger(u);
if (!p.mul(u).mod(q).isOne()) {
return false;
}
e = new BigInteger(e);
d = new BigInteger(d);
/**
* In RSA pkcs#1 the exponents (d, e) are inverses modulo lcm(p-1, q-1)
* We check that [de = 1 mod (p-1)] and [de = 1 mod (q-1)]
* By CRT on coprime factors of (p-1, q-1) it follows that [de = 1 mod lcm(p-1, q-1)]
*
* We blind the multiplication with r, and check that rde = r mod lcm(p-1, q-1)
*/
const nSizeOver3 = new BigInteger(Math.floor(n.bitLength() / 3));
const r = await getRandomBigInteger(two, two.leftShift(nSizeOver3)); // r in [ 2, 2^{|n|/3} ) < p and q
const rde = r.mul(d).mul(e);
const areInverses = rde.mod(p.dec()).equal(r) && rde.mod(q.dec()).equal(r);
if (!areInverses) {
return false;
}
return true;
}
async function bnSign(hashAlgo, n, d, hashed) {
const BigInteger = await util.getBigInteger();
n = new BigInteger(n);
const m = new BigInteger(await emsaEncode(hashAlgo, hashed, n.byteLength()));
d = new BigInteger(d);
if (m.gte(n)) {
throw new Error('Message size cannot exceed modulus size');
}
return m.modExp(d, n).toUint8Array('be', n.byteLength());
}
async function webSign(hashName, data, n, e, d, p, q, u) {
/** OpenPGP keys require that p < q, and Safari Web Crypto requires that p > q.
* We swap them in privateToJWK, so it usually works out, but nevertheless,
* not all OpenPGP keys are compatible with this requirement.
* OpenPGP.js used to generate RSA keys the wrong way around (p > q), and still
* does if the underlying Web Crypto does so (though the tested implementations
* don't do so).
*/
const jwk = await privateToJWK(n, e, d, p, q, u);
const algo = {
name: 'RSASSA-PKCS1-v1_5',
hash: { name: hashName }
};
const key = await webCrypto$5.importKey('jwk', jwk, algo, false, ['sign']);
return new Uint8Array(await webCrypto$5.sign('RSASSA-PKCS1-v1_5', key, data));
}
async function nodeSign(hashAlgo, data, n, e, d, p, q, u) {
const { default: BN } = await import('./bn.mjs');
const pBNum = new BN(p);
const qBNum = new BN(q);
const dBNum = new BN(d);
const dq = dBNum.mod(qBNum.subn(1)); // d mod (q-1)
const dp = dBNum.mod(pBNum.subn(1)); // d mod (p-1)
const sign = nodeCrypto$6.createSign(enums.read(enums.hash, hashAlgo));
sign.write(data);
sign.end();
const keyObject = {
version: 0,
modulus: new BN(n),
publicExponent: new BN(e),
privateExponent: new BN(d),
// switch p and q
prime1: new BN(q),
prime2: new BN(p),
// switch dp and dq
exponent1: dq,
exponent2: dp,
coefficient: new BN(u)
};
if (typeof nodeCrypto$6.createPrivateKey !== 'undefined') { //from version 11.6.0 Node supports der encoded key objects
const der = RSAPrivateKey.encode(keyObject, 'der');
return new Uint8Array(sign.sign({ key: der, format: 'der', type: 'pkcs1' }));
}
const pem = RSAPrivateKey.encode(keyObject, 'pem', {
label: 'RSA PRIVATE KEY'
});
return new Uint8Array(sign.sign(pem));
}
async function bnVerify(hashAlgo, s, n, e, hashed) {
const BigInteger = await util.getBigInteger();
n = new BigInteger(n);
s = new BigInteger(s);
e = new BigInteger(e);
if (s.gte(n)) {
throw new Error('Signature size cannot exceed modulus size');
}
const EM1 = s.modExp(e, n).toUint8Array('be', n.byteLength());
const EM2 = await emsaEncode(hashAlgo, hashed, n.byteLength());
return util.equalsUint8Array(EM1, EM2);
}
async function webVerify(hashName, data, s, n, e) {
const jwk = publicToJWK(n, e);
const key = await webCrypto$5.importKey('jwk', jwk, {
name: 'RSASSA-PKCS1-v1_5',
hash: { name: hashName }
}, false, ['verify']);
return webCrypto$5.verify('RSASSA-PKCS1-v1_5', key, s, data);
}
async function nodeVerify(hashAlgo, data, s, n, e) {
const { default: BN } = await import('./bn.mjs');
const verify = nodeCrypto$6.createVerify(enums.read(enums.hash, hashAlgo));
verify.write(data);
verify.end();
const keyObject = {
modulus: new BN(n),
publicExponent: new BN(e)
};
let key;
if (typeof nodeCrypto$6.createPrivateKey !== 'undefined') { //from version 11.6.0 Node supports der encoded key objects
const der = RSAPublicKey.encode(keyObject, 'der');
key = { key: der, format: 'der', type: 'pkcs1' };
} else {
key = RSAPublicKey.encode(keyObject, 'pem', {
label: 'RSA PUBLIC KEY'
});
}
try {
return await verify.verify(key, s);
} catch (err) {
return false;
}
}
async function nodeEncrypt$1(data, n, e) {
const { default: BN } = await import('./bn.mjs');
const keyObject = {
modulus: new BN(n),
publicExponent: new BN(e)
};
let key;
if (typeof nodeCrypto$6.createPrivateKey !== 'undefined') {
const der = RSAPublicKey.encode(keyObject, 'der');
key = { key: der, format: 'der', type: 'pkcs1', padding: nodeCrypto$6.constants.RSA_PKCS1_PADDING };
} else {
const pem = RSAPublicKey.encode(keyObject, 'pem', {
label: 'RSA PUBLIC KEY'
});
key = { key: pem, padding: nodeCrypto$6.constants.RSA_PKCS1_PADDING };
}
return new Uint8Array(nodeCrypto$6.publicEncrypt(key, data));
}
async function bnEncrypt(data, n, e) {
const BigInteger = await util.getBigInteger();
n = new BigInteger(n);
data = new BigInteger(emeEncode(data, n.byteLength()));
e = new BigInteger(e);
if (data.gte(n)) {
throw new Error('Message size cannot exceed modulus size');
}
return data.modExp(e, n).toUint8Array('be', n.byteLength());
}
async function nodeDecrypt$1(data, n, e, d, p, q, u, randomPayload) {
const { default: BN } = await import('./bn.mjs');
const pBNum = new BN(p);
const qBNum = new BN(q);
const dBNum = new BN(d);
const dq = dBNum.mod(qBNum.subn(1)); // d mod (q-1)
const dp = dBNum.mod(pBNum.subn(1)); // d mod (p-1)
const keyObject = {
version: 0,
modulus: new BN(n),
publicExponent: new BN(e),
privateExponent: new BN(d),
// switch p and q
prime1: new BN(q),
prime2: new BN(p),
// switch dp and dq
exponent1: dq,
exponent2: dp,
coefficient: new BN(u)
};
let key;
if (typeof nodeCrypto$6.createPrivateKey !== 'undefined') {
const der = RSAPrivateKey.encode(keyObject, 'der');
key = { key: der, format: 'der' , type: 'pkcs1', padding: nodeCrypto$6.constants.RSA_PKCS1_PADDING };
} else {
const pem = RSAPrivateKey.encode(keyObject, 'pem', {
label: 'RSA PRIVATE KEY'
});
key = { key: pem, padding: nodeCrypto$6.constants.RSA_PKCS1_PADDING };
}
try {
return new Uint8Array(nodeCrypto$6.privateDecrypt(key, data));
} catch (err) {
if (randomPayload) {
return randomPayload;
}
throw new Error('Decryption error');
}
}
async function bnDecrypt(data, n, e, d, p, q, u, randomPayload) {
const BigInteger = await util.getBigInteger();
data = new BigInteger(data);
n = new BigInteger(n);
e = new BigInteger(e);
d = new BigInteger(d);
p = new BigInteger(p);
q = new BigInteger(q);
u = new BigInteger(u);
if (data.gte(n)) {
throw new Error('Data too large.');
}
const dq = d.mod(q.dec()); // d mod (q-1)
const dp = d.mod(p.dec()); // d mod (p-1)
const unblinder = (await getRandomBigInteger(new BigInteger(2), n)).mod(n);
const blinder = unblinder.modInv(n).modExp(e, n);
data = data.mul(blinder).mod(n);
const mp = data.modExp(dp, p); // data**{d mod (q-1)} mod p
const mq = data.modExp(dq, q); // data**{d mod (p-1)} mod q
const h = u.mul(mq.sub(mp)).mod(q); // u * (mq-mp) mod q (operands already < q)
let result = h.mul(p).add(mp); // result < n due to relations above
result = result.mul(unblinder).mod(n);
return emeDecode(result.toUint8Array('be', n.byteLength()), randomPayload);
}
/** Convert Openpgp private key params to jwk key according to
* @link https://tools.ietf.org/html/rfc7517
* @param {String} hashAlgo
* @param {Uint8Array} n
* @param {Uint8Array} e
* @param {Uint8Array} d
* @param {Uint8Array} p
* @param {Uint8Array} q
* @param {Uint8Array} u
*/
async function privateToJWK(n, e, d, p, q, u) {
const BigInteger = await util.getBigInteger();
const pNum = new BigInteger(p);
const qNum = new BigInteger(q);
const dNum = new BigInteger(d);
let dq = dNum.mod(qNum.dec()); // d mod (q-1)
let dp = dNum.mod(pNum.dec()); // d mod (p-1)
dp = dp.toUint8Array();
dq = dq.toUint8Array();
return {
kty: 'RSA',
n: uint8ArrayToB64(n, true),
e: uint8ArrayToB64(e, true),
d: uint8ArrayToB64(d, true),
// switch p and q
p: uint8ArrayToB64(q, true),
q: uint8ArrayToB64(p, true),
// switch dp and dq
dp: uint8ArrayToB64(dq, true),
dq: uint8ArrayToB64(dp, true),
qi: uint8ArrayToB64(u, true),
ext: true
};
}
/** Convert Openpgp key public params to jwk key according to
* @link https://tools.ietf.org/html/rfc7517
* @param {String} hashAlgo
* @param {Uint8Array} n
* @param {Uint8Array} e
*/
function publicToJWK(n, e) {
return {
kty: 'RSA',
n: uint8ArrayToB64(n, true),
e: uint8ArrayToB64(e, true),
ext: true
};
}
var rsa = /*#__PURE__*/Object.freeze({
__proto__: null,
sign: sign,
verify: verify,
encrypt: encrypt$1,
decrypt: decrypt$1,
generate: generate,
validateParams: validateParams
});
// GPG4Browsers - An OpenPGP implementation in javascript
/**
* ElGamal Encryption function
* Note that in OpenPGP, the message needs to be padded with PKCS#1 (same as RSA)
* @param {Uint8Array} data - To be padded and encrypted
* @param {Uint8Array} p
* @param {Uint8Array} g
* @param {Uint8Array} y
* @returns {Promise<{ c1: Uint8Array, c2: Uint8Array }>}
* @async
*/
async function encrypt$2(data, p, g, y) {
const BigInteger = await util.getBigInteger();
p = new BigInteger(p);
g = new BigInteger(g);
y = new BigInteger(y);
const padded = emeEncode(data, p.byteLength());
const m = new BigInteger(padded);
// OpenPGP uses a "special" version of ElGamal where g is generator of the full group Z/pZ*
// hence g has order p-1, and to avoid that k = 0 mod p-1, we need to pick k in [1, p-2]
const k = await getRandomBigInteger(new BigInteger(1), p.dec());
return {
c1: g.modExp(k, p).toUint8Array(),
c2: y.modExp(k, p).imul(m).imod(p).toUint8Array()
};
}
/**
* ElGamal Encryption function
* @param {Uint8Array} c1
* @param {Uint8Array} c2
* @param {Uint8Array} p
* @param {Uint8Array} x
* @param {Uint8Array} randomPayload - Data to return on unpadding error, instead of throwing
* (needed for constant-time processing)
* @returns {Promise} Unpadded message.
* @throws {Error} on decryption error, unless `randomPayload` is given
* @async
*/
async function decrypt$2(c1, c2, p, x, randomPayload) {
const BigInteger = await util.getBigInteger();
c1 = new BigInteger(c1);
c2 = new BigInteger(c2);
p = new BigInteger(p);
x = new BigInteger(x);
const padded = c1.modExp(x, p).modInv(p).imul(c2).imod(p);
return emeDecode(padded.toUint8Array('be', p.byteLength()), randomPayload);
}
/**
* Validate ElGamal parameters
* @param {Uint8Array} p - ElGamal prime
* @param {Uint8Array} g - ElGamal group generator
* @param {Uint8Array} y - ElGamal public key
* @param {Uint8Array} x - ElGamal private exponent
* @returns {Promise} Whether params are valid.
* @async
*/
async function validateParams$1(p, g, y, x) {
const BigInteger = await util.getBigInteger();
p = new BigInteger(p);
g = new BigInteger(g);
y = new BigInteger(y);
const one = new BigInteger(1);
// Check that 1 < g < p
if (g.lte(one) || g.gte(p)) {
return false;
}
// Expect p-1 to be large
const pSize = new BigInteger(p.bitLength());
const n1023 = new BigInteger(1023);
if (pSize.lt(n1023)) {
return false;
}
/**
* g should have order p-1
* Check that g ** (p-1) = 1 mod p
*/
if (!g.modExp(p.dec(), p).isOne()) {
return false;
}
/**
* Since p-1 is not prime, g might have a smaller order that divides p-1
* We want to make sure that the order is large enough to hinder a small subgroup attack
*
* We just check g**i != 1 for all i up to a threshold
*/
let res = g;
const i = new BigInteger(1);
const threshold = new BigInteger(2).leftShift(new BigInteger(17)); // we want order > threshold
while (i.lt(threshold)) {
res = res.mul(g).imod(p);
if (res.isOne()) {
return false;
}
i.iinc();
}
/**
* Re-derive public key y' = g ** x mod p
* Expect y == y'
*
* Blinded exponentiation computes g**{r(p-1) + x} to compare to y
*/
x = new BigInteger(x);
const two = new BigInteger(2);
const r = await getRandomBigInteger(two.leftShift(pSize.dec()), two.leftShift(pSize)); // draw r of same size as p-1
const rqx = p.dec().imul(r).iadd(x);
if (!y.equal(g.modExp(rqx, p))) {
return false;
}
return true;
}
var elgamal = /*#__PURE__*/Object.freeze({
__proto__: null,
encrypt: encrypt$2,
decrypt: decrypt$2,
validateParams: validateParams$1
});
// OpenPGP.js - An OpenPGP implementation in javascript
class OID {
constructor(oid) {
if (oid instanceof OID) {
this.oid = oid.oid;
} else if (util.isArray(oid) ||
util.isUint8Array(oid)) {
oid = new Uint8Array(oid);
if (oid[0] === 0x06) { // DER encoded oid byte array
if (oid[1] !== oid.length - 2) {
throw new Error('Length mismatch in DER encoded oid');
}
oid = oid.subarray(2);
}
this.oid = oid;
} else {
this.oid = '';
}
}
/**
* Method to read an OID object
* @param {Uint8Array} input - Where to read the OID from
* @returns {Number} Number of read bytes.
*/
read(input) {
if (input.length >= 1) {
const length = input[0];
if (input.length >= 1 + length) {
this.oid = input.subarray(1, 1 + length);
return 1 + this.oid.length;
}
}
throw new Error('Invalid oid');
}
/**
* Serialize an OID object
* @returns {Uint8Array} Array with the serialized value the OID.
*/
write() {
return util.concatUint8Array([new Uint8Array([this.oid.length]), this.oid]);
}
/**
* Serialize an OID object as a hex string
* @returns {string} String with the hex value of the OID.
*/
toHex() {
return util.uint8ArrayToHex(this.oid);
}
/**
* If a known curve object identifier, return the canonical name of the curve
* @returns {string} String with the canonical name of the curve.
*/
getName() {
const hex = this.toHex();
if (enums.curve[hex]) {
return enums.write(enums.curve, hex);
} else {
throw new Error('Unknown curve object identifier.');
}
}
}
// OpenPGP.js - An OpenPGP implementation in javascript
function keyFromPrivate(indutnyCurve, priv) {
const keyPair = indutnyCurve.keyPair({ priv: priv });
return keyPair;
}
function keyFromPublic(indutnyCurve, pub) {
const keyPair = indutnyCurve.keyPair({ pub: pub });
if (keyPair.validate().result !== true) {
throw new Error('Invalid elliptic public key');
}
return keyPair;
}
async function getIndutnyCurve(name) {
if (!config.useIndutnyElliptic) {
throw new Error('This curve is only supported in the full build of OpenPGP.js');
}
const { default: elliptic } = await import('./elliptic.mjs');
return new elliptic.ec(name);
}
// GPG4Browsers - An OpenPGP implementation in javascript
function readSimpleLength(bytes) {
let len = 0;
let offset;
const type = bytes[0];
if (type < 192) {
[len] = bytes;
offset = 1;
} else if (type < 255) {
len = ((bytes[0] - 192) << 8) + (bytes[1]) + 192;
offset = 2;
} else if (type === 255) {
len = util.readNumber(bytes.subarray(1, 1 + 4));
offset = 5;
}
return {
len: len,
offset: offset
};
}
/**
* Encodes a given integer of length to the openpgp length specifier to a
* string
*
* @param {Integer} length - The length to encode
* @returns {Uint8Array} String with openpgp length representation.
*/
function writeSimpleLength(length) {
if (length < 192) {
return new Uint8Array([length]);
} else if (length > 191 && length < 8384) {
/*
* let a = (total data packet length) - 192 let bc = two octet
* representation of a let d = b + 192
*/
return new Uint8Array([((length - 192) >> 8) + 192, (length - 192) & 0xFF]);
}
return util.concatUint8Array([new Uint8Array([255]), util.writeNumber(length, 4)]);
}
function writePartialLength(power) {
if (power < 0 || power > 30) {
throw new Error('Partial Length power must be between 1 and 30');
}
return new Uint8Array([224 + power]);
}
function writeTag(tag_type) {
/* we're only generating v4 packet headers here */
return new Uint8Array([0xC0 | tag_type]);
}
/**
* Writes a packet header version 4 with the given tag_type and length to a
* string
*
* @param {Integer} tag_type - Tag type
* @param {Integer} length - Length of the payload
* @returns {String} String of the header.
*/
function writeHeader(tag_type, length) {
/* we're only generating v4 packet headers here */
return util.concatUint8Array([writeTag(tag_type), writeSimpleLength(length)]);
}
/**
* Whether the packet type supports partial lengths per RFC4880
* @param {Integer} tag - Tag type
* @returns {Boolean} String of the header.
*/
function supportsStreaming(tag) {
return [
enums.packet.literalData,
enums.packet.compressedData,
enums.packet.symmetricallyEncryptedData,
enums.packet.symEncryptedIntegrityProtectedData,
enums.packet.aeadEncryptedData
].includes(tag);
}
/**
* Generic static Packet Parser function
*
* @param {Uint8Array | ReadableStream} input - Input stream as string
* @param {Function} callback - Function to call with the parsed packet
* @returns {Boolean} Returns false if the stream was empty and parsing is done, and true otherwise.
*/
async function readPackets(input, callback) {
const reader = getReader(input);
let writer;
let callbackReturned;
try {
const peekedBytes = await reader.peekBytes(2);
// some sanity checks
if (!peekedBytes || peekedBytes.length < 2 || (peekedBytes[0] & 0x80) === 0) {
throw new Error('Error during parsing. This message / key probably does not conform to a valid OpenPGP format.');
}
const headerByte = await reader.readByte();
let tag = -1;
let format = -1;
let packetLength;
format = 0; // 0 = old format; 1 = new format
if ((headerByte & 0x40) !== 0) {
format = 1;
}
let packetLengthType;
if (format) {
// new format header
tag = headerByte & 0x3F; // bit 5-0
} else {
// old format header
tag = (headerByte & 0x3F) >> 2; // bit 5-2
packetLengthType = headerByte & 0x03; // bit 1-0
}
const packetSupportsStreaming = supportsStreaming(tag);
let packet = null;
if (packetSupportsStreaming) {
if (util.isStream(input) === 'array') {
const arrayStream = new ArrayStream();
writer = getWriter(arrayStream);
packet = arrayStream;
} else {
const transform = new TransformStream();
writer = getWriter(transform.writable);
packet = transform.readable;
}
// eslint-disable-next-line callback-return
callbackReturned = callback({ tag, packet });
} else {
packet = [];
}
let wasPartialLength;
do {
if (!format) {
// 4.2.1. Old Format Packet Lengths
switch (packetLengthType) {
case 0:
// The packet has a one-octet length. The header is 2 octets
// long.
packetLength = await reader.readByte();
break;
case 1:
// The packet has a two-octet length. The header is 3 octets
// long.
packetLength = (await reader.readByte() << 8) | await reader.readByte();
break;
case 2:
// The packet has a four-octet length. The header is 5
// octets long.
packetLength = (await reader.readByte() << 24) | (await reader.readByte() << 16) | (await reader.readByte() <<
8) | await reader.readByte();
break;
default:
// 3 - The packet is of indeterminate length. The header is 1
// octet long, and the implementation must determine how long
// the packet is. If the packet is in a file, this means that
// the packet extends until the end of the file. In general,
// an implementation SHOULD NOT use indeterminate-length
// packets except where the end of the data will be clear
// from the context, and even then it is better to use a
// definite length, or a new format header. The new format
// headers described below have a mechanism for precisely
// encoding data of indeterminate length.
packetLength = Infinity;
break;
}
} else { // 4.2.2. New Format Packet Lengths
// 4.2.2.1. One-Octet Lengths
const lengthByte = await reader.readByte();
wasPartialLength = false;
if (lengthByte < 192) {
packetLength = lengthByte;
// 4.2.2.2. Two-Octet Lengths
} else if (lengthByte >= 192 && lengthByte < 224) {
packetLength = ((lengthByte - 192) << 8) + (await reader.readByte()) + 192;
// 4.2.2.4. Partial Body Lengths
} else if (lengthByte > 223 && lengthByte < 255) {
packetLength = 1 << (lengthByte & 0x1F);
wasPartialLength = true;
if (!packetSupportsStreaming) {
throw new TypeError('This packet type does not support partial lengths.');
}
// 4.2.2.3. Five-Octet Lengths
} else {
packetLength = (await reader.readByte() << 24) | (await reader.readByte() << 16) | (await reader.readByte() <<
8) | await reader.readByte();
}
}
if (packetLength > 0) {
let bytesRead = 0;
while (true) {
if (writer) await writer.ready;
const { done, value } = await reader.read();
if (done) {
if (packetLength === Infinity) break;
throw new Error('Unexpected end of packet');
}
const chunk = packetLength === Infinity ? value : value.subarray(0, packetLength - bytesRead);
if (writer) await writer.write(chunk);
else packet.push(chunk);
bytesRead += value.length;
if (bytesRead >= packetLength) {
reader.unshift(value.subarray(packetLength - bytesRead + value.length));
break;
}
}
}
} while (wasPartialLength);
// If this was not a packet that "supports streaming", we peek to check
// whether it is the last packet in the message. We peek 2 bytes instead
// of 1 because the beginning of this function also peeks 2 bytes, and we
// want to cut a `subarray` of the correct length into `web-stream-tools`'
// `externalBuffer` as a tiny optimization here.
//
// If it *was* a streaming packet (i.e. the data packets), we peek at the
// entire remainder of the stream, in order to forward errors in the
// remainder of the stream to the packet data. (Note that this means we
// read/peek at all signature packets before closing the literal data
// packet, for example.) This forwards MDC errors to the literal data
// stream, for example, so that they don't get lost / forgotten on
// decryptedMessage.packets.stream, which we never look at.
//
// An example of what we do when stream-parsing a message containing
// [ one-pass signature packet, literal data packet, signature packet ]:
// 1. Read the one-pass signature packet
// 2. Peek 2 bytes of the literal data packet
// 3. Parse the one-pass signature packet
//
// 4. Read the literal data packet, simultaneously stream-parsing it
// 5. Peek until the end of the message
// 6. Finish parsing the literal data packet
//
// 7. Read the signature packet again (we already peeked at it in step 5)
// 8. Peek at the end of the stream again (`peekBytes` returns undefined)
// 9. Parse the signature packet
//
// Note that this means that if there's an error in the very end of the
// stream, such as an MDC error, we throw in step 5 instead of in step 8
// (or never), which is the point of this exercise.
const nextPacket = await reader.peekBytes(packetSupportsStreaming ? Infinity : 2);
if (writer) {
await writer.ready;
await writer.close();
} else {
packet = util.concatUint8Array(packet);
// eslint-disable-next-line callback-return
await callback({ tag, packet });
}
return !nextPacket || !nextPacket.length;
} catch (e) {
if (writer) {
await writer.abort(e);
return true;
} else {
throw e;
}
} finally {
if (writer) {
await callbackReturned;
}
reader.releaseLock();
}
}
class UnsupportedError extends Error {
constructor(...params) {
super(...params);
if (Error.captureStackTrace) {
Error.captureStackTrace(this, UnsupportedError);
}
this.name = 'UnsupportedError';
}
}
class UnparseablePacket {
constructor(tag, rawContent) {
this.tag = tag;
this.rawContent = rawContent;
}
write() {
return this.rawContent;
}
}
// OpenPGP.js - An OpenPGP implementation in javascript
const webCrypto$6 = util.getWebCrypto();
const nodeCrypto$7 = util.getNodeCrypto();
const webCurves = {
'p256': 'P-256',
'p384': 'P-384',
'p521': 'P-521'
};
const knownCurves = nodeCrypto$7 ? nodeCrypto$7.getCurves() : [];
const nodeCurves = nodeCrypto$7 ? {
secp256k1: knownCurves.includes('secp256k1') ? 'secp256k1' : undefined,
p256: knownCurves.includes('prime256v1') ? 'prime256v1' : undefined,
p384: knownCurves.includes('secp384r1') ? 'secp384r1' : undefined,
p521: knownCurves.includes('secp521r1') ? 'secp521r1' : undefined,
ed25519: knownCurves.includes('ED25519') ? 'ED25519' : undefined,
curve25519: knownCurves.includes('X25519') ? 'X25519' : undefined,
brainpoolP256r1: knownCurves.includes('brainpoolP256r1') ? 'brainpoolP256r1' : undefined,
brainpoolP384r1: knownCurves.includes('brainpoolP384r1') ? 'brainpoolP384r1' : undefined,
brainpoolP512r1: knownCurves.includes('brainpoolP512r1') ? 'brainpoolP512r1' : undefined
} : {};
const curves = {
p256: {
oid: [0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07],
keyType: enums.publicKey.ecdsa,
hash: enums.hash.sha256,
cipher: enums.symmetric.aes128,
node: nodeCurves.p256,
web: webCurves.p256,
payloadSize: 32,
sharedSize: 256
},
p384: {
oid: [0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22],
keyType: enums.publicKey.ecdsa,
hash: enums.hash.sha384,
cipher: enums.symmetric.aes192,
node: nodeCurves.p384,
web: webCurves.p384,
payloadSize: 48,
sharedSize: 384
},
p521: {
oid: [0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23],
keyType: enums.publicKey.ecdsa,
hash: enums.hash.sha512,
cipher: enums.symmetric.aes256,
node: nodeCurves.p521,
web: webCurves.p521,
payloadSize: 66,
sharedSize: 528
},
secp256k1: {
oid: [0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x0A],
keyType: enums.publicKey.ecdsa,
hash: enums.hash.sha256,
cipher: enums.symmetric.aes128,
node: nodeCurves.secp256k1,
payloadSize: 32
},
ed25519: {
oid: [0x06, 0x09, 0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01],
keyType: enums.publicKey.eddsa,
hash: enums.hash.sha512,
node: false, // nodeCurves.ed25519 TODO
payloadSize: 32
},
curve25519: {
oid: [0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01],
keyType: enums.publicKey.ecdh,
hash: enums.hash.sha256,
cipher: enums.symmetric.aes128,
node: false, // nodeCurves.curve25519 TODO
payloadSize: 32
},
brainpoolP256r1: {
oid: [0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07],
keyType: enums.publicKey.ecdsa,
hash: enums.hash.sha256,
cipher: enums.symmetric.aes128,
node: nodeCurves.brainpoolP256r1,
payloadSize: 32
},
brainpoolP384r1: {
oid: [0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B],
keyType: enums.publicKey.ecdsa,
hash: enums.hash.sha384,
cipher: enums.symmetric.aes192,
node: nodeCurves.brainpoolP384r1,
payloadSize: 48
},
brainpoolP512r1: {
oid: [0x06, 0x09, 0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D],
keyType: enums.publicKey.ecdsa,
hash: enums.hash.sha512,
cipher: enums.symmetric.aes256,
node: nodeCurves.brainpoolP512r1,
payloadSize: 64
}
};
class Curve {
constructor(oidOrName, params) {
try {
if (util.isArray(oidOrName) ||
util.isUint8Array(oidOrName)) {
// by oid byte array
oidOrName = new OID(oidOrName);
}
if (oidOrName instanceof OID) {
// by curve OID
oidOrName = oidOrName.getName();
}
// by curve name or oid string
this.name = enums.write(enums.curve, oidOrName);
} catch (err) {
throw new UnsupportedError('Unknown curve');
}
params = params || curves[this.name];
this.keyType = params.keyType;
this.oid = params.oid;
this.hash = params.hash;
this.cipher = params.cipher;
this.node = params.node && curves[this.name];
this.web = params.web && curves[this.name];
this.payloadSize = params.payloadSize;
if (this.web && util.getWebCrypto()) {
this.type = 'web';
} else if (this.node && util.getNodeCrypto()) {
this.type = 'node';
} else if (this.name === 'curve25519') {
this.type = 'curve25519';
} else if (this.name === 'ed25519') {
this.type = 'ed25519';
}
}
async genKeyPair() {
let keyPair;
switch (this.type) {
case 'web':
try {
return await webGenKeyPair(this.name);
} catch (err) {
util.printDebugError('Browser did not support generating ec key ' + err.message);
break;
}
case 'node':
return nodeGenKeyPair(this.name);
case 'curve25519': {
const privateKey = getRandomBytes(32);
privateKey[0] = (privateKey[0] & 127) | 64;
privateKey[31] &= 248;
const secretKey = privateKey.slice().reverse();
keyPair = naclFastLight.box.keyPair.fromSecretKey(secretKey);
const publicKey = util.concatUint8Array([new Uint8Array([0x40]), keyPair.publicKey]);
return { publicKey, privateKey };
}
case 'ed25519': {
const privateKey = getRandomBytes(32);
const keyPair = naclFastLight.sign.keyPair.fromSeed(privateKey);
const publicKey = util.concatUint8Array([new Uint8Array([0x40]), keyPair.publicKey]);
return { publicKey, privateKey };
}
}
const indutnyCurve = await getIndutnyCurve(this.name);
keyPair = await indutnyCurve.genKeyPair({
entropy: util.uint8ArrayToString(getRandomBytes(32))
});
return { publicKey: new Uint8Array(keyPair.getPublic('array', false)), privateKey: keyPair.getPrivate().toArrayLike(Uint8Array) };
}
}
async function generate$1(curve) {
const BigInteger = await util.getBigInteger();
curve = new Curve(curve);
const keyPair = await curve.genKeyPair();
const Q = new BigInteger(keyPair.publicKey).toUint8Array();
const secret = new BigInteger(keyPair.privateKey).toUint8Array('be', curve.payloadSize);
return {
oid: curve.oid,
Q,
secret,
hash: curve.hash,
cipher: curve.cipher
};
}
/**
* Get preferred hash algo to use with the given curve
* @param {module:type/oid} oid - curve oid
* @returns {enums.hash} hash algorithm
*/
function getPreferredHashAlgo(oid) {
return curves[enums.write(enums.curve, oid.toHex())].hash;
}
/**
* Validate ECDH and ECDSA parameters
* Not suitable for EdDSA (different secret key format)
* @param {module:enums.publicKey} algo - EC algorithm, to filter supported curves
* @param {module:type/oid} oid - EC object identifier
* @param {Uint8Array} Q - EC public point
* @param {Uint8Array} d - EC secret scalar
* @returns {Promise} Whether params are valid.
* @async
*/
async function validateStandardParams(algo, oid, Q, d) {
const supportedCurves = {
p256: true,
p384: true,
p521: true,
secp256k1: true,
curve25519: algo === enums.publicKey.ecdh,
brainpoolP256r1: true,
brainpoolP384r1: true,
brainpoolP512r1: true
};
// Check whether the given curve is supported
const curveName = oid.getName();
if (!supportedCurves[curveName]) {
return false;
}
if (curveName === 'curve25519') {
d = d.slice().reverse();
// Re-derive public point Q'
const { publicKey } = naclFastLight.box.keyPair.fromSecretKey(d);
Q = new Uint8Array(Q);
const dG = new Uint8Array([0x40, ...publicKey]); // Add public key prefix
if (!util.equalsUint8Array(dG, Q)) {
return false;
}
return true;
}
const curve = await getIndutnyCurve(curveName);
try {
// Parse Q and check that it is on the curve but not at infinity
Q = keyFromPublic(curve, Q).getPublic();
} catch (validationErrors) {
return false;
}
/**
* Re-derive public point Q' = dG from private key
* Expect Q == Q'
*/
const dG = keyFromPrivate(curve, d).getPublic();
if (!dG.eq(Q)) {
return false;
}
return true;
}
//////////////////////////
// //
// Helper functions //
// //
//////////////////////////
async function webGenKeyPair(name) {
// Note: keys generated with ECDSA and ECDH are structurally equivalent
const webCryptoKey = await webCrypto$6.generateKey({ name: 'ECDSA', namedCurve: webCurves[name] }, true, ['sign', 'verify']);
const privateKey = await webCrypto$6.exportKey('jwk', webCryptoKey.privateKey);
const publicKey = await webCrypto$6.exportKey('jwk', webCryptoKey.publicKey);
return {
publicKey: jwkToRawPublic(publicKey),
privateKey: b64ToUint8Array(privateKey.d)
};
}
async function nodeGenKeyPair(name) {
// Note: ECDSA and ECDH key generation is structurally equivalent
const ecdh = nodeCrypto$7.createECDH(nodeCurves[name]);
await ecdh.generateKeys();
return {
publicKey: new Uint8Array(ecdh.getPublicKey()),
privateKey: new Uint8Array(ecdh.getPrivateKey())
};
}
//////////////////////////
// //
// Helper functions //
// //
//////////////////////////
/**
* @param {JsonWebKey} jwk - key for conversion
*
* @returns {Uint8Array} Raw public key.
*/
function jwkToRawPublic(jwk) {
const bufX = b64ToUint8Array(jwk.x);
const bufY = b64ToUint8Array(jwk.y);
const publicKey = new Uint8Array(bufX.length + bufY.length + 1);
publicKey[0] = 0x04;
publicKey.set(bufX, 1);
publicKey.set(bufY, bufX.length + 1);
return publicKey;
}
/**
* @param {Integer} payloadSize - ec payload size
* @param {String} name - curve name
* @param {Uint8Array} publicKey - public key
*
* @returns {JsonWebKey} Public key in jwk format.
*/
function rawPublicToJWK(payloadSize, name, publicKey) {
const len = payloadSize;
const bufX = publicKey.slice(1, len + 1);
const bufY = publicKey.slice(len + 1, len * 2 + 1);
// https://www.rfc-editor.org/rfc/rfc7518.txt
const jwk = {
kty: 'EC',
crv: name,
x: uint8ArrayToB64(bufX, true),
y: uint8ArrayToB64(bufY, true),
ext: true
};
return jwk;
}
/**
* @param {Integer} payloadSize - ec payload size
* @param {String} name - curve name
* @param {Uint8Array} publicKey - public key
* @param {Uint8Array} privateKey - private key
*
* @returns {JsonWebKey} Private key in jwk format.
*/
function privateToJWK$1(payloadSize, name, publicKey, privateKey) {
const jwk = rawPublicToJWK(payloadSize, name, publicKey);
jwk.d = uint8ArrayToB64(privateKey, true);
return jwk;
}
// OpenPGP.js - An OpenPGP implementation in javascript
const webCrypto$7 = util.getWebCrypto();
const nodeCrypto$8 = util.getNodeCrypto();
/**
* Sign a message using the provided key
* @param {module:type/oid} oid - Elliptic curve object identifier
* @param {module:enums.hash} hashAlgo - Hash algorithm used to sign
* @param {Uint8Array} message - Message to sign
* @param {Uint8Array} publicKey - Public key
* @param {Uint8Array} privateKey - Private key used to sign the message
* @param {Uint8Array} hashed - The hashed message
* @returns {Promise<{
* r: Uint8Array,
* s: Uint8Array
* }>} Signature of the message
* @async
*/
async function sign$1(oid, hashAlgo, message, publicKey, privateKey, hashed) {
const curve = new Curve(oid);
if (message && !util.isStream(message)) {
const keyPair = { publicKey, privateKey };
switch (curve.type) {
case 'web': {
// If browser doesn't support a curve, we'll catch it
try {
// Need to await to make sure browser succeeds
return await webSign$1(curve, hashAlgo, message, keyPair);
} catch (err) {
// We do not fallback if the error is related to key integrity
// Unfortunaley Safari does not support p521 and throws a DataError when using it
// So we need to always fallback for that curve
if (curve.name !== 'p521' && (err.name === 'DataError' || err.name === 'OperationError')) {
throw err;
}
util.printDebugError('Browser did not support signing: ' + err.message);
}
break;
}
case 'node': {
const signature = await nodeSign$1(curve, hashAlgo, message, keyPair);
return {
r: signature.r.toArrayLike(Uint8Array),
s: signature.s.toArrayLike(Uint8Array)
};
}
}
}
return ellipticSign(curve, hashed, privateKey);
}
/**
* Verifies if a signature is valid for a message
* @param {module:type/oid} oid - Elliptic curve object identifier
* @param {module:enums.hash} hashAlgo - Hash algorithm used in the signature
* @param {{r: Uint8Array,
s: Uint8Array}} signature Signature to verify
* @param {Uint8Array} message - Message to verify
* @param {Uint8Array} publicKey - Public key used to verify the message
* @param {Uint8Array} hashed - The hashed message
* @returns {Boolean}
* @async
*/
async function verify$1(oid, hashAlgo, signature, message, publicKey, hashed) {
const curve = new Curve(oid);
if (message && !util.isStream(message)) {
switch (curve.type) {
case 'web':
try {
// Need to await to make sure browser succeeds
return await webVerify$1(curve, hashAlgo, signature, message, publicKey);
} catch (err) {
// We do not fallback if the error is related to key integrity
// Unfortunately Safari does not support p521 and throws a DataError when using it
// So we need to always fallback for that curve
if (curve.name !== 'p521' && (err.name === 'DataError' || err.name === 'OperationError')) {
throw err;
}
util.printDebugError('Browser did not support verifying: ' + err.message);
}
break;
case 'node':
return nodeVerify$1(curve, hashAlgo, signature, message, publicKey);
}
}
const digest = (typeof hashAlgo === 'undefined') ? message : hashed;
return ellipticVerify(curve, signature, digest, publicKey);
}
/**
* Validate ECDSA parameters
* @param {module:type/oid} oid - Elliptic curve object identifier
* @param {Uint8Array} Q - ECDSA public point
* @param {Uint8Array} d - ECDSA secret scalar
* @returns {Promise} Whether params are valid.
* @async
*/
async function validateParams$2(oid, Q, d) {
const curve = new Curve(oid);
// Reject curves x25519 and ed25519
if (curve.keyType !== enums.publicKey.ecdsa) {
return false;
}
// To speed up the validation, we try to use node- or webcrypto when available
// and sign + verify a random message
switch (curve.type) {
case 'web':
case 'node': {
const message = getRandomBytes(8);
const hashAlgo = enums.hash.sha256;
const hashed = await hash.digest(hashAlgo, message);
try {
const signature = await sign$1(oid, hashAlgo, message, Q, d, hashed);
return await verify$1(oid, hashAlgo, signature, message, Q, hashed);
} catch (err) {
return false;
}
}
default:
return validateStandardParams(enums.publicKey.ecdsa, oid, Q, d);
}
}
//////////////////////////
// //
// Helper functions //
// //
//////////////////////////
async function ellipticSign(curve, hashed, privateKey) {
const indutnyCurve = await getIndutnyCurve(curve.name);
const key = keyFromPrivate(indutnyCurve, privateKey);
const signature = key.sign(hashed);
return {
r: signature.r.toArrayLike(Uint8Array),
s: signature.s.toArrayLike(Uint8Array)
};
}
async function ellipticVerify(curve, signature, digest, publicKey) {
const indutnyCurve = await getIndutnyCurve(curve.name);
const key = keyFromPublic(indutnyCurve, publicKey);
return key.verify(digest, signature);
}
async function webSign$1(curve, hashAlgo, message, keyPair) {
const len = curve.payloadSize;
const jwk = privateToJWK$1(curve.payloadSize, webCurves[curve.name], keyPair.publicKey, keyPair.privateKey);
const key = await webCrypto$7.importKey(
'jwk',
jwk,
{
'name': 'ECDSA',
'namedCurve': webCurves[curve.name],
'hash': { name: enums.read(enums.webHash, curve.hash) }
},
false,
['sign']
);
const signature = new Uint8Array(await webCrypto$7.sign(
{
'name': 'ECDSA',
'namedCurve': webCurves[curve.name],
'hash': { name: enums.read(enums.webHash, hashAlgo) }
},
key,
message
));
return {
r: signature.slice(0, len),
s: signature.slice(len, len << 1)
};
}
async function webVerify$1(curve, hashAlgo, { r, s }, message, publicKey) {
const jwk = rawPublicToJWK(curve.payloadSize, webCurves[curve.name], publicKey);
const key = await webCrypto$7.importKey(
'jwk',
jwk,
{
'name': 'ECDSA',
'namedCurve': webCurves[curve.name],
'hash': { name: enums.read(enums.webHash, curve.hash) }
},
false,
['verify']
);
const signature = util.concatUint8Array([r, s]).buffer;
return webCrypto$7.verify(
{
'name': 'ECDSA',
'namedCurve': webCurves[curve.name],
'hash': { name: enums.read(enums.webHash, hashAlgo) }
},
key,
signature,
message
);
}
async function nodeSign$1(curve, hashAlgo, message, keyPair) {
const sign = nodeCrypto$8.createSign(enums.read(enums.hash, hashAlgo));
sign.write(message);
sign.end();
const key = ECPrivateKey.encode({
version: 1,
parameters: curve.oid,
privateKey: Array.from(keyPair.privateKey),
publicKey: { unused: 0, data: Array.from(keyPair.publicKey) }
}, 'pem', {
label: 'EC PRIVATE KEY'
});
return ECDSASignature.decode(sign.sign(key), 'der');
}
async function nodeVerify$1(curve, hashAlgo, { r, s }, message, publicKey) {
const { default: BN } = await import('./bn.mjs');
const verify = nodeCrypto$8.createVerify(enums.read(enums.hash, hashAlgo));
verify.write(message);
verify.end();
const key = SubjectPublicKeyInfo.encode({
algorithm: {
algorithm: [1, 2, 840, 10045, 2, 1],
parameters: curve.oid
},
subjectPublicKey: { unused: 0, data: Array.from(publicKey) }
}, 'pem', {
label: 'PUBLIC KEY'
});
const signature = ECDSASignature.encode({
r: new BN(r), s: new BN(s)
}, 'der');
try {
return verify.verify(key, signature);
} catch (err) {
return false;
}
}
// Originally written by Owen Smith https://github.com/omsmith
// Adapted on Feb 2018 from https://github.com/Brightspace/node-jwk-to-pem/
/* eslint-disable no-invalid-this */
const asn1$1 = nodeCrypto$8 ? void('asn1.js') : undefined;
const ECDSASignature = nodeCrypto$8 ?
asn1$1.define('ECDSASignature', function() {
this.seq().obj(
this.key('r').int(),
this.key('s').int()
);
}) : undefined;
const ECPrivateKey = nodeCrypto$8 ?
asn1$1.define('ECPrivateKey', function() {
this.seq().obj(
this.key('version').int(),
this.key('privateKey').octstr(),
this.key('parameters').explicit(0).optional().any(),
this.key('publicKey').explicit(1).optional().bitstr()
);
}) : undefined;
const AlgorithmIdentifier = nodeCrypto$8 ?
asn1$1.define('AlgorithmIdentifier', function() {
this.seq().obj(
this.key('algorithm').objid(),
this.key('parameters').optional().any()
);
}) : undefined;
const SubjectPublicKeyInfo = nodeCrypto$8 ?
asn1$1.define('SubjectPublicKeyInfo', function() {
this.seq().obj(
this.key('algorithm').use(AlgorithmIdentifier),
this.key('subjectPublicKey').bitstr()
);
}) : undefined;
var ecdsa = /*#__PURE__*/Object.freeze({
__proto__: null,
sign: sign$1,
verify: verify$1,
validateParams: validateParams$2
});
// OpenPGP.js - An OpenPGP implementation in javascript
naclFastLight.hash = bytes => new Uint8Array(_512().update(bytes).digest());
/**
* Sign a message using the provided key
* @param {module:type/oid} oid - Elliptic curve object identifier
* @param {module:enums.hash} hashAlgo - Hash algorithm used to sign (must be sha256 or stronger)
* @param {Uint8Array} message - Message to sign
* @param {Uint8Array} publicKey - Public key
* @param {Uint8Array} privateKey - Private key used to sign the message
* @param {Uint8Array} hashed - The hashed message
* @returns {Promise<{
* r: Uint8Array,
* s: Uint8Array
* }>} Signature of the message
* @async
*/
async function sign$2(oid, hashAlgo, message, publicKey, privateKey, hashed) {
if (hash.getHashByteLength(hashAlgo) < hash.getHashByteLength(enums.hash.sha256)) {
// see https://tools.ietf.org/id/draft-ietf-openpgp-rfc4880bis-10.html#section-15-7.2
throw new Error('Hash algorithm too weak: sha256 or stronger is required for EdDSA.');
}
const secretKey = util.concatUint8Array([privateKey, publicKey.subarray(1)]);
const signature = naclFastLight.sign.detached(hashed, secretKey);
// EdDSA signature params are returned in little-endian format
return {
r: signature.subarray(0, 32),
s: signature.subarray(32)
};
}
/**
* Verifies if a signature is valid for a message
* @param {module:type/oid} oid - Elliptic curve object identifier
* @param {module:enums.hash} hashAlgo - Hash algorithm used in the signature
* @param {{r: Uint8Array,
s: Uint8Array}} signature Signature to verify the message
* @param {Uint8Array} m - Message to verify
* @param {Uint8Array} publicKey - Public key used to verify the message
* @param {Uint8Array} hashed - The hashed message
* @returns {Boolean}
* @async
*/
async function verify$2(oid, hashAlgo, { r, s }, m, publicKey, hashed) {
const signature = util.concatUint8Array([r, s]);
return naclFastLight.sign.detached.verify(hashed, signature, publicKey.subarray(1));
}
/**
* Validate EdDSA parameters
* @param {module:type/oid} oid - Elliptic curve object identifier
* @param {Uint8Array} Q - EdDSA public point
* @param {Uint8Array} k - EdDSA secret seed
* @returns {Promise} Whether params are valid.
* @async
*/
async function validateParams$3(oid, Q, k) {
// Check whether the given curve is supported
if (oid.getName() !== 'ed25519') {
return false;
}
/**
* Derive public point Q' = dG from private key
* and expect Q == Q'
*/
const { publicKey } = naclFastLight.sign.keyPair.fromSeed(k);
const dG = new Uint8Array([0x40, ...publicKey]); // Add public key prefix
return util.equalsUint8Array(Q, dG);
}
var eddsa = /*#__PURE__*/Object.freeze({
__proto__: null,
sign: sign$2,
verify: verify$2,
validateParams: validateParams$3
});
// OpenPGP.js - An OpenPGP implementation in javascript
/**
* AES key wrap
* @function
* @param {Uint8Array} key
* @param {Uint8Array} data
* @returns {Uint8Array}
*/
function wrap(key, data) {
const aes = new cipher['aes' + (key.length * 8)](key);
const IV = new Uint32Array([0xA6A6A6A6, 0xA6A6A6A6]);
const P = unpack(data);
let A = IV;
const R = P;
const n = P.length / 2;
const t = new Uint32Array([0, 0]);
let B = new Uint32Array(4);
for (let j = 0; j <= 5; ++j) {
for (let i = 0; i < n; ++i) {
t[1] = n * j + (1 + i);
// B = A
B[0] = A[0];
B[1] = A[1];
// B = A || R[i]
B[2] = R[2 * i];
B[3] = R[2 * i + 1];
// B = AES(K, B)
B = unpack(aes.encrypt(pack(B)));
// A = MSB(64, B) ^ t
A = B.subarray(0, 2);
A[0] ^= t[0];
A[1] ^= t[1];
// R[i] = LSB(64, B)
R[2 * i] = B[2];
R[2 * i + 1] = B[3];
}
}
return pack(A, R);
}
/**
* AES key unwrap
* @function
* @param {String} key
* @param {String} data
* @returns {Uint8Array}
* @throws {Error}
*/
function unwrap(key, data) {
const aes = new cipher['aes' + (key.length * 8)](key);
const IV = new Uint32Array([0xA6A6A6A6, 0xA6A6A6A6]);
const C = unpack(data);
let A = C.subarray(0, 2);
const R = C.subarray(2);
const n = C.length / 2 - 1;
const t = new Uint32Array([0, 0]);
let B = new Uint32Array(4);
for (let j = 5; j >= 0; --j) {
for (let i = n - 1; i >= 0; --i) {
t[1] = n * j + (i + 1);
// B = A ^ t
B[0] = A[0] ^ t[0];
B[1] = A[1] ^ t[1];
// B = (A ^ t) || R[i]
B[2] = R[2 * i];
B[3] = R[2 * i + 1];
// B = AES-1(B)
B = unpack(aes.decrypt(pack(B)));
// A = MSB(64, B)
A = B.subarray(0, 2);
// R[i] = LSB(64, B)
R[2 * i] = B[2];
R[2 * i + 1] = B[3];
}
}
if (A[0] === IV[0] && A[1] === IV[1]) {
return pack(R);
}
throw new Error('Key Data Integrity failed');
}
function createArrayBuffer(data) {
if (util.isString(data)) {
const { length } = data;
const buffer = new ArrayBuffer(length);
const view = new Uint8Array(buffer);
for (let j = 0; j < length; ++j) {
view[j] = data.charCodeAt(j);
}
return buffer;
}
return new Uint8Array(data).buffer;
}
function unpack(data) {
const { length } = data;
const buffer = createArrayBuffer(data);
const view = new DataView(buffer);
const arr = new Uint32Array(length / 4);
for (let i = 0; i < length / 4; ++i) {
arr[i] = view.getUint32(4 * i);
}
return arr;
}
function pack() {
let length = 0;
for (let k = 0; k < arguments.length; ++k) {
length += 4 * arguments[k].length;
}
const buffer = new ArrayBuffer(length);
const view = new DataView(buffer);
let offset = 0;
for (let i = 0; i < arguments.length; ++i) {
for (let j = 0; j < arguments[i].length; ++j) {
view.setUint32(offset + 4 * j, arguments[i][j]);
}
offset += 4 * arguments[i].length;
}
return new Uint8Array(buffer);
}
var aesKW = /*#__PURE__*/Object.freeze({
__proto__: null,
wrap: wrap,
unwrap: unwrap
});
// OpenPGP.js - An OpenPGP implementation in javascript
/**
* @fileoverview Functions to add and remove PKCS5 padding
* @see PublicKeyEncryptedSessionKeyPacket
* @module crypto/pkcs5
* @private
*/
/**
* Add pkcs5 padding to a message
* @param {Uint8Array} message - message to pad
* @returns {Uint8Array} Padded message.
*/
function encode$1(message) {
const c = 8 - (message.length % 8);
const padded = new Uint8Array(message.length + c).fill(c);
padded.set(message);
return padded;
}
/**
* Remove pkcs5 padding from a message
* @param {Uint8Array} message - message to remove padding from
* @returns {Uint8Array} Message without padding.
*/
function decode$1(message) {
const len = message.length;
if (len > 0) {
const c = message[len - 1];
if (c >= 1) {
const provided = message.subarray(len - c);
const computed = new Uint8Array(c).fill(c);
if (util.equalsUint8Array(provided, computed)) {
return message.subarray(0, len - c);
}
}
}
throw new Error('Invalid padding');
}
var pkcs5 = /*#__PURE__*/Object.freeze({
__proto__: null,
encode: encode$1,
decode: decode$1
});
// OpenPGP.js - An OpenPGP implementation in javascript
const webCrypto$8 = util.getWebCrypto();
const nodeCrypto$9 = util.getNodeCrypto();
/**
* Validate ECDH parameters
* @param {module:type/oid} oid - Elliptic curve object identifier
* @param {Uint8Array} Q - ECDH public point
* @param {Uint8Array} d - ECDH secret scalar
* @returns {Promise} Whether params are valid.
* @async
*/
async function validateParams$4(oid, Q, d) {
return validateStandardParams(enums.publicKey.ecdh, oid, Q, d);
}
// Build Param for ECDH algorithm (RFC 6637)
function buildEcdhParam(public_algo, oid, kdfParams, fingerprint) {
return util.concatUint8Array([
oid.write(),
new Uint8Array([public_algo]),
kdfParams.write(),
util.stringToUint8Array('Anonymous Sender '),
fingerprint.subarray(0, 20)
]);
}
// Key Derivation Function (RFC 6637)
async function kdf(hashAlgo, X, length, param, stripLeading = false, stripTrailing = false) {
// Note: X is little endian for Curve25519, big-endian for all others.
// This is not ideal, but the RFC's are unclear
// https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-02#appendix-B
let i;
if (stripLeading) {
// Work around old go crypto bug
for (i = 0; i < X.length && X[i] === 0; i++);
X = X.subarray(i);
}
if (stripTrailing) {
// Work around old OpenPGP.js bug
for (i = X.length - 1; i >= 0 && X[i] === 0; i--);
X = X.subarray(0, i + 1);
}
const digest = await hash.digest(hashAlgo, util.concatUint8Array([
new Uint8Array([0, 0, 0, 1]),
X,
param
]));
return digest.subarray(0, length);
}
/**
* Generate ECDHE ephemeral key and secret from public key
*
* @param {Curve} curve - Elliptic curve object
* @param {Uint8Array} Q - Recipient public key
* @returns {Promise<{publicKey: Uint8Array, sharedKey: Uint8Array}>}
* @async
*/
async function genPublicEphemeralKey(curve, Q) {
switch (curve.type) {
case 'curve25519': {
const d = getRandomBytes(32);
const { secretKey, sharedKey } = await genPrivateEphemeralKey(curve, Q, null, d);
let { publicKey } = naclFastLight.box.keyPair.fromSecretKey(secretKey);
publicKey = util.concatUint8Array([new Uint8Array([0x40]), publicKey]);
return { publicKey, sharedKey }; // Note: sharedKey is little-endian here, unlike below
}
case 'web':
if (curve.web && util.getWebCrypto()) {
try {
return await webPublicEphemeralKey(curve, Q);
} catch (err) {
util.printDebugError(err);
}
}
break;
case 'node':
return nodePublicEphemeralKey(curve, Q);
}
return ellipticPublicEphemeralKey(curve, Q);
}
/**
* Encrypt and wrap a session key
*
* @param {module:type/oid} oid - Elliptic curve object identifier
* @param {module:type/kdf_params} kdfParams - KDF params including cipher and algorithm to use
* @param {Uint8Array} data - Unpadded session key data
* @param {Uint8Array} Q - Recipient public key
* @param {Uint8Array} fingerprint - Recipient fingerprint
* @returns {Promise<{publicKey: Uint8Array, wrappedKey: Uint8Array}>}
* @async
*/
async function encrypt$3(oid, kdfParams, data, Q, fingerprint) {
const m = encode$1(data);
const curve = new Curve(oid);
const { publicKey, sharedKey } = await genPublicEphemeralKey(curve, Q);
const param = buildEcdhParam(enums.publicKey.ecdh, oid, kdfParams, fingerprint);
const { keySize } = getCipher(kdfParams.cipher);
const Z = await kdf(kdfParams.hash, sharedKey, keySize, param);
const wrappedKey = wrap(Z, m);
return { publicKey, wrappedKey };
}
/**
* Generate ECDHE secret from private key and public part of ephemeral key
*
* @param {Curve} curve - Elliptic curve object
* @param {Uint8Array} V - Public part of ephemeral key
* @param {Uint8Array} Q - Recipient public key
* @param {Uint8Array} d - Recipient private key
* @returns {Promise<{secretKey: Uint8Array, sharedKey: Uint8Array}>}
* @async
*/
async function genPrivateEphemeralKey(curve, V, Q, d) {
if (d.length !== curve.payloadSize) {
const privateKey = new Uint8Array(curve.payloadSize);
privateKey.set(d, curve.payloadSize - d.length);
d = privateKey;
}
switch (curve.type) {
case 'curve25519': {
const secretKey = d.slice().reverse();
const sharedKey = naclFastLight.scalarMult(secretKey, V.subarray(1));
return { secretKey, sharedKey }; // Note: sharedKey is little-endian here, unlike below
}
case 'web':
if (curve.web && util.getWebCrypto()) {
try {
return await webPrivateEphemeralKey(curve, V, Q, d);
} catch (err) {
util.printDebugError(err);
}
}
break;
case 'node':
return nodePrivateEphemeralKey(curve, V, d);
}
return ellipticPrivateEphemeralKey(curve, V, d);
}
/**
* Decrypt and unwrap the value derived from session key
*
* @param {module:type/oid} oid - Elliptic curve object identifier
* @param {module:type/kdf_params} kdfParams - KDF params including cipher and algorithm to use
* @param {Uint8Array} V - Public part of ephemeral key
* @param {Uint8Array} C - Encrypted and wrapped value derived from session key
* @param {Uint8Array} Q - Recipient public key
* @param {Uint8Array} d - Recipient private key
* @param {Uint8Array} fingerprint - Recipient fingerprint
* @returns {Promise} Value derived from session key.
* @async
*/
async function decrypt$3(oid, kdfParams, V, C, Q, d, fingerprint) {
const curve = new Curve(oid);
const { sharedKey } = await genPrivateEphemeralKey(curve, V, Q, d);
const param = buildEcdhParam(enums.publicKey.ecdh, oid, kdfParams, fingerprint);
const { keySize } = getCipher(kdfParams.cipher);
let err;
for (let i = 0; i < 3; i++) {
try {
// Work around old go crypto bug and old OpenPGP.js bug, respectively.
const Z = await kdf(kdfParams.hash, sharedKey, keySize, param, i === 1, i === 2);
return decode$1(unwrap(Z, C));
} catch (e) {
err = e;
}
}
throw err;
}
/**
* Generate ECDHE secret from private key and public part of ephemeral key using webCrypto
*
* @param {Curve} curve - Elliptic curve object
* @param {Uint8Array} V - Public part of ephemeral key
* @param {Uint8Array} Q - Recipient public key
* @param {Uint8Array} d - Recipient private key
* @returns {Promise<{secretKey: Uint8Array, sharedKey: Uint8Array}>}
* @async
*/
async function webPrivateEphemeralKey(curve, V, Q, d) {
const recipient = privateToJWK$1(curve.payloadSize, curve.web.web, Q, d);
let privateKey = webCrypto$8.importKey(
'jwk',
recipient,
{
name: 'ECDH',
namedCurve: curve.web.web
},
true,
['deriveKey', 'deriveBits']
);
const jwk = rawPublicToJWK(curve.payloadSize, curve.web.web, V);
let sender = webCrypto$8.importKey(
'jwk',
jwk,
{
name: 'ECDH',
namedCurve: curve.web.web
},
true,
[]
);
[privateKey, sender] = await Promise.all([privateKey, sender]);
let S = webCrypto$8.deriveBits(
{
name: 'ECDH',
namedCurve: curve.web.web,
public: sender
},
privateKey,
curve.web.sharedSize
);
let secret = webCrypto$8.exportKey(
'jwk',
privateKey
);
[S, secret] = await Promise.all([S, secret]);
const sharedKey = new Uint8Array(S);
const secretKey = b64ToUint8Array(secret.d);
return { secretKey, sharedKey };
}
/**
* Generate ECDHE ephemeral key and secret from public key using webCrypto
*
* @param {Curve} curve - Elliptic curve object
* @param {Uint8Array} Q - Recipient public key
* @returns {Promise<{publicKey: Uint8Array, sharedKey: Uint8Array}>}
* @async
*/
async function webPublicEphemeralKey(curve, Q) {
const jwk = rawPublicToJWK(curve.payloadSize, curve.web.web, Q);
let keyPair = webCrypto$8.generateKey(
{
name: 'ECDH',
namedCurve: curve.web.web
},
true,
['deriveKey', 'deriveBits']
);
let recipient = webCrypto$8.importKey(
'jwk',
jwk,
{
name: 'ECDH',
namedCurve: curve.web.web
},
false,
[]
);
[keyPair, recipient] = await Promise.all([keyPair, recipient]);
let s = webCrypto$8.deriveBits(
{
name: 'ECDH',
namedCurve: curve.web.web,
public: recipient
},
keyPair.privateKey,
curve.web.sharedSize
);
let p = webCrypto$8.exportKey(
'jwk',
keyPair.publicKey
);
[s, p] = await Promise.all([s, p]);
const sharedKey = new Uint8Array(s);
const publicKey = new Uint8Array(jwkToRawPublic(p));
return { publicKey, sharedKey };
}
/**
* Generate ECDHE secret from private key and public part of ephemeral key using indutny/elliptic
*
* @param {Curve} curve - Elliptic curve object
* @param {Uint8Array} V - Public part of ephemeral key
* @param {Uint8Array} d - Recipient private key
* @returns {Promise<{secretKey: Uint8Array, sharedKey: Uint8Array}>}
* @async
*/
async function ellipticPrivateEphemeralKey(curve, V, d) {
const indutnyCurve = await getIndutnyCurve(curve.name);
V = keyFromPublic(indutnyCurve, V);
d = keyFromPrivate(indutnyCurve, d);
const secretKey = new Uint8Array(d.getPrivate());
const S = d.derive(V.getPublic());
const len = indutnyCurve.curve.p.byteLength();
const sharedKey = S.toArrayLike(Uint8Array, 'be', len);
return { secretKey, sharedKey };
}
/**
* Generate ECDHE ephemeral key and secret from public key using indutny/elliptic
*
* @param {Curve} curve - Elliptic curve object
* @param {Uint8Array} Q - Recipient public key
* @returns {Promise<{publicKey: Uint8Array, sharedKey: Uint8Array}>}
* @async
*/
async function ellipticPublicEphemeralKey(curve, Q) {
const indutnyCurve = await getIndutnyCurve(curve.name);
const v = await curve.genKeyPair();
Q = keyFromPublic(indutnyCurve, Q);
const V = keyFromPrivate(indutnyCurve, v.privateKey);
const publicKey = v.publicKey;
const S = V.derive(Q.getPublic());
const len = indutnyCurve.curve.p.byteLength();
const sharedKey = S.toArrayLike(Uint8Array, 'be', len);
return { publicKey, sharedKey };
}
/**
* Generate ECDHE secret from private key and public part of ephemeral key using nodeCrypto
*
* @param {Curve} curve - Elliptic curve object
* @param {Uint8Array} V - Public part of ephemeral key
* @param {Uint8Array} d - Recipient private key
* @returns {Promise<{secretKey: Uint8Array, sharedKey: Uint8Array}>}
* @async
*/
async function nodePrivateEphemeralKey(curve, V, d) {
const recipient = nodeCrypto$9.createECDH(curve.node.node);
recipient.setPrivateKey(d);
const sharedKey = new Uint8Array(recipient.computeSecret(V));
const secretKey = new Uint8Array(recipient.getPrivateKey());
return { secretKey, sharedKey };
}
/**
* Generate ECDHE ephemeral key and secret from public key using nodeCrypto
*
* @param {Curve} curve - Elliptic curve object
* @param {Uint8Array} Q - Recipient public key
* @returns {Promise<{publicKey: Uint8Array, sharedKey: Uint8Array}>}
* @async
*/
async function nodePublicEphemeralKey(curve, Q) {
const sender = nodeCrypto$9.createECDH(curve.node.node);
sender.generateKeys();
const sharedKey = new Uint8Array(sender.computeSecret(Q));
const publicKey = new Uint8Array(sender.getPublicKey());
return { publicKey, sharedKey };
}
var ecdh = /*#__PURE__*/Object.freeze({
__proto__: null,
validateParams: validateParams$4,
encrypt: encrypt$3,
decrypt: decrypt$3
});
// OpenPGP.js - An OpenPGP implementation in javascript
var elliptic = /*#__PURE__*/Object.freeze({
__proto__: null,
Curve: Curve,
ecdh: ecdh,
ecdsa: ecdsa,
eddsa: eddsa,
generate: generate$1,
getPreferredHashAlgo: getPreferredHashAlgo
});
// GPG4Browsers - An OpenPGP implementation in javascript
/*
TODO regarding the hash function, read:
https://tools.ietf.org/html/rfc4880#section-13.6
https://tools.ietf.org/html/rfc4880#section-14
*/
/**
* DSA Sign function
* @param {Integer} hashAlgo
* @param {Uint8Array} hashed
* @param {Uint8Array} g
* @param {Uint8Array} p
* @param {Uint8Array} q
* @param {Uint8Array} x
* @returns {Promise<{ r: Uint8Array, s: Uint8Array }>}
* @async
*/
async function sign$3(hashAlgo, hashed, g, p, q, x) {
const BigInteger = await util.getBigInteger();
const one = new BigInteger(1);
p = new BigInteger(p);
q = new BigInteger(q);
g = new BigInteger(g);
x = new BigInteger(x);
let k;
let r;
let s;
let t;
g = g.mod(p);
x = x.mod(q);
// If the output size of the chosen hash is larger than the number of
// bits of q, the hash result is truncated to fit by taking the number
// of leftmost bits equal to the number of bits of q. This (possibly
// truncated) hash function result is treated as a number and used
// directly in the DSA signature algorithm.
const h = new BigInteger(hashed.subarray(0, q.byteLength())).mod(q);
// FIPS-186-4, section 4.6:
// The values of r and s shall be checked to determine if r = 0 or s = 0.
// If either r = 0 or s = 0, a new value of k shall be generated, and the
// signature shall be recalculated. It is extremely unlikely that r = 0
// or s = 0 if signatures are generated properly.
while (true) {
// See Appendix B here: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
k = await getRandomBigInteger(one, q); // returns in [1, q-1]
r = g.modExp(k, p).imod(q); // (g**k mod p) mod q
if (r.isZero()) {
continue;
}
const xr = x.mul(r).imod(q);
t = h.add(xr).imod(q); // H(m) + x*r mod q
s = k.modInv(q).imul(t).imod(q); // k**-1 * (H(m) + x*r) mod q
if (s.isZero()) {
continue;
}
break;
}
return {
r: r.toUint8Array('be', q.byteLength()),
s: s.toUint8Array('be', q.byteLength())
};
}
/**
* DSA Verify function
* @param {Integer} hashAlgo
* @param {Uint8Array} r
* @param {Uint8Array} s
* @param {Uint8Array} hashed
* @param {Uint8Array} g
* @param {Uint8Array} p
* @param {Uint8Array} q
* @param {Uint8Array} y
* @returns {boolean}
* @async
*/
async function verify$3(hashAlgo, r, s, hashed, g, p, q, y) {
const BigInteger = await util.getBigInteger();
const zero = new BigInteger(0);
r = new BigInteger(r);
s = new BigInteger(s);
p = new BigInteger(p);
q = new BigInteger(q);
g = new BigInteger(g);
y = new BigInteger(y);
if (r.lte(zero) || r.gte(q) ||
s.lte(zero) || s.gte(q)) {
util.printDebug('invalid DSA Signature');
return false;
}
const h = new BigInteger(hashed.subarray(0, q.byteLength())).imod(q);
const w = s.modInv(q); // s**-1 mod q
if (w.isZero()) {
util.printDebug('invalid DSA Signature');
return false;
}
g = g.mod(p);
y = y.mod(p);
const u1 = h.mul(w).imod(q); // H(m) * w mod q
const u2 = r.mul(w).imod(q); // r * w mod q
const t1 = g.modExp(u1, p); // g**u1 mod p
const t2 = y.modExp(u2, p); // y**u2 mod p
const v = t1.mul(t2).imod(p).imod(q); // (g**u1 * y**u2 mod p) mod q
return v.equal(r);
}
/**
* Validate DSA parameters
* @param {Uint8Array} p - DSA prime
* @param {Uint8Array} q - DSA group order
* @param {Uint8Array} g - DSA sub-group generator
* @param {Uint8Array} y - DSA public key
* @param {Uint8Array} x - DSA private key
* @returns {Promise} Whether params are valid.
* @async
*/
async function validateParams$5(p, q, g, y, x) {
const BigInteger = await util.getBigInteger();
p = new BigInteger(p);
q = new BigInteger(q);
g = new BigInteger(g);
y = new BigInteger(y);
const one = new BigInteger(1);
// Check that 1 < g < p
if (g.lte(one) || g.gte(p)) {
return false;
}
/**
* Check that subgroup order q divides p-1
*/
if (!p.dec().mod(q).isZero()) {
return false;
}
/**
* g has order q
* Check that g ** q = 1 mod p
*/
if (!g.modExp(q, p).isOne()) {
return false;
}
/**
* Check q is large and probably prime (we mainly want to avoid small factors)
*/
const qSize = new BigInteger(q.bitLength());
const n150 = new BigInteger(150);
if (qSize.lt(n150) || !(await isProbablePrime(q, null, 32))) {
return false;
}
/**
* Re-derive public key y' = g ** x mod p
* Expect y == y'
*
* Blinded exponentiation computes g**{rq + x} to compare to y
*/
x = new BigInteger(x);
const two = new BigInteger(2);
const r = await getRandomBigInteger(two.leftShift(qSize.dec()), two.leftShift(qSize)); // draw r of same size as q
const rqx = q.mul(r).add(x);
if (!y.equal(g.modExp(rqx, p))) {
return false;
}
return true;
}
var dsa = /*#__PURE__*/Object.freeze({
__proto__: null,
sign: sign$3,
verify: verify$3,
validateParams: validateParams$5
});
/**
* @fileoverview Asymmetric cryptography functions
* @module crypto/public_key
* @private
*/
var publicKey = {
/** @see module:crypto/public_key/rsa */
rsa: rsa,
/** @see module:crypto/public_key/elgamal */
elgamal: elgamal,
/** @see module:crypto/public_key/elliptic */
elliptic: elliptic,
/** @see module:crypto/public_key/dsa */
dsa: dsa,
/** @see tweetnacl */
nacl: naclFastLight
};
/**
* @fileoverview Provides functions for asymmetric signing and signature verification
* @module crypto/signature
* @private
*/
/**
* Parse signature in binary form to get the parameters.
* The returned values are only padded for EdDSA, since in the other cases their expected length
* depends on the key params, hence we delegate the padding to the signature verification function.
* See {@link https://tools.ietf.org/html/rfc4880#section-9.1|RFC 4880 9.1}
* See {@link https://tools.ietf.org/html/rfc4880#section-5.2.2|RFC 4880 5.2.2.}
* @param {module:enums.publicKey} algo - Public key algorithm
* @param {Uint8Array} signature - Data for which the signature was created
* @returns {Promise} True if signature is valid.
* @async
*/
function parseSignatureParams(algo, signature) {
let read = 0;
switch (algo) {
// Algorithm-Specific Fields for RSA signatures:
// - MPI of RSA signature value m**d mod n.
case enums.publicKey.rsaEncryptSign:
case enums.publicKey.rsaEncrypt:
case enums.publicKey.rsaSign: {
const s = util.readMPI(signature.subarray(read));
// The signature needs to be the same length as the public key modulo n.
// We pad s on signature verification, where we have access to n.
return { s };
}
// Algorithm-Specific Fields for DSA or ECDSA signatures:
// - MPI of DSA or ECDSA value r.
// - MPI of DSA or ECDSA value s.
case enums.publicKey.dsa:
case enums.publicKey.ecdsa:
{
const r = util.readMPI(signature.subarray(read)); read += r.length + 2;
const s = util.readMPI(signature.subarray(read));
return { r, s };
}
// Algorithm-Specific Fields for EdDSA signatures:
// - MPI of an EC point r.
// - EdDSA value s, in MPI, in the little endian representation
case enums.publicKey.eddsa: {
// When parsing little-endian MPI data, we always need to left-pad it, as done with big-endian values:
// https://www.ietf.org/archive/id/draft-ietf-openpgp-rfc4880bis-10.html#section-3.2-9
let r = util.readMPI(signature.subarray(read)); read += r.length + 2;
r = util.leftPad(r, 32);
let s = util.readMPI(signature.subarray(read));
s = util.leftPad(s, 32);
return { r, s };
}
default:
throw new UnsupportedError('Unknown signature algorithm.');
}
}
/**
* Verifies the signature provided for data using specified algorithms and public key parameters.
* See {@link https://tools.ietf.org/html/rfc4880#section-9.1|RFC 4880 9.1}
* and {@link https://tools.ietf.org/html/rfc4880#section-9.4|RFC 4880 9.4}
* for public key and hash algorithms.
* @param {module:enums.publicKey} algo - Public key algorithm
* @param {module:enums.hash} hashAlgo - Hash algorithm
* @param {Object} signature - Named algorithm-specific signature parameters
* @param {Object} publicParams - Algorithm-specific public key parameters
* @param {Uint8Array} data - Data for which the signature was created
* @param {Uint8Array} hashed - The hashed data
* @returns {Promise} True if signature is valid.
* @async
*/
async function verify$4(algo, hashAlgo, signature, publicParams, data, hashed) {
switch (algo) {
case enums.publicKey.rsaEncryptSign:
case enums.publicKey.rsaEncrypt:
case enums.publicKey.rsaSign: {
const { n, e } = publicParams;
const s = util.leftPad(signature.s, n.length); // padding needed for webcrypto and node crypto
return publicKey.rsa.verify(hashAlgo, data, s, n, e, hashed);
}
case enums.publicKey.dsa: {
const { g, p, q, y } = publicParams;
const { r, s } = signature; // no need to pad, since we always handle them as BigIntegers
return publicKey.dsa.verify(hashAlgo, r, s, hashed, g, p, q, y);
}
case enums.publicKey.ecdsa: {
const { oid, Q } = publicParams;
const curveSize = new publicKey.elliptic.Curve(oid).payloadSize;
// padding needed for webcrypto
const r = util.leftPad(signature.r, curveSize);
const s = util.leftPad(signature.s, curveSize);
return publicKey.elliptic.ecdsa.verify(oid, hashAlgo, { r, s }, data, Q, hashed);
}
case enums.publicKey.eddsa: {
const { oid, Q } = publicParams;
// signature already padded on parsing
return publicKey.elliptic.eddsa.verify(oid, hashAlgo, signature, data, Q, hashed);
}
default:
throw new Error('Unknown signature algorithm.');
}
}
/**
* Creates a signature on data using specified algorithms and private key parameters.
* See {@link https://tools.ietf.org/html/rfc4880#section-9.1|RFC 4880 9.1}
* and {@link https://tools.ietf.org/html/rfc4880#section-9.4|RFC 4880 9.4}
* for public key and hash algorithms.
* @param {module:enums.publicKey} algo - Public key algorithm
* @param {module:enums.hash} hashAlgo - Hash algorithm
* @param {Object} publicKeyParams - Algorithm-specific public and private key parameters
* @param {Object} privateKeyParams - Algorithm-specific public and private key parameters
* @param {Uint8Array} data - Data to be signed
* @param {Uint8Array} hashed - The hashed data
* @returns {Promise} Signature Object containing named signature parameters.
* @async
*/
async function sign$4(algo, hashAlgo, publicKeyParams, privateKeyParams, data, hashed) {
if (!publicKeyParams || !privateKeyParams) {
throw new Error('Missing key parameters');
}
switch (algo) {
case enums.publicKey.rsaEncryptSign:
case enums.publicKey.rsaEncrypt:
case enums.publicKey.rsaSign: {
const { n, e } = publicKeyParams;
const { d, p, q, u } = privateKeyParams;
const s = await publicKey.rsa.sign(hashAlgo, data, n, e, d, p, q, u, hashed);
return { s };
}
case enums.publicKey.dsa: {
const { g, p, q } = publicKeyParams;
const { x } = privateKeyParams;
return publicKey.dsa.sign(hashAlgo, hashed, g, p, q, x);
}
case enums.publicKey.elgamal: {
throw new Error('Signing with Elgamal is not defined in the OpenPGP standard.');
}
case enums.publicKey.ecdsa: {
const { oid, Q } = publicKeyParams;
const { d } = privateKeyParams;
return publicKey.elliptic.ecdsa.sign(oid, hashAlgo, data, Q, d, hashed);
}
case enums.publicKey.eddsa: {
const { oid, Q } = publicKeyParams;
const { seed } = privateKeyParams;
return publicKey.elliptic.eddsa.sign(oid, hashAlgo, data, Q, seed, hashed);
}
default:
throw new Error('Unknown signature algorithm.');
}
}
var signature = /*#__PURE__*/Object.freeze({
__proto__: null,
parseSignatureParams: parseSignatureParams,
verify: verify$4,
sign: sign$4
});
// OpenPGP.js - An OpenPGP implementation in javascript
class ECDHSymmetricKey {
constructor(data) {
if (typeof data === 'undefined') {
data = new Uint8Array([]);
} else if (util.isString(data)) {
data = util.stringToUint8Array(data);
} else {
data = new Uint8Array(data);
}
this.data = data;
}
/**
* Read an ECDHSymmetricKey from an Uint8Array
* @param {Uint8Array} input - Where to read the encoded symmetric key from
* @returns {Number} Number of read bytes.
*/
read(input) {
if (input.length >= 1) {
const length = input[0];
if (input.length >= 1 + length) {
this.data = input.subarray(1, 1 + length);
return 1 + this.data.length;
}
}
throw new Error('Invalid symmetric key');
}
/**
* Write an ECDHSymmetricKey as an Uint8Array
* @returns {Uint8Array} An array containing the value
*/
write() {
return util.concatUint8Array([new Uint8Array([this.data.length]), this.data]);
}
}
// OpenPGP.js - An OpenPGP implementation in javascript
// Copyright (C) 2015-2016 Decentral
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3.0 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
/**
* Implementation of type KDF parameters
*
* {@link https://tools.ietf.org/html/rfc6637#section-7|RFC 6637 7}:
* A key derivation function (KDF) is necessary to implement the EC
* encryption. The Concatenation Key Derivation Function (Approved
* Alternative 1) [NIST-SP800-56A] with the KDF hash function that is
* SHA2-256 [FIPS-180-3] or stronger is REQUIRED.
* @module type/kdf_params
* @private
*/
class KDFParams {
/**
* @param {enums.hash} hash - Hash algorithm
* @param {enums.symmetric} cipher - Symmetric algorithm
*/
constructor(data) {
if (data) {
const { hash, cipher } = data;
this.hash = hash;
this.cipher = cipher;
} else {
this.hash = null;
this.cipher = null;
}
}
/**
* Read KDFParams from an Uint8Array
* @param {Uint8Array} input - Where to read the KDFParams from
* @returns {Number} Number of read bytes.
*/
read(input) {
if (input.length < 4 || input[0] !== 3 || input[1] !== 1) {
throw new Error('Cannot read KDFParams');
}
this.hash = input[2];
this.cipher = input[3];
return 4;
}
/**
* Write KDFParams to an Uint8Array
* @returns {Uint8Array} Array with the KDFParams value
*/
write() {
return new Uint8Array([3, 1, this.hash, this.cipher]);
}
}
// GPG4Browsers - An OpenPGP implementation in javascript
/**
* Encrypts data using specified algorithm and public key parameters.
* See {@link https://tools.ietf.org/html/rfc4880#section-9.1|RFC 4880 9.1} for public key algorithms.
* @param {module:enums.publicKey} algo - Public key algorithm
* @param {Object} publicParams - Algorithm-specific public key parameters
* @param {Uint8Array} data - Data to be encrypted
* @param {Uint8Array} fingerprint - Recipient fingerprint
* @returns {Promise} Encrypted session key parameters.
* @async
*/
async function publicKeyEncrypt(algo, publicParams, data, fingerprint) {
switch (algo) {
case enums.publicKey.rsaEncrypt:
case enums.publicKey.rsaEncryptSign: {
const { n, e } = publicParams;
const c = await publicKey.rsa.encrypt(data, n, e);
return { c };
}
case enums.publicKey.elgamal: {
const { p, g, y } = publicParams;
return publicKey.elgamal.encrypt(data, p, g, y);
}
case enums.publicKey.ecdh: {
const { oid, Q, kdfParams } = publicParams;
const { publicKey: V, wrappedKey: C } = await publicKey.elliptic.ecdh.encrypt(
oid, kdfParams, data, Q, fingerprint);
return { V, C: new ECDHSymmetricKey(C) };
}
default:
return [];
}
}
/**
* Decrypts data using specified algorithm and private key parameters.
* See {@link https://tools.ietf.org/html/rfc4880#section-5.5.3|RFC 4880 5.5.3}
* @param {module:enums.publicKey} algo - Public key algorithm
* @param {Object} publicKeyParams - Algorithm-specific public key parameters
* @param {Object} privateKeyParams - Algorithm-specific private key parameters
* @param {Object} sessionKeyParams - Encrypted session key parameters
* @param {Uint8Array} fingerprint - Recipient fingerprint
* @param {Uint8Array} [randomPayload] - Data to return on decryption error, instead of throwing
* (needed for constant-time processing in RSA and ElGamal)
* @returns {Promise} Decrypted data.
* @throws {Error} on sensitive decryption error, unless `randomPayload` is given
* @async
*/
async function publicKeyDecrypt(algo, publicKeyParams, privateKeyParams, sessionKeyParams, fingerprint, randomPayload) {
switch (algo) {
case enums.publicKey.rsaEncryptSign:
case enums.publicKey.rsaEncrypt: {
const { c } = sessionKeyParams;
const { n, e } = publicKeyParams;
const { d, p, q, u } = privateKeyParams;
return publicKey.rsa.decrypt(c, n, e, d, p, q, u, randomPayload);
}
case enums.publicKey.elgamal: {
const { c1, c2 } = sessionKeyParams;
const p = publicKeyParams.p;
const x = privateKeyParams.x;
return publicKey.elgamal.decrypt(c1, c2, p, x, randomPayload);
}
case enums.publicKey.ecdh: {
const { oid, Q, kdfParams } = publicKeyParams;
const { d } = privateKeyParams;
const { V, C } = sessionKeyParams;
return publicKey.elliptic.ecdh.decrypt(
oid, kdfParams, V, C.data, Q, d, fingerprint);
}
default:
throw new Error('Unknown public key encryption algorithm.');
}
}
/**
* Parse public key material in binary form to get the key parameters
* @param {module:enums.publicKey} algo - The key algorithm
* @param {Uint8Array} bytes - The key material to parse
* @returns {{ read: Number, publicParams: Object }} Number of read bytes plus key parameters referenced by name.
*/
function parsePublicKeyParams(algo, bytes) {
let read = 0;
switch (algo) {
case enums.publicKey.rsaEncrypt:
case enums.publicKey.rsaEncryptSign:
case enums.publicKey.rsaSign: {
const n = util.readMPI(bytes.subarray(read)); read += n.length + 2;
const e = util.readMPI(bytes.subarray(read)); read += e.length + 2;
return { read, publicParams: { n, e } };
}
case enums.publicKey.dsa: {
const p = util.readMPI(bytes.subarray(read)); read += p.length + 2;
const q = util.readMPI(bytes.subarray(read)); read += q.length + 2;
const g = util.readMPI(bytes.subarray(read)); read += g.length + 2;
const y = util.readMPI(bytes.subarray(read)); read += y.length + 2;
return { read, publicParams: { p, q, g, y } };
}
case enums.publicKey.elgamal: {
const p = util.readMPI(bytes.subarray(read)); read += p.length + 2;
const g = util.readMPI(bytes.subarray(read)); read += g.length + 2;
const y = util.readMPI(bytes.subarray(read)); read += y.length + 2;
return { read, publicParams: { p, g, y } };
}
case enums.publicKey.ecdsa: {
const oid = new OID(); read += oid.read(bytes);
checkSupportedCurve(oid);
const Q = util.readMPI(bytes.subarray(read)); read += Q.length + 2;
return { read: read, publicParams: { oid, Q } };
}
case enums.publicKey.eddsa: {
const oid = new OID(); read += oid.read(bytes);
checkSupportedCurve(oid);
let Q = util.readMPI(bytes.subarray(read)); read += Q.length + 2;
Q = util.leftPad(Q, 33);
return { read: read, publicParams: { oid, Q } };
}
case enums.publicKey.ecdh: {
const oid = new OID(); read += oid.read(bytes);
checkSupportedCurve(oid);
const Q = util.readMPI(bytes.subarray(read)); read += Q.length + 2;
const kdfParams = new KDFParams(); read += kdfParams.read(bytes.subarray(read));
return { read: read, publicParams: { oid, Q, kdfParams } };
}
default:
throw new UnsupportedError('Unknown public key encryption algorithm.');
}
}
/**
* Parse private key material in binary form to get the key parameters
* @param {module:enums.publicKey} algo - The key algorithm
* @param {Uint8Array} bytes - The key material to parse
* @param {Object} publicParams - (ECC only) public params, needed to format some private params
* @returns {{ read: Number, privateParams: Object }} Number of read bytes plus the key parameters referenced by name.
*/
function parsePrivateKeyParams(algo, bytes, publicParams) {
let read = 0;
switch (algo) {
case enums.publicKey.rsaEncrypt:
case enums.publicKey.rsaEncryptSign:
case enums.publicKey.rsaSign: {
const d = util.readMPI(bytes.subarray(read)); read += d.length + 2;
const p = util.readMPI(bytes.subarray(read)); read += p.length + 2;
const q = util.readMPI(bytes.subarray(read)); read += q.length + 2;
const u = util.readMPI(bytes.subarray(read)); read += u.length + 2;
return { read, privateParams: { d, p, q, u } };
}
case enums.publicKey.dsa:
case enums.publicKey.elgamal: {
const x = util.readMPI(bytes.subarray(read)); read += x.length + 2;
return { read, privateParams: { x } };
}
case enums.publicKey.ecdsa:
case enums.publicKey.ecdh: {
const curve = new Curve(publicParams.oid);
let d = util.readMPI(bytes.subarray(read)); read += d.length + 2;
d = util.leftPad(d, curve.payloadSize);
return { read, privateParams: { d } };
}
case enums.publicKey.eddsa: {
const curve = new Curve(publicParams.oid);
let seed = util.readMPI(bytes.subarray(read)); read += seed.length + 2;
seed = util.leftPad(seed, curve.payloadSize);
return { read, privateParams: { seed } };
}
default:
throw new UnsupportedError('Unknown public key encryption algorithm.');
}
}
/** Returns the types comprising the encrypted session key of an algorithm
* @param {module:enums.publicKey} algo - The key algorithm
* @param {Uint8Array} bytes - The key material to parse
* @returns {Object} The session key parameters referenced by name.
*/
function parseEncSessionKeyParams(algo, bytes) {
let read = 0;
switch (algo) {
// Algorithm-Specific Fields for RSA encrypted session keys:
// - MPI of RSA encrypted value m**e mod n.
case enums.publicKey.rsaEncrypt:
case enums.publicKey.rsaEncryptSign: {
const c = util.readMPI(bytes.subarray(read));
return { c };
}
// Algorithm-Specific Fields for Elgamal encrypted session keys:
// - MPI of Elgamal value g**k mod p
// - MPI of Elgamal value m * y**k mod p
case enums.publicKey.elgamal: {
const c1 = util.readMPI(bytes.subarray(read)); read += c1.length + 2;
const c2 = util.readMPI(bytes.subarray(read));
return { c1, c2 };
}
// Algorithm-Specific Fields for ECDH encrypted session keys:
// - MPI containing the ephemeral key used to establish the shared secret
// - ECDH Symmetric Key
case enums.publicKey.ecdh: {
const V = util.readMPI(bytes.subarray(read)); read += V.length + 2;
const C = new ECDHSymmetricKey(); C.read(bytes.subarray(read));
return { V, C };
}
default:
throw new UnsupportedError('Unknown public key encryption algorithm.');
}
}
/**
* Convert params to MPI and serializes them in the proper order
* @param {module:enums.publicKey} algo - The public key algorithm
* @param {Object} params - The key parameters indexed by name
* @returns {Uint8Array} The array containing the MPIs.
*/
function serializeParams(algo, params) {
const orderedParams = Object.keys(params).map(name => {
const param = params[name];
return util.isUint8Array(param) ? util.uint8ArrayToMPI(param) : param.write();
});
return util.concatUint8Array(orderedParams);
}
/**
* Generate algorithm-specific key parameters
* @param {module:enums.publicKey} algo - The public key algorithm
* @param {Integer} bits - Bit length for RSA keys
* @param {module:type/oid} oid - Object identifier for ECC keys
* @returns {Promise<{ publicParams: {Object}, privateParams: {Object} }>} The parameters referenced by name.
* @async
*/
function generateParams(algo, bits, oid) {
switch (algo) {
case enums.publicKey.rsaEncrypt:
case enums.publicKey.rsaEncryptSign:
case enums.publicKey.rsaSign: {
return publicKey.rsa.generate(bits, 65537).then(({ n, e, d, p, q, u }) => ({
privateParams: { d, p, q, u },
publicParams: { n, e }
}));
}
case enums.publicKey.ecdsa:
return publicKey.elliptic.generate(oid).then(({ oid, Q, secret }) => ({
privateParams: { d: secret },
publicParams: { oid: new OID(oid), Q }
}));
case enums.publicKey.eddsa:
return publicKey.elliptic.generate(oid).then(({ oid, Q, secret }) => ({
privateParams: { seed: secret },
publicParams: { oid: new OID(oid), Q }
}));
case enums.publicKey.ecdh:
return publicKey.elliptic.generate(oid).then(({ oid, Q, secret, hash, cipher }) => ({
privateParams: { d: secret },
publicParams: {
oid: new OID(oid),
Q,
kdfParams: new KDFParams({ hash, cipher })
}
}));
case enums.publicKey.dsa:
case enums.publicKey.elgamal:
throw new Error('Unsupported algorithm for key generation.');
default:
throw new Error('Unknown public key algorithm.');
}
}
/**
* Validate algorithm-specific key parameters
* @param {module:enums.publicKey} algo - The public key algorithm
* @param {Object} publicParams - Algorithm-specific public key parameters
* @param {Object} privateParams - Algorithm-specific private key parameters
* @returns {Promise} Whether the parameters are valid.
* @async
*/
async function validateParams$6(algo, publicParams, privateParams) {
if (!publicParams || !privateParams) {
throw new Error('Missing key parameters');
}
switch (algo) {
case enums.publicKey.rsaEncrypt:
case enums.publicKey.rsaEncryptSign:
case enums.publicKey.rsaSign: {
const { n, e } = publicParams;
const { d, p, q, u } = privateParams;
return publicKey.rsa.validateParams(n, e, d, p, q, u);
}
case enums.publicKey.dsa: {
const { p, q, g, y } = publicParams;
const { x } = privateParams;
return publicKey.dsa.validateParams(p, q, g, y, x);
}
case enums.publicKey.elgamal: {
const { p, g, y } = publicParams;
const { x } = privateParams;
return publicKey.elgamal.validateParams(p, g, y, x);
}
case enums.publicKey.ecdsa:
case enums.publicKey.ecdh: {
const algoModule = publicKey.elliptic[enums.read(enums.publicKey, algo)];
const { oid, Q } = publicParams;
const { d } = privateParams;
return algoModule.validateParams(oid, Q, d);
}
case enums.publicKey.eddsa: {
const { oid, Q } = publicParams;
const { seed } = privateParams;
return publicKey.elliptic.eddsa.validateParams(oid, Q, seed);
}
default:
throw new Error('Unknown public key algorithm.');
}
}
/**
* Generates a random byte prefix for the specified algorithm
* See {@link https://tools.ietf.org/html/rfc4880#section-9.2|RFC 4880 9.2} for algorithms.
* @param {module:enums.symmetric} algo - Symmetric encryption algorithm
* @returns {Promise} Random bytes with length equal to the block size of the cipher, plus the last two bytes repeated.
* @async
*/
async function getPrefixRandom(algo) {
const { blockSize } = getCipher(algo);
const prefixrandom = await getRandomBytes(blockSize);
const repeat = new Uint8Array([prefixrandom[prefixrandom.length - 2], prefixrandom[prefixrandom.length - 1]]);
return util.concat([prefixrandom, repeat]);
}
/**
* Generating a session key for the specified symmetric algorithm
* See {@link https://tools.ietf.org/html/rfc4880#section-9.2|RFC 4880 9.2} for algorithms.
* @param {module:enums.symmetric} algo - Symmetric encryption algorithm
* @returns {Uint8Array} Random bytes as a string to be used as a key.
*/
function generateSessionKey(algo) {
const { keySize } = getCipher(algo);
return getRandomBytes(keySize);
}
/**
* Get implementation of the given AEAD mode
* @param {enums.aead} algo
* @returns {Object}
* @throws {Error} on invalid algo
*/
function getAEADMode(algo) {
const algoName = enums.read(enums.aead, algo);
return mode[algoName];
}
/**
* Check whether the given curve OID is supported
* @param {module:type/oid} oid - EC object identifier
* @throws {UnsupportedError} if curve is not supported
*/
function checkSupportedCurve(oid) {
try {
oid.getName();
} catch (e) {
throw new UnsupportedError('Unknown curve OID');
}
}
var crypto$1 = /*#__PURE__*/Object.freeze({
__proto__: null,
publicKeyEncrypt: publicKeyEncrypt,
publicKeyDecrypt: publicKeyDecrypt,
parsePublicKeyParams: parsePublicKeyParams,
parsePrivateKeyParams: parsePrivateKeyParams,
parseEncSessionKeyParams: parseEncSessionKeyParams,
serializeParams: serializeParams,
generateParams: generateParams,
validateParams: validateParams$6,
getPrefixRandom: getPrefixRandom,
generateSessionKey: generateSessionKey,
getAEADMode: getAEADMode,
getCipher: getCipher
});
/**
* @fileoverview Provides access to all cryptographic primitives used in OpenPGP.js
* @see module:crypto/crypto
* @see module:crypto/signature
* @see module:crypto/public_key
* @see module:crypto/cipher
* @see module:crypto/random
* @see module:crypto/hash
* @module crypto
* @private
*/
// TODO move cfb and gcm to cipher
const mod = {
/** @see module:crypto/cipher */
cipher: cipher,
/** @see module:crypto/hash */
hash: hash,
/** @see module:crypto/mode */
mode: mode,
/** @see module:crypto/public_key */
publicKey: publicKey,
/** @see module:crypto/signature */
signature: signature,
/** @see module:crypto/random */
random: random,
/** @see module:crypto/pkcs1 */
pkcs1: pkcs1,
/** @see module:crypto/pkcs5 */
pkcs5: pkcs5,
/** @see module:crypto/aes_kw */
aesKW: aesKW
};
Object.assign(mod, crypto$1);
var TYPED_OK = typeof Uint8Array !== "undefined" &&
typeof Uint16Array !== "undefined" &&
typeof Int32Array !== "undefined";
// reduce buffer size, avoiding mem copy
function shrinkBuf(buf, size) {
if (buf.length === size) {
return buf;
}
if (buf.subarray) {
return buf.subarray(0, size);
}
buf.length = size;
return buf;
}
const fnTyped = {
arraySet: function (dest, src, src_offs, len, dest_offs) {
if (src.subarray && dest.subarray) {
dest.set(src.subarray(src_offs, src_offs + len), dest_offs);
return;
}
// Fallback to ordinary array
for (let i = 0; i < len; i++) {
dest[dest_offs + i] = src[src_offs + i];
}
},
// Join array of chunks to single array.
flattenChunks: function (chunks) {
let i, l, len, pos, chunk;
// calculate data length
len = 0;
for (i = 0, l = chunks.length; i < l; i++) {
len += chunks[i].length;
}
// join chunks
const result = new Uint8Array(len);
pos = 0;
for (i = 0, l = chunks.length; i < l; i++) {
chunk = chunks[i];
result.set(chunk, pos);
pos += chunk.length;
}
return result;
}
};
const fnUntyped = {
arraySet: function (dest, src, src_offs, len, dest_offs) {
for (let i = 0; i < len; i++) {
dest[dest_offs + i] = src[src_offs + i];
}
},
// Join array of chunks to single array.
flattenChunks: function (chunks) {
return [].concat.apply([], chunks);
}
};
// Enable/Disable typed arrays use, for testing
//
let Buf8 = TYPED_OK ? Uint8Array : Array;
let Buf16 = TYPED_OK ? Uint16Array : Array;
let Buf32 = TYPED_OK ? Int32Array : Array;
let flattenChunks = TYPED_OK ? fnTyped.flattenChunks : fnUntyped.flattenChunks;
let arraySet = TYPED_OK ? fnTyped.arraySet : fnUntyped.arraySet;
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
/* Allowed flush values; see deflate() and inflate() below for details */
const Z_NO_FLUSH = 0;
const Z_PARTIAL_FLUSH = 1;
const Z_SYNC_FLUSH = 2;
const Z_FULL_FLUSH = 3;
const Z_FINISH = 4;
const Z_BLOCK = 5;
const Z_TREES = 6;
/* Return codes for the compression/decompression functions. Negative values
* are errors, positive values are used for special but normal events.
*/
const Z_OK = 0;
const Z_STREAM_END = 1;
const Z_NEED_DICT = 2;
const Z_STREAM_ERROR = -2;
const Z_DATA_ERROR = -3;
//export const Z_MEM_ERROR = -4;
const Z_BUF_ERROR = -5;
const Z_DEFAULT_COMPRESSION = -1;
const Z_FILTERED = 1;
const Z_HUFFMAN_ONLY = 2;
const Z_RLE = 3;
const Z_FIXED = 4;
const Z_DEFAULT_STRATEGY = 0;
/* Possible values of the data_type field (though see inflate()) */
const Z_BINARY = 0;
const Z_TEXT = 1;
//export const Z_ASCII = 1; // = Z_TEXT (deprecated)
const Z_UNKNOWN = 2;
/* The deflate compression method */
const Z_DEFLATED = 8;
//export const Z_NULL = null // Use -1 or null inline, depending on var type
/*============================================================================*/
function zero$1(buf) {
let len = buf.length; while (--len >= 0) {
buf[len] = 0;
}
}
// From zutil.h
const STORED_BLOCK = 0;
const STATIC_TREES = 1;
const DYN_TREES = 2;
/* The three kinds of block type */
const MIN_MATCH = 3;
const MAX_MATCH = 258;
/* The minimum and maximum match lengths */
// From deflate.h
/* ===========================================================================
* Internal compression state.
*/
const LENGTH_CODES = 29;
/* number of length codes, not counting the special END_BLOCK code */
const LITERALS = 256;
/* number of literal bytes 0..255 */
const L_CODES = LITERALS + 1 + LENGTH_CODES;
/* number of Literal or Length codes, including the END_BLOCK code */
const D_CODES = 30;
/* number of distance codes */
const BL_CODES = 19;
/* number of codes used to transfer the bit lengths */
const HEAP_SIZE = 2 * L_CODES + 1;
/* maximum heap size */
const MAX_BITS = 15;
/* All codes must not exceed MAX_BITS bits */
const Buf_size = 16;
/* size of bit buffer in bi_buf */
/* ===========================================================================
* Constants
*/
const MAX_BL_BITS = 7;
/* Bit length codes must not exceed MAX_BL_BITS bits */
const END_BLOCK = 256;
/* end of block literal code */
const REP_3_6 = 16;
/* repeat previous bit length 3-6 times (2 bits of repeat count) */
const REPZ_3_10 = 17;
/* repeat a zero length 3-10 times (3 bits of repeat count) */
const REPZ_11_138 = 18;
/* repeat a zero length 11-138 times (7 bits of repeat count) */
/* eslint-disable comma-spacing,array-bracket-spacing */
const extra_lbits = /* extra bits for each length code */
[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0];
const extra_dbits = /* extra bits for each distance code */
[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13];
const extra_blbits = /* extra bits for each bit length code */
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7];
const bl_order =
[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];
/* eslint-enable comma-spacing,array-bracket-spacing */
/* The lengths of the bit length codes are sent in order of decreasing
* probability, to avoid transmitting the lengths for unused bit length codes.
*/
/* ===========================================================================
* Local data. These are initialized only once.
*/
// We pre-fill arrays with 0 to avoid uninitialized gaps
const DIST_CODE_LEN = 512; /* see definition of array dist_code below */
// !!!! Use flat array instead of structure, Freq = i*2, Len = i*2+1
const static_ltree = new Array((L_CODES + 2) * 2);
zero$1(static_ltree);
/* The static literal tree. Since the bit lengths are imposed, there is no
* need for the L_CODES extra codes used during heap construction. However
* The codes 286 and 287 are needed to build a canonical tree (see _tr_init
* below).
*/
const static_dtree = new Array(D_CODES * 2);
zero$1(static_dtree);
/* The static distance tree. (Actually a trivial tree since all codes use
* 5 bits.)
*/
const _dist_code = new Array(DIST_CODE_LEN);
zero$1(_dist_code);
/* Distance codes. The first 256 values correspond to the distances
* 3 .. 258, the last 256 values correspond to the top 8 bits of
* the 15 bit distances.
*/
const _length_code = new Array(MAX_MATCH - MIN_MATCH + 1);
zero$1(_length_code);
/* length code for each normalized match length (0 == MIN_MATCH) */
const base_length = new Array(LENGTH_CODES);
zero$1(base_length);
/* First normalized length for each code (0 = MIN_MATCH) */
const base_dist = new Array(D_CODES);
zero$1(base_dist);
/* First normalized distance for each code (0 = distance of 1) */
function StaticTreeDesc(static_tree, extra_bits, extra_base, elems, max_length) {
this.static_tree = static_tree; /* static tree or NULL */
this.extra_bits = extra_bits; /* extra bits for each code or NULL */
this.extra_base = extra_base; /* base index for extra_bits */
this.elems = elems; /* max number of elements in the tree */
this.max_length = max_length; /* max bit length for the codes */
// show if `static_tree` has data or dummy - needed for monomorphic objects
this.has_stree = static_tree && static_tree.length;
}
let static_l_desc;
let static_d_desc;
let static_bl_desc;
function TreeDesc(dyn_tree, stat_desc) {
this.dyn_tree = dyn_tree; /* the dynamic tree */
this.max_code = 0; /* largest code with non zero frequency */
this.stat_desc = stat_desc; /* the corresponding static tree */
}
function d_code(dist) {
return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)];
}
/* ===========================================================================
* Output a short LSB first on the stream.
* IN assertion: there is enough room in pendingBuf.
*/
function put_short(s, w) {
// put_byte(s, (uch)((w) & 0xff));
// put_byte(s, (uch)((ush)(w) >> 8));
s.pending_buf[s.pending++] = w & 0xff;
s.pending_buf[s.pending++] = w >>> 8 & 0xff;
}
/* ===========================================================================
* Send a value on a given number of bits.
* IN assertion: length <= 16 and value fits in length bits.
*/
function send_bits(s, value, length) {
if (s.bi_valid > Buf_size - length) {
s.bi_buf |= value << s.bi_valid & 0xffff;
put_short(s, s.bi_buf);
s.bi_buf = value >> Buf_size - s.bi_valid;
s.bi_valid += length - Buf_size;
} else {
s.bi_buf |= value << s.bi_valid & 0xffff;
s.bi_valid += length;
}
}
function send_code(s, c, tree) {
send_bits(s, tree[c * 2]/*.Code*/, tree[c * 2 + 1]/*.Len*/);
}
/* ===========================================================================
* Reverse the first len bits of a code, using straightforward code (a faster
* method would use a table)
* IN assertion: 1 <= len <= 15
*/
function bi_reverse(code, len) {
let res = 0;
do {
res |= code & 1;
code >>>= 1;
res <<= 1;
} while (--len > 0);
return res >>> 1;
}
/* ===========================================================================
* Flush the bit buffer, keeping at most 7 bits in it.
*/
function bi_flush(s) {
if (s.bi_valid === 16) {
put_short(s, s.bi_buf);
s.bi_buf = 0;
s.bi_valid = 0;
} else if (s.bi_valid >= 8) {
s.pending_buf[s.pending++] = s.bi_buf & 0xff;
s.bi_buf >>= 8;
s.bi_valid -= 8;
}
}
/* ===========================================================================
* Compute the optimal bit lengths for a tree and update the total bit length
* for the current block.
* IN assertion: the fields freq and dad are set, heap[heap_max] and
* above are the tree nodes sorted by increasing frequency.
* OUT assertions: the field len is set to the optimal bit length, the
* array bl_count contains the frequencies for each bit length.
* The length opt_len is updated; static_len is also updated if stree is
* not null.
*/
function gen_bitlen(s, desc)
// deflate_state *s;
// tree_desc *desc; /* the tree descriptor */
{
const tree = desc.dyn_tree;
const max_code = desc.max_code;
const stree = desc.stat_desc.static_tree;
const has_stree = desc.stat_desc.has_stree;
const extra = desc.stat_desc.extra_bits;
const base = desc.stat_desc.extra_base;
const max_length = desc.stat_desc.max_length;
let h; /* heap index */
let n, m; /* iterate over the tree elements */
let bits; /* bit length */
let xbits; /* extra bits */
let f; /* frequency */
let overflow = 0; /* number of elements with bit length too large */
for (bits = 0; bits <= MAX_BITS; bits++) {
s.bl_count[bits] = 0;
}
/* In a first pass, compute the optimal bit lengths (which may
* overflow in the case of the bit length tree).
*/
tree[s.heap[s.heap_max] * 2 + 1]/*.Len*/ = 0; /* root of the heap */
for (h = s.heap_max + 1; h < HEAP_SIZE; h++) {
n = s.heap[h];
bits = tree[tree[n * 2 + 1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1;
if (bits > max_length) {
bits = max_length;
overflow++;
}
tree[n * 2 + 1]/*.Len*/ = bits;
/* We overwrite tree[n].Dad which is no longer needed */
if (n > max_code) {
continue;
} /* not a leaf node */
s.bl_count[bits]++;
xbits = 0;
if (n >= base) {
xbits = extra[n - base];
}
f = tree[n * 2]/*.Freq*/;
s.opt_len += f * (bits + xbits);
if (has_stree) {
s.static_len += f * (stree[n * 2 + 1]/*.Len*/ + xbits);
}
}
if (overflow === 0) {
return;
}
// Trace((stderr,"\nbit length overflow\n"));
/* This happens for example on obj2 and pic of the Calgary corpus */
/* Find the first bit length which could increase: */
do {
bits = max_length - 1;
while (s.bl_count[bits] === 0) {
bits--;
}
s.bl_count[bits]--; /* move one leaf down the tree */
s.bl_count[bits + 1] += 2; /* move one overflow item as its brother */
s.bl_count[max_length]--;
/* The brother of the overflow item also moves one step up,
* but this does not affect bl_count[max_length]
*/
overflow -= 2;
} while (overflow > 0);
/* Now recompute all bit lengths, scanning in increasing frequency.
* h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
* lengths instead of fixing only the wrong ones. This idea is taken
* from 'ar' written by Haruhiko Okumura.)
*/
for (bits = max_length; bits !== 0; bits--) {
n = s.bl_count[bits];
while (n !== 0) {
m = s.heap[--h];
if (m > max_code) {
continue;
}
if (tree[m * 2 + 1]/*.Len*/ !== bits) {
// Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
s.opt_len += (bits - tree[m * 2 + 1]/*.Len*/) * tree[m * 2]/*.Freq*/;
tree[m * 2 + 1]/*.Len*/ = bits;
}
n--;
}
}
}
/* ===========================================================================
* Generate the codes for a given tree and bit counts (which need not be
* optimal).
* IN assertion: the array bl_count contains the bit length statistics for
* the given tree and the field len is set for all tree elements.
* OUT assertion: the field code is set for all tree elements of non
* zero code length.
*/
function gen_codes(tree, max_code, bl_count)
// ct_data *tree; /* the tree to decorate */
// int max_code; /* largest code with non zero frequency */
// ushf *bl_count; /* number of codes at each bit length */
{
const next_code = new Array(MAX_BITS + 1); /* next code value for each bit length */
let code = 0; /* running code value */
let bits; /* bit index */
let n; /* code index */
/* The distribution counts are first used to generate the code values
* without bit reversal.
*/
for (bits = 1; bits <= MAX_BITS; bits++) {
next_code[bits] = code = code + bl_count[bits - 1] << 1;
}
/* Check that the bit counts in bl_count are consistent. The last code
* must be all ones.
*/
//Assert (code + bl_count[MAX_BITS]-1 == (1< length code (0..28) */
length = 0;
for (code = 0; code < LENGTH_CODES - 1; code++) {
base_length[code] = length;
for (n = 0; n < 1 << extra_lbits[code]; n++) {
_length_code[length++] = code;
}
}
//Assert (length == 256, "tr_static_init: length != 256");
/* Note that the length 255 (match length 258) can be represented
* in two different ways: code 284 + 5 bits or code 285, so we
* overwrite length_code[255] to use the best encoding:
*/
_length_code[length - 1] = code;
/* Initialize the mapping dist (0..32K) -> dist code (0..29) */
dist = 0;
for (code = 0; code < 16; code++) {
base_dist[code] = dist;
for (n = 0; n < 1 << extra_dbits[code]; n++) {
_dist_code[dist++] = code;
}
}
//Assert (dist == 256, "tr_static_init: dist != 256");
dist >>= 7; /* from now on, all distances are divided by 128 */
for (; code < D_CODES; code++) {
base_dist[code] = dist << 7;
for (n = 0; n < 1 << extra_dbits[code] - 7; n++) {
_dist_code[256 + dist++] = code;
}
}
//Assert (dist == 256, "tr_static_init: 256+dist != 512");
/* Construct the codes of the static literal tree */
for (bits = 0; bits <= MAX_BITS; bits++) {
bl_count[bits] = 0;
}
n = 0;
while (n <= 143) {
static_ltree[n * 2 + 1]/*.Len*/ = 8;
n++;
bl_count[8]++;
}
while (n <= 255) {
static_ltree[n * 2 + 1]/*.Len*/ = 9;
n++;
bl_count[9]++;
}
while (n <= 279) {
static_ltree[n * 2 + 1]/*.Len*/ = 7;
n++;
bl_count[7]++;
}
while (n <= 287) {
static_ltree[n * 2 + 1]/*.Len*/ = 8;
n++;
bl_count[8]++;
}
/* Codes 286 and 287 do not exist, but we must include them in the
* tree construction to get a canonical Huffman tree (longest code
* all ones)
*/
gen_codes(static_ltree, L_CODES + 1, bl_count);
/* The static distance tree is trivial: */
for (n = 0; n < D_CODES; n++) {
static_dtree[n * 2 + 1]/*.Len*/ = 5;
static_dtree[n * 2]/*.Code*/ = bi_reverse(n, 5);
}
// Now data ready and we can init static trees
static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS + 1, L_CODES, MAX_BITS);
static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0, D_CODES, MAX_BITS);
static_bl_desc = new StaticTreeDesc(new Array(0), extra_blbits, 0, BL_CODES, MAX_BL_BITS);
//static_init_done = true;
}
/* ===========================================================================
* Initialize a new block.
*/
function init_block(s) {
let n; /* iterates over tree elements */
/* Initialize the trees. */
for (n = 0; n < L_CODES; n++) {
s.dyn_ltree[n * 2]/*.Freq*/ = 0;
}
for (n = 0; n < D_CODES; n++) {
s.dyn_dtree[n * 2]/*.Freq*/ = 0;
}
for (n = 0; n < BL_CODES; n++) {
s.bl_tree[n * 2]/*.Freq*/ = 0;
}
s.dyn_ltree[END_BLOCK * 2]/*.Freq*/ = 1;
s.opt_len = s.static_len = 0;
s.last_lit = s.matches = 0;
}
/* ===========================================================================
* Flush the bit buffer and align the output on a byte boundary
*/
function bi_windup(s) {
if (s.bi_valid > 8) {
put_short(s, s.bi_buf);
} else if (s.bi_valid > 0) {
//put_byte(s, (Byte)s->bi_buf);
s.pending_buf[s.pending++] = s.bi_buf;
}
s.bi_buf = 0;
s.bi_valid = 0;
}
/* ===========================================================================
* Copy a stored block, storing first the length and its
* one's complement if requested.
*/
function copy_block(s, buf, len, header)
//DeflateState *s;
//charf *buf; /* the input data */
//unsigned len; /* its length */
//int header; /* true if block header must be written */
{
bi_windup(s); /* align on byte boundary */
if (header) {
put_short(s, len);
put_short(s, ~len);
}
// while (len--) {
// put_byte(s, *buf++);
// }
arraySet(s.pending_buf, s.window, buf, len, s.pending);
s.pending += len;
}
/* ===========================================================================
* Compares to subtrees, using the tree depth as tie breaker when
* the subtrees have equal frequency. This minimizes the worst case length.
*/
function smaller(tree, n, m, depth) {
const _n2 = n * 2;
const _m2 = m * 2;
return tree[_n2]/*.Freq*/ < tree[_m2]/*.Freq*/ ||
tree[_n2]/*.Freq*/ === tree[_m2]/*.Freq*/ && depth[n] <= depth[m];
}
/* ===========================================================================
* Restore the heap property by moving down the tree starting at node k,
* exchanging a node with the smallest of its two sons if necessary, stopping
* when the heap property is re-established (each father smaller than its
* two sons).
*/
function pqdownheap(s, tree, k)
// deflate_state *s;
// ct_data *tree; /* the tree to restore */
// int k; /* node to move down */
{
const v = s.heap[k];
let j = k << 1; /* left son of k */
while (j <= s.heap_len) {
/* Set j to the smallest of the two sons: */
if (j < s.heap_len &&
smaller(tree, s.heap[j + 1], s.heap[j], s.depth)) {
j++;
}
/* Exit if v is smaller than both sons */
if (smaller(tree, v, s.heap[j], s.depth)) {
break;
}
/* Exchange v with the smallest son */
s.heap[k] = s.heap[j];
k = j;
/* And continue down the tree, setting j to the left son of k */
j <<= 1;
}
s.heap[k] = v;
}
// inlined manually
// var SMALLEST = 1;
/* ===========================================================================
* Send the block data compressed using the given Huffman trees
*/
function compress_block(s, ltree, dtree)
// deflate_state *s;
// const ct_data *ltree; /* literal tree */
// const ct_data *dtree; /* distance tree */
{
let dist; /* distance of matched string */
let lc; /* match length or unmatched char (if dist == 0) */
let lx = 0; /* running index in l_buf */
let code; /* the code to send */
let extra; /* number of extra bits to send */
if (s.last_lit !== 0) {
do {
dist = s.pending_buf[s.d_buf + lx * 2] << 8 | s.pending_buf[s.d_buf + lx * 2 + 1];
lc = s.pending_buf[s.l_buf + lx];
lx++;
if (dist === 0) {
send_code(s, lc, ltree); /* send a literal byte */
//Tracecv(isgraph(lc), (stderr," '%c' ", lc));
} else {
/* Here, lc is the match length - MIN_MATCH */
code = _length_code[lc];
send_code(s, code + LITERALS + 1, ltree); /* send the length code */
extra = extra_lbits[code];
if (extra !== 0) {
lc -= base_length[code];
send_bits(s, lc, extra); /* send the extra length bits */
}
dist--; /* dist is now the match distance - 1 */
code = d_code(dist);
//Assert (code < D_CODES, "bad d_code");
send_code(s, code, dtree); /* send the distance code */
extra = extra_dbits[code];
if (extra !== 0) {
dist -= base_dist[code];
send_bits(s, dist, extra); /* send the extra distance bits */
}
} /* literal or match pair ? */
/* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
//Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
// "pendingBuf overflow");
} while (lx < s.last_lit);
}
send_code(s, END_BLOCK, ltree);
}
/* ===========================================================================
* Construct one Huffman tree and assigns the code bit strings and lengths.
* Update the total bit length for the current block.
* IN assertion: the field freq is set for all tree elements.
* OUT assertions: the fields len and code are set to the optimal bit length
* and corresponding code. The length opt_len is updated; static_len is
* also updated if stree is not null. The field max_code is set.
*/
function build_tree(s, desc)
// deflate_state *s;
// tree_desc *desc; /* the tree descriptor */
{
const tree = desc.dyn_tree;
const stree = desc.stat_desc.static_tree;
const has_stree = desc.stat_desc.has_stree;
const elems = desc.stat_desc.elems;
let n, m; /* iterate over heap elements */
let max_code = -1; /* largest code with non zero frequency */
let node; /* new node being created */
/* Construct the initial heap, with least frequent element in
* heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
* heap[0] is not used.
*/
s.heap_len = 0;
s.heap_max = HEAP_SIZE;
for (n = 0; n < elems; n++) {
if (tree[n * 2]/*.Freq*/ !== 0) {
s.heap[++s.heap_len] = max_code = n;
s.depth[n] = 0;
} else {
tree[n * 2 + 1]/*.Len*/ = 0;
}
}
/* The pkzip format requires that at least one distance code exists,
* and that at least one bit should be sent even if there is only one
* possible code. So to avoid special checks later on we force at least
* two codes of non zero frequency.
*/
while (s.heap_len < 2) {
node = s.heap[++s.heap_len] = max_code < 2 ? ++max_code : 0;
tree[node * 2]/*.Freq*/ = 1;
s.depth[node] = 0;
s.opt_len--;
if (has_stree) {
s.static_len -= stree[node * 2 + 1]/*.Len*/;
}
/* node is 0 or 1 so it does not have extra bits */
}
desc.max_code = max_code;
/* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
* establish sub-heaps of increasing lengths:
*/
for (n = s.heap_len >> 1/*int /2*/; n >= 1; n--) {
pqdownheap(s, tree, n);
}
/* Construct the Huffman tree by repeatedly combining the least two
* frequent nodes.
*/
node = elems; /* next internal node of the tree */
do {
//pqremove(s, tree, n); /* n = node of least frequency */
/*** pqremove ***/
n = s.heap[1/*SMALLEST*/];
s.heap[1/*SMALLEST*/] = s.heap[s.heap_len--];
pqdownheap(s, tree, 1/*SMALLEST*/);
/***/
m = s.heap[1/*SMALLEST*/]; /* m = node of next least frequency */
s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */
s.heap[--s.heap_max] = m;
/* Create a new node father of n and m */
tree[node * 2]/*.Freq*/ = tree[n * 2]/*.Freq*/ + tree[m * 2]/*.Freq*/;
s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1;
tree[n * 2 + 1]/*.Dad*/ = tree[m * 2 + 1]/*.Dad*/ = node;
/* and insert the new node in the heap */
s.heap[1/*SMALLEST*/] = node++;
pqdownheap(s, tree, 1/*SMALLEST*/);
} while (s.heap_len >= 2);
s.heap[--s.heap_max] = s.heap[1/*SMALLEST*/];
/* At this point, the fields freq and dad are set. We can now
* generate the bit lengths.
*/
gen_bitlen(s, desc);
/* The field len is now set, we can generate the bit codes */
gen_codes(tree, max_code, s.bl_count);
}
/* ===========================================================================
* Scan a literal or distance tree to determine the frequencies of the codes
* in the bit length tree.
*/
function scan_tree(s, tree, max_code)
// deflate_state *s;
// ct_data *tree; /* the tree to be scanned */
// int max_code; /* and its largest code of non zero frequency */
{
let n; /* iterates over all tree elements */
let prevlen = -1; /* last emitted length */
let curlen; /* length of current code */
let nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */
let count = 0; /* repeat count of the current code */
let max_count = 7; /* max repeat count */
let min_count = 4; /* min repeat count */
if (nextlen === 0) {
max_count = 138;
min_count = 3;
}
tree[(max_code + 1) * 2 + 1]/*.Len*/ = 0xffff; /* guard */
for (n = 0; n <= max_code; n++) {
curlen = nextlen;
nextlen = tree[(n + 1) * 2 + 1]/*.Len*/;
if (++count < max_count && curlen === nextlen) {
continue;
} else if (count < min_count) {
s.bl_tree[curlen * 2]/*.Freq*/ += count;
} else if (curlen !== 0) {
if (curlen !== prevlen) {
s.bl_tree[curlen * 2]/*.Freq*/++;
}
s.bl_tree[REP_3_6 * 2]/*.Freq*/++;
} else if (count <= 10) {
s.bl_tree[REPZ_3_10 * 2]/*.Freq*/++;
} else {
s.bl_tree[REPZ_11_138 * 2]/*.Freq*/++;
}
count = 0;
prevlen = curlen;
if (nextlen === 0) {
max_count = 138;
min_count = 3;
} else if (curlen === nextlen) {
max_count = 6;
min_count = 3;
} else {
max_count = 7;
min_count = 4;
}
}
}
/* ===========================================================================
* Send a literal or distance tree in compressed form, using the codes in
* bl_tree.
*/
function send_tree(s, tree, max_code)
// deflate_state *s;
// ct_data *tree; /* the tree to be scanned */
// int max_code; /* and its largest code of non zero frequency */
{
let n; /* iterates over all tree elements */
let prevlen = -1; /* last emitted length */
let curlen; /* length of current code */
let nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */
let count = 0; /* repeat count of the current code */
let max_count = 7; /* max repeat count */
let min_count = 4; /* min repeat count */
/* tree[max_code+1].Len = -1; */ /* guard already set */
if (nextlen === 0) {
max_count = 138;
min_count = 3;
}
for (n = 0; n <= max_code; n++) {
curlen = nextlen;
nextlen = tree[(n + 1) * 2 + 1]/*.Len*/;
if (++count < max_count && curlen === nextlen) {
continue;
} else if (count < min_count) {
do {
send_code(s, curlen, s.bl_tree);
} while (--count !== 0);
} else if (curlen !== 0) {
if (curlen !== prevlen) {
send_code(s, curlen, s.bl_tree);
count--;
}
//Assert(count >= 3 && count <= 6, " 3_6?");
send_code(s, REP_3_6, s.bl_tree);
send_bits(s, count - 3, 2);
} else if (count <= 10) {
send_code(s, REPZ_3_10, s.bl_tree);
send_bits(s, count - 3, 3);
} else {
send_code(s, REPZ_11_138, s.bl_tree);
send_bits(s, count - 11, 7);
}
count = 0;
prevlen = curlen;
if (nextlen === 0) {
max_count = 138;
min_count = 3;
} else if (curlen === nextlen) {
max_count = 6;
min_count = 3;
} else {
max_count = 7;
min_count = 4;
}
}
}
/* ===========================================================================
* Construct the Huffman tree for the bit lengths and return the index in
* bl_order of the last bit length code to send.
*/
function build_bl_tree(s) {
let max_blindex; /* index of last bit length code of non zero freq */
/* Determine the bit length frequencies for literal and distance trees */
scan_tree(s, s.dyn_ltree, s.l_desc.max_code);
scan_tree(s, s.dyn_dtree, s.d_desc.max_code);
/* Build the bit length tree: */
build_tree(s, s.bl_desc);
/* opt_len now includes the length of the tree representations, except
* the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
*/
/* Determine the number of bit length codes to send. The pkzip format
* requires that at least 4 bit length codes be sent. (appnote.txt says
* 3 but the actual value used is 4.)
*/
for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) {
if (s.bl_tree[bl_order[max_blindex] * 2 + 1]/*.Len*/ !== 0) {
break;
}
}
/* Update opt_len to include the bit length tree and counts */
s.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4;
//Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
// s->opt_len, s->static_len));
return max_blindex;
}
/* ===========================================================================
* Send the header for a block using dynamic Huffman trees: the counts, the
* lengths of the bit length codes, the literal tree and the distance tree.
* IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
*/
function send_all_trees(s, lcodes, dcodes, blcodes)
// deflate_state *s;
// int lcodes, dcodes, blcodes; /* number of codes for each tree */
{
let rank; /* index in bl_order */
//Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
//Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
// "too many codes");
//Tracev((stderr, "\nbl counts: "));
send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */
send_bits(s, dcodes - 1, 5);
send_bits(s, blcodes - 4, 4); /* not -3 as stated in appnote.txt */
for (rank = 0; rank < blcodes; rank++) {
//Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
send_bits(s, s.bl_tree[bl_order[rank] * 2 + 1]/*.Len*/, 3);
}
//Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
send_tree(s, s.dyn_ltree, lcodes - 1); /* literal tree */
//Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
send_tree(s, s.dyn_dtree, dcodes - 1); /* distance tree */
//Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
}
/* ===========================================================================
* Check if the data type is TEXT or BINARY, using the following algorithm:
* - TEXT if the two conditions below are satisfied:
* a) There are no non-portable control characters belonging to the
* "black list" (0..6, 14..25, 28..31).
* b) There is at least one printable character belonging to the
* "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
* - BINARY otherwise.
* - The following partially-portable control characters form a
* "gray list" that is ignored in this detection algorithm:
* (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
* IN assertion: the fields Freq of dyn_ltree are set.
*/
function detect_data_type(s) {
/* black_mask is the bit mask of black-listed bytes
* set bits 0..6, 14..25, and 28..31
* 0xf3ffc07f = binary 11110011111111111100000001111111
*/
let black_mask = 0xf3ffc07f;
let n;
/* Check for non-textual ("black-listed") bytes. */
for (n = 0; n <= 31; n++, black_mask >>>= 1) {
if (black_mask & 1 && s.dyn_ltree[n * 2]/*.Freq*/ !== 0) {
return Z_BINARY;
}
}
/* Check for textual ("white-listed") bytes. */
if (s.dyn_ltree[9 * 2]/*.Freq*/ !== 0 || s.dyn_ltree[10 * 2]/*.Freq*/ !== 0 ||
s.dyn_ltree[13 * 2]/*.Freq*/ !== 0) {
return Z_TEXT;
}
for (n = 32; n < LITERALS; n++) {
if (s.dyn_ltree[n * 2]/*.Freq*/ !== 0) {
return Z_TEXT;
}
}
/* There are no "black-listed" or "white-listed" bytes:
* this stream either is empty or has tolerated ("gray-listed") bytes only.
*/
return Z_BINARY;
}
let static_init_done = false;
/* ===========================================================================
* Initialize the tree data structures for a new zlib stream.
*/
function _tr_init(s) {
if (!static_init_done) {
tr_static_init();
static_init_done = true;
}
s.l_desc = new TreeDesc(s.dyn_ltree, static_l_desc);
s.d_desc = new TreeDesc(s.dyn_dtree, static_d_desc);
s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc);
s.bi_buf = 0;
s.bi_valid = 0;
/* Initialize the first block of the first file: */
init_block(s);
}
/* ===========================================================================
* Send a stored block
*/
function _tr_stored_block(s, buf, stored_len, last)
//DeflateState *s;
//charf *buf; /* input block */
//ulg stored_len; /* length of input block */
//int last; /* one if this is the last block for a file */
{
send_bits(s, (STORED_BLOCK << 1) + (last ? 1 : 0), 3); /* send block type */
copy_block(s, buf, stored_len, true); /* with header */
}
/* ===========================================================================
* Send one empty static block to give enough lookahead for inflate.
* This takes 10 bits, of which 7 may remain in the bit buffer.
*/
function _tr_align(s) {
send_bits(s, STATIC_TREES << 1, 3);
send_code(s, END_BLOCK, static_ltree);
bi_flush(s);
}
/* ===========================================================================
* Determine the best encoding for the current block: dynamic trees, static
* trees or store, and output the encoded block to the zip file.
*/
function _tr_flush_block(s, buf, stored_len, last)
//DeflateState *s;
//charf *buf; /* input block, or NULL if too old */
//ulg stored_len; /* length of input block */
//int last; /* one if this is the last block for a file */
{
let opt_lenb, static_lenb; /* opt_len and static_len in bytes */
let max_blindex = 0; /* index of last bit length code of non zero freq */
/* Build the Huffman trees unless a stored block is forced */
if (s.level > 0) {
/* Check if the file is binary or text */
if (s.strm.data_type === Z_UNKNOWN) {
s.strm.data_type = detect_data_type(s);
}
/* Construct the literal and distance trees */
build_tree(s, s.l_desc);
// Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
// s->static_len));
build_tree(s, s.d_desc);
// Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
// s->static_len));
/* At this point, opt_len and static_len are the total bit lengths of
* the compressed block data, excluding the tree representations.
*/
/* Build the bit length tree for the above two trees, and get the index
* in bl_order of the last bit length code to send.
*/
max_blindex = build_bl_tree(s);
/* Determine the best encoding. Compute the block lengths in bytes. */
opt_lenb = s.opt_len + 3 + 7 >>> 3;
static_lenb = s.static_len + 3 + 7 >>> 3;
// Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
// opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
// s->last_lit));
if (static_lenb <= opt_lenb) {
opt_lenb = static_lenb;
}
} else {
// Assert(buf != (char*)0, "lost buf");
opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
}
if (stored_len + 4 <= opt_lenb && buf !== -1) {
/* 4: two words for the lengths */
/* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
* Otherwise we can't have processed more than WSIZE input bytes since
* the last block flush, because compression would have been
* successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
* transform a block into a stored block.
*/
_tr_stored_block(s, buf, stored_len, last);
} else if (s.strategy === Z_FIXED || static_lenb === opt_lenb) {
send_bits(s, (STATIC_TREES << 1) + (last ? 1 : 0), 3);
compress_block(s, static_ltree, static_dtree);
} else {
send_bits(s, (DYN_TREES << 1) + (last ? 1 : 0), 3);
send_all_trees(s, s.l_desc.max_code + 1, s.d_desc.max_code + 1, max_blindex + 1);
compress_block(s, s.dyn_ltree, s.dyn_dtree);
}
// Assert (s->compressed_len == s->bits_sent, "bad compressed size");
/* The above check is made mod 2^32, for files larger than 512 MB
* and uLong implemented on 32 bits.
*/
init_block(s);
if (last) {
bi_windup(s);
}
// Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
// s->compressed_len-7*last));
}
/* ===========================================================================
* Save the match info and tally the frequency counts. Return true if
* the current block must be flushed.
*/
function _tr_tally(s, dist, lc)
// deflate_state *s;
// unsigned dist; /* distance of matched string */
// unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
{
//var out_length, in_length, dcode;
s.pending_buf[s.d_buf + s.last_lit * 2] = dist >>> 8 & 0xff;
s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 0xff;
s.pending_buf[s.l_buf + s.last_lit] = lc & 0xff;
s.last_lit++;
if (dist === 0) {
/* lc is the unmatched char */
s.dyn_ltree[lc * 2]/*.Freq*/++;
} else {
s.matches++;
/* Here, lc is the match length - MIN_MATCH */
dist--; /* dist = match distance - 1 */
//Assert((ush)dist < (ush)MAX_DIST(s) &&
// (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
// (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
s.dyn_ltree[(_length_code[lc] + LITERALS + 1) * 2]/*.Freq*/++;
s.dyn_dtree[d_code(dist) * 2]/*.Freq*/++;
}
// (!) This block is disabled in zlib defaults,
// don't enable it for binary compatibility
//#ifdef TRUNCATE_BLOCK
// /* Try to guess if it is profitable to stop the current block here */
// if ((s.last_lit & 0x1fff) === 0 && s.level > 2) {
// /* Compute an upper bound for the compressed length */
// out_length = s.last_lit*8;
// in_length = s.strstart - s.block_start;
//
// for (dcode = 0; dcode < D_CODES; dcode++) {
// out_length += s.dyn_dtree[dcode*2]/*.Freq*/ * (5 + extra_dbits[dcode]);
// }
// out_length >>>= 3;
// //Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
// // s->last_lit, in_length, out_length,
// // 100L - out_length*100L/in_length));
// if (s.matches < (s.last_lit>>1)/*int /2*/ && out_length < (in_length>>1)/*int /2*/) {
// return true;
// }
// }
//#endif
return s.last_lit === s.lit_bufsize - 1;
/* We avoid equality with lit_bufsize because of wraparound at 64K
* on 16 bit machines and because stored blocks are restricted to
* 64K-1 bytes.
*/
}
// Note: adler32 takes 12% for level 0 and 2% for level 6.
// It isn't worth it to make additional optimizations as in original.
// Small size is preferable.
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
function adler32(adler, buf, len, pos) {
let s1 = adler & 0xffff |0,
s2 = adler >>> 16 & 0xffff |0,
n = 0;
while (len !== 0) {
// Set limit ~ twice less than 5552, to keep
// s2 in 31-bits, because we force signed ints.
// in other case %= will fail.
n = len > 2000 ? 2000 : len;
len -= n;
do {
s1 = s1 + buf[pos++] |0;
s2 = s2 + s1 |0;
} while (--n);
s1 %= 65521;
s2 %= 65521;
}
return s1 | s2 << 16 |0;
}
// Note: we can't get significant speed boost here.
// So write code to minimize size - no pregenerated tables
// and array tools dependencies.
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
// Use ordinary array, since untyped makes no boost here
function makeTable() {
let c;
const table = [];
for (let n = 0; n < 256; n++) {
c = n;
for (let k = 0; k < 8; k++) {
c = c & 1 ? 0xEDB88320 ^ c >>> 1 : c >>> 1;
}
table[n] = c;
}
return table;
}
// Create table on load. Just 255 signed longs. Not a problem.
const crcTable = makeTable();
function crc32(crc, buf, len, pos) {
const t = crcTable,
end = pos + len;
crc ^= -1;
for (let i = pos; i < end; i++) {
crc = crc >>> 8 ^ t[(crc ^ buf[i]) & 0xFF];
}
return crc ^ -1; // >>> 0;
}
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
var msg = {
2: "need dictionary", /* Z_NEED_DICT 2 */
1: "stream end", /* Z_STREAM_END 1 */
0: "", /* Z_OK 0 */
"-1": "file error", /* Z_ERRNO (-1) */
"-2": "stream error", /* Z_STREAM_ERROR (-2) */
"-3": "data error", /* Z_DATA_ERROR (-3) */
"-4": "insufficient memory", /* Z_MEM_ERROR (-4) */
"-5": "buffer error", /* Z_BUF_ERROR (-5) */
"-6": "incompatible version" /* Z_VERSION_ERROR (-6) */
};
/*============================================================================*/
const MAX_MEM_LEVEL = 9;
const LENGTH_CODES$1 = 29;
/* number of length codes, not counting the special END_BLOCK code */
const LITERALS$1 = 256;
/* number of literal bytes 0..255 */
const L_CODES$1 = LITERALS$1 + 1 + LENGTH_CODES$1;
/* number of Literal or Length codes, including the END_BLOCK code */
const D_CODES$1 = 30;
/* number of distance codes */
const BL_CODES$1 = 19;
/* number of codes used to transfer the bit lengths */
const HEAP_SIZE$1 = 2 * L_CODES$1 + 1;
/* maximum heap size */
const MAX_BITS$1 = 15;
/* All codes must not exceed MAX_BITS bits */
const MIN_MATCH$1 = 3;
const MAX_MATCH$1 = 258;
const MIN_LOOKAHEAD = (MAX_MATCH$1 + MIN_MATCH$1 + 1);
const PRESET_DICT = 0x20;
const INIT_STATE = 42;
const EXTRA_STATE = 69;
const NAME_STATE = 73;
const COMMENT_STATE = 91;
const HCRC_STATE = 103;
const BUSY_STATE = 113;
const FINISH_STATE = 666;
const BS_NEED_MORE = 1; /* block not completed, need more input or more output */
const BS_BLOCK_DONE = 2; /* block flush performed */
const BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */
const BS_FINISH_DONE = 4; /* finish done, accept no more input or output */
const OS_CODE = 0x03; // Unix :) . Don't detect, use this default.
function err(strm, errorCode) {
strm.msg = msg[errorCode];
return errorCode;
}
function rank(f) {
return ((f) << 1) - ((f) > 4 ? 9 : 0);
}
function zero$2(buf) { let len = buf.length; while (--len >= 0) { buf[len] = 0; } }
/* =========================================================================
* Flush as much pending output as possible. All deflate() output goes
* through this function so some applications may wish to modify it
* to avoid allocating a large strm->output buffer and copying into it.
* (See also read_buf()).
*/
function flush_pending(strm) {
const s = strm.state;
//_tr_flush_bits(s);
let len = s.pending;
if (len > strm.avail_out) {
len = strm.avail_out;
}
if (len === 0) { return; }
arraySet(strm.output, s.pending_buf, s.pending_out, len, strm.next_out);
strm.next_out += len;
s.pending_out += len;
strm.total_out += len;
strm.avail_out -= len;
s.pending -= len;
if (s.pending === 0) {
s.pending_out = 0;
}
}
function flush_block_only(s, last) {
_tr_flush_block(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last);
s.block_start = s.strstart;
flush_pending(s.strm);
}
function put_byte(s, b) {
s.pending_buf[s.pending++] = b;
}
/* =========================================================================
* Put a short in the pending buffer. The 16-bit value is put in MSB order.
* IN assertion: the stream state is correct and there is enough room in
* pending_buf.
*/
function putShortMSB(s, b) {
// put_byte(s, (Byte)(b >> 8));
// put_byte(s, (Byte)(b & 0xff));
s.pending_buf[s.pending++] = (b >>> 8) & 0xff;
s.pending_buf[s.pending++] = b & 0xff;
}
/* ===========================================================================
* Read a new buffer from the current input stream, update the adler32
* and total number of bytes read. All deflate() input goes through
* this function so some applications may wish to modify it to avoid
* allocating a large strm->input buffer and copying from it.
* (See also flush_pending()).
*/
function read_buf(strm, buf, start, size) {
let len = strm.avail_in;
if (len > size) { len = size; }
if (len === 0) { return 0; }
strm.avail_in -= len;
// zmemcpy(buf, strm->next_in, len);
arraySet(buf, strm.input, strm.next_in, len, start);
if (strm.state.wrap === 1) {
strm.adler = adler32(strm.adler, buf, len, start);
}
else if (strm.state.wrap === 2) {
strm.adler = crc32(strm.adler, buf, len, start);
}
strm.next_in += len;
strm.total_in += len;
return len;
}
/* ===========================================================================
* Set match_start to the longest match starting at the given string and
* return its length. Matches shorter or equal to prev_length are discarded,
* in which case the result is equal to prev_length and match_start is
* garbage.
* IN assertions: cur_match is the head of the hash chain for the current
* string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
* OUT assertion: the match length is not greater than s->lookahead.
*/
function longest_match(s, cur_match) {
let chain_length = s.max_chain_length; /* max hash chain length */
let scan = s.strstart; /* current string */
let match; /* matched string */
let len; /* length of current match */
let best_len = s.prev_length; /* best match length so far */
let nice_match = s.nice_match; /* stop if match long enough */
const limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ?
s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/;
const _win = s.window; // shortcut
const wmask = s.w_mask;
const prev = s.prev;
/* Stop when cur_match becomes <= limit. To simplify the code,
* we prevent matches with the string of window index 0.
*/
const strend = s.strstart + MAX_MATCH$1;
let scan_end1 = _win[scan + best_len - 1];
let scan_end = _win[scan + best_len];
/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
* It is easy to get rid of this optimization if necessary.
*/
// Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
/* Do not waste too much time if we already have a good match: */
if (s.prev_length >= s.good_match) {
chain_length >>= 2;
}
/* Do not look for matches beyond the end of the input. This is necessary
* to make deflate deterministic.
*/
if (nice_match > s.lookahead) { nice_match = s.lookahead; }
// Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
do {
// Assert(cur_match < s->strstart, "no future");
match = cur_match;
/* Skip to next match if the match length cannot increase
* or if the match length is less than 2. Note that the checks below
* for insufficient lookahead only occur occasionally for performance
* reasons. Therefore uninitialized memory will be accessed, and
* conditional jumps will be made that depend on those values.
* However the length of the match is limited to the lookahead, so
* the output of deflate is not affected by the uninitialized values.
*/
if (_win[match + best_len] !== scan_end ||
_win[match + best_len - 1] !== scan_end1 ||
_win[match] !== _win[scan] ||
_win[++match] !== _win[scan + 1]) {
continue;
}
/* The check at best_len-1 can be removed because it will be made
* again later. (This heuristic is not always a win.)
* It is not necessary to compare scan[2] and match[2] since they
* are always equal when the other bytes match, given that
* the hash keys are equal and that HASH_BITS >= 8.
*/
scan += 2;
match++;
// Assert(*scan == *match, "match[2]?");
/* We check for insufficient lookahead only every 8th comparison;
* the 256th check will be made at strstart+258.
*/
do {
/*jshint noempty:false*/
} while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
_win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
_win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
_win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
scan < strend);
// Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
len = MAX_MATCH$1 - (strend - scan);
scan = strend - MAX_MATCH$1;
if (len > best_len) {
s.match_start = cur_match;
best_len = len;
if (len >= nice_match) {
break;
}
scan_end1 = _win[scan + best_len - 1];
scan_end = _win[scan + best_len];
}
} while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0);
if (best_len <= s.lookahead) {
return best_len;
}
return s.lookahead;
}
/* ===========================================================================
* Fill the window when the lookahead becomes insufficient.
* Updates strstart and lookahead.
*
* IN assertion: lookahead < MIN_LOOKAHEAD
* OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
* At least one byte has been read, or avail_in == 0; reads are
* performed for at least two bytes (required for the zip translate_eol
* option -- not supported here).
*/
function fill_window(s) {
const _w_size = s.w_size;
let p, n, m, more, str;
//Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead");
do {
more = s.window_size - s.lookahead - s.strstart;
// JS ints have 32 bit, block below not needed
/* Deal with !@#$% 64K limit: */
//if (sizeof(int) <= 2) {
// if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
// more = wsize;
//
// } else if (more == (unsigned)(-1)) {
// /* Very unlikely, but possible on 16 bit machine if
// * strstart == 0 && lookahead == 1 (input done a byte at time)
// */
// more--;
// }
//}
/* If the window is almost full and there is insufficient lookahead,
* move the upper half to the lower one to make room in the upper half.
*/
if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) {
arraySet(s.window, s.window, _w_size, _w_size, 0);
s.match_start -= _w_size;
s.strstart -= _w_size;
/* we now have strstart >= MAX_DIST */
s.block_start -= _w_size;
/* Slide the hash table (could be avoided with 32 bit values
at the expense of memory usage). We slide even when level == 0
to keep the hash table consistent if we switch back to level > 0
later. (Using level 0 permanently is not an optimal usage of
zlib, so we don't care about this pathological case.)
*/
n = s.hash_size;
p = n;
do {
m = s.head[--p];
s.head[p] = (m >= _w_size ? m - _w_size : 0);
} while (--n);
n = _w_size;
p = n;
do {
m = s.prev[--p];
s.prev[p] = (m >= _w_size ? m - _w_size : 0);
/* If n is not on any hash chain, prev[n] is garbage but
* its value will never be used.
*/
} while (--n);
more += _w_size;
}
if (s.strm.avail_in === 0) {
break;
}
/* If there was no sliding:
* strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
* more == window_size - lookahead - strstart
* => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
* => more >= window_size - 2*WSIZE + 2
* In the BIG_MEM or MMAP case (not yet supported),
* window_size == input_size + MIN_LOOKAHEAD &&
* strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
* Otherwise, window_size == 2*WSIZE so more >= 2.
* If there was sliding, more >= WSIZE. So in all cases, more >= 2.
*/
//Assert(more >= 2, "more < 2");
n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more);
s.lookahead += n;
/* Initialize the hash value now that we have some input: */
if (s.lookahead + s.insert >= MIN_MATCH$1) {
str = s.strstart - s.insert;
s.ins_h = s.window[str];
/* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */
s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + 1]) & s.hash_mask;
//#if MIN_MATCH != 3
// Call update_hash() MIN_MATCH-3 more times
//#endif
while (s.insert) {
/* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */
s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH$1 - 1]) & s.hash_mask;
s.prev[str & s.w_mask] = s.head[s.ins_h];
s.head[s.ins_h] = str;
str++;
s.insert--;
if (s.lookahead + s.insert < MIN_MATCH$1) {
break;
}
}
}
/* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
* but this is not important since only literal bytes will be emitted.
*/
} while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0);
/* If the WIN_INIT bytes after the end of the current data have never been
* written, then zero those bytes in order to avoid memory check reports of
* the use of uninitialized (or uninitialised as Julian writes) bytes by
* the longest match routines. Update the high water mark for the next
* time through here. WIN_INIT is set to MAX_MATCH since the longest match
* routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.
*/
// if (s.high_water < s.window_size) {
// var curr = s.strstart + s.lookahead;
// var init = 0;
//
// if (s.high_water < curr) {
// /* Previous high water mark below current data -- zero WIN_INIT
// * bytes or up to end of window, whichever is less.
// */
// init = s.window_size - curr;
// if (init > WIN_INIT)
// init = WIN_INIT;
// zmemzero(s->window + curr, (unsigned)init);
// s->high_water = curr + init;
// }
// else if (s->high_water < (ulg)curr + WIN_INIT) {
// /* High water mark at or above current data, but below current data
// * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
// * to end of window, whichever is less.
// */
// init = (ulg)curr + WIN_INIT - s->high_water;
// if (init > s->window_size - s->high_water)
// init = s->window_size - s->high_water;
// zmemzero(s->window + s->high_water, (unsigned)init);
// s->high_water += init;
// }
// }
//
// Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
// "not enough room for search");
}
/* ===========================================================================
* Copy without compression as much as possible from the input stream, return
* the current block state.
* This function does not insert new strings in the dictionary since
* uncompressible data is probably not useful. This function is used
* only for the level=0 compression option.
* NOTE: this function should be optimized to avoid extra copying from
* window to pending_buf.
*/
function deflate_stored(s, flush) {
/* Stored blocks are limited to 0xffff bytes, pending_buf is limited
* to pending_buf_size, and each stored block has a 5 byte header:
*/
let max_block_size = 0xffff;
if (max_block_size > s.pending_buf_size - 5) {
max_block_size = s.pending_buf_size - 5;
}
/* Copy as much as possible from input to output: */
for (; ;) {
/* Fill the window as much as possible: */
if (s.lookahead <= 1) {
//Assert(s->strstart < s->w_size+MAX_DIST(s) ||
// s->block_start >= (long)s->w_size, "slide too late");
// if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) ||
// s.block_start >= s.w_size)) {
// throw new Error("slide too late");
// }
fill_window(s);
if (s.lookahead === 0 && flush === Z_NO_FLUSH) {
return BS_NEED_MORE;
}
if (s.lookahead === 0) {
break;
}
/* flush the current block */
}
//Assert(s->block_start >= 0L, "block gone");
// if (s.block_start < 0) throw new Error("block gone");
s.strstart += s.lookahead;
s.lookahead = 0;
/* Emit a stored block if pending_buf will be full: */
const max_start = s.block_start + max_block_size;
if (s.strstart === 0 || s.strstart >= max_start) {
/* strstart == 0 is possible when wraparound on 16-bit machine */
s.lookahead = s.strstart - max_start;
s.strstart = max_start;
/*** FLUSH_BLOCK(s, 0); ***/
flush_block_only(s, false);
if (s.strm.avail_out === 0) {
return BS_NEED_MORE;
}
/***/
}
/* Flush if we may have to slide, otherwise block_start may become
* negative and the data will be gone:
*/
if (s.strstart - s.block_start >= (s.w_size - MIN_LOOKAHEAD)) {
/*** FLUSH_BLOCK(s, 0); ***/
flush_block_only(s, false);
if (s.strm.avail_out === 0) {
return BS_NEED_MORE;
}
/***/
}
}
s.insert = 0;
if (flush === Z_FINISH) {
/*** FLUSH_BLOCK(s, 1); ***/
flush_block_only(s, true);
if (s.strm.avail_out === 0) {
return BS_FINISH_STARTED;
}
/***/
return BS_FINISH_DONE;
}
if (s.strstart > s.block_start) {
/*** FLUSH_BLOCK(s, 0); ***/
flush_block_only(s, false);
if (s.strm.avail_out === 0) {
return BS_NEED_MORE;
}
/***/
}
return BS_NEED_MORE;
}
/* ===========================================================================
* Compress as much as possible from the input stream, return the current
* block state.
* This function does not perform lazy evaluation of matches and inserts
* new strings in the dictionary only for unmatched strings or for short
* matches. It is used only for the fast compression options.
*/
function deflate_fast(s, flush) {
let hash_head; /* head of the hash chain */
let bflush; /* set if current block must be flushed */
for (; ;) {
/* Make sure that we always have enough lookahead, except
* at the end of the input file. We need MAX_MATCH bytes
* for the next match, plus MIN_MATCH bytes to insert the
* string following the next match.
*/
if (s.lookahead < MIN_LOOKAHEAD) {
fill_window(s);
if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {
return BS_NEED_MORE;
}
if (s.lookahead === 0) {
break; /* flush the current block */
}
}
/* Insert the string window[strstart .. strstart+2] in the
* dictionary, and set hash_head to the head of the hash chain:
*/
hash_head = 0/*NIL*/;
if (s.lookahead >= MIN_MATCH$1) {
/*** INSERT_STRING(s, s.strstart, hash_head); ***/
s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH$1 - 1]) & s.hash_mask;
hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
s.head[s.ins_h] = s.strstart;
/***/
}
/* Find the longest match, discarding those <= prev_length.
* At this point we have always match_length < MIN_MATCH
*/
if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) {
/* To simplify the code, we prevent matches with the string
* of window index 0 (in particular we have to avoid a match
* of the string with itself at the start of the input file).
*/
s.match_length = longest_match(s, hash_head);
/* longest_match() sets match_start */
}
if (s.match_length >= MIN_MATCH$1) {
// check_match(s, s.strstart, s.match_start, s.match_length); // for debug only
/*** _tr_tally_dist(s, s.strstart - s.match_start,
s.match_length - MIN_MATCH, bflush); ***/
bflush = _tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH$1);
s.lookahead -= s.match_length;
/* Insert new strings in the hash table only if the match length
* is not too large. This saves time but degrades compression.
*/
if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH$1) {
s.match_length--; /* string at strstart already in table */
do {
s.strstart++;
/*** INSERT_STRING(s, s.strstart, hash_head); ***/
s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH$1 - 1]) & s.hash_mask;
hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
s.head[s.ins_h] = s.strstart;
/***/
/* strstart never exceeds WSIZE-MAX_MATCH, so there are
* always MIN_MATCH bytes ahead.
*/
} while (--s.match_length !== 0);
s.strstart++;
} else {
s.strstart += s.match_length;
s.match_length = 0;
s.ins_h = s.window[s.strstart];
/* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */
s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + 1]) & s.hash_mask;
//#if MIN_MATCH != 3
// Call UPDATE_HASH() MIN_MATCH-3 more times
//#endif
/* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
* matter since it will be recomputed at next deflate call.
*/
}
} else {
/* No match, output a literal byte */
//Tracevv((stderr,"%c", s.window[s.strstart]));
/*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
bflush = _tr_tally(s, 0, s.window[s.strstart]);
s.lookahead--;
s.strstart++;
}
if (bflush) {
/*** FLUSH_BLOCK(s, 0); ***/
flush_block_only(s, false);
if (s.strm.avail_out === 0) {
return BS_NEED_MORE;
}
/***/
}
}
s.insert = ((s.strstart < (MIN_MATCH$1 - 1)) ? s.strstart : MIN_MATCH$1 - 1);
if (flush === Z_FINISH) {
/*** FLUSH_BLOCK(s, 1); ***/
flush_block_only(s, true);
if (s.strm.avail_out === 0) {
return BS_FINISH_STARTED;
}
/***/
return BS_FINISH_DONE;
}
if (s.last_lit) {
/*** FLUSH_BLOCK(s, 0); ***/
flush_block_only(s, false);
if (s.strm.avail_out === 0) {
return BS_NEED_MORE;
}
/***/
}
return BS_BLOCK_DONE;
}
/* ===========================================================================
* Same as above, but achieves better compression. We use a lazy
* evaluation for matches: a match is finally adopted only if there is
* no better match at the next window position.
*/
function deflate_slow(s, flush) {
let hash_head; /* head of hash chain */
let bflush; /* set if current block must be flushed */
let max_insert;
/* Process the input block. */
for (; ;) {
/* Make sure that we always have enough lookahead, except
* at the end of the input file. We need MAX_MATCH bytes
* for the next match, plus MIN_MATCH bytes to insert the
* string following the next match.
*/
if (s.lookahead < MIN_LOOKAHEAD) {
fill_window(s);
if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {
return BS_NEED_MORE;
}
if (s.lookahead === 0) { break; } /* flush the current block */
}
/* Insert the string window[strstart .. strstart+2] in the
* dictionary, and set hash_head to the head of the hash chain:
*/
hash_head = 0/*NIL*/;
if (s.lookahead >= MIN_MATCH$1) {
/*** INSERT_STRING(s, s.strstart, hash_head); ***/
s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH$1 - 1]) & s.hash_mask;
hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
s.head[s.ins_h] = s.strstart;
/***/
}
/* Find the longest match, discarding those <= prev_length.
*/
s.prev_length = s.match_length;
s.prev_match = s.match_start;
s.match_length = MIN_MATCH$1 - 1;
if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match &&
s.strstart - hash_head <= (s.w_size - MIN_LOOKAHEAD)/*MAX_DIST(s)*/) {
/* To simplify the code, we prevent matches with the string
* of window index 0 (in particular we have to avoid a match
* of the string with itself at the start of the input file).
*/
s.match_length = longest_match(s, hash_head);
/* longest_match() sets match_start */
if (s.match_length <= 5 &&
(s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH$1 && s.strstart - s.match_start > 4096/*TOO_FAR*/))) {
/* If prev_match is also MIN_MATCH, match_start is garbage
* but we will ignore the current match anyway.
*/
s.match_length = MIN_MATCH$1 - 1;
}
}
/* If there was a match at the previous step and the current
* match is not better, output the previous match:
*/
if (s.prev_length >= MIN_MATCH$1 && s.match_length <= s.prev_length) {
max_insert = s.strstart + s.lookahead - MIN_MATCH$1;
/* Do not insert strings in hash table beyond this. */
//check_match(s, s.strstart-1, s.prev_match, s.prev_length);
/***_tr_tally_dist(s, s.strstart - 1 - s.prev_match,
s.prev_length - MIN_MATCH, bflush);***/
bflush = _tr_tally(s, s.strstart - 1 - s.prev_match, s.prev_length - MIN_MATCH$1);
/* Insert in hash table all strings up to the end of the match.
* strstart-1 and strstart are already inserted. If there is not
* enough lookahead, the last two strings are not inserted in
* the hash table.
*/
s.lookahead -= s.prev_length - 1;
s.prev_length -= 2;
do {
if (++s.strstart <= max_insert) {
/*** INSERT_STRING(s, s.strstart, hash_head); ***/
s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH$1 - 1]) & s.hash_mask;
hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
s.head[s.ins_h] = s.strstart;
/***/
}
} while (--s.prev_length !== 0);
s.match_available = 0;
s.match_length = MIN_MATCH$1 - 1;
s.strstart++;
if (bflush) {
/*** FLUSH_BLOCK(s, 0); ***/
flush_block_only(s, false);
if (s.strm.avail_out === 0) {
return BS_NEED_MORE;
}
/***/
}
} else if (s.match_available) {
/* If there was no match at the previous position, output a
* single literal. If there was a match but the current match
* is longer, truncate the previous match to a single literal.
*/
//Tracevv((stderr,"%c", s->window[s->strstart-1]));
/*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/
bflush = _tr_tally(s, 0, s.window[s.strstart - 1]);
if (bflush) {
/*** FLUSH_BLOCK_ONLY(s, 0) ***/
flush_block_only(s, false);
/***/
}
s.strstart++;
s.lookahead--;
if (s.strm.avail_out === 0) {
return BS_NEED_MORE;
}
} else {
/* There is no previous match to compare with, wait for
* the next step to decide.
*/
s.match_available = 1;
s.strstart++;
s.lookahead--;
}
}
//Assert (flush != Z_NO_FLUSH, "no flush?");
if (s.match_available) {
//Tracevv((stderr,"%c", s->window[s->strstart-1]));
/*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/
bflush = _tr_tally(s, 0, s.window[s.strstart - 1]);
s.match_available = 0;
}
s.insert = s.strstart < MIN_MATCH$1 - 1 ? s.strstart : MIN_MATCH$1 - 1;
if (flush === Z_FINISH) {
/*** FLUSH_BLOCK(s, 1); ***/
flush_block_only(s, true);
if (s.strm.avail_out === 0) {
return BS_FINISH_STARTED;
}
/***/
return BS_FINISH_DONE;
}
if (s.last_lit) {
/*** FLUSH_BLOCK(s, 0); ***/
flush_block_only(s, false);
if (s.strm.avail_out === 0) {
return BS_NEED_MORE;
}
/***/
}
return BS_BLOCK_DONE;
}
/* ===========================================================================
* For Z_RLE, simply look for runs of bytes, generate matches only of distance
* one. Do not maintain a hash table. (It will be regenerated if this run of
* deflate switches away from Z_RLE.)
*/
function deflate_rle(s, flush) {
let bflush; /* set if current block must be flushed */
let prev; /* byte at distance one to match */
let scan, strend; /* scan goes up to strend for length of run */
const _win = s.window;
for (; ;) {
/* Make sure that we always have enough lookahead, except
* at the end of the input file. We need MAX_MATCH bytes
* for the longest run, plus one for the unrolled loop.
*/
if (s.lookahead <= MAX_MATCH$1) {
fill_window(s);
if (s.lookahead <= MAX_MATCH$1 && flush === Z_NO_FLUSH) {
return BS_NEED_MORE;
}
if (s.lookahead === 0) { break; } /* flush the current block */
}
/* See how many times the previous byte repeats */
s.match_length = 0;
if (s.lookahead >= MIN_MATCH$1 && s.strstart > 0) {
scan = s.strstart - 1;
prev = _win[scan];
if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) {
strend = s.strstart + MAX_MATCH$1;
do {
/*jshint noempty:false*/
} while (prev === _win[++scan] && prev === _win[++scan] &&
prev === _win[++scan] && prev === _win[++scan] &&
prev === _win[++scan] && prev === _win[++scan] &&
prev === _win[++scan] && prev === _win[++scan] &&
scan < strend);
s.match_length = MAX_MATCH$1 - (strend - scan);
if (s.match_length > s.lookahead) {
s.match_length = s.lookahead;
}
}
//Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan");
}
/* Emit match if have run of MIN_MATCH or longer, else emit literal */
if (s.match_length >= MIN_MATCH$1) {
//check_match(s, s.strstart, s.strstart - 1, s.match_length);
/*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/
bflush = _tr_tally(s, 1, s.match_length - MIN_MATCH$1);
s.lookahead -= s.match_length;
s.strstart += s.match_length;
s.match_length = 0;
} else {
/* No match, output a literal byte */
//Tracevv((stderr,"%c", s->window[s->strstart]));
/*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
bflush = _tr_tally(s, 0, s.window[s.strstart]);
s.lookahead--;
s.strstart++;
}
if (bflush) {
/*** FLUSH_BLOCK(s, 0); ***/
flush_block_only(s, false);
if (s.strm.avail_out === 0) {
return BS_NEED_MORE;
}
/***/
}
}
s.insert = 0;
if (flush === Z_FINISH) {
/*** FLUSH_BLOCK(s, 1); ***/
flush_block_only(s, true);
if (s.strm.avail_out === 0) {
return BS_FINISH_STARTED;
}
/***/
return BS_FINISH_DONE;
}
if (s.last_lit) {
/*** FLUSH_BLOCK(s, 0); ***/
flush_block_only(s, false);
if (s.strm.avail_out === 0) {
return BS_NEED_MORE;
}
/***/
}
return BS_BLOCK_DONE;
}
/* ===========================================================================
* For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table.
* (It will be regenerated if this run of deflate switches away from Huffman.)
*/
function deflate_huff(s, flush) {
let bflush; /* set if current block must be flushed */
for (; ;) {
/* Make sure that we have a literal to write. */
if (s.lookahead === 0) {
fill_window(s);
if (s.lookahead === 0) {
if (flush === Z_NO_FLUSH) {
return BS_NEED_MORE;
}
break; /* flush the current block */
}
}
/* Output a literal byte */
s.match_length = 0;
//Tracevv((stderr,"%c", s->window[s->strstart]));
/*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
bflush = _tr_tally(s, 0, s.window[s.strstart]);
s.lookahead--;
s.strstart++;
if (bflush) {
/*** FLUSH_BLOCK(s, 0); ***/
flush_block_only(s, false);
if (s.strm.avail_out === 0) {
return BS_NEED_MORE;
}
/***/
}
}
s.insert = 0;
if (flush === Z_FINISH) {
/*** FLUSH_BLOCK(s, 1); ***/
flush_block_only(s, true);
if (s.strm.avail_out === 0) {
return BS_FINISH_STARTED;
}
/***/
return BS_FINISH_DONE;
}
if (s.last_lit) {
/*** FLUSH_BLOCK(s, 0); ***/
flush_block_only(s, false);
if (s.strm.avail_out === 0) {
return BS_NEED_MORE;
}
/***/
}
return BS_BLOCK_DONE;
}
/* Values for max_lazy_match, good_match and max_chain_length, depending on
* the desired pack level (0..9). The values given below have been tuned to
* exclude worst case performance for pathological files. Better values may be
* found for specific files.
*/
class Config {
constructor(good_length, max_lazy, nice_length, max_chain, func) {
this.good_length = good_length;
this.max_lazy = max_lazy;
this.nice_length = nice_length;
this.max_chain = max_chain;
this.func = func;
}
}
const configuration_table = [
/* good lazy nice chain */
new Config(0, 0, 0, 0, deflate_stored), /* 0 store only */
new Config(4, 4, 8, 4, deflate_fast), /* 1 max speed, no lazy matches */
new Config(4, 5, 16, 8, deflate_fast), /* 2 */
new Config(4, 6, 32, 32, deflate_fast), /* 3 */
new Config(4, 4, 16, 16, deflate_slow), /* 4 lazy matches */
new Config(8, 16, 32, 32, deflate_slow), /* 5 */
new Config(8, 16, 128, 128, deflate_slow), /* 6 */
new Config(8, 32, 128, 256, deflate_slow), /* 7 */
new Config(32, 128, 258, 1024, deflate_slow), /* 8 */
new Config(32, 258, 258, 4096, deflate_slow) /* 9 max compression */
];
/* ===========================================================================
* Initialize the "longest match" routines for a new zlib stream
*/
function lm_init(s) {
s.window_size = 2 * s.w_size;
/*** CLEAR_HASH(s); ***/
zero$2(s.head); // Fill with NIL (= 0);
/* Set the default configuration parameters:
*/
s.max_lazy_match = configuration_table[s.level].max_lazy;
s.good_match = configuration_table[s.level].good_length;
s.nice_match = configuration_table[s.level].nice_length;
s.max_chain_length = configuration_table[s.level].max_chain;
s.strstart = 0;
s.block_start = 0;
s.lookahead = 0;
s.insert = 0;
s.match_length = s.prev_length = MIN_MATCH$1 - 1;
s.match_available = 0;
s.ins_h = 0;
}
class DeflateState {
constructor() {
this.strm = null; /* pointer back to this zlib stream */
this.status = 0; /* as the name implies */
this.pending_buf = null; /* output still pending */
this.pending_buf_size = 0; /* size of pending_buf */
this.pending_out = 0; /* next pending byte to output to the stream */
this.pending = 0; /* nb of bytes in the pending buffer */
this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */
this.gzhead = null; /* gzip header information to write */
this.gzindex = 0; /* where in extra, name, or comment */
this.method = Z_DEFLATED; /* can only be DEFLATED */
this.last_flush = -1; /* value of flush param for previous deflate call */
this.w_size = 0; /* LZ77 window size (32K by default) */
this.w_bits = 0; /* log2(w_size) (8..16) */
this.w_mask = 0; /* w_size - 1 */
this.window = null;
/* Sliding window. Input bytes are read into the second half of the window,
* and move to the first half later to keep a dictionary of at least wSize
* bytes. With this organization, matches are limited to a distance of
* wSize-MAX_MATCH bytes, but this ensures that IO is always
* performed with a length multiple of the block size.
*/
this.window_size = 0;
/* Actual size of window: 2*wSize, except when the user input buffer
* is directly used as sliding window.
*/
this.prev = null;
/* Link to older string with same hash index. To limit the size of this
* array to 64K, this link is maintained only for the last 32K strings.
* An index in this array is thus a window index modulo 32K.
*/
this.head = null; /* Heads of the hash chains or NIL. */
this.ins_h = 0; /* hash index of string to be inserted */
this.hash_size = 0; /* number of elements in hash table */
this.hash_bits = 0; /* log2(hash_size) */
this.hash_mask = 0; /* hash_size-1 */
this.hash_shift = 0;
/* Number of bits by which ins_h must be shifted at each input
* step. It must be such that after MIN_MATCH steps, the oldest
* byte no longer takes part in the hash key, that is:
* hash_shift * MIN_MATCH >= hash_bits
*/
this.block_start = 0;
/* Window position at the beginning of the current output block. Gets
* negative when the window is moved backwards.
*/
this.match_length = 0; /* length of best match */
this.prev_match = 0; /* previous match */
this.match_available = 0; /* set if previous match exists */
this.strstart = 0; /* start of string to insert */
this.match_start = 0; /* start of matching string */
this.lookahead = 0; /* number of valid bytes ahead in window */
this.prev_length = 0;
/* Length of the best match at previous step. Matches not greater than this
* are discarded. This is used in the lazy match evaluation.
*/
this.max_chain_length = 0;
/* To speed up deflation, hash chains are never searched beyond this
* length. A higher limit improves compression ratio but degrades the
* speed.
*/
this.max_lazy_match = 0;
/* Attempt to find a better match only when the current match is strictly
* smaller than this value. This mechanism is used only for compression
* levels >= 4.
*/
// That's alias to max_lazy_match, don't use directly
//this.max_insert_length = 0;
/* Insert new strings in the hash table only if the match length is not
* greater than this length. This saves time but degrades compression.
* max_insert_length is used only for compression levels <= 3.
*/
this.level = 0; /* compression level (1..9) */
this.strategy = 0; /* favor or force Huffman coding*/
this.good_match = 0;
/* Use a faster search when the previous match is longer than this */
this.nice_match = 0; /* Stop searching when current match exceeds this */
/* used by trees.c: */
/* Didn't use ct_data typedef below to suppress compiler warning */
// struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
// struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
// struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
// Use flat array of DOUBLE size, with interleaved fata,
// because JS does not support effective
this.dyn_ltree = new Buf16(HEAP_SIZE$1 * 2);
this.dyn_dtree = new Buf16((2 * D_CODES$1 + 1) * 2);
this.bl_tree = new Buf16((2 * BL_CODES$1 + 1) * 2);
zero$2(this.dyn_ltree);
zero$2(this.dyn_dtree);
zero$2(this.bl_tree);
this.l_desc = null; /* desc. for literal tree */
this.d_desc = null; /* desc. for distance tree */
this.bl_desc = null; /* desc. for bit length tree */
//ush bl_count[MAX_BITS+1];
this.bl_count = new Buf16(MAX_BITS$1 + 1);
/* number of codes at each bit length for an optimal tree */
//int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
this.heap = new Buf16(2 * L_CODES$1 + 1); /* heap used to build the Huffman trees */
zero$2(this.heap);
this.heap_len = 0; /* number of elements in the heap */
this.heap_max = 0; /* element of largest frequency */
/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
* The same heap array is used to build all trees.
*/
this.depth = new Buf16(2 * L_CODES$1 + 1); //uch depth[2*L_CODES+1];
zero$2(this.depth);
/* Depth of each subtree used as tie breaker for trees of equal frequency
*/
this.l_buf = 0; /* buffer index for literals or lengths */
this.lit_bufsize = 0;
/* Size of match buffer for literals/lengths. There are 4 reasons for
* limiting lit_bufsize to 64K:
* - frequencies can be kept in 16 bit counters
* - if compression is not successful for the first block, all input
* data is still in the window so we can still emit a stored block even
* when input comes from standard input. (This can also be done for
* all blocks if lit_bufsize is not greater than 32K.)
* - if compression is not successful for a file smaller than 64K, we can
* even emit a stored file instead of a stored block (saving 5 bytes).
* This is applicable only for zip (not gzip or zlib).
* - creating new Huffman trees less frequently may not provide fast
* adaptation to changes in the input data statistics. (Take for
* example a binary file with poorly compressible code followed by
* a highly compressible string table.) Smaller buffer sizes give
* fast adaptation but have of course the overhead of transmitting
* trees more frequently.
* - I can't count above 4
*/
this.last_lit = 0; /* running index in l_buf */
this.d_buf = 0;
/* Buffer index for distances. To simplify the code, d_buf and l_buf have
* the same number of elements. To use different lengths, an extra flag
* array would be necessary.
*/
this.opt_len = 0; /* bit length of current block with optimal trees */
this.static_len = 0; /* bit length of current block with static trees */
this.matches = 0; /* number of string matches in current block */
this.insert = 0; /* bytes at end of window left to insert */
this.bi_buf = 0;
/* Output buffer. bits are inserted starting at the bottom (least
* significant bits).
*/
this.bi_valid = 0;
/* Number of valid bits in bi_buf. All bits above the last valid bit
* are always zero.
*/
// Used for window memory init. We safely ignore it for JS. That makes
// sense only for pointers and memory check tools.
//this.high_water = 0;
/* High water mark offset in window for initialized bytes -- bytes above
* this are set to zero in order to avoid memory check warnings when
* longest match routines access bytes past the input. This is then
* updated to the new high water mark.
*/
}
}
function deflateResetKeep(strm) {
let s;
if (!strm || !strm.state) {
return err(strm, Z_STREAM_ERROR);
}
strm.total_in = strm.total_out = 0;
strm.data_type = Z_UNKNOWN;
s = strm.state;
s.pending = 0;
s.pending_out = 0;
if (s.wrap < 0) {
s.wrap = -s.wrap;
/* was made negative by deflate(..., Z_FINISH); */
}
s.status = (s.wrap ? INIT_STATE : BUSY_STATE);
strm.adler = (s.wrap === 2) ?
0 // crc32(0, Z_NULL, 0)
:
1; // adler32(0, Z_NULL, 0)
s.last_flush = Z_NO_FLUSH;
_tr_init(s);
return Z_OK;
}
function deflateReset(strm) {
const ret = deflateResetKeep(strm);
if (ret === Z_OK) {
lm_init(strm.state);
}
return ret;
}
function deflateSetHeader(strm, head) {
if (!strm || !strm.state) { return Z_STREAM_ERROR; }
if (strm.state.wrap !== 2) { return Z_STREAM_ERROR; }
strm.state.gzhead = head;
return Z_OK;
}
function deflateInit2(strm, level, method, windowBits, memLevel, strategy) {
if (!strm) { // === Z_NULL
return Z_STREAM_ERROR;
}
let wrap = 1;
if (level === Z_DEFAULT_COMPRESSION) {
level = 6;
}
if (windowBits < 0) { /* suppress zlib wrapper */
wrap = 0;
windowBits = -windowBits;
}
else if (windowBits > 15) {
wrap = 2; /* write gzip wrapper instead */
windowBits -= 16;
}
if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED ||
windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
strategy < 0 || strategy > Z_FIXED) {
return err(strm, Z_STREAM_ERROR);
}
if (windowBits === 8) {
windowBits = 9;
}
/* until 256-byte window bug fixed */
const s = new DeflateState();
strm.state = s;
s.strm = strm;
s.wrap = wrap;
s.gzhead = null;
s.w_bits = windowBits;
s.w_size = 1 << s.w_bits;
s.w_mask = s.w_size - 1;
s.hash_bits = memLevel + 7;
s.hash_size = 1 << s.hash_bits;
s.hash_mask = s.hash_size - 1;
s.hash_shift = ~~((s.hash_bits + MIN_MATCH$1 - 1) / MIN_MATCH$1);
s.window = new Buf8(s.w_size * 2);
s.head = new Buf16(s.hash_size);
s.prev = new Buf16(s.w_size);
// Don't need mem init magic for JS.
//s.high_water = 0; /* nothing written to s->window yet */
s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
s.pending_buf_size = s.lit_bufsize * 4;
//overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
//s->pending_buf = (uchf *) overlay;
s.pending_buf = new Buf8(s.pending_buf_size);
// It is offset from `s.pending_buf` (size is `s.lit_bufsize * 2`)
//s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
s.d_buf = 1 * s.lit_bufsize;
//s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
s.l_buf = (1 + 2) * s.lit_bufsize;
s.level = level;
s.strategy = strategy;
s.method = method;
return deflateReset(strm);
}
function deflate(strm, flush) {
let old_flush, s;
let beg, val; // for gzip header write only
if (!strm || !strm.state ||
flush > Z_BLOCK || flush < 0) {
return strm ? err(strm, Z_STREAM_ERROR) : Z_STREAM_ERROR;
}
s = strm.state;
if (!strm.output ||
(!strm.input && strm.avail_in !== 0) ||
(s.status === FINISH_STATE && flush !== Z_FINISH)) {
return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR : Z_STREAM_ERROR);
}
s.strm = strm; /* just in case */
old_flush = s.last_flush;
s.last_flush = flush;
/* Write the header */
if (s.status === INIT_STATE) {
if (s.wrap === 2) { // GZIP header
strm.adler = 0; //crc32(0L, Z_NULL, 0);
put_byte(s, 31);
put_byte(s, 139);
put_byte(s, 8);
if (!s.gzhead) { // s->gzhead == Z_NULL
put_byte(s, 0);
put_byte(s, 0);
put_byte(s, 0);
put_byte(s, 0);
put_byte(s, 0);
put_byte(s, s.level === 9 ? 2 :
(s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?
4 : 0));
put_byte(s, OS_CODE);
s.status = BUSY_STATE;
}
else {
put_byte(s, (s.gzhead.text ? 1 : 0) +
(s.gzhead.hcrc ? 2 : 0) +
(!s.gzhead.extra ? 0 : 4) +
(!s.gzhead.name ? 0 : 8) +
(!s.gzhead.comment ? 0 : 16)
);
put_byte(s, s.gzhead.time & 0xff);
put_byte(s, (s.gzhead.time >> 8) & 0xff);
put_byte(s, (s.gzhead.time >> 16) & 0xff);
put_byte(s, (s.gzhead.time >> 24) & 0xff);
put_byte(s, s.level === 9 ? 2 :
(s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?
4 : 0));
put_byte(s, s.gzhead.os & 0xff);
if (s.gzhead.extra && s.gzhead.extra.length) {
put_byte(s, s.gzhead.extra.length & 0xff);
put_byte(s, (s.gzhead.extra.length >> 8) & 0xff);
}
if (s.gzhead.hcrc) {
strm.adler = crc32(strm.adler, s.pending_buf, s.pending, 0);
}
s.gzindex = 0;
s.status = EXTRA_STATE;
}
}
else // DEFLATE header
{
let header = (Z_DEFLATED + ((s.w_bits - 8) << 4)) << 8;
let level_flags = -1;
if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) {
level_flags = 0;
} else if (s.level < 6) {
level_flags = 1;
} else if (s.level === 6) {
level_flags = 2;
} else {
level_flags = 3;
}
header |= (level_flags << 6);
if (s.strstart !== 0) { header |= PRESET_DICT; }
header += 31 - (header % 31);
s.status = BUSY_STATE;
putShortMSB(s, header);
/* Save the adler32 of the preset dictionary: */
if (s.strstart !== 0) {
putShortMSB(s, strm.adler >>> 16);
putShortMSB(s, strm.adler & 0xffff);
}
strm.adler = 1; // adler32(0L, Z_NULL, 0);
}
}
//#ifdef GZIP
if (s.status === EXTRA_STATE) {
if (s.gzhead.extra/* != Z_NULL*/) {
beg = s.pending; /* start of bytes to update crc */
while (s.gzindex < (s.gzhead.extra.length & 0xffff)) {
if (s.pending === s.pending_buf_size) {
if (s.gzhead.hcrc && s.pending > beg) {
strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
}
flush_pending(strm);
beg = s.pending;
if (s.pending === s.pending_buf_size) {
break;
}
}
put_byte(s, s.gzhead.extra[s.gzindex] & 0xff);
s.gzindex++;
}
if (s.gzhead.hcrc && s.pending > beg) {
strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
}
if (s.gzindex === s.gzhead.extra.length) {
s.gzindex = 0;
s.status = NAME_STATE;
}
}
else {
s.status = NAME_STATE;
}
}
if (s.status === NAME_STATE) {
if (s.gzhead.name/* != Z_NULL*/) {
beg = s.pending; /* start of bytes to update crc */
//int val;
do {
if (s.pending === s.pending_buf_size) {
if (s.gzhead.hcrc && s.pending > beg) {
strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
}
flush_pending(strm);
beg = s.pending;
if (s.pending === s.pending_buf_size) {
val = 1;
break;
}
}
// JS specific: little magic to add zero terminator to end of string
if (s.gzindex < s.gzhead.name.length) {
val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff;
} else {
val = 0;
}
put_byte(s, val);
} while (val !== 0);
if (s.gzhead.hcrc && s.pending > beg) {
strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
}
if (val === 0) {
s.gzindex = 0;
s.status = COMMENT_STATE;
}
}
else {
s.status = COMMENT_STATE;
}
}
if (s.status === COMMENT_STATE) {
if (s.gzhead.comment/* != Z_NULL*/) {
beg = s.pending; /* start of bytes to update crc */
//int val;
do {
if (s.pending === s.pending_buf_size) {
if (s.gzhead.hcrc && s.pending > beg) {
strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
}
flush_pending(strm);
beg = s.pending;
if (s.pending === s.pending_buf_size) {
val = 1;
break;
}
}
// JS specific: little magic to add zero terminator to end of string
if (s.gzindex < s.gzhead.comment.length) {
val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff;
} else {
val = 0;
}
put_byte(s, val);
} while (val !== 0);
if (s.gzhead.hcrc && s.pending > beg) {
strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
}
if (val === 0) {
s.status = HCRC_STATE;
}
}
else {
s.status = HCRC_STATE;
}
}
if (s.status === HCRC_STATE) {
if (s.gzhead.hcrc) {
if (s.pending + 2 > s.pending_buf_size) {
flush_pending(strm);
}
if (s.pending + 2 <= s.pending_buf_size) {
put_byte(s, strm.adler & 0xff);
put_byte(s, (strm.adler >> 8) & 0xff);
strm.adler = 0; //crc32(0L, Z_NULL, 0);
s.status = BUSY_STATE;
}
}
else {
s.status = BUSY_STATE;
}
}
//#endif
/* Flush as much pending output as possible */
if (s.pending !== 0) {
flush_pending(strm);
if (strm.avail_out === 0) {
/* Since avail_out is 0, deflate will be called again with
* more output space, but possibly with both pending and
* avail_in equal to zero. There won't be anything to do,
* but this is not an error situation so make sure we
* return OK instead of BUF_ERROR at next call of deflate:
*/
s.last_flush = -1;
return Z_OK;
}
/* Make sure there is something to do and avoid duplicate consecutive
* flushes. For repeated and useless calls with Z_FINISH, we keep
* returning Z_STREAM_END instead of Z_BUF_ERROR.
*/
} else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) &&
flush !== Z_FINISH) {
return err(strm, Z_BUF_ERROR);
}
/* User must not provide more input after the first FINISH: */
if (s.status === FINISH_STATE && strm.avail_in !== 0) {
return err(strm, Z_BUF_ERROR);
}
/* Start a new block or continue the current one.
*/
if (strm.avail_in !== 0 || s.lookahead !== 0 ||
(flush !== Z_NO_FLUSH && s.status !== FINISH_STATE)) {
var bstate = (s.strategy === Z_HUFFMAN_ONLY) ? deflate_huff(s, flush) :
(s.strategy === Z_RLE ? deflate_rle(s, flush) :
configuration_table[s.level].func(s, flush));
if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) {
s.status = FINISH_STATE;
}
if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) {
if (strm.avail_out === 0) {
s.last_flush = -1;
/* avoid BUF_ERROR next call, see above */
}
return Z_OK;
/* If flush != Z_NO_FLUSH && avail_out == 0, the next call
* of deflate should use the same flush parameter to make sure
* that the flush is complete. So we don't have to output an
* empty block here, this will be done at next call. This also
* ensures that for a very small output buffer, we emit at most
* one empty block.
*/
}
if (bstate === BS_BLOCK_DONE) {
if (flush === Z_PARTIAL_FLUSH) {
_tr_align(s);
}
else if (flush !== Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */
_tr_stored_block(s, 0, 0, false);
/* For a full flush, this empty block will be recognized
* as a special marker by inflate_sync().
*/
if (flush === Z_FULL_FLUSH) {
/*** CLEAR_HASH(s); ***/ /* forget history */
zero$2(s.head); // Fill with NIL (= 0);
if (s.lookahead === 0) {
s.strstart = 0;
s.block_start = 0;
s.insert = 0;
}
}
}
flush_pending(strm);
if (strm.avail_out === 0) {
s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */
return Z_OK;
}
}
}
//Assert(strm->avail_out > 0, "bug2");
//if (strm.avail_out <= 0) { throw new Error("bug2");}
if (flush !== Z_FINISH) { return Z_OK; }
if (s.wrap <= 0) { return Z_STREAM_END; }
/* Write the trailer */
if (s.wrap === 2) {
put_byte(s, strm.adler & 0xff);
put_byte(s, (strm.adler >> 8) & 0xff);
put_byte(s, (strm.adler >> 16) & 0xff);
put_byte(s, (strm.adler >> 24) & 0xff);
put_byte(s, strm.total_in & 0xff);
put_byte(s, (strm.total_in >> 8) & 0xff);
put_byte(s, (strm.total_in >> 16) & 0xff);
put_byte(s, (strm.total_in >> 24) & 0xff);
}
else {
putShortMSB(s, strm.adler >>> 16);
putShortMSB(s, strm.adler & 0xffff);
}
flush_pending(strm);
/* If avail_out is zero, the application will call deflate again
* to flush the rest.
*/
if (s.wrap > 0) { s.wrap = -s.wrap; }
/* write the trailer only once! */
return s.pending !== 0 ? Z_OK : Z_STREAM_END;
}
function deflateEnd(strm) {
let status;
if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) {
return Z_STREAM_ERROR;
}
status = strm.state.status;
if (status !== INIT_STATE &&
status !== EXTRA_STATE &&
status !== NAME_STATE &&
status !== COMMENT_STATE &&
status !== HCRC_STATE &&
status !== BUSY_STATE &&
status !== FINISH_STATE
) {
return err(strm, Z_STREAM_ERROR);
}
strm.state = null;
return status === BUSY_STATE ? err(strm, Z_DATA_ERROR) : Z_OK;
}
/* =========================================================================
* Initializes the compression dictionary from the given byte
* sequence without producing any compressed output.
*/
function deflateSetDictionary(strm, dictionary) {
let dictLength = dictionary.length;
let s;
let str, n;
let wrap;
let avail;
let next;
let input;
let tmpDict;
if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) {
return Z_STREAM_ERROR;
}
s = strm.state;
wrap = s.wrap;
if (wrap === 2 || (wrap === 1 && s.status !== INIT_STATE) || s.lookahead) {
return Z_STREAM_ERROR;
}
/* when using zlib wrappers, compute Adler-32 for provided dictionary */
if (wrap === 1) {
/* adler32(strm->adler, dictionary, dictLength); */
strm.adler = adler32(strm.adler, dictionary, dictLength, 0);
}
s.wrap = 0; /* avoid computing Adler-32 in read_buf */
/* if dictionary would fill window, just replace the history */
if (dictLength >= s.w_size) {
if (wrap === 0) { /* already empty otherwise */
/*** CLEAR_HASH(s); ***/
zero$2(s.head); // Fill with NIL (= 0);
s.strstart = 0;
s.block_start = 0;
s.insert = 0;
}
/* use the tail */
// dictionary = dictionary.slice(dictLength - s.w_size);
tmpDict = new Buf8(s.w_size);
arraySet(tmpDict, dictionary, dictLength - s.w_size, s.w_size, 0);
dictionary = tmpDict;
dictLength = s.w_size;
}
/* insert dictionary into window and hash */
avail = strm.avail_in;
next = strm.next_in;
input = strm.input;
strm.avail_in = dictLength;
strm.next_in = 0;
strm.input = dictionary;
fill_window(s);
while (s.lookahead >= MIN_MATCH$1) {
str = s.strstart;
n = s.lookahead - (MIN_MATCH$1 - 1);
do {
/* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */
s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH$1 - 1]) & s.hash_mask;
s.prev[str & s.w_mask] = s.head[s.ins_h];
s.head[s.ins_h] = str;
str++;
} while (--n);
s.strstart = str;
s.lookahead = MIN_MATCH$1 - 1;
fill_window(s);
}
s.strstart += s.lookahead;
s.block_start = s.strstart;
s.insert = s.lookahead;
s.lookahead = 0;
s.match_length = s.prev_length = MIN_MATCH$1 - 1;
s.match_available = 0;
strm.next_in = next;
strm.input = input;
strm.avail_in = avail;
s.wrap = wrap;
return Z_OK;
}
/* Not implemented
exports.deflateBound = deflateBound;
exports.deflateCopy = deflateCopy;
exports.deflateParams = deflateParams;
exports.deflatePending = deflatePending;
exports.deflatePrime = deflatePrime;
exports.deflateTune = deflateTune;
*/
// String encode/decode helpers
try {
String.fromCharCode.apply(null, [ 0 ]);
} catch (__) {
}
try {
String.fromCharCode.apply(null, new Uint8Array(1));
} catch (__) {
}
// Table with utf8 lengths (calculated by first byte of sequence)
// Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS,
// because max possible codepoint is 0x10ffff
const _utf8len = new Buf8(256);
for (let q = 0; q < 256; q++) {
_utf8len[q] = q >= 252 ? 6 : q >= 248 ? 5 : q >= 240 ? 4 : q >= 224 ? 3 : q >= 192 ? 2 : 1;
}
_utf8len[254] = _utf8len[254] = 1; // Invalid sequence start
// convert string to array (typed, when possible)
function string2buf (str) {
let c, c2, m_pos, i, buf_len = 0;
const str_len = str.length;
// count binary size
for (m_pos = 0; m_pos < str_len; m_pos++) {
c = str.charCodeAt(m_pos);
if ((c & 0xfc00) === 0xd800 && m_pos + 1 < str_len) {
c2 = str.charCodeAt(m_pos + 1);
if ((c2 & 0xfc00) === 0xdc00) {
c = 0x10000 + (c - 0xd800 << 10) + (c2 - 0xdc00);
m_pos++;
}
}
buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4;
}
// allocate buffer
const buf = new Buf8(buf_len);
// convert
for (i = 0, m_pos = 0; i < buf_len; m_pos++) {
c = str.charCodeAt(m_pos);
if ((c & 0xfc00) === 0xd800 && m_pos + 1 < str_len) {
c2 = str.charCodeAt(m_pos + 1);
if ((c2 & 0xfc00) === 0xdc00) {
c = 0x10000 + (c - 0xd800 << 10) + (c2 - 0xdc00);
m_pos++;
}
}
if (c < 0x80) {
/* one byte */
buf[i++] = c;
} else if (c < 0x800) {
/* two bytes */
buf[i++] = 0xC0 | c >>> 6;
buf[i++] = 0x80 | c & 0x3f;
} else if (c < 0x10000) {
/* three bytes */
buf[i++] = 0xE0 | c >>> 12;
buf[i++] = 0x80 | c >>> 6 & 0x3f;
buf[i++] = 0x80 | c & 0x3f;
} else {
/* four bytes */
buf[i++] = 0xf0 | c >>> 18;
buf[i++] = 0x80 | c >>> 12 & 0x3f;
buf[i++] = 0x80 | c >>> 6 & 0x3f;
buf[i++] = 0x80 | c & 0x3f;
}
}
return buf;
}
// Convert binary string (typed, when possible)
function binstring2buf (str) {
const buf = new Buf8(str.length);
for (let i = 0, len = buf.length; i < len; i++) {
buf[i] = str.charCodeAt(i);
}
return buf;
}
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
class ZStream {
constructor() {
/* next input byte */
this.input = null; // JS specific, because we have no pointers
this.next_in = 0;
/* number of bytes available at input */
this.avail_in = 0;
/* total number of input bytes read so far */
this.total_in = 0;
/* next output byte should be put there */
this.output = null; // JS specific, because we have no pointers
this.next_out = 0;
/* remaining free space at output */
this.avail_out = 0;
/* total number of bytes output so far */
this.total_out = 0;
/* last error message, NULL if no error */
this.msg = ''/*Z_NULL*/;
/* not visible by applications */
this.state = null;
/* best guess about the data type: binary or text */
this.data_type = 2/*Z_UNKNOWN*/;
/* adler32 value of the uncompressed data */
this.adler = 0;
}
}
/* ===========================================================================*/
/**
* class Deflate
*
* Generic JS-style wrapper for zlib calls. If you don't need
* streaming behaviour - use more simple functions: [[deflate]],
* [[deflateRaw]] and [[gzip]].
**/
/* internal
* Deflate.chunks -> Array
*
* Chunks of output data, if [[Deflate#onData]] not overridden.
**/
/**
* Deflate.result -> Uint8Array|Array
*
* Compressed result, generated by default [[Deflate#onData]]
* and [[Deflate#onEnd]] handlers. Filled after you push last chunk
* (call [[Deflate#push]] with `Z_FINISH` / `true` param) or if you
* push a chunk with explicit flush (call [[Deflate#push]] with
* `Z_SYNC_FLUSH` param).
**/
/**
* Deflate.err -> Number
*
* Error code after deflate finished. 0 (Z_OK) on success.
* You will not need it in real life, because deflate errors
* are possible only on wrong options or bad `onData` / `onEnd`
* custom handlers.
**/
/**
* Deflate.msg -> String
*
* Error message, if [[Deflate.err]] != 0
**/
/**
* new Deflate(options)
* - options (Object): zlib deflate options.
*
* Creates new deflator instance with specified params. Throws exception
* on bad params. Supported options:
*
* - `level`
* - `windowBits`
* - `memLevel`
* - `strategy`
* - `dictionary`
*
* [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
* for more information on these.
*
* Additional options, for internal needs:
*
* - `chunkSize` - size of generated data chunks (16K by default)
* - `raw` (Boolean) - do raw deflate
* - `gzip` (Boolean) - create gzip wrapper
* - `to` (String) - if equal to 'string', then result will be "binary string"
* (each char code [0..255])
* - `header` (Object) - custom header for gzip
* - `text` (Boolean) - true if compressed data believed to be text
* - `time` (Number) - modification time, unix timestamp
* - `os` (Number) - operation system code
* - `extra` (Array) - array of bytes with extra data (max 65536)
* - `name` (String) - file name (binary string)
* - `comment` (String) - comment (binary string)
* - `hcrc` (Boolean) - true if header crc should be added
*
* ##### Example:
*
* ```javascript
* var pako = void('pako')
* , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9])
* , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]);
*
* var deflate = new pako.Deflate({ level: 3});
*
* deflate.push(chunk1, false);
* deflate.push(chunk2, true); // true -> last chunk
*
* if (deflate.err) { throw new Error(deflate.err); }
*
* console.log(deflate.result);
* ```
**/
class Deflate {
constructor(options) {
this.options = {
level: Z_DEFAULT_COMPRESSION,
method: Z_DEFLATED,
chunkSize: 16384,
windowBits: 15,
memLevel: 8,
strategy: Z_DEFAULT_STRATEGY,
...(options || {})
};
const opt = this.options;
if (opt.raw && (opt.windowBits > 0)) {
opt.windowBits = -opt.windowBits;
}
else if (opt.gzip && (opt.windowBits > 0) && (opt.windowBits < 16)) {
opt.windowBits += 16;
}
this.err = 0; // error code, if happens (0 = Z_OK)
this.msg = ''; // error message
this.ended = false; // used to avoid multiple onEnd() calls
this.chunks = []; // chunks of compressed data
this.strm = new ZStream();
this.strm.avail_out = 0;
var status = deflateInit2(
this.strm,
opt.level,
opt.method,
opt.windowBits,
opt.memLevel,
opt.strategy
);
if (status !== Z_OK) {
throw new Error(msg[status]);
}
if (opt.header) {
deflateSetHeader(this.strm, opt.header);
}
if (opt.dictionary) {
let dict;
// Convert data if needed
if (typeof opt.dictionary === 'string') {
// If we need to compress text, change encoding to utf8.
dict = string2buf(opt.dictionary);
} else if (opt.dictionary instanceof ArrayBuffer) {
dict = new Uint8Array(opt.dictionary);
} else {
dict = opt.dictionary;
}
status = deflateSetDictionary(this.strm, dict);
if (status !== Z_OK) {
throw new Error(msg[status]);
}
this._dict_set = true;
}
}
/**
* Deflate#push(data[, mode]) -> Boolean
* - data (Uint8Array|Array|ArrayBuffer|String): input data. Strings will be
* converted to utf8 byte sequence.
* - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.
* See constants. Skipped or `false` means Z_NO_FLUSH, `true` means Z_FINISH.
*
* Sends input data to deflate pipe, generating [[Deflate#onData]] calls with
* new compressed chunks. Returns `true` on success. The last data block must have
* mode Z_FINISH (or `true`). That will flush internal pending buffers and call
* [[Deflate#onEnd]]. For interim explicit flushes (without ending the stream) you
* can use mode Z_SYNC_FLUSH, keeping the compression context.
*
* On fail call [[Deflate#onEnd]] with error code and return false.
*
* We strongly recommend to use `Uint8Array` on input for best speed (output
* array format is detected automatically). Also, don't skip last param and always
* use the same type in your code (boolean or number). That will improve JS speed.
*
* For regular `Array`-s make sure all elements are [0..255].
*
* ##### Example
*
* ```javascript
* push(chunk, false); // push one of data chunks
* ...
* push(chunk, true); // push last chunk
* ```
**/
push(data, mode) {
const { strm, options: { chunkSize } } = this;
var status, _mode;
if (this.ended) { return false; }
_mode = (mode === ~~mode) ? mode : ((mode === true) ? Z_FINISH : Z_NO_FLUSH);
// Convert data if needed
if (typeof data === 'string') {
// If we need to compress text, change encoding to utf8.
strm.input = string2buf(data);
} else if (data instanceof ArrayBuffer) {
strm.input = new Uint8Array(data);
} else {
strm.input = data;
}
strm.next_in = 0;
strm.avail_in = strm.input.length;
do {
if (strm.avail_out === 0) {
strm.output = new Buf8(chunkSize);
strm.next_out = 0;
strm.avail_out = chunkSize;
}
status = deflate(strm, _mode); /* no bad return value */
if (status !== Z_STREAM_END && status !== Z_OK) {
this.onEnd(status);
this.ended = true;
return false;
}
if (strm.avail_out === 0 || (strm.avail_in === 0 && (_mode === Z_FINISH || _mode === Z_SYNC_FLUSH))) {
this.onData(shrinkBuf(strm.output, strm.next_out));
}
} while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== Z_STREAM_END);
// Finalize on the last chunk.
if (_mode === Z_FINISH) {
status = deflateEnd(this.strm);
this.onEnd(status);
this.ended = true;
return status === Z_OK;
}
// callback interim results if Z_SYNC_FLUSH.
if (_mode === Z_SYNC_FLUSH) {
this.onEnd(Z_OK);
strm.avail_out = 0;
return true;
}
return true;
};
/**
* Deflate#onData(chunk) -> Void
* - chunk (Uint8Array|Array|String): output data. Type of array depends
* on js engine support. When string output requested, each chunk
* will be string.
*
* By default, stores data blocks in `chunks[]` property and glue
* those in `onEnd`. Override this handler, if you need another behaviour.
**/
onData(chunk) {
this.chunks.push(chunk);
};
/**
* Deflate#onEnd(status) -> Void
* - status (Number): deflate status. 0 (Z_OK) on success,
* other if not.
*
* Called once after you tell deflate that the input stream is
* complete (Z_FINISH) or should be flushed (Z_SYNC_FLUSH)
* or if an error happened. By default - join collected chunks,
* free memory and fill `results` / `err` properties.
**/
onEnd(status) {
// On success - join
if (status === Z_OK) {
this.result = flattenChunks(this.chunks);
}
this.chunks = [];
this.err = status;
this.msg = this.strm.msg;
};
}
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
// See state defs from inflate.js
const BAD = 30; /* got a data error -- remain here until reset */
const TYPE = 12; /* i: waiting for type bits, including last-flag bit */
/*
Decode literal, length, and distance codes and write out the resulting
literal and match bytes until either not enough input or output is
available, an end-of-block is encountered, or a data error is encountered.
When large enough input and output buffers are supplied to inflate(), for
example, a 16K input buffer and a 64K output buffer, more than 95% of the
inflate execution time is spent in this routine.
Entry assumptions:
state.mode === LEN
strm.avail_in >= 6
strm.avail_out >= 258
start >= strm.avail_out
state.bits < 8
On return, state.mode is one of:
LEN -- ran out of enough output space or enough available input
TYPE -- reached end of block code, inflate() to interpret next block
BAD -- error in block data
Notes:
- The maximum input bits used by a length/distance pair is 15 bits for the
length code, 5 bits for the length extra, 15 bits for the distance code,
and 13 bits for the distance extra. This totals 48 bits, or six bytes.
Therefore if strm.avail_in >= 6, then there is enough input to avoid
checking for available input while decoding.
- The maximum bytes that a single length/distance pair can output is 258
bytes, which is the maximum length that can be coded. inflate_fast()
requires strm.avail_out >= 258 for each loop to avoid checking for
output space.
*/
function inflate_fast(strm, start) {
let _in; /* local strm.input */
let _out; /* local strm.output */
// Use `s_window` instead `window`, avoid conflict with instrumentation tools
let hold; /* local strm.hold */
let bits; /* local strm.bits */
let here; /* retrieved table entry */
let op; /* code bits, operation, extra bits, or */
/* window position, window bytes to copy */
let len; /* match length, unused bytes */
let dist; /* match distance */
let from; /* where to copy match from */
let from_source;
/* copy state to local variables */
const state = strm.state;
//here = state.here;
_in = strm.next_in;
const input = strm.input;
const last = _in + (strm.avail_in - 5);
_out = strm.next_out;
const output = strm.output;
const beg = _out - (start - strm.avail_out);
const end = _out + (strm.avail_out - 257);
//#ifdef INFLATE_STRICT
const dmax = state.dmax;
//#endif
const wsize = state.wsize;
const whave = state.whave;
const wnext = state.wnext;
const s_window = state.window;
hold = state.hold;
bits = state.bits;
const lcode = state.lencode;
const dcode = state.distcode;
const lmask = (1 << state.lenbits) - 1;
const dmask = (1 << state.distbits) - 1;
/* decode literals and length/distances until end-of-block or not enough
input data or output space */
top:
do {
if (bits < 15) {
hold += input[_in++] << bits;
bits += 8;
hold += input[_in++] << bits;
bits += 8;
}
here = lcode[hold & lmask];
dolen:
for (;;) { // Goto emulation
op = here >>> 24/*here.bits*/;
hold >>>= op;
bits -= op;
op = here >>> 16 & 0xff/*here.op*/;
if (op === 0) { /* literal */
//Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
// "inflate: literal '%c'\n" :
// "inflate: literal 0x%02x\n", here.val));
output[_out++] = here & 0xffff/*here.val*/;
} else if (op & 16) { /* length base */
len = here & 0xffff/*here.val*/;
op &= 15; /* number of extra bits */
if (op) {
if (bits < op) {
hold += input[_in++] << bits;
bits += 8;
}
len += hold & (1 << op) - 1;
hold >>>= op;
bits -= op;
}
//Tracevv((stderr, "inflate: length %u\n", len));
if (bits < 15) {
hold += input[_in++] << bits;
bits += 8;
hold += input[_in++] << bits;
bits += 8;
}
here = dcode[hold & dmask];
dodist:
for (;;) { // goto emulation
op = here >>> 24/*here.bits*/;
hold >>>= op;
bits -= op;
op = here >>> 16 & 0xff/*here.op*/;
if (op & 16) { /* distance base */
dist = here & 0xffff/*here.val*/;
op &= 15; /* number of extra bits */
if (bits < op) {
hold += input[_in++] << bits;
bits += 8;
if (bits < op) {
hold += input[_in++] << bits;
bits += 8;
}
}
dist += hold & (1 << op) - 1;
//#ifdef INFLATE_STRICT
if (dist > dmax) {
strm.msg = "invalid distance too far back";
state.mode = BAD;
break top;
}
//#endif
hold >>>= op;
bits -= op;
//Tracevv((stderr, "inflate: distance %u\n", dist));
op = _out - beg; /* max distance in output */
if (dist > op) { /* see if copy from window */
op = dist - op; /* distance back in window */
if (op > whave) {
if (state.sane) {
strm.msg = "invalid distance too far back";
state.mode = BAD;
break top;
}
// (!) This block is disabled in zlib defaults,
// don't enable it for binary compatibility
//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
// if (len <= op - whave) {
// do {
// output[_out++] = 0;
// } while (--len);
// continue top;
// }
// len -= op - whave;
// do {
// output[_out++] = 0;
// } while (--op > whave);
// if (op === 0) {
// from = _out - dist;
// do {
// output[_out++] = output[from++];
// } while (--len);
// continue top;
// }
//#endif
}
from = 0; // window index
from_source = s_window;
if (wnext === 0) { /* very common case */
from += wsize - op;
if (op < len) { /* some from window */
len -= op;
do {
output[_out++] = s_window[from++];
} while (--op);
from = _out - dist; /* rest from output */
from_source = output;
}
} else if (wnext < op) { /* wrap around window */
from += wsize + wnext - op;
op -= wnext;
if (op < len) { /* some from end of window */
len -= op;
do {
output[_out++] = s_window[from++];
} while (--op);
from = 0;
if (wnext < len) { /* some from start of window */
op = wnext;
len -= op;
do {
output[_out++] = s_window[from++];
} while (--op);
from = _out - dist; /* rest from output */
from_source = output;
}
}
} else { /* contiguous in window */
from += wnext - op;
if (op < len) { /* some from window */
len -= op;
do {
output[_out++] = s_window[from++];
} while (--op);
from = _out - dist; /* rest from output */
from_source = output;
}
}
while (len > 2) {
output[_out++] = from_source[from++];
output[_out++] = from_source[from++];
output[_out++] = from_source[from++];
len -= 3;
}
if (len) {
output[_out++] = from_source[from++];
if (len > 1) {
output[_out++] = from_source[from++];
}
}
} else {
from = _out - dist; /* copy direct from output */
do { /* minimum length is three */
output[_out++] = output[from++];
output[_out++] = output[from++];
output[_out++] = output[from++];
len -= 3;
} while (len > 2);
if (len) {
output[_out++] = output[from++];
if (len > 1) {
output[_out++] = output[from++];
}
}
}
} else if ((op & 64) === 0) { /* 2nd level distance code */
here = dcode[(here & 0xffff)/*here.val*/ + (hold & (1 << op) - 1)];
continue dodist;
} else {
strm.msg = "invalid distance code";
state.mode = BAD;
break top;
}
break; // need to emulate goto via "continue"
}
} else if ((op & 64) === 0) { /* 2nd level length code */
here = lcode[(here & 0xffff)/*here.val*/ + (hold & (1 << op) - 1)];
continue dolen;
} else if (op & 32) { /* end-of-block */
//Tracevv((stderr, "inflate: end of block\n"));
state.mode = TYPE;
break top;
} else {
strm.msg = "invalid literal/length code";
state.mode = BAD;
break top;
}
break; // need to emulate goto via "continue"
}
} while (_in < last && _out < end);
/* return unused bytes (on entry, bits < 8, so in won't go too far back) */
len = bits >> 3;
_in -= len;
bits -= len << 3;
hold &= (1 << bits) - 1;
/* update state and return */
strm.next_in = _in;
strm.next_out = _out;
strm.avail_in = _in < last ? 5 + (last - _in) : 5 - (_in - last);
strm.avail_out = _out < end ? 257 + (end - _out) : 257 - (_out - end);
state.hold = hold;
state.bits = bits;
return;
}
const MAXBITS = 15;
const ENOUGH_LENS = 852;
const ENOUGH_DISTS = 592;
//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS);
const CODES = 0;
const LENS = 1;
const DISTS = 2;
const lbase = [ /* Length codes 257..285 base */
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
];
const lext = [ /* Length codes 257..285 extra */
16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78
];
const dbase = [ /* Distance codes 0..29 base */
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
8193, 12289, 16385, 24577, 0, 0
];
const dext = [ /* Distance codes 0..29 extra */
16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
28, 28, 29, 29, 64, 64
];
function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts) {
const bits = opts.bits;
//here = opts.here; /* table entry for duplication */
let len = 0; /* a code's length in bits */
let sym = 0; /* index of code symbols */
let min = 0, max = 0; /* minimum and maximum code lengths */
let root = 0; /* number of index bits for root table */
let curr = 0; /* number of index bits for current table */
let drop = 0; /* code bits to drop for sub-table */
let left = 0; /* number of prefix codes available */
let used = 0; /* code entries in table used */
let huff = 0; /* Huffman code */
let incr; /* for incrementing code, index */
let fill; /* index for replicating entries */
let low; /* low bits for current root entry */
let next; /* next available space in table */
let base = null; /* base value table to use */
let base_index = 0;
// var shoextra; /* extra bits table to use */
let end; /* use base and extra for symbol > end */
const count = new Buf16(MAXBITS + 1); //[MAXBITS+1]; /* number of codes of each length */
const offs = new Buf16(MAXBITS + 1); //[MAXBITS+1]; /* offsets in table for each length */
let extra = null;
let extra_index = 0;
let here_bits, here_op, here_val;
/*
Process a set of code lengths to create a canonical Huffman code. The
code lengths are lens[0..codes-1]. Each length corresponds to the
symbols 0..codes-1. The Huffman code is generated by first sorting the
symbols by length from short to long, and retaining the symbol order
for codes with equal lengths. Then the code starts with all zero bits
for the first code of the shortest length, and the codes are integer
increments for the same length, and zeros are appended as the length
increases. For the deflate format, these bits are stored backwards
from their more natural integer increment ordering, and so when the
decoding tables are built in the large loop below, the integer codes
are incremented backwards.
This routine assumes, but does not check, that all of the entries in
lens[] are in the range 0..MAXBITS. The caller must assure this.
1..MAXBITS is interpreted as that code length. zero means that that
symbol does not occur in this code.
The codes are sorted by computing a count of codes for each length,
creating from that a table of starting indices for each length in the
sorted table, and then entering the symbols in order in the sorted
table. The sorted table is work[], with that space being provided by
the caller.
The length counts are used for other purposes as well, i.e. finding
the minimum and maximum length codes, determining if there are any
codes at all, checking for a valid set of lengths, and looking ahead
at length counts to determine sub-table sizes when building the
decoding tables.
*/
/* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
for (len = 0; len <= MAXBITS; len++) {
count[len] = 0;
}
for (sym = 0; sym < codes; sym++) {
count[lens[lens_index + sym]]++;
}
/* bound code lengths, force root to be within code lengths */
root = bits;
for (max = MAXBITS; max >= 1; max--) {
if (count[max] !== 0) {
break;
}
}
if (root > max) {
root = max;
}
if (max === 0) { /* no symbols to code at all */
//table.op[opts.table_index] = 64; //here.op = (var char)64; /* invalid code marker */
//table.bits[opts.table_index] = 1; //here.bits = (var char)1;
//table.val[opts.table_index++] = 0; //here.val = (var short)0;
table[table_index++] = 1 << 24 | 64 << 16 | 0;
//table.op[opts.table_index] = 64;
//table.bits[opts.table_index] = 1;
//table.val[opts.table_index++] = 0;
table[table_index++] = 1 << 24 | 64 << 16 | 0;
opts.bits = 1;
return 0; /* no symbols, but wait for decoding to report error */
}
for (min = 1; min < max; min++) {
if (count[min] !== 0) {
break;
}
}
if (root < min) {
root = min;
}
/* check for an over-subscribed or incomplete set of lengths */
left = 1;
for (len = 1; len <= MAXBITS; len++) {
left <<= 1;
left -= count[len];
if (left < 0) {
return -1;
} /* over-subscribed */
}
if (left > 0 && (type === CODES || max !== 1)) {
return -1; /* incomplete set */
}
/* generate offsets into symbol table for each length for sorting */
offs[1] = 0;
for (len = 1; len < MAXBITS; len++) {
offs[len + 1] = offs[len] + count[len];
}
/* sort symbols by length, by symbol order within each length */
for (sym = 0; sym < codes; sym++) {
if (lens[lens_index + sym] !== 0) {
work[offs[lens[lens_index + sym]]++] = sym;
}
}
/*
Create and fill in decoding tables. In this loop, the table being
filled is at next and has curr index bits. The code being used is huff
with length len. That code is converted to an index by dropping drop
bits off of the bottom. For codes where len is less than drop + curr,
those top drop + curr - len bits are incremented through all values to
fill the table with replicated entries.
root is the number of index bits for the root table. When len exceeds
root, sub-tables are created pointed to by the root entry with an index
of the low root bits of huff. This is saved in low to check for when a
new sub-table should be started. drop is zero when the root table is
being filled, and drop is root when sub-tables are being filled.
When a new sub-table is needed, it is necessary to look ahead in the
code lengths to determine what size sub-table is needed. The length
counts are used for this, and so count[] is decremented as codes are
entered in the tables.
used keeps track of how many table entries have been allocated from the
provided *table space. It is checked for LENS and DIST tables against
the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
the initial root table size constants. See the comments in inftrees.h
for more information.
sym increments through all symbols, and the loop terminates when
all codes of length max, i.e. all codes, have been processed. This
routine permits incomplete codes, so another loop after this one fills
in the rest of the decoding tables with invalid code markers.
*/
/* set up for code type */
// poor man optimization - use if-else instead of switch,
// to avoid deopts in old v8
if (type === CODES) {
base = extra = work; /* dummy value--not used */
end = 19;
} else if (type === LENS) {
base = lbase;
base_index -= 257;
extra = lext;
extra_index -= 257;
end = 256;
} else { /* DISTS */
base = dbase;
extra = dext;
end = -1;
}
/* initialize opts for loop */
huff = 0; /* starting code */
sym = 0; /* starting code symbol */
len = min; /* starting code length */
next = table_index; /* current table to fill in */
curr = root; /* current table index bits */
drop = 0; /* current bits to drop from code for index */
low = -1; /* trigger new sub-table when len > root */
used = 1 << root; /* use root table entries */
const mask = used - 1; /* mask for comparing low */
/* check available table space */
if (type === LENS && used > ENOUGH_LENS ||
type === DISTS && used > ENOUGH_DISTS) {
return 1;
}
/* process all codes and make table entries */
for (;;) {
/* create table entry */
here_bits = len - drop;
if (work[sym] < end) {
here_op = 0;
here_val = work[sym];
} else if (work[sym] > end) {
here_op = extra[extra_index + work[sym]];
here_val = base[base_index + work[sym]];
} else {
here_op = 32 + 64; /* end of block */
here_val = 0;
}
/* replicate for those indices with low len bits equal to huff */
incr = 1 << len - drop;
fill = 1 << curr;
min = fill; /* save offset to next table */
do {
fill -= incr;
table[next + (huff >> drop) + fill] = here_bits << 24 | here_op << 16 | here_val |0;
} while (fill !== 0);
/* backwards increment the len-bit code huff */
incr = 1 << len - 1;
while (huff & incr) {
incr >>= 1;
}
if (incr !== 0) {
huff &= incr - 1;
huff += incr;
} else {
huff = 0;
}
/* go to next symbol, update count, len */
sym++;
if (--count[len] === 0) {
if (len === max) {
break;
}
len = lens[lens_index + work[sym]];
}
/* create new sub-table if needed */
if (len > root && (huff & mask) !== low) {
/* if first time, transition to sub-tables */
if (drop === 0) {
drop = root;
}
/* increment past last table */
next += min; /* here min is 1 << curr */
/* determine length of next table */
curr = len - drop;
left = 1 << curr;
while (curr + drop < max) {
left -= count[curr + drop];
if (left <= 0) {
break;
}
curr++;
left <<= 1;
}
/* check for enough space */
used += 1 << curr;
if (type === LENS && used > ENOUGH_LENS ||
type === DISTS && used > ENOUGH_DISTS) {
return 1;
}
/* point entry in root table to sub-table */
low = huff & mask;
/*table.op[low] = curr;
table.bits[low] = root;
table.val[low] = next - opts.table_index;*/
table[low] = root << 24 | curr << 16 | next - table_index |0;
}
}
/* fill in remaining table entry if code is incomplete (guaranteed to have
at most one remaining entry, since if the code is incomplete, the
maximum code length that was allowed to get this far is one bit) */
if (huff !== 0) {
//table.op[next + huff] = 64; /* invalid code marker */
//table.bits[next + huff] = len - drop;
//table.val[next + huff] = 0;
table[next + huff] = len - drop << 24 | 64 << 16 |0;
}
/* set return parameters */
//opts.table_index += used;
opts.bits = root;
return 0;
}
const CODES$1 = 0;
const LENS$1 = 1;
const DISTS$1 = 2;
/* STATES ====================================================================*/
/* ===========================================================================*/
const HEAD = 1; /* i: waiting for magic header */
const FLAGS = 2; /* i: waiting for method and flags (gzip) */
const TIME = 3; /* i: waiting for modification time (gzip) */
const OS = 4; /* i: waiting for extra flags and operating system (gzip) */
const EXLEN = 5; /* i: waiting for extra length (gzip) */
const EXTRA = 6; /* i: waiting for extra bytes (gzip) */
const NAME = 7; /* i: waiting for end of file name (gzip) */
const COMMENT = 8; /* i: waiting for end of comment (gzip) */
const HCRC = 9; /* i: waiting for header crc (gzip) */
const DICTID = 10; /* i: waiting for dictionary check value */
const DICT = 11; /* waiting for inflateSetDictionary() call */
const TYPE$1 = 12; /* i: waiting for type bits, including last-flag bit */
const TYPEDO = 13; /* i: same, but skip check to exit inflate on new block */
const STORED = 14; /* i: waiting for stored size (length and complement) */
const COPY_ = 15; /* i/o: same as COPY below, but only first time in */
const COPY = 16; /* i/o: waiting for input or output to copy stored block */
const TABLE = 17; /* i: waiting for dynamic block table lengths */
const LENLENS = 18; /* i: waiting for code length code lengths */
const CODELENS = 19; /* i: waiting for length/lit and distance code lengths */
const LEN_ = 20; /* i: same as LEN below, but only first time in */
const LEN = 21; /* i: waiting for length/lit/eob code */
const LENEXT = 22; /* i: waiting for length extra bits */
const DIST = 23; /* i: waiting for distance code */
const DISTEXT = 24; /* i: waiting for distance extra bits */
const MATCH = 25; /* o: waiting for output space to copy string */
const LIT = 26; /* o: waiting for output space to write literal */
const CHECK = 27; /* i: waiting for 32-bit check value */
const LENGTH = 28; /* i: waiting for 32-bit length (gzip) */
const DONE = 29; /* finished check, done -- remain here until reset */
const BAD$1 = 30; /* got a data error -- remain here until reset */
//const MEM = 31; /* got an inflate() memory error -- remain here until reset */
const SYNC = 32; /* looking for synchronization bytes to restart inflate() */
/* ===========================================================================*/
const ENOUGH_LENS$1 = 852;
const ENOUGH_DISTS$1 = 592;
function zswap32(q) {
return (((q >>> 24) & 0xff) +
((q >>> 8) & 0xff00) +
((q & 0xff00) << 8) +
((q & 0xff) << 24));
}
class InflateState {
constructor() {
this.mode = 0; /* current inflate mode */
this.last = false; /* true if processing last block */
this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */
this.havedict = false; /* true if dictionary provided */
this.flags = 0; /* gzip header method and flags (0 if zlib) */
this.dmax = 0; /* zlib header max distance (INFLATE_STRICT) */
this.check = 0; /* protected copy of check value */
this.total = 0; /* protected copy of output count */
// TODO: may be {}
this.head = null; /* where to save gzip header information */
/* sliding window */
this.wbits = 0; /* log base 2 of requested window size */
this.wsize = 0; /* window size or zero if not using window */
this.whave = 0; /* valid bytes in the window */
this.wnext = 0; /* window write index */
this.window = null; /* allocated sliding window, if needed */
/* bit accumulator */
this.hold = 0; /* input bit accumulator */
this.bits = 0; /* number of bits in "in" */
/* for string and stored block copying */
this.length = 0; /* literal or length of data to copy */
this.offset = 0; /* distance back to copy string from */
/* for table and code decoding */
this.extra = 0; /* extra bits needed */
/* fixed and dynamic code tables */
this.lencode = null; /* starting table for length/literal codes */
this.distcode = null; /* starting table for distance codes */
this.lenbits = 0; /* index bits for lencode */
this.distbits = 0; /* index bits for distcode */
/* dynamic table building */
this.ncode = 0; /* number of code length code lengths */
this.nlen = 0; /* number of length code lengths */
this.ndist = 0; /* number of distance code lengths */
this.have = 0; /* number of code lengths in lens[] */
this.next = null; /* next available space in codes[] */
this.lens = new Buf16(320); /* temporary storage for code lengths */
this.work = new Buf16(288); /* work area for code table building */
/*
because we don't have pointers in js, we use lencode and distcode directly
as buffers so we don't need codes
*/
//this.codes = new utils.Buf32(ENOUGH); /* space for code tables */
this.lendyn = null; /* dynamic table for length/literal codes (JS specific) */
this.distdyn = null; /* dynamic table for distance codes (JS specific) */
this.sane = 0; /* if false, allow invalid distance too far */
this.back = 0; /* bits back of last unprocessed length/lit */
this.was = 0; /* initial length of match */
}
}
function inflateResetKeep(strm) {
let state;
if (!strm || !strm.state) { return Z_STREAM_ERROR; }
state = strm.state;
strm.total_in = strm.total_out = state.total = 0;
strm.msg = ''; /*Z_NULL*/
if (state.wrap) { /* to support ill-conceived Java test suite */
strm.adler = state.wrap & 1;
}
state.mode = HEAD;
state.last = 0;
state.havedict = 0;
state.dmax = 32768;
state.head = null/*Z_NULL*/;
state.hold = 0;
state.bits = 0;
//state.lencode = state.distcode = state.next = state.codes;
state.lencode = state.lendyn = new Buf32(ENOUGH_LENS$1);
state.distcode = state.distdyn = new Buf32(ENOUGH_DISTS$1);
state.sane = 1;
state.back = -1;
//Tracev((stderr, "inflate: reset\n"));
return Z_OK;
}
function inflateReset(strm) {
let state;
if (!strm || !strm.state) { return Z_STREAM_ERROR; }
state = strm.state;
state.wsize = 0;
state.whave = 0;
state.wnext = 0;
return inflateResetKeep(strm);
}
function inflateReset2(strm, windowBits) {
let wrap;
let state;
/* get the state */
if (!strm || !strm.state) { return Z_STREAM_ERROR; }
state = strm.state;
/* extract wrap request from windowBits parameter */
if (windowBits < 0) {
wrap = 0;
windowBits = -windowBits;
}
else {
wrap = (windowBits >> 4) + 1;
if (windowBits < 48) {
windowBits &= 15;
}
}
/* set number of window bits, free window if different */
if (windowBits && (windowBits < 8 || windowBits > 15)) {
return Z_STREAM_ERROR;
}
if (state.window !== null && state.wbits !== windowBits) {
state.window = null;
}
/* update state and reset the rest of it */
state.wrap = wrap;
state.wbits = windowBits;
return inflateReset(strm);
}
function inflateInit2(strm, windowBits) {
let ret;
let state;
if (!strm) { return Z_STREAM_ERROR; }
//strm.msg = Z_NULL; /* in case we return an error */
state = new InflateState();
//if (state === Z_NULL) return Z_MEM_ERROR;
//Tracev((stderr, "inflate: allocated\n"));
strm.state = state;
state.window = null/*Z_NULL*/;
ret = inflateReset2(strm, windowBits);
if (ret !== Z_OK) {
strm.state = null/*Z_NULL*/;
}
return ret;
}
/*
Return state with length and distance decoding tables and index sizes set to
fixed code decoding. Normally this returns fixed tables from inffixed.h.
If BUILDFIXED is defined, then instead this routine builds the tables the
first time it's called, and returns those tables the first time and
thereafter. This reduces the size of the code by about 2K bytes, in
exchange for a little execution time. However, BUILDFIXED should not be
used for threaded applications, since the rewriting of the tables and virgin
may not be thread-safe.
*/
let virgin = true;
let lenfix, distfix; // We have no pointers in JS, so keep tables separate
function fixedtables(state) {
/* build fixed huffman tables if first call (may not be thread safe) */
if (virgin) {
let sym;
lenfix = new Buf32(512);
distfix = new Buf32(32);
/* literal/length table */
sym = 0;
while (sym < 144) { state.lens[sym++] = 8; }
while (sym < 256) { state.lens[sym++] = 9; }
while (sym < 280) { state.lens[sym++] = 7; }
while (sym < 288) { state.lens[sym++] = 8; }
inflate_table(LENS$1, state.lens, 0, 288, lenfix, 0, state.work, { bits: 9 });
/* distance table */
sym = 0;
while (sym < 32) { state.lens[sym++] = 5; }
inflate_table(DISTS$1, state.lens, 0, 32, distfix, 0, state.work, { bits: 5 });
/* do this just once */
virgin = false;
}
state.lencode = lenfix;
state.lenbits = 9;
state.distcode = distfix;
state.distbits = 5;
}
/*
Update the window with the last wsize (normally 32K) bytes written before
returning. If window does not exist yet, create it. This is only called
when a window is already in use, or when output has been written during this
inflate call, but the end of the deflate stream has not been reached yet.
It is also called to create a window for dictionary data when a dictionary
is loaded.
Providing output buffers larger than 32K to inflate() should provide a speed
advantage, since only the last 32K of output is copied to the sliding window
upon return from inflate(), and since all distances after the first 32K of
output will fall in the output data, making match copies simpler and faster.
The advantage may be dependent on the size of the processor's data caches.
*/
function updatewindow(strm, src, end, copy) {
let dist;
const state = strm.state;
/* if it hasn't been done already, allocate space for the window */
if (state.window === null) {
state.wsize = 1 << state.wbits;
state.wnext = 0;
state.whave = 0;
state.window = new Buf8(state.wsize);
}
/* copy state->wsize or less output bytes into the circular window */
if (copy >= state.wsize) {
arraySet(state.window, src, end - state.wsize, state.wsize, 0);
state.wnext = 0;
state.whave = state.wsize;
}
else {
dist = state.wsize - state.wnext;
if (dist > copy) {
dist = copy;
}
//zmemcpy(state->window + state->wnext, end - copy, dist);
arraySet(state.window, src, end - copy, dist, state.wnext);
copy -= dist;
if (copy) {
//zmemcpy(state->window, end - copy, copy);
arraySet(state.window, src, end - copy, copy, 0);
state.wnext = copy;
state.whave = state.wsize;
}
else {
state.wnext += dist;
if (state.wnext === state.wsize) { state.wnext = 0; }
if (state.whave < state.wsize) { state.whave += dist; }
}
}
return 0;
}
function inflate(strm, flush) {
let state;
let input, output; // input/output buffers
let next; /* next input INDEX */
let put; /* next output INDEX */
let have, left; /* available input and output */
let hold; /* bit buffer */
let bits; /* bits in bit buffer */
let _in, _out; /* save starting available input and output */
let copy; /* number of stored or match bytes to copy */
let from; /* where to copy match bytes from */
let from_source;
let here = 0; /* current decoding table entry */
let here_bits, here_op, here_val; // paked "here" denormalized (JS specific)
//var last; /* parent table entry */
let last_bits, last_op, last_val; // paked "last" denormalized (JS specific)
let len; /* length to copy for repeats, bits to drop */
let ret; /* return code */
let hbuf = new Buf8(4); /* buffer for gzip header crc calculation */
let opts;
let n; // temporary var for NEED_BITS
const order = /* permutation of code lengths */
[ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];
if (!strm || !strm.state || !strm.output ||
(!strm.input && strm.avail_in !== 0)) {
return Z_STREAM_ERROR;
}
state = strm.state;
if (state.mode === TYPE$1) { state.mode = TYPEDO; } /* skip check */
//--- LOAD() ---
put = strm.next_out;
output = strm.output;
left = strm.avail_out;
next = strm.next_in;
input = strm.input;
have = strm.avail_in;
hold = state.hold;
bits = state.bits;
//---
_in = have;
_out = left;
ret = Z_OK;
inf_leave: // goto emulation
for (;;) {
switch (state.mode) {
case HEAD:
if (state.wrap === 0) {
state.mode = TYPEDO;
break;
}
//=== NEEDBITS(16);
while (bits < 16) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
if ((state.wrap & 2) && hold === 0x8b1f) { /* gzip header */
state.check = 0/*crc32(0L, Z_NULL, 0)*/;
//=== CRC2(state.check, hold);
hbuf[0] = hold & 0xff;
hbuf[1] = (hold >>> 8) & 0xff;
state.check = crc32(state.check, hbuf, 2, 0);
//===//
//=== INITBITS();
hold = 0;
bits = 0;
//===//
state.mode = FLAGS;
break;
}
state.flags = 0; /* expect zlib header */
if (state.head) {
state.head.done = false;
}
if (!(state.wrap & 1) || /* check if zlib header allowed */
(((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) {
strm.msg = 'incorrect header check';
state.mode = BAD$1;
break;
}
if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED) {
strm.msg = 'unknown compression method';
state.mode = BAD$1;
break;
}
//--- DROPBITS(4) ---//
hold >>>= 4;
bits -= 4;
//---//
len = (hold & 0x0f)/*BITS(4)*/ + 8;
if (state.wbits === 0) {
state.wbits = len;
}
else if (len > state.wbits) {
strm.msg = 'invalid window size';
state.mode = BAD$1;
break;
}
state.dmax = 1 << len;
//Tracev((stderr, "inflate: zlib header ok\n"));
strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;
state.mode = hold & 0x200 ? DICTID : TYPE$1;
//=== INITBITS();
hold = 0;
bits = 0;
//===//
break;
case FLAGS:
//=== NEEDBITS(16); */
while (bits < 16) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
state.flags = hold;
if ((state.flags & 0xff) !== Z_DEFLATED) {
strm.msg = 'unknown compression method';
state.mode = BAD$1;
break;
}
if (state.flags & 0xe000) {
strm.msg = 'unknown header flags set';
state.mode = BAD$1;
break;
}
if (state.head) {
state.head.text = ((hold >> 8) & 1);
}
if (state.flags & 0x0200) {
//=== CRC2(state.check, hold);
hbuf[0] = hold & 0xff;
hbuf[1] = (hold >>> 8) & 0xff;
state.check = crc32(state.check, hbuf, 2, 0);
//===//
}
//=== INITBITS();
hold = 0;
bits = 0;
//===//
state.mode = TIME;
/* falls through */
case TIME:
//=== NEEDBITS(32); */
while (bits < 32) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
if (state.head) {
state.head.time = hold;
}
if (state.flags & 0x0200) {
//=== CRC4(state.check, hold)
hbuf[0] = hold & 0xff;
hbuf[1] = (hold >>> 8) & 0xff;
hbuf[2] = (hold >>> 16) & 0xff;
hbuf[3] = (hold >>> 24) & 0xff;
state.check = crc32(state.check, hbuf, 4, 0);
//===
}
//=== INITBITS();
hold = 0;
bits = 0;
//===//
state.mode = OS;
/* falls through */
case OS:
//=== NEEDBITS(16); */
while (bits < 16) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
if (state.head) {
state.head.xflags = (hold & 0xff);
state.head.os = (hold >> 8);
}
if (state.flags & 0x0200) {
//=== CRC2(state.check, hold);
hbuf[0] = hold & 0xff;
hbuf[1] = (hold >>> 8) & 0xff;
state.check = crc32(state.check, hbuf, 2, 0);
//===//
}
//=== INITBITS();
hold = 0;
bits = 0;
//===//
state.mode = EXLEN;
/* falls through */
case EXLEN:
if (state.flags & 0x0400) {
//=== NEEDBITS(16); */
while (bits < 16) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
state.length = hold;
if (state.head) {
state.head.extra_len = hold;
}
if (state.flags & 0x0200) {
//=== CRC2(state.check, hold);
hbuf[0] = hold & 0xff;
hbuf[1] = (hold >>> 8) & 0xff;
state.check = crc32(state.check, hbuf, 2, 0);
//===//
}
//=== INITBITS();
hold = 0;
bits = 0;
//===//
}
else if (state.head) {
state.head.extra = null/*Z_NULL*/;
}
state.mode = EXTRA;
/* falls through */
case EXTRA:
if (state.flags & 0x0400) {
copy = state.length;
if (copy > have) { copy = have; }
if (copy) {
if (state.head) {
len = state.head.extra_len - state.length;
if (!state.head.extra) {
// Use untyped array for more convenient processing later
state.head.extra = new Array(state.head.extra_len);
}
arraySet(
state.head.extra,
input,
next,
// extra field is limited to 65536 bytes
// - no need for additional size check
copy,
/*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/
len
);
//zmemcpy(state.head.extra + len, next,
// len + copy > state.head.extra_max ?
// state.head.extra_max - len : copy);
}
if (state.flags & 0x0200) {
state.check = crc32(state.check, input, copy, next);
}
have -= copy;
next += copy;
state.length -= copy;
}
if (state.length) { break inf_leave; }
}
state.length = 0;
state.mode = NAME;
/* falls through */
case NAME:
if (state.flags & 0x0800) {
if (have === 0) { break inf_leave; }
copy = 0;
do {
// TODO: 2 or 1 bytes?
len = input[next + copy++];
/* use constant limit because in js we should not preallocate memory */
if (state.head && len &&
(state.length < 65536 /*state.head.name_max*/)) {
state.head.name += String.fromCharCode(len);
}
} while (len && copy < have);
if (state.flags & 0x0200) {
state.check = crc32(state.check, input, copy, next);
}
have -= copy;
next += copy;
if (len) { break inf_leave; }
}
else if (state.head) {
state.head.name = null;
}
state.length = 0;
state.mode = COMMENT;
/* falls through */
case COMMENT:
if (state.flags & 0x1000) {
if (have === 0) { break inf_leave; }
copy = 0;
do {
len = input[next + copy++];
/* use constant limit because in js we should not preallocate memory */
if (state.head && len &&
(state.length < 65536 /*state.head.comm_max*/)) {
state.head.comment += String.fromCharCode(len);
}
} while (len && copy < have);
if (state.flags & 0x0200) {
state.check = crc32(state.check, input, copy, next);
}
have -= copy;
next += copy;
if (len) { break inf_leave; }
}
else if (state.head) {
state.head.comment = null;
}
state.mode = HCRC;
/* falls through */
case HCRC:
if (state.flags & 0x0200) {
//=== NEEDBITS(16); */
while (bits < 16) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
if (hold !== (state.check & 0xffff)) {
strm.msg = 'header crc mismatch';
state.mode = BAD$1;
break;
}
//=== INITBITS();
hold = 0;
bits = 0;
//===//
}
if (state.head) {
state.head.hcrc = ((state.flags >> 9) & 1);
state.head.done = true;
}
strm.adler = state.check = 0;
state.mode = TYPE$1;
break;
case DICTID:
//=== NEEDBITS(32); */
while (bits < 32) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
strm.adler = state.check = zswap32(hold);
//=== INITBITS();
hold = 0;
bits = 0;
//===//
state.mode = DICT;
/* falls through */
case DICT:
if (state.havedict === 0) {
//--- RESTORE() ---
strm.next_out = put;
strm.avail_out = left;
strm.next_in = next;
strm.avail_in = have;
state.hold = hold;
state.bits = bits;
//---
return Z_NEED_DICT;
}
strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;
state.mode = TYPE$1;
/* falls through */
case TYPE$1:
if (flush === Z_BLOCK || flush === Z_TREES) { break inf_leave; }
/* falls through */
case TYPEDO:
if (state.last) {
//--- BYTEBITS() ---//
hold >>>= bits & 7;
bits -= bits & 7;
//---//
state.mode = CHECK;
break;
}
//=== NEEDBITS(3); */
while (bits < 3) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
state.last = (hold & 0x01)/*BITS(1)*/;
//--- DROPBITS(1) ---//
hold >>>= 1;
bits -= 1;
//---//
switch ((hold & 0x03)/*BITS(2)*/) {
case 0: /* stored block */
//Tracev((stderr, "inflate: stored block%s\n",
// state.last ? " (last)" : ""));
state.mode = STORED;
break;
case 1: /* fixed block */
fixedtables(state);
//Tracev((stderr, "inflate: fixed codes block%s\n",
// state.last ? " (last)" : ""));
state.mode = LEN_; /* decode codes */
if (flush === Z_TREES) {
//--- DROPBITS(2) ---//
hold >>>= 2;
bits -= 2;
//---//
break inf_leave;
}
break;
case 2: /* dynamic block */
//Tracev((stderr, "inflate: dynamic codes block%s\n",
// state.last ? " (last)" : ""));
state.mode = TABLE;
break;
case 3:
strm.msg = 'invalid block type';
state.mode = BAD$1;
}
//--- DROPBITS(2) ---//
hold >>>= 2;
bits -= 2;
//---//
break;
case STORED:
//--- BYTEBITS() ---// /* go to byte boundary */
hold >>>= bits & 7;
bits -= bits & 7;
//---//
//=== NEEDBITS(32); */
while (bits < 32) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) {
strm.msg = 'invalid stored block lengths';
state.mode = BAD$1;
break;
}
state.length = hold & 0xffff;
//Tracev((stderr, "inflate: stored length %u\n",
// state.length));
//=== INITBITS();
hold = 0;
bits = 0;
//===//
state.mode = COPY_;
if (flush === Z_TREES) { break inf_leave; }
/* falls through */
case COPY_:
state.mode = COPY;
/* falls through */
case COPY:
copy = state.length;
if (copy) {
if (copy > have) { copy = have; }
if (copy > left) { copy = left; }
if (copy === 0) { break inf_leave; }
//--- zmemcpy(put, next, copy); ---
arraySet(output, input, next, copy, put);
//---//
have -= copy;
next += copy;
left -= copy;
put += copy;
state.length -= copy;
break;
}
//Tracev((stderr, "inflate: stored end\n"));
state.mode = TYPE$1;
break;
case TABLE:
//=== NEEDBITS(14); */
while (bits < 14) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257;
//--- DROPBITS(5) ---//
hold >>>= 5;
bits -= 5;
//---//
state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1;
//--- DROPBITS(5) ---//
hold >>>= 5;
bits -= 5;
//---//
state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4;
//--- DROPBITS(4) ---//
hold >>>= 4;
bits -= 4;
//---//
//#ifndef PKZIP_BUG_WORKAROUND
if (state.nlen > 286 || state.ndist > 30) {
strm.msg = 'too many length or distance symbols';
state.mode = BAD$1;
break;
}
//#endif
//Tracev((stderr, "inflate: table sizes ok\n"));
state.have = 0;
state.mode = LENLENS;
/* falls through */
case LENLENS:
while (state.have < state.ncode) {
//=== NEEDBITS(3);
while (bits < 3) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
state.lens[order[state.have++]] = (hold & 0x07);//BITS(3);
//--- DROPBITS(3) ---//
hold >>>= 3;
bits -= 3;
//---//
}
while (state.have < 19) {
state.lens[order[state.have++]] = 0;
}
// We have separate tables & no pointers. 2 commented lines below not needed.
//state.next = state.codes;
//state.lencode = state.next;
// Switch to use dynamic table
state.lencode = state.lendyn;
state.lenbits = 7;
opts = { bits: state.lenbits };
ret = inflate_table(CODES$1, state.lens, 0, 19, state.lencode, 0, state.work, opts);
state.lenbits = opts.bits;
if (ret) {
strm.msg = 'invalid code lengths set';
state.mode = BAD$1;
break;
}
//Tracev((stderr, "inflate: code lengths ok\n"));
state.have = 0;
state.mode = CODELENS;
/* falls through */
case CODELENS:
while (state.have < state.nlen + state.ndist) {
for (;;) {
here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/
here_bits = here >>> 24;
here_op = (here >>> 16) & 0xff;
here_val = here & 0xffff;
if ((here_bits) <= bits) { break; }
//--- PULLBYTE() ---//
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
//---//
}
if (here_val < 16) {
//--- DROPBITS(here.bits) ---//
hold >>>= here_bits;
bits -= here_bits;
//---//
state.lens[state.have++] = here_val;
}
else {
if (here_val === 16) {
//=== NEEDBITS(here.bits + 2);
n = here_bits + 2;
while (bits < n) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
//--- DROPBITS(here.bits) ---//
hold >>>= here_bits;
bits -= here_bits;
//---//
if (state.have === 0) {
strm.msg = 'invalid bit length repeat';
state.mode = BAD$1;
break;
}
len = state.lens[state.have - 1];
copy = 3 + (hold & 0x03);//BITS(2);
//--- DROPBITS(2) ---//
hold >>>= 2;
bits -= 2;
//---//
}
else if (here_val === 17) {
//=== NEEDBITS(here.bits + 3);
n = here_bits + 3;
while (bits < n) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
//--- DROPBITS(here.bits) ---//
hold >>>= here_bits;
bits -= here_bits;
//---//
len = 0;
copy = 3 + (hold & 0x07);//BITS(3);
//--- DROPBITS(3) ---//
hold >>>= 3;
bits -= 3;
//---//
}
else {
//=== NEEDBITS(here.bits + 7);
n = here_bits + 7;
while (bits < n) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
//--- DROPBITS(here.bits) ---//
hold >>>= here_bits;
bits -= here_bits;
//---//
len = 0;
copy = 11 + (hold & 0x7f);//BITS(7);
//--- DROPBITS(7) ---//
hold >>>= 7;
bits -= 7;
//---//
}
if (state.have + copy > state.nlen + state.ndist) {
strm.msg = 'invalid bit length repeat';
state.mode = BAD$1;
break;
}
while (copy--) {
state.lens[state.have++] = len;
}
}
}
/* handle error breaks in while */
if (state.mode === BAD$1) { break; }
/* check for end-of-block code (better have one) */
if (state.lens[256] === 0) {
strm.msg = 'invalid code -- missing end-of-block';
state.mode = BAD$1;
break;
}
/* build code tables -- note: do not change the lenbits or distbits
values here (9 and 6) without reading the comments in inftrees.h
concerning the ENOUGH constants, which depend on those values */
state.lenbits = 9;
opts = { bits: state.lenbits };
ret = inflate_table(LENS$1, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts);
// We have separate tables & no pointers. 2 commented lines below not needed.
// state.next_index = opts.table_index;
state.lenbits = opts.bits;
// state.lencode = state.next;
if (ret) {
strm.msg = 'invalid literal/lengths set';
state.mode = BAD$1;
break;
}
state.distbits = 6;
//state.distcode.copy(state.codes);
// Switch to use dynamic table
state.distcode = state.distdyn;
opts = { bits: state.distbits };
ret = inflate_table(DISTS$1, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts);
// We have separate tables & no pointers. 2 commented lines below not needed.
// state.next_index = opts.table_index;
state.distbits = opts.bits;
// state.distcode = state.next;
if (ret) {
strm.msg = 'invalid distances set';
state.mode = BAD$1;
break;
}
//Tracev((stderr, 'inflate: codes ok\n'));
state.mode = LEN_;
if (flush === Z_TREES) { break inf_leave; }
/* falls through */
case LEN_:
state.mode = LEN;
/* falls through */
case LEN:
if (have >= 6 && left >= 258) {
//--- RESTORE() ---
strm.next_out = put;
strm.avail_out = left;
strm.next_in = next;
strm.avail_in = have;
state.hold = hold;
state.bits = bits;
//---
inflate_fast(strm, _out);
//--- LOAD() ---
put = strm.next_out;
output = strm.output;
left = strm.avail_out;
next = strm.next_in;
input = strm.input;
have = strm.avail_in;
hold = state.hold;
bits = state.bits;
//---
if (state.mode === TYPE$1) {
state.back = -1;
}
break;
}
state.back = 0;
for (;;) {
here = state.lencode[hold & ((1 << state.lenbits) - 1)]; /*BITS(state.lenbits)*/
here_bits = here >>> 24;
here_op = (here >>> 16) & 0xff;
here_val = here & 0xffff;
if (here_bits <= bits) { break; }
//--- PULLBYTE() ---//
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
//---//
}
if (here_op && (here_op & 0xf0) === 0) {
last_bits = here_bits;
last_op = here_op;
last_val = here_val;
for (;;) {
here = state.lencode[last_val +
((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)];
here_bits = here >>> 24;
here_op = (here >>> 16) & 0xff;
here_val = here & 0xffff;
if ((last_bits + here_bits) <= bits) { break; }
//--- PULLBYTE() ---//
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
//---//
}
//--- DROPBITS(last.bits) ---//
hold >>>= last_bits;
bits -= last_bits;
//---//
state.back += last_bits;
}
//--- DROPBITS(here.bits) ---//
hold >>>= here_bits;
bits -= here_bits;
//---//
state.back += here_bits;
state.length = here_val;
if (here_op === 0) {
//Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
// "inflate: literal '%c'\n" :
// "inflate: literal 0x%02x\n", here.val));
state.mode = LIT;
break;
}
if (here_op & 32) {
//Tracevv((stderr, "inflate: end of block\n"));
state.back = -1;
state.mode = TYPE$1;
break;
}
if (here_op & 64) {
strm.msg = 'invalid literal/length code';
state.mode = BAD$1;
break;
}
state.extra = here_op & 15;
state.mode = LENEXT;
/* falls through */
case LENEXT:
if (state.extra) {
//=== NEEDBITS(state.extra);
n = state.extra;
while (bits < n) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
state.length += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/;
//--- DROPBITS(state.extra) ---//
hold >>>= state.extra;
bits -= state.extra;
//---//
state.back += state.extra;
}
//Tracevv((stderr, "inflate: length %u\n", state.length));
state.was = state.length;
state.mode = DIST;
/* falls through */
case DIST:
for (;;) {
here = state.distcode[hold & ((1 << state.distbits) - 1)];/*BITS(state.distbits)*/
here_bits = here >>> 24;
here_op = (here >>> 16) & 0xff;
here_val = here & 0xffff;
if ((here_bits) <= bits) { break; }
//--- PULLBYTE() ---//
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
//---//
}
if ((here_op & 0xf0) === 0) {
last_bits = here_bits;
last_op = here_op;
last_val = here_val;
for (;;) {
here = state.distcode[last_val +
((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)];
here_bits = here >>> 24;
here_op = (here >>> 16) & 0xff;
here_val = here & 0xffff;
if ((last_bits + here_bits) <= bits) { break; }
//--- PULLBYTE() ---//
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
//---//
}
//--- DROPBITS(last.bits) ---//
hold >>>= last_bits;
bits -= last_bits;
//---//
state.back += last_bits;
}
//--- DROPBITS(here.bits) ---//
hold >>>= here_bits;
bits -= here_bits;
//---//
state.back += here_bits;
if (here_op & 64) {
strm.msg = 'invalid distance code';
state.mode = BAD$1;
break;
}
state.offset = here_val;
state.extra = (here_op) & 15;
state.mode = DISTEXT;
/* falls through */
case DISTEXT:
if (state.extra) {
//=== NEEDBITS(state.extra);
n = state.extra;
while (bits < n) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
state.offset += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/;
//--- DROPBITS(state.extra) ---//
hold >>>= state.extra;
bits -= state.extra;
//---//
state.back += state.extra;
}
//#ifdef INFLATE_STRICT
if (state.offset > state.dmax) {
strm.msg = 'invalid distance too far back';
state.mode = BAD$1;
break;
}
//#endif
//Tracevv((stderr, "inflate: distance %u\n", state.offset));
state.mode = MATCH;
/* falls through */
case MATCH:
if (left === 0) { break inf_leave; }
copy = _out - left;
if (state.offset > copy) { /* copy from window */
copy = state.offset - copy;
if (copy > state.whave) {
if (state.sane) {
strm.msg = 'invalid distance too far back';
state.mode = BAD$1;
break;
}
// (!) This block is disabled in zlib defaults,
// don't enable it for binary compatibility
//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
// Trace((stderr, "inflate.c too far\n"));
// copy -= state.whave;
// if (copy > state.length) { copy = state.length; }
// if (copy > left) { copy = left; }
// left -= copy;
// state.length -= copy;
// do {
// output[put++] = 0;
// } while (--copy);
// if (state.length === 0) { state.mode = LEN; }
// break;
//#endif
}
if (copy > state.wnext) {
copy -= state.wnext;
from = state.wsize - copy;
}
else {
from = state.wnext - copy;
}
if (copy > state.length) { copy = state.length; }
from_source = state.window;
}
else { /* copy from output */
from_source = output;
from = put - state.offset;
copy = state.length;
}
if (copy > left) { copy = left; }
left -= copy;
state.length -= copy;
do {
output[put++] = from_source[from++];
} while (--copy);
if (state.length === 0) { state.mode = LEN; }
break;
case LIT:
if (left === 0) { break inf_leave; }
output[put++] = state.length;
left--;
state.mode = LEN;
break;
case CHECK:
if (state.wrap) {
//=== NEEDBITS(32);
while (bits < 32) {
if (have === 0) { break inf_leave; }
have--;
// Use '|' instead of '+' to make sure that result is signed
hold |= input[next++] << bits;
bits += 8;
}
//===//
_out -= left;
strm.total_out += _out;
state.total += _out;
if (_out) {
strm.adler = state.check =
/*UPDATE(state.check, put - _out, _out);*/
(state.flags ? crc32(state.check, output, _out, put - _out) : adler32(state.check, output, _out, put - _out));
}
_out = left;
// NB: crc32 stored as signed 32-bit int, zswap32 returns signed too
if ((state.flags ? hold : zswap32(hold)) !== state.check) {
strm.msg = 'incorrect data check';
state.mode = BAD$1;
break;
}
//=== INITBITS();
hold = 0;
bits = 0;
//===//
//Tracev((stderr, "inflate: check matches trailer\n"));
}
state.mode = LENGTH;
/* falls through */
case LENGTH:
if (state.wrap && state.flags) {
//=== NEEDBITS(32);
while (bits < 32) {
if (have === 0) { break inf_leave; }
have--;
hold += input[next++] << bits;
bits += 8;
}
//===//
if (hold !== (state.total & 0xffffffff)) {
strm.msg = 'incorrect length check';
state.mode = BAD$1;
break;
}
//=== INITBITS();
hold = 0;
bits = 0;
//===//
//Tracev((stderr, "inflate: length matches trailer\n"));
}
state.mode = DONE;
/* falls through */
case DONE:
ret = Z_STREAM_END;
break inf_leave;
case BAD$1:
ret = Z_DATA_ERROR;
break inf_leave;
// case MEM:
// return Z_MEM_ERROR;
case SYNC:
/* falls through */
default:
return Z_STREAM_ERROR;
}
}
// inf_leave <- here is real place for "goto inf_leave", emulated via "break inf_leave"
/*
Return from inflate(), updating the total counts and the check value.
If there was no progress during the inflate() call, return a buffer
error. Call updatewindow() to create and/or update the window state.
Note: a memory error from inflate() is non-recoverable.
*/
//--- RESTORE() ---
strm.next_out = put;
strm.avail_out = left;
strm.next_in = next;
strm.avail_in = have;
state.hold = hold;
state.bits = bits;
//---
if (state.wsize || (_out !== strm.avail_out && state.mode < BAD$1 &&
(state.mode < CHECK || flush !== Z_FINISH))) {
if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) ;
}
_in -= strm.avail_in;
_out -= strm.avail_out;
strm.total_in += _in;
strm.total_out += _out;
state.total += _out;
if (state.wrap && _out) {
strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/
(state.flags ? crc32(state.check, output, _out, strm.next_out - _out) : adler32(state.check, output, _out, strm.next_out - _out));
}
strm.data_type = state.bits + (state.last ? 64 : 0) +
(state.mode === TYPE$1 ? 128 : 0) +
(state.mode === LEN_ || state.mode === COPY_ ? 256 : 0);
if (((_in === 0 && _out === 0) || flush === Z_FINISH) && ret === Z_OK) {
ret = Z_BUF_ERROR;
}
return ret;
}
function inflateEnd(strm) {
if (!strm || !strm.state /*|| strm->zfree == (free_func)0*/) {
return Z_STREAM_ERROR;
}
const state = strm.state;
if (state.window) {
state.window = null;
}
strm.state = null;
return Z_OK;
}
function inflateGetHeader(strm, head) {
let state;
/* check state */
if (!strm || !strm.state) { return Z_STREAM_ERROR; }
state = strm.state;
if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR; }
/* save header structure */
state.head = head;
head.done = false;
return Z_OK;
}
function inflateSetDictionary(strm, dictionary) {
const dictLength = dictionary.length;
let state;
let dictid;
/* check state */
if (!strm /* == Z_NULL */ || !strm.state /* == Z_NULL */) { return Z_STREAM_ERROR; }
state = strm.state;
if (state.wrap !== 0 && state.mode !== DICT) {
return Z_STREAM_ERROR;
}
/* check for correct dictionary identifier */
if (state.mode === DICT) {
dictid = 1; /* adler32(0, null, 0)*/
/* dictid = adler32(dictid, dictionary, dictLength); */
dictid = adler32(dictid, dictionary, dictLength, 0);
if (dictid !== state.check) {
return Z_DATA_ERROR;
}
}
/* copy dictionary to window using updatewindow(), which will amend the
existing dictionary if appropriate */
updatewindow(strm, dictionary, dictLength, dictLength);
// if (ret) {
// state.mode = MEM;
// return Z_MEM_ERROR;
// }
state.havedict = 1;
// Tracev((stderr, "inflate: dictionary set\n"));
return Z_OK;
}
/* Not implemented
exports.inflateCopy = inflateCopy;
exports.inflateGetDictionary = inflateGetDictionary;
exports.inflateMark = inflateMark;
exports.inflatePrime = inflatePrime;
exports.inflateSync = inflateSync;
exports.inflateSyncPoint = inflateSyncPoint;
exports.inflateUndermine = inflateUndermine;
*/
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
class GZheader {
constructor() {
/* true if compressed data believed to be text */
this.text = 0;
/* modification time */
this.time = 0;
/* extra flags (not used when writing a gzip file) */
this.xflags = 0;
/* operating system */
this.os = 0;
/* pointer to extra field or Z_NULL if none */
this.extra = null;
/* extra field length (valid if extra != Z_NULL) */
this.extra_len = 0; // Actually, we don't need it in JS,
// but leave for few code modifications
//
// Setup limits is not necessary because in js we should not preallocate memory
// for inflate use constant limit in 65536 bytes
//
/* space at extra (only when reading header) */
// this.extra_max = 0;
/* pointer to zero-terminated file name or Z_NULL */
this.name = '';
/* space at name (only when reading header) */
// this.name_max = 0;
/* pointer to zero-terminated comment or Z_NULL */
this.comment = '';
/* space at comment (only when reading header) */
// this.comm_max = 0;
/* true if there was or will be a header crc */
this.hcrc = 0;
/* true when done reading gzip header (not used when writing a gzip file) */
this.done = false;
}
}
/**
* class Inflate
*
* Generic JS-style wrapper for zlib calls. If you don't need
* streaming behaviour - use more simple functions: [[inflate]]
* and [[inflateRaw]].
**/
/* internal
* inflate.chunks -> Array
*
* Chunks of output data, if [[Inflate#onData]] not overridden.
**/
/**
* Inflate.result -> Uint8Array|Array|String
*
* Uncompressed result, generated by default [[Inflate#onData]]
* and [[Inflate#onEnd]] handlers. Filled after you push last chunk
* (call [[Inflate#push]] with `Z_FINISH` / `true` param) or if you
* push a chunk with explicit flush (call [[Inflate#push]] with
* `Z_SYNC_FLUSH` param).
**/
/**
* Inflate.err -> Number
*
* Error code after inflate finished. 0 (Z_OK) on success.
* Should be checked if broken data possible.
**/
/**
* Inflate.msg -> String
*
* Error message, if [[Inflate.err]] != 0
**/
/**
* new Inflate(options)
* - options (Object): zlib inflate options.
*
* Creates new inflator instance with specified params. Throws exception
* on bad params. Supported options:
*
* - `windowBits`
* - `dictionary`
*
* [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
* for more information on these.
*
* Additional options, for internal needs:
*
* - `chunkSize` - size of generated data chunks (16K by default)
* - `raw` (Boolean) - do raw inflate
* - `to` (String) - if equal to 'string', then result will be converted
* from utf8 to utf16 (javascript) string. When string output requested,
* chunk length can differ from `chunkSize`, depending on content.
*
* By default, when no options set, autodetect deflate/gzip data format via
* wrapper header.
*
* ##### Example:
*
* ```javascript
* var pako = void('pako')
* , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9])
* , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]);
*
* var inflate = new pako.Inflate({ level: 3});
*
* inflate.push(chunk1, false);
* inflate.push(chunk2, true); // true -> last chunk
*
* if (inflate.err) { throw new Error(inflate.err); }
*
* console.log(inflate.result);
* ```
**/
class Inflate {
constructor(options) {
this.options = {
chunkSize: 16384,
windowBits: 0,
...(options || {})
};
const opt = this.options;
// Force window size for `raw` data, if not set directly,
// because we have no header for autodetect.
if (opt.raw && (opt.windowBits >= 0) && (opt.windowBits < 16)) {
opt.windowBits = -opt.windowBits;
if (opt.windowBits === 0) { opt.windowBits = -15; }
}
// If `windowBits` not defined (and mode not raw) - set autodetect flag for gzip/deflate
if ((opt.windowBits >= 0) && (opt.windowBits < 16) &&
!(options && options.windowBits)) {
opt.windowBits += 32;
}
// Gzip header has no info about windows size, we can do autodetect only
// for deflate. So, if window size not set, force it to max when gzip possible
if ((opt.windowBits > 15) && (opt.windowBits < 48)) {
// bit 3 (16) -> gzipped data
// bit 4 (32) -> autodetect gzip/deflate
if ((opt.windowBits & 15) === 0) {
opt.windowBits |= 15;
}
}
this.err = 0; // error code, if happens (0 = Z_OK)
this.msg = ''; // error message
this.ended = false; // used to avoid multiple onEnd() calls
this.chunks = []; // chunks of compressed data
this.strm = new ZStream();
this.strm.avail_out = 0;
let status = inflateInit2(
this.strm,
opt.windowBits
);
if (status !== Z_OK) {
throw new Error(msg[status]);
}
this.header = new GZheader();
inflateGetHeader(this.strm, this.header);
// Setup dictionary
if (opt.dictionary) {
// Convert data if needed
if (typeof opt.dictionary === 'string') {
opt.dictionary = string2buf(opt.dictionary);
} else if (opt.dictionary instanceof ArrayBuffer) {
opt.dictionary = new Uint8Array(opt.dictionary);
}
if (opt.raw) { //In raw mode we need to set the dictionary early
status = inflateSetDictionary(this.strm, opt.dictionary);
if (status !== Z_OK) {
throw new Error(msg[status]);
}
}
}
}
/**
* Inflate#push(data[, mode]) -> Boolean
* - data (Uint8Array|Array|ArrayBuffer|String): input data
* - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.
* See constants. Skipped or `false` means Z_NO_FLUSH, `true` means Z_FINISH.
*
* Sends input data to inflate pipe, generating [[Inflate#onData]] calls with
* new output chunks. Returns `true` on success. The last data block must have
* mode Z_FINISH (or `true`). That will flush internal pending buffers and call
* [[Inflate#onEnd]]. For interim explicit flushes (without ending the stream) you
* can use mode Z_SYNC_FLUSH, keeping the decompression context.
*
* On fail call [[Inflate#onEnd]] with error code and return false.
*
* We strongly recommend to use `Uint8Array` on input for best speed (output
* format is detected automatically). Also, don't skip last param and always
* use the same type in your code (boolean or number). That will improve JS speed.
*
* For regular `Array`-s make sure all elements are [0..255].
*
* ##### Example
*
* ```javascript
* push(chunk, false); // push one of data chunks
* ...
* push(chunk, true); // push last chunk
* ```
**/
push(data, mode) {
const { strm, options: { chunkSize, dictionary } } = this;
let status, _mode;
// Flag to properly process Z_BUF_ERROR on testing inflate call
// when we check that all output data was flushed.
let allowBufError = false;
if (this.ended) { return false; }
_mode = (mode === ~~mode) ? mode : ((mode === true) ? Z_FINISH : Z_NO_FLUSH);
// Convert data if needed
if (typeof data === 'string') {
// Only binary strings can be decompressed on practice
strm.input = binstring2buf(data);
} else if (data instanceof ArrayBuffer) {
strm.input = new Uint8Array(data);
} else {
strm.input = data;
}
strm.next_in = 0;
strm.avail_in = strm.input.length;
do {
if (strm.avail_out === 0) {
strm.output = new Buf8(chunkSize);
strm.next_out = 0;
strm.avail_out = chunkSize;
}
status = inflate(strm, Z_NO_FLUSH); /* no bad return value */
if (status === Z_NEED_DICT && dictionary) {
status = inflateSetDictionary(this.strm, dictionary);
}
if (status === Z_BUF_ERROR && allowBufError === true) {
status = Z_OK;
allowBufError = false;
}
if (status !== Z_STREAM_END && status !== Z_OK) {
this.onEnd(status);
this.ended = true;
return false;
}
if (strm.next_out) {
if (strm.avail_out === 0 || status === Z_STREAM_END || (strm.avail_in === 0 && (_mode === Z_FINISH || _mode === Z_SYNC_FLUSH))) {
this.onData(shrinkBuf(strm.output, strm.next_out));
}
}
// When no more input data, we should check that internal inflate buffers
// are flushed. The only way to do it when avail_out = 0 - run one more
// inflate pass. But if output data not exists, inflate return Z_BUF_ERROR.
// Here we set flag to process this error properly.
//
// NOTE. Deflate does not return error in this case and does not needs such
// logic.
if (strm.avail_in === 0 && strm.avail_out === 0) {
allowBufError = true;
}
} while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== Z_STREAM_END);
if (status === Z_STREAM_END) {
_mode = Z_FINISH;
}
// Finalize on the last chunk.
if (_mode === Z_FINISH) {
status = inflateEnd(this.strm);
this.onEnd(status);
this.ended = true;
return status === Z_OK;
}
// callback interim results if Z_SYNC_FLUSH.
if (_mode === Z_SYNC_FLUSH) {
this.onEnd(Z_OK);
strm.avail_out = 0;
return true;
}
return true;
};
/**
* Inflate#onData(chunk) -> Void
* - chunk (Uint8Array|Array|String): output data. Type of array depends
* on js engine support. When string output requested, each chunk
* will be string.
*
* By default, stores data blocks in `chunks[]` property and glue
* those in `onEnd`. Override this handler, if you need another behaviour.
**/
onData(chunk) {
this.chunks.push(chunk);
};
/**
* Inflate#onEnd(status) -> Void
* - status (Number): inflate status. 0 (Z_OK) on success,
* other if not.
*
* Called either after you tell inflate that the input stream is
* complete (Z_FINISH) or should be flushed (Z_SYNC_FLUSH)
* or if an error happened. By default - join collected chunks,
* free memory and fill `results` / `err` properties.
**/
onEnd(status) {
// On success - join
if (status === Z_OK) {
this.result = flattenChunks(this.chunks);
}
this.chunks = [];
this.err = status;
this.msg = this.strm.msg;
};
}
/*
node-bzip - a pure-javascript Node.JS module for decoding bzip2 data
Copyright (C) 2012 Eli Skeggs
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see
http://www.gnu.org/licenses/lgpl-2.1.html
Adapted from bzip2.js, copyright 2011 antimatter15 (antimatter15@gmail.com).
Based on micro-bunzip by Rob Landley (rob@landley.net).
Based on bzip2 decompression code by Julian R Seward (jseward@acm.org),
which also acknowledges contributions by Mike Burrows, David Wheeler,
Peter Fenwick, Alistair Moffat, Radford Neal, Ian H. Witten,
Robert Sedgewick, and Jon L. Bentley.
*/
var BITMASK = [0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF];
// offset in bytes
var BitReader = function(stream) {
this.stream = stream;
this.bitOffset = 0;
this.curByte = 0;
this.hasByte = false;
};
BitReader.prototype._ensureByte = function() {
if (!this.hasByte) {
this.curByte = this.stream.readByte();
this.hasByte = true;
}
};
// reads bits from the buffer
BitReader.prototype.read = function(bits) {
var result = 0;
while (bits > 0) {
this._ensureByte();
var remaining = 8 - this.bitOffset;
// if we're in a byte
if (bits >= remaining) {
result <<= remaining;
result |= BITMASK[remaining] & this.curByte;
this.hasByte = false;
this.bitOffset = 0;
bits -= remaining;
} else {
result <<= bits;
var shift = remaining - bits;
result |= (this.curByte & (BITMASK[bits] << shift)) >> shift;
this.bitOffset += bits;
bits = 0;
}
}
return result;
};
// seek to an arbitrary point in the buffer (expressed in bits)
BitReader.prototype.seek = function(pos) {
var n_bit = pos % 8;
var n_byte = (pos - n_bit) / 8;
this.bitOffset = n_bit;
this.stream.seek(n_byte);
this.hasByte = false;
};
// reads 6 bytes worth of data using the read method
BitReader.prototype.pi = function() {
var buf = new Uint8Array(6), i;
for (i = 0; i < buf.length; i++) {
buf[i] = this.read(8);
}
return bufToHex(buf);
};
function bufToHex(buf) {
return Array.prototype.map.call(buf, x => ('00' + x.toString(16)).slice(-2)).join('');
}
var bitreader = BitReader;
/* very simple input/output stream interface */
var Stream = function() {
};
// input streams //////////////
/** Returns the next byte, or -1 for EOF. */
Stream.prototype.readByte = function() {
throw new Error("abstract method readByte() not implemented");
};
/** Attempts to fill the buffer; returns number of bytes read, or
* -1 for EOF. */
Stream.prototype.read = function(buffer, bufOffset, length) {
var bytesRead = 0;
while (bytesRead < length) {
var c = this.readByte();
if (c < 0) { // EOF
return (bytesRead===0) ? -1 : bytesRead;
}
buffer[bufOffset++] = c;
bytesRead++;
}
return bytesRead;
};
Stream.prototype.seek = function(new_pos) {
throw new Error("abstract method seek() not implemented");
};
// output streams ///////////
Stream.prototype.writeByte = function(_byte) {
throw new Error("abstract method readByte() not implemented");
};
Stream.prototype.write = function(buffer, bufOffset, length) {
var i;
for (i=0; i>> 0; // return an unsigned value
};
/**
* Update the CRC with a single byte
* @param value The value to update the CRC with
*/
this.updateCRC = function(value) {
crc = (crc << 8) ^ crc32Lookup[((crc >>> 24) ^ value) & 0xff];
};
/**
* Update the CRC with a sequence of identical bytes
* @param value The value to update the CRC with
* @param count The number of bytes
*/
this.updateCRCRun = function(value, count) {
while (count-- > 0) {
crc = (crc << 8) ^ crc32Lookup[((crc >>> 24) ^ value) & 0xff];
}
};
};
return CRC32;
})();
/*
seek-bzip - a pure-javascript module for seeking within bzip2 data
Copyright (C) 2013 C. Scott Ananian
Copyright (C) 2012 Eli Skeggs
Copyright (C) 2011 Kevin Kwok
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see
http://www.gnu.org/licenses/lgpl-2.1.html
Adapted from node-bzip, copyright 2012 Eli Skeggs.
Adapted from bzip2.js, copyright 2011 Kevin Kwok (antimatter15@gmail.com).
Based on micro-bunzip by Rob Landley (rob@landley.net).
Based on bzip2 decompression code by Julian R Seward (jseward@acm.org),
which also acknowledges contributions by Mike Burrows, David Wheeler,
Peter Fenwick, Alistair Moffat, Radford Neal, Ian H. Witten,
Robert Sedgewick, and Jon L. Bentley.
*/
var MAX_HUFCODE_BITS = 20;
var MAX_SYMBOLS = 258;
var SYMBOL_RUNA = 0;
var SYMBOL_RUNB = 1;
var MIN_GROUPS = 2;
var MAX_GROUPS = 6;
var GROUP_SIZE = 50;
var WHOLEPI = "314159265359";
var SQRTPI = "177245385090";
var mtf = function(array, index) {
var src = array[index], i;
for (i = index; i > 0; i--) {
array[i] = array[i-1];
}
array[0] = src;
return src;
};
var Err = {
OK: 0,
LAST_BLOCK: -1,
NOT_BZIP_DATA: -2,
UNEXPECTED_INPUT_EOF: -3,
UNEXPECTED_OUTPUT_EOF: -4,
DATA_ERROR: -5,
OUT_OF_MEMORY: -6,
OBSOLETE_INPUT: -7,
END_OF_BLOCK: -8
};
var ErrorMessages = {};
ErrorMessages[Err.LAST_BLOCK] = "Bad file checksum";
ErrorMessages[Err.NOT_BZIP_DATA] = "Not bzip data";
ErrorMessages[Err.UNEXPECTED_INPUT_EOF] = "Unexpected input EOF";
ErrorMessages[Err.UNEXPECTED_OUTPUT_EOF] = "Unexpected output EOF";
ErrorMessages[Err.DATA_ERROR] = "Data error";
ErrorMessages[Err.OUT_OF_MEMORY] = "Out of memory";
ErrorMessages[Err.OBSOLETE_INPUT] = "Obsolete (pre 0.9.5) bzip format not supported.";
var _throw = function(status, optDetail) {
var msg = ErrorMessages[status] || 'unknown error';
if (optDetail) { msg += ': '+optDetail; }
var e = new TypeError(msg);
e.errorCode = status;
throw e;
};
var Bunzip = function(inputStream, outputStream) {
this.writePos = this.writeCurrent = this.writeCount = 0;
this._start_bunzip(inputStream, outputStream);
};
Bunzip.prototype._init_block = function() {
var moreBlocks = this._get_next_block();
if ( !moreBlocks ) {
this.writeCount = -1;
return false; /* no more blocks */
}
this.blockCRC = new crc32$1();
return true;
};
/* XXX micro-bunzip uses (inputStream, inputBuffer, len) as arguments */
Bunzip.prototype._start_bunzip = function(inputStream, outputStream) {
/* Ensure that file starts with "BZh['1'-'9']." */
var buf = new Uint8Array(4);
if (inputStream.read(buf, 0, 4) !== 4 ||
String.fromCharCode(buf[0], buf[1], buf[2]) !== 'BZh')
_throw(Err.NOT_BZIP_DATA, 'bad magic');
var level = buf[3] - 0x30;
if (level < 1 || level > 9)
_throw(Err.NOT_BZIP_DATA, 'level out of range');
this.reader = new bitreader(inputStream);
/* Fourth byte (ascii '1'-'9'), indicates block size in units of 100k of
uncompressed data. Allocate intermediate buffer for block. */
this.dbufSize = 100000 * level;
this.nextoutput = 0;
this.outputStream = outputStream;
this.streamCRC = 0;
};
Bunzip.prototype._get_next_block = function() {
var i, j, k;
var reader = this.reader;
// this is get_next_block() function from micro-bunzip:
/* Read in header signature and CRC, then validate signature.
(last block signature means CRC is for whole file, return now) */
var h = reader.pi();
if (h === SQRTPI) { // last block
return false; /* no more blocks */
}
if (h !== WHOLEPI)
_throw(Err.NOT_BZIP_DATA);
this.targetBlockCRC = reader.read(32) >>> 0; // (convert to unsigned)
this.streamCRC = (this.targetBlockCRC ^
((this.streamCRC << 1) | (this.streamCRC>>>31))) >>> 0;
/* We can add support for blockRandomised if anybody complains. There was
some code for this in busybox 1.0.0-pre3, but nobody ever noticed that
it didn't actually work. */
if (reader.read(1))
_throw(Err.OBSOLETE_INPUT);
var origPointer = reader.read(24);
if (origPointer > this.dbufSize)
_throw(Err.DATA_ERROR, 'initial position out of bounds');
/* mapping table: if some byte values are never used (encoding things
like ascii text), the compression code removes the gaps to have fewer
symbols to deal with, and writes a sparse bitfield indicating which
values were present. We make a translation table to convert the symbols
back to the corresponding bytes. */
var t = reader.read(16);
var symToByte = new Uint8Array(256), symTotal = 0;
for (i = 0; i < 16; i++) {
if (t & (1 << (0xF - i))) {
var o = i * 16;
k = reader.read(16);
for (j = 0; j < 16; j++)
if (k & (1 << (0xF - j)))
symToByte[symTotal++] = o + j;
}
}
/* How many different huffman coding groups does this block use? */
var groupCount = reader.read(3);
if (groupCount < MIN_GROUPS || groupCount > MAX_GROUPS)
_throw(Err.DATA_ERROR);
/* nSelectors: Every GROUP_SIZE many symbols we select a new huffman coding
group. Read in the group selector list, which is stored as MTF encoded
bit runs. (MTF=Move To Front, as each value is used it's moved to the
start of the list.) */
var nSelectors = reader.read(15);
if (nSelectors === 0)
_throw(Err.DATA_ERROR);
var mtfSymbol = new Uint8Array(256);
for (i = 0; i < groupCount; i++)
mtfSymbol[i] = i;
var selectors = new Uint8Array(nSelectors); // was 32768...
for (i = 0; i < nSelectors; i++) {
/* Get next value */
for (j = 0; reader.read(1); j++)
if (j >= groupCount) _throw(Err.DATA_ERROR);
/* Decode MTF to get the next selector */
selectors[i] = mtf(mtfSymbol, j);
}
/* Read the huffman coding tables for each group, which code for symTotal
literal symbols, plus two run symbols (RUNA, RUNB) */
var symCount = symTotal + 2;
var groups = [], hufGroup;
for (j = 0; j < groupCount; j++) {
var length = new Uint8Array(symCount), temp = new Uint16Array(MAX_HUFCODE_BITS + 1);
/* Read huffman code lengths for each symbol. They're stored in
a way similar to mtf; record a starting value for the first symbol,
and an offset from the previous value for everys symbol after that. */
t = reader.read(5); // lengths
for (i = 0; i < symCount; i++) {
for (;;) {
if (t < 1 || t > MAX_HUFCODE_BITS) _throw(Err.DATA_ERROR);
/* If first bit is 0, stop. Else second bit indicates whether
to increment or decrement the value. */
if(!reader.read(1))
break;
if(!reader.read(1))
t++;
else
t--;
}
length[i] = t;
}
/* Find largest and smallest lengths in this group */
var minLen, maxLen;
minLen = maxLen = length[0];
for (i = 1; i < symCount; i++) {
if (length[i] > maxLen)
maxLen = length[i];
else if (length[i] < minLen)
minLen = length[i];
}
/* Calculate permute[], base[], and limit[] tables from length[].
*
* permute[] is the lookup table for converting huffman coded symbols
* into decoded symbols. base[] is the amount to subtract from the
* value of a huffman symbol of a given length when using permute[].
*
* limit[] indicates the largest numerical value a symbol with a given
* number of bits can have. This is how the huffman codes can vary in
* length: each code with a value>limit[length] needs another bit.
*/
hufGroup = {};
groups.push(hufGroup);
hufGroup.permute = new Uint16Array(MAX_SYMBOLS);
hufGroup.limit = new Uint32Array(MAX_HUFCODE_BITS + 2);
hufGroup.base = new Uint32Array(MAX_HUFCODE_BITS + 1);
hufGroup.minLen = minLen;
hufGroup.maxLen = maxLen;
/* Calculate permute[]. Concurently, initialize temp[] and limit[]. */
var pp = 0;
for (i = minLen; i <= maxLen; i++) {
temp[i] = hufGroup.limit[i] = 0;
for (t = 0; t < symCount; t++)
if (length[t] === i)
hufGroup.permute[pp++] = t;
}
/* Count symbols coded for at each bit length */
for (i = 0; i < symCount; i++)
temp[length[i]]++;
/* Calculate limit[] (the largest symbol-coding value at each bit
* length, which is (previous limit<<1)+symbols at this level), and
* base[] (number of symbols to ignore at each bit length, which is
* limit minus the cumulative count of symbols coded for already). */
pp = t = 0;
for (i = minLen; i < maxLen; i++) {
pp += temp[i];
/* We read the largest possible symbol size and then unget bits
after determining how many we need, and those extra bits could
be set to anything. (They're noise from future symbols.) At
each level we're really only interested in the first few bits,
so here we set all the trailing to-be-ignored bits to 1 so they
don't affect the value>limit[length] comparison. */
hufGroup.limit[i] = pp - 1;
pp <<= 1;
t += temp[i];
hufGroup.base[i + 1] = pp - t;
}
hufGroup.limit[maxLen + 1] = Number.MAX_VALUE; /* Sentinal value for reading next sym. */
hufGroup.limit[maxLen] = pp + temp[maxLen] - 1;
hufGroup.base[minLen] = 0;
}
/* We've finished reading and digesting the block header. Now read this
block's huffman coded symbols from the file and undo the huffman coding
and run length encoding, saving the result into dbuf[dbufCount++]=uc */
/* Initialize symbol occurrence counters and symbol Move To Front table */
var byteCount = new Uint32Array(256);
for (i = 0; i < 256; i++)
mtfSymbol[i] = i;
/* Loop through compressed symbols. */
var runPos = 0, dbufCount = 0, selector = 0, uc;
var dbuf = this.dbuf = new Uint32Array(this.dbufSize);
symCount = 0;
for (;;) {
/* Determine which huffman coding group to use. */
if (!(symCount--)) {
symCount = GROUP_SIZE - 1;
if (selector >= nSelectors) { _throw(Err.DATA_ERROR); }
hufGroup = groups[selectors[selector++]];
}
/* Read next huffman-coded symbol. */
i = hufGroup.minLen;
j = reader.read(i);
for (;;i++) {
if (i > hufGroup.maxLen) { _throw(Err.DATA_ERROR); }
if (j <= hufGroup.limit[i])
break;
j = (j << 1) | reader.read(1);
}
/* Huffman decode value to get nextSym (with bounds checking) */
j -= hufGroup.base[i];
if (j < 0 || j >= MAX_SYMBOLS) { _throw(Err.DATA_ERROR); }
var nextSym = hufGroup.permute[j];
/* We have now decoded the symbol, which indicates either a new literal
byte, or a repeated run of the most recent literal byte. First,
check if nextSym indicates a repeated run, and if so loop collecting
how many times to repeat the last literal. */
if (nextSym === SYMBOL_RUNA || nextSym === SYMBOL_RUNB) {
/* If this is the start of a new run, zero out counter */
if (!runPos){
runPos = 1;
t = 0;
}
/* Neat trick that saves 1 symbol: instead of or-ing 0 or 1 at
each bit position, add 1 or 2 instead. For example,
1011 is 1<<0 + 1<<1 + 2<<2. 1010 is 2<<0 + 2<<1 + 1<<2.
You can make any bit pattern that way using 1 less symbol than
the basic or 0/1 method (except all bits 0, which would use no
symbols, but a run of length 0 doesn't mean anything in this
context). Thus space is saved. */
if (nextSym === SYMBOL_RUNA)
t += runPos;
else
t += 2 * runPos;
runPos <<= 1;
continue;
}
/* When we hit the first non-run symbol after a run, we now know
how many times to repeat the last literal, so append that many
copies to our buffer of decoded symbols (dbuf) now. (The last
literal used is the one at the head of the mtfSymbol array.) */
if (runPos){
runPos = 0;
if (dbufCount + t > this.dbufSize) { _throw(Err.DATA_ERROR); }
uc = symToByte[mtfSymbol[0]];
byteCount[uc] += t;
while (t--)
dbuf[dbufCount++] = uc;
}
/* Is this the terminating symbol? */
if (nextSym > symTotal)
break;
/* At this point, nextSym indicates a new literal character. Subtract
one to get the position in the MTF array at which this literal is
currently to be found. (Note that the result can't be -1 or 0,
because 0 and 1 are RUNA and RUNB. But another instance of the
first symbol in the mtf array, position 0, would have been handled
as part of a run above. Therefore 1 unused mtf position minus
2 non-literal nextSym values equals -1.) */
if (dbufCount >= this.dbufSize) { _throw(Err.DATA_ERROR); }
i = nextSym - 1;
uc = mtf(mtfSymbol, i);
uc = symToByte[uc];
/* We have our literal byte. Save it into dbuf. */
byteCount[uc]++;
dbuf[dbufCount++] = uc;
}
/* At this point, we've read all the huffman-coded symbols (and repeated
runs) for this block from the input stream, and decoded them into the
intermediate buffer. There are dbufCount many decoded bytes in dbuf[].
Now undo the Burrows-Wheeler transform on dbuf.
See http://dogma.net/markn/articles/bwt/bwt.htm
*/
if (origPointer < 0 || origPointer >= dbufCount) { _throw(Err.DATA_ERROR); }
/* Turn byteCount into cumulative occurrence counts of 0 to n-1. */
j = 0;
for (i = 0; i < 256; i++) {
k = j + byteCount[i];
byteCount[i] = j;
j = k;
}
/* Figure out what order dbuf would be in if we sorted it. */
for (i = 0; i < dbufCount; i++) {
uc = dbuf[i] & 0xff;
dbuf[byteCount[uc]] |= (i << 8);
byteCount[uc]++;
}
/* Decode first byte by hand to initialize "previous" byte. Note that it
doesn't get output, and if the first three characters are identical
it doesn't qualify as a run (hence writeRunCountdown=5). */
var pos = 0, current = 0, run = 0;
if (dbufCount) {
pos = dbuf[origPointer];
current = (pos & 0xff);
pos >>= 8;
run = -1;
}
this.writePos = pos;
this.writeCurrent = current;
this.writeCount = dbufCount;
this.writeRun = run;
return true; /* more blocks to come */
};
/* Undo burrows-wheeler transform on intermediate buffer to produce output.
If start_bunzip was initialized with out_fd=-1, then up to len bytes of
data are written to outbuf. Return value is number of bytes written or
error (all errors are negative numbers). If out_fd!=-1, outbuf and len
are ignored, data is written to out_fd and return is RETVAL_OK or error.
*/
Bunzip.prototype._read_bunzip = function(outputBuffer, len) {
var copies, previous, outbyte;
/* james@jamestaylor.org: writeCount goes to -1 when the buffer is fully
decoded, which results in this returning RETVAL_LAST_BLOCK, also
equal to -1... Confusing, I'm returning 0 here to indicate no
bytes written into the buffer */
if (this.writeCount < 0) { return 0; }
var dbuf = this.dbuf, pos = this.writePos, current = this.writeCurrent;
var dbufCount = this.writeCount; this.outputsize;
var run = this.writeRun;
while (dbufCount) {
dbufCount--;
previous = current;
pos = dbuf[pos];
current = pos & 0xff;
pos >>= 8;
if (run++ === 3){
copies = current;
outbyte = previous;
current = -1;
} else {
copies = 1;
outbyte = current;
}
this.blockCRC.updateCRCRun(outbyte, copies);
while (copies--) {
this.outputStream.writeByte(outbyte);
this.nextoutput++;
}
if (current != previous)
run = 0;
}
this.writeCount = dbufCount;
// check CRC
if (this.blockCRC.getCRC() !== this.targetBlockCRC) {
_throw(Err.DATA_ERROR, "Bad block CRC "+
"(got "+this.blockCRC.getCRC().toString(16)+
" expected "+this.targetBlockCRC.toString(16)+")");
}
return this.nextoutput;
};
var coerceInputStream = function(input) {
if ('readByte' in input) { return input; }
var inputStream = new stream();
inputStream.pos = 0;
inputStream.readByte = function() { return input[this.pos++]; };
inputStream.seek = function(pos) { this.pos = pos; };
inputStream.eof = function() { return this.pos >= input.length; };
return inputStream;
};
var coerceOutputStream = function(output) {
var outputStream = new stream();
var resizeOk = true;
if (output) {
if (typeof(output)==='number') {
outputStream.buffer = new Uint8Array(output);
resizeOk = false;
} else if ('writeByte' in output) {
return output;
} else {
outputStream.buffer = output;
resizeOk = false;
}
} else {
outputStream.buffer = new Uint8Array(16384);
}
outputStream.pos = 0;
outputStream.writeByte = function(_byte) {
if (resizeOk && this.pos >= this.buffer.length) {
var newBuffer = new Uint8Array(this.buffer.length*2);
newBuffer.set(this.buffer);
this.buffer = newBuffer;
}
this.buffer[this.pos++] = _byte;
};
outputStream.getBuffer = function() {
// trim buffer
if (this.pos !== this.buffer.length) {
if (!resizeOk)
throw new TypeError('outputsize does not match decoded input');
var newBuffer = new Uint8Array(this.pos);
newBuffer.set(this.buffer.subarray(0, this.pos));
this.buffer = newBuffer;
}
return this.buffer;
};
outputStream._coerced = true;
return outputStream;
};
/* Static helper functions */
// 'input' can be a stream or a buffer
// 'output' can be a stream or a buffer or a number (buffer size)
const decode$2 = function(input, output, multistream) {
// make a stream from a buffer, if necessary
var inputStream = coerceInputStream(input);
var outputStream = coerceOutputStream(output);
var bz = new Bunzip(inputStream, outputStream);
while (true) {
if ('eof' in inputStream && inputStream.eof()) break;
if (bz._init_block()) {
bz._read_bunzip();
} else {
var targetStreamCRC = bz.reader.read(32) >>> 0; // (convert to unsigned)
if (targetStreamCRC !== bz.streamCRC) {
_throw(Err.DATA_ERROR, "Bad stream CRC "+
"(got "+bz.streamCRC.toString(16)+
" expected "+targetStreamCRC.toString(16)+")");
}
if (multistream &&
'eof' in inputStream &&
!inputStream.eof()) {
// note that start_bunzip will also resync the bit reader to next byte
bz._start_bunzip(inputStream, outputStream);
} else break;
}
}
if ('getBuffer' in outputStream)
return outputStream.getBuffer();
};
const decodeBlock = function(input, pos, output) {
// make a stream from a buffer, if necessary
var inputStream = coerceInputStream(input);
var outputStream = coerceOutputStream(output);
var bz = new Bunzip(inputStream, outputStream);
bz.reader.seek(pos);
/* Fill the decode buffer for the block */
var moreBlocks = bz._get_next_block();
if (moreBlocks) {
/* Init the CRC for writing */
bz.blockCRC = new crc32$1();
/* Zero this so the current byte from before the seek is not written */
bz.writeCopies = 0;
/* Decompress the block and write to stdout */
bz._read_bunzip();
// XXX keep writing?
}
if ('getBuffer' in outputStream)
return outputStream.getBuffer();
};
/* Reads bzip2 file from stream or buffer `input`, and invoke
* `callback(position, size)` once for each bzip2 block,
* where position gives the starting position (in *bits*)
* and size gives uncompressed size of the block (in *bytes*). */
const table = function(input, callback, multistream) {
// make a stream from a buffer, if necessary
var inputStream = new stream();
inputStream.delegate = coerceInputStream(input);
inputStream.pos = 0;
inputStream.readByte = function() {
this.pos++;
return this.delegate.readByte();
};
if (inputStream.delegate.eof) {
inputStream.eof = inputStream.delegate.eof.bind(inputStream.delegate);
}
var outputStream = new stream();
outputStream.pos = 0;
outputStream.writeByte = function() { this.pos++; };
var bz = new Bunzip(inputStream, outputStream);
var blockSize = bz.dbufSize;
while (true) {
if ('eof' in inputStream && inputStream.eof()) break;
var position = inputStream.pos*8 + bz.reader.bitOffset;
if (bz.reader.hasByte) { position -= 8; }
if (bz._init_block()) {
var start = outputStream.pos;
bz._read_bunzip();
callback(position, outputStream.pos - start);
} else {
bz.reader.read(32); // (but we ignore the crc)
if (multistream &&
'eof' in inputStream &&
!inputStream.eof()) {
// note that start_bunzip will also resync the bit reader to next byte
bz._start_bunzip(inputStream, outputStream);
console.assert(bz.dbufSize === blockSize,
"shouldn't change block size within multistream file");
} else break;
}
}
};
var lib = {
Bunzip,
Stream: stream,
Err,
decode: decode$2,
decodeBlock,
table
};
var lib_4 = lib.decode;
// GPG4Browsers - An OpenPGP implementation in javascript
/**
* Implementation of the Literal Data Packet (Tag 11)
*
* {@link https://tools.ietf.org/html/rfc4880#section-5.9|RFC4880 5.9}:
* A Literal Data packet contains the body of a message; data that is not to be
* further interpreted.
*/
class LiteralDataPacket {
static get tag() {
return enums.packet.literalData;
}
/**
* @param {Date} date - The creation date of the literal package
*/
constructor(date = new Date()) {
this.format = enums.literal.utf8; // default format for literal data packets
this.date = util.normalizeDate(date);
this.text = null; // textual data representation
this.data = null; // literal data representation
this.filename = '';
}
/**
* Set the packet data to a javascript native string, end of line
* will be normalized to \r\n and by default text is converted to UTF8
* @param {String | ReadableStream} text - Any native javascript string
* @param {enums.literal} [format] - The format of the string of bytes
*/
setText(text, format = enums.literal.utf8) {
this.format = format;
this.text = text;
this.data = null;
}
/**
* Returns literal data packets as native JavaScript string
* with normalized end of line to \n
* @param {Boolean} [clone] - Whether to return a clone so that getBytes/getText can be called again
* @returns {String | ReadableStream} Literal data as text.
*/
getText(clone = false) {
if (this.text === null || util.isStream(this.text)) { // Assume that this.text has been read
this.text = util.decodeUTF8(util.nativeEOL(this.getBytes(clone)));
}
return this.text;
}
/**
* Set the packet data to value represented by the provided string of bytes.
* @param {Uint8Array | ReadableStream} bytes - The string of bytes
* @param {enums.literal} format - The format of the string of bytes
*/
setBytes(bytes, format) {
this.format = format;
this.data = bytes;
this.text = null;
}
/**
* Get the byte sequence representing the literal packet data
* @param {Boolean} [clone] - Whether to return a clone so that getBytes/getText can be called again
* @returns {Uint8Array | ReadableStream} A sequence of bytes.
*/
getBytes(clone = false) {
if (this.data === null) {
// encode UTF8 and normalize EOL to \r\n
this.data = util.canonicalizeEOL(util.encodeUTF8(this.text));
}
if (clone) {
return passiveClone(this.data);
}
return this.data;
}
/**
* Sets the filename of the literal packet data
* @param {String} filename - Any native javascript string
*/
setFilename(filename) {
this.filename = filename;
}
/**
* Get the filename of the literal packet data
* @returns {String} Filename.
*/
getFilename() {
return this.filename;
}
/**
* Parsing function for a literal data packet (tag 11).
*
* @param {Uint8Array | ReadableStream} input - Payload of a tag 11 packet
* @returns {Promise} Object representation.
* @async
*/
async read(bytes) {
await parse(bytes, async reader => {
// - A one-octet field that describes how the data is formatted.
const format = await reader.readByte(); // enums.literal
const filename_len = await reader.readByte();
this.filename = util.decodeUTF8(await reader.readBytes(filename_len));
this.date = util.readDate(await reader.readBytes(4));
let data = reader.remainder();
if (isArrayStream(data)) data = await readToEnd(data);
this.setBytes(data, format);
});
}
/**
* Creates a Uint8Array representation of the packet, excluding the data
*
* @returns {Uint8Array} Uint8Array representation of the packet.
*/
writeHeader() {
const filename = util.encodeUTF8(this.filename);
const filename_length = new Uint8Array([filename.length]);
const format = new Uint8Array([this.format]);
const date = util.writeDate(this.date);
return util.concatUint8Array([format, filename_length, filename, date]);
}
/**
* Creates a Uint8Array representation of the packet
*
* @returns {Uint8Array | ReadableStream} Uint8Array representation of the packet.
*/
write() {
const header = this.writeHeader();
const data = this.getBytes();
return util.concat([header, data]);
}
}
// GPG4Browsers - An OpenPGP implementation in javascript
// Symbol to store cryptographic validity of the signature, to avoid recomputing multiple times on verification.
const verified = Symbol('verified');
// GPG puts the Issuer and Signature subpackets in the unhashed area.
// Tampering with those invalidates the signature, so we still trust them and parse them.
// All other unhashed subpackets are ignored.
const allowedUnhashedSubpackets = new Set([
enums.signatureSubpacket.issuer,
enums.signatureSubpacket.issuerFingerprint,
enums.signatureSubpacket.embeddedSignature
]);
/**
* Implementation of the Signature Packet (Tag 2)
*
* {@link https://tools.ietf.org/html/rfc4880#section-5.2|RFC4480 5.2}:
* A Signature packet describes a binding between some public key and
* some data. The most common signatures are a signature of a file or a
* block of text, and a signature that is a certification of a User ID.
*/
class SignaturePacket {
static get tag() {
return enums.packet.signature;
}
constructor() {
this.version = null;
/** @type {enums.signature} */
this.signatureType = null;
/** @type {enums.hash} */
this.hashAlgorithm = null;
/** @type {enums.publicKey} */
this.publicKeyAlgorithm = null;
this.signatureData = null;
this.unhashedSubpackets = [];
this.signedHashValue = null;
this.created = null;
this.signatureExpirationTime = null;
this.signatureNeverExpires = true;
this.exportable = null;
this.trustLevel = null;
this.trustAmount = null;
this.regularExpression = null;
this.revocable = null;
this.keyExpirationTime = null;
this.keyNeverExpires = null;
this.preferredSymmetricAlgorithms = null;
this.revocationKeyClass = null;
this.revocationKeyAlgorithm = null;
this.revocationKeyFingerprint = null;
this.issuerKeyID = new KeyID();
this.rawNotations = [];
this.notations = {};
this.preferredHashAlgorithms = null;
this.preferredCompressionAlgorithms = null;
this.keyServerPreferences = null;
this.preferredKeyServer = null;
this.isPrimaryUserID = null;
this.policyURI = null;
this.keyFlags = null;
this.signersUserID = null;
this.reasonForRevocationFlag = null;
this.reasonForRevocationString = null;
this.features = null;
this.signatureTargetPublicKeyAlgorithm = null;
this.signatureTargetHashAlgorithm = null;
this.signatureTargetHash = null;
this.embeddedSignature = null;
this.issuerKeyVersion = null;
this.issuerFingerprint = null;
this.preferredAEADAlgorithms = null;
this.revoked = null;
this[verified] = null;
}
/**
* parsing function for a signature packet (tag 2).
* @param {String} bytes - Payload of a tag 2 packet
* @returns {SignaturePacket} Object representation.
*/
read(bytes) {
let i = 0;
this.version = bytes[i++];
if (this.version !== 4 && this.version !== 5) {
throw new UnsupportedError(`Version ${this.version} of the signature packet is unsupported.`);
}
this.signatureType = bytes[i++];
this.publicKeyAlgorithm = bytes[i++];
this.hashAlgorithm = bytes[i++];
// hashed subpackets
i += this.readSubPackets(bytes.subarray(i, bytes.length), true);
if (!this.created) {
throw new Error('Missing signature creation time subpacket.');
}
// A V4 signature hashes the packet body
// starting from its first field, the version number, through the end
// of the hashed subpacket data. Thus, the fields hashed are the
// signature version, the signature type, the public-key algorithm, the
// hash algorithm, the hashed subpacket length, and the hashed
// subpacket body.
this.signatureData = bytes.subarray(0, i);
// unhashed subpackets
i += this.readSubPackets(bytes.subarray(i, bytes.length), false);
// Two-octet field holding left 16 bits of signed hash value.
this.signedHashValue = bytes.subarray(i, i + 2);
i += 2;
this.params = mod.signature.parseSignatureParams(this.publicKeyAlgorithm, bytes.subarray(i, bytes.length));
}
/**
* @returns {Uint8Array | ReadableStream}
*/
writeParams() {
if (this.params instanceof Promise) {
return fromAsync(
async () => mod.serializeParams(this.publicKeyAlgorithm, await this.params)
);
}
return mod.serializeParams(this.publicKeyAlgorithm, this.params);
}
write() {
const arr = [];
arr.push(this.signatureData);
arr.push(this.writeUnhashedSubPackets());
arr.push(this.signedHashValue);
arr.push(this.writeParams());
return util.concat(arr);
}
/**
* Signs provided data. This needs to be done prior to serialization.
* @param {SecretKeyPacket} key - Private key used to sign the message.
* @param {Object} data - Contains packets to be signed.
* @param {Date} [date] - The signature creation time.
* @param {Boolean} [detached] - Whether to create a detached signature
* @throws {Error} if signing failed
* @async
*/
async sign(key, data, date = new Date(), detached = false) {
if (key.version === 5) {
this.version = 5;
} else {
this.version = 4;
}
const arr = [new Uint8Array([this.version, this.signatureType, this.publicKeyAlgorithm, this.hashAlgorithm])];
this.created = util.normalizeDate(date);
this.issuerKeyVersion = key.version;
this.issuerFingerprint = key.getFingerprintBytes();
this.issuerKeyID = key.getKeyID();
// Add hashed subpackets
arr.push(this.writeHashedSubPackets());
// Remove unhashed subpackets, in case some allowed unhashed
// subpackets existed, in order not to duplicate them (in both
// the hashed and unhashed subpackets) when re-signing.
this.unhashedSubpackets = [];
this.signatureData = util.concat(arr);
const toHash = this.toHash(this.signatureType, data, detached);
const hash = await this.hash(this.signatureType, data, toHash, detached);
this.signedHashValue = slice(clone(hash), 0, 2);
const signed = async () => mod.signature.sign(
this.publicKeyAlgorithm, this.hashAlgorithm, key.publicParams, key.privateParams, toHash, await readToEnd(hash)
);
if (util.isStream(hash)) {
this.params = signed();
} else {
this.params = await signed();
// Store the fact that this signature is valid, e.g. for when we call `await
// getLatestValidSignature(this.revocationSignatures, key, data)` later.
// Note that this only holds up if the key and data passed to verify are the
// same as the ones passed to sign.
this[verified] = true;
}
}
/**
* Creates Uint8Array of bytes of all subpacket data except Issuer and Embedded Signature subpackets
* @returns {Uint8Array} Subpacket data.
*/
writeHashedSubPackets() {
const sub = enums.signatureSubpacket;
const arr = [];
let bytes;
if (this.created === null) {
throw new Error('Missing signature creation time');
}
arr.push(writeSubPacket(sub.signatureCreationTime, true, util.writeDate(this.created)));
if (this.signatureExpirationTime !== null) {
arr.push(writeSubPacket(sub.signatureExpirationTime, true, util.writeNumber(this.signatureExpirationTime, 4)));
}
if (this.exportable !== null) {
arr.push(writeSubPacket(sub.exportableCertification, true, new Uint8Array([this.exportable ? 1 : 0])));
}
if (this.trustLevel !== null) {
bytes = new Uint8Array([this.trustLevel, this.trustAmount]);
arr.push(writeSubPacket(sub.trustSignature, true, bytes));
}
if (this.regularExpression !== null) {
arr.push(writeSubPacket(sub.regularExpression, true, this.regularExpression));
}
if (this.revocable !== null) {
arr.push(writeSubPacket(sub.revocable, true, new Uint8Array([this.revocable ? 1 : 0])));
}
if (this.keyExpirationTime !== null) {
arr.push(writeSubPacket(sub.keyExpirationTime, true, util.writeNumber(this.keyExpirationTime, 4)));
}
if (this.preferredSymmetricAlgorithms !== null) {
bytes = util.stringToUint8Array(util.uint8ArrayToString(this.preferredSymmetricAlgorithms));
arr.push(writeSubPacket(sub.preferredSymmetricAlgorithms, false, bytes));
}
if (this.revocationKeyClass !== null) {
bytes = new Uint8Array([this.revocationKeyClass, this.revocationKeyAlgorithm]);
bytes = util.concat([bytes, this.revocationKeyFingerprint]);
arr.push(writeSubPacket(sub.revocationKey, false, bytes));
}
if (!this.issuerKeyID.isNull() && this.issuerKeyVersion !== 5) {
// If the version of [the] key is greater than 4, this subpacket
// MUST NOT be included in the signature.
arr.push(writeSubPacket(sub.issuer, true, this.issuerKeyID.write()));
}
this.rawNotations.forEach(({ name, value, humanReadable, critical }) => {
bytes = [new Uint8Array([humanReadable ? 0x80 : 0, 0, 0, 0])];
const encodedName = util.encodeUTF8(name);
// 2 octets of name length
bytes.push(util.writeNumber(encodedName.length, 2));
// 2 octets of value length
bytes.push(util.writeNumber(value.length, 2));
bytes.push(encodedName);
bytes.push(value);
bytes = util.concat(bytes);
arr.push(writeSubPacket(sub.notationData, critical, bytes));
});
if (this.preferredHashAlgorithms !== null) {
bytes = util.stringToUint8Array(util.uint8ArrayToString(this.preferredHashAlgorithms));
arr.push(writeSubPacket(sub.preferredHashAlgorithms, false, bytes));
}
if (this.preferredCompressionAlgorithms !== null) {
bytes = util.stringToUint8Array(util.uint8ArrayToString(this.preferredCompressionAlgorithms));
arr.push(writeSubPacket(sub.preferredCompressionAlgorithms, false, bytes));
}
if (this.keyServerPreferences !== null) {
bytes = util.stringToUint8Array(util.uint8ArrayToString(this.keyServerPreferences));
arr.push(writeSubPacket(sub.keyServerPreferences, false, bytes));
}
if (this.preferredKeyServer !== null) {
arr.push(writeSubPacket(sub.preferredKeyServer, false, util.encodeUTF8(this.preferredKeyServer)));
}
if (this.isPrimaryUserID !== null) {
arr.push(writeSubPacket(sub.primaryUserID, false, new Uint8Array([this.isPrimaryUserID ? 1 : 0])));
}
if (this.policyURI !== null) {
arr.push(writeSubPacket(sub.policyURI, false, util.encodeUTF8(this.policyURI)));
}
if (this.keyFlags !== null) {
bytes = util.stringToUint8Array(util.uint8ArrayToString(this.keyFlags));
arr.push(writeSubPacket(sub.keyFlags, true, bytes));
}
if (this.signersUserID !== null) {
arr.push(writeSubPacket(sub.signersUserID, false, util.encodeUTF8(this.signersUserID)));
}
if (this.reasonForRevocationFlag !== null) {
bytes = util.stringToUint8Array(String.fromCharCode(this.reasonForRevocationFlag) + this.reasonForRevocationString);
arr.push(writeSubPacket(sub.reasonForRevocation, true, bytes));
}
if (this.features !== null) {
bytes = util.stringToUint8Array(util.uint8ArrayToString(this.features));
arr.push(writeSubPacket(sub.features, false, bytes));
}
if (this.signatureTargetPublicKeyAlgorithm !== null) {
bytes = [new Uint8Array([this.signatureTargetPublicKeyAlgorithm, this.signatureTargetHashAlgorithm])];
bytes.push(util.stringToUint8Array(this.signatureTargetHash));
bytes = util.concat(bytes);
arr.push(writeSubPacket(sub.signatureTarget, true, bytes));
}
if (this.embeddedSignature !== null) {
arr.push(writeSubPacket(sub.embeddedSignature, true, this.embeddedSignature.write()));
}
if (this.issuerFingerprint !== null) {
bytes = [new Uint8Array([this.issuerKeyVersion]), this.issuerFingerprint];
bytes = util.concat(bytes);
arr.push(writeSubPacket(sub.issuerFingerprint, this.version === 5, bytes));
}
if (this.preferredAEADAlgorithms !== null) {
bytes = util.stringToUint8Array(util.uint8ArrayToString(this.preferredAEADAlgorithms));
arr.push(writeSubPacket(sub.preferredAEADAlgorithms, false, bytes));
}
const result = util.concat(arr);
const length = util.writeNumber(result.length, 2);
return util.concat([length, result]);
}
/**
* Creates an Uint8Array containing the unhashed subpackets
* @returns {Uint8Array} Subpacket data.
*/
writeUnhashedSubPackets() {
const arr = [];
this.unhashedSubpackets.forEach(data => {
arr.push(writeSimpleLength(data.length));
arr.push(data);
});
const result = util.concat(arr);
const length = util.writeNumber(result.length, 2);
return util.concat([length, result]);
}
// V4 signature sub packets
readSubPacket(bytes, hashed = true) {
let mypos = 0;
// The leftmost bit denotes a "critical" packet
const critical = !!(bytes[mypos] & 0x80);
const type = bytes[mypos] & 0x7F;
if (!hashed) {
this.unhashedSubpackets.push(bytes.subarray(mypos, bytes.length));
if (!allowedUnhashedSubpackets.has(type)) {
return;
}
}
mypos++;
// subpacket type
switch (type) {
case enums.signatureSubpacket.signatureCreationTime:
// Signature Creation Time
this.created = util.readDate(bytes.subarray(mypos, bytes.length));
break;
case enums.signatureSubpacket.signatureExpirationTime: {
// Signature Expiration Time in seconds
const seconds = util.readNumber(bytes.subarray(mypos, bytes.length));
this.signatureNeverExpires = seconds === 0;
this.signatureExpirationTime = seconds;
break;
}
case enums.signatureSubpacket.exportableCertification:
// Exportable Certification
this.exportable = bytes[mypos++] === 1;
break;
case enums.signatureSubpacket.trustSignature:
// Trust Signature
this.trustLevel = bytes[mypos++];
this.trustAmount = bytes[mypos++];
break;
case enums.signatureSubpacket.regularExpression:
// Regular Expression
this.regularExpression = bytes[mypos];
break;
case enums.signatureSubpacket.revocable:
// Revocable
this.revocable = bytes[mypos++] === 1;
break;
case enums.signatureSubpacket.keyExpirationTime: {
// Key Expiration Time in seconds
const seconds = util.readNumber(bytes.subarray(mypos, bytes.length));
this.keyExpirationTime = seconds;
this.keyNeverExpires = seconds === 0;
break;
}
case enums.signatureSubpacket.preferredSymmetricAlgorithms:
// Preferred Symmetric Algorithms
this.preferredSymmetricAlgorithms = [...bytes.subarray(mypos, bytes.length)];
break;
case enums.signatureSubpacket.revocationKey:
// Revocation Key
// (1 octet of class, 1 octet of public-key algorithm ID, 20
// octets of
// fingerprint)
this.revocationKeyClass = bytes[mypos++];
this.revocationKeyAlgorithm = bytes[mypos++];
this.revocationKeyFingerprint = bytes.subarray(mypos, mypos + 20);
break;
case enums.signatureSubpacket.issuer:
// Issuer
this.issuerKeyID.read(bytes.subarray(mypos, bytes.length));
break;
case enums.signatureSubpacket.notationData: {
// Notation Data
const humanReadable = !!(bytes[mypos] & 0x80);
// We extract key/value tuple from the byte stream.
mypos += 4;
const m = util.readNumber(bytes.subarray(mypos, mypos + 2));
mypos += 2;
const n = util.readNumber(bytes.subarray(mypos, mypos + 2));
mypos += 2;
const name = util.decodeUTF8(bytes.subarray(mypos, mypos + m));
const value = bytes.subarray(mypos + m, mypos + m + n);
this.rawNotations.push({ name, humanReadable, value, critical });
if (humanReadable) {
this.notations[name] = util.decodeUTF8(value);
}
break;
}
case enums.signatureSubpacket.preferredHashAlgorithms:
// Preferred Hash Algorithms
this.preferredHashAlgorithms = [...bytes.subarray(mypos, bytes.length)];
break;
case enums.signatureSubpacket.preferredCompressionAlgorithms:
// Preferred Compression Algorithms
this.preferredCompressionAlgorithms = [...bytes.subarray(mypos, bytes.length)];
break;
case enums.signatureSubpacket.keyServerPreferences:
// Key Server Preferences
this.keyServerPreferences = [...bytes.subarray(mypos, bytes.length)];
break;
case enums.signatureSubpacket.preferredKeyServer:
// Preferred Key Server
this.preferredKeyServer = util.decodeUTF8(bytes.subarray(mypos, bytes.length));
break;
case enums.signatureSubpacket.primaryUserID:
// Primary User ID
this.isPrimaryUserID = bytes[mypos++] !== 0;
break;
case enums.signatureSubpacket.policyURI:
// Policy URI
this.policyURI = util.decodeUTF8(bytes.subarray(mypos, bytes.length));
break;
case enums.signatureSubpacket.keyFlags:
// Key Flags
this.keyFlags = [...bytes.subarray(mypos, bytes.length)];
break;
case enums.signatureSubpacket.signersUserID:
// Signer's User ID
this.signersUserID = util.decodeUTF8(bytes.subarray(mypos, bytes.length));
break;
case enums.signatureSubpacket.reasonForRevocation:
// Reason for Revocation
this.reasonForRevocationFlag = bytes[mypos++];
this.reasonForRevocationString = util.decodeUTF8(bytes.subarray(mypos, bytes.length));
break;
case enums.signatureSubpacket.features:
// Features
this.features = [...bytes.subarray(mypos, bytes.length)];
break;
case enums.signatureSubpacket.signatureTarget: {
// Signature Target
// (1 octet public-key algorithm, 1 octet hash algorithm, N octets hash)
this.signatureTargetPublicKeyAlgorithm = bytes[mypos++];
this.signatureTargetHashAlgorithm = bytes[mypos++];
const len = mod.getHashByteLength(this.signatureTargetHashAlgorithm);
this.signatureTargetHash = util.uint8ArrayToString(bytes.subarray(mypos, mypos + len));
break;
}
case enums.signatureSubpacket.embeddedSignature:
// Embedded Signature
this.embeddedSignature = new SignaturePacket();
this.embeddedSignature.read(bytes.subarray(mypos, bytes.length));
break;
case enums.signatureSubpacket.issuerFingerprint:
// Issuer Fingerprint
this.issuerKeyVersion = bytes[mypos++];
this.issuerFingerprint = bytes.subarray(mypos, bytes.length);
if (this.issuerKeyVersion === 5) {
this.issuerKeyID.read(this.issuerFingerprint);
} else {
this.issuerKeyID.read(this.issuerFingerprint.subarray(-8));
}
break;
case enums.signatureSubpacket.preferredAEADAlgorithms:
// Preferred AEAD Algorithms
this.preferredAEADAlgorithms = [...bytes.subarray(mypos, bytes.length)];
break;
default: {
const err = new Error(`Unknown signature subpacket type ${type}`);
if (critical) {
throw err;
} else {
util.printDebug(err);
}
}
}
}
readSubPackets(bytes, trusted = true, config) {
// Two-octet scalar octet count for following subpacket data.
const subpacketLength = util.readNumber(bytes.subarray(0, 2));
let i = 2;
// subpacket data set (zero or more subpackets)
while (i < 2 + subpacketLength) {
const len = readSimpleLength(bytes.subarray(i, bytes.length));
i += len.offset;
this.readSubPacket(bytes.subarray(i, i + len.len), trusted, config);
i += len.len;
}
return i;
}
// Produces data to produce signature on
toSign(type, data) {
const t = enums.signature;
switch (type) {
case t.binary:
if (data.text !== null) {
return util.encodeUTF8(data.getText(true));
}
return data.getBytes(true);
case t.text: {
const bytes = data.getBytes(true);
// normalize EOL to \r\n
return util.canonicalizeEOL(bytes);
}
case t.standalone:
return new Uint8Array(0);
case t.certGeneric:
case t.certPersona:
case t.certCasual:
case t.certPositive:
case t.certRevocation: {
let packet;
let tag;
if (data.userID) {
tag = 0xB4;
packet = data.userID;
} else if (data.userAttribute) {
tag = 0xD1;
packet = data.userAttribute;
} else {
throw new Error('Either a userID or userAttribute packet needs to be ' +
'supplied for certification.');
}
const bytes = packet.write();
return util.concat([this.toSign(t.key, data),
new Uint8Array([tag]),
util.writeNumber(bytes.length, 4),
bytes]);
}
case t.subkeyBinding:
case t.subkeyRevocation:
case t.keyBinding:
return util.concat([this.toSign(t.key, data), this.toSign(t.key, {
key: data.bind
})]);
case t.key:
if (data.key === undefined) {
throw new Error('Key packet is required for this signature.');
}
return data.key.writeForHash(this.version);
case t.keyRevocation:
return this.toSign(t.key, data);
case t.timestamp:
return new Uint8Array(0);
case t.thirdParty:
throw new Error('Not implemented');
default:
throw new Error('Unknown signature type.');
}
}
calculateTrailer(data, detached) {
let length = 0;
return transform(clone(this.signatureData), value => {
length += value.length;
}, () => {
const arr = [];
if (this.version === 5 && (this.signatureType === enums.signature.binary || this.signatureType === enums.signature.text)) {
if (detached) {
arr.push(new Uint8Array(6));
} else {
arr.push(data.writeHeader());
}
}
arr.push(new Uint8Array([this.version, 0xFF]));
if (this.version === 5) {
arr.push(new Uint8Array(4));
}
arr.push(util.writeNumber(length, 4));
// For v5, this should really be writeNumber(length, 8) rather than the
// hardcoded 4 zero bytes above
return util.concat(arr);
});
}
toHash(signatureType, data, detached = false) {
const bytes = this.toSign(signatureType, data);
return util.concat([bytes, this.signatureData, this.calculateTrailer(data, detached)]);
}
async hash(signatureType, data, toHash, detached = false) {
if (!toHash) toHash = this.toHash(signatureType, data, detached);
return mod.hash.digest(this.hashAlgorithm, toHash);
}
/**
* verifies the signature packet. Note: not all signature types are implemented
* @param {PublicSubkeyPacket|PublicKeyPacket|
* SecretSubkeyPacket|SecretKeyPacket} key - the public key to verify the signature
* @param {module:enums.signature} signatureType - Expected signature type
* @param {Uint8Array|Object} data - Data which on the signature applies
* @param {Date} [date] - Use the given date instead of the current time to check for signature validity and expiration
* @param {Boolean} [detached] - Whether to verify a detached signature
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @throws {Error} if signature validation failed
* @async
*/
async verify(key, signatureType, data, date = new Date(), detached = false, config$1 = config) {
if (!this.issuerKeyID.equals(key.getKeyID())) {
throw new Error('Signature was not issued by the given public key');
}
if (this.publicKeyAlgorithm !== key.algorithm) {
throw new Error('Public key algorithm used to sign signature does not match issuer key algorithm.');
}
const isMessageSignature = signatureType === enums.signature.binary || signatureType === enums.signature.text;
// Cryptographic validity is cached after one successful verification.
// However, for message signatures, we always re-verify, since the passed `data` can change
const skipVerify = this[verified] && !isMessageSignature;
if (!skipVerify) {
let toHash;
let hash;
if (this.hashed) {
hash = await this.hashed;
} else {
toHash = this.toHash(signatureType, data, detached);
hash = await this.hash(signatureType, data, toHash);
}
hash = await readToEnd(hash);
if (this.signedHashValue[0] !== hash[0] ||
this.signedHashValue[1] !== hash[1]) {
throw new Error('Signed digest did not match');
}
this.params = await this.params;
this[verified] = await mod.signature.verify(
this.publicKeyAlgorithm, this.hashAlgorithm, this.params, key.publicParams,
toHash, hash
);
if (!this[verified]) {
throw new Error('Signature verification failed');
}
}
const normDate = util.normalizeDate(date);
if (normDate && this.created > normDate) {
throw new Error('Signature creation time is in the future');
}
if (normDate && normDate >= this.getExpirationTime()) {
throw new Error('Signature is expired');
}
if (config$1.rejectHashAlgorithms.has(this.hashAlgorithm)) {
throw new Error('Insecure hash algorithm: ' + enums.read(enums.hash, this.hashAlgorithm).toUpperCase());
}
if (config$1.rejectMessageHashAlgorithms.has(this.hashAlgorithm) &&
[enums.signature.binary, enums.signature.text].includes(this.signatureType)) {
throw new Error('Insecure message hash algorithm: ' + enums.read(enums.hash, this.hashAlgorithm).toUpperCase());
}
this.rawNotations.forEach(({ name, critical }) => {
if (critical && (config$1.knownNotations.indexOf(name) < 0)) {
throw new Error(`Unknown critical notation: ${name}`);
}
});
if (this.revocationKeyClass !== null) {
throw new Error('This key is intended to be revoked with an authorized key, which OpenPGP.js does not support.');
}
}
/**
* Verifies signature expiration date
* @param {Date} [date] - Use the given date for verification instead of the current time
* @returns {Boolean} True if expired.
*/
isExpired(date = new Date()) {
const normDate = util.normalizeDate(date);
if (normDate !== null) {
return !(this.created <= normDate && normDate < this.getExpirationTime());
}
return false;
}
/**
* Returns the expiration time of the signature or Infinity if signature does not expire
* @returns {Date | Infinity} Expiration time.
*/
getExpirationTime() {
return this.signatureNeverExpires ? Infinity : new Date(this.created.getTime() + this.signatureExpirationTime * 1000);
}
}
/**
* Creates a Uint8Array representation of a sub signature packet
* @see {@link https://tools.ietf.org/html/rfc4880#section-5.2.3.1|RFC4880 5.2.3.1}
* @see {@link https://tools.ietf.org/html/rfc4880#section-5.2.3.2|RFC4880 5.2.3.2}
* @param {Integer} type - Subpacket signature type.
* @param {Boolean} critical - Whether the subpacket should be critical.
* @param {String} data - Data to be included
* @returns {Uint8Array} The signature subpacket.
* @private
*/
function writeSubPacket(type, critical, data) {
const arr = [];
arr.push(writeSimpleLength(data.length + 1));
arr.push(new Uint8Array([(critical ? 0x80 : 0) | type]));
arr.push(data);
return util.concat(arr);
}
// GPG4Browsers - An OpenPGP implementation in javascript
const VERSION = 3;
/**
* Implementation of the One-Pass Signature Packets (Tag 4)
*
* {@link https://tools.ietf.org/html/rfc4880#section-5.4|RFC4880 5.4}:
* The One-Pass Signature packet precedes the signed data and contains
* enough information to allow the receiver to begin calculating any
* hashes needed to verify the signature. It allows the Signature
* packet to be placed at the end of the message, so that the signer
* can compute the entire signed message in one pass.
*/
class OnePassSignaturePacket {
static get tag() {
return enums.packet.onePassSignature;
}
constructor() {
/** A one-octet version number. The current version is 3. */
this.version = null;
/**
* A one-octet signature type.
* Signature types are described in
* {@link https://tools.ietf.org/html/rfc4880#section-5.2.1|RFC4880 Section 5.2.1}.
* @type {enums.signature}
*/
this.signatureType = null;
/**
* A one-octet number describing the hash algorithm used.
* @see {@link https://tools.ietf.org/html/rfc4880#section-9.4|RFC4880 9.4}
* @type {enums.hash}
*/
this.hashAlgorithm = null;
/**
* A one-octet number describing the public-key algorithm used.
* @see {@link https://tools.ietf.org/html/rfc4880#section-9.1|RFC4880 9.1}
* @type {enums.publicKey}
*/
this.publicKeyAlgorithm = null;
/** An eight-octet number holding the Key ID of the signing key. */
this.issuerKeyID = null;
/**
* A one-octet number holding a flag showing whether the signature is nested.
* A zero value indicates that the next packet is another One-Pass Signature packet
* that describes another signature to be applied to the same message data.
*/
this.flags = null;
}
/**
* parsing function for a one-pass signature packet (tag 4).
* @param {Uint8Array} bytes - Payload of a tag 4 packet
* @returns {OnePassSignaturePacket} Object representation.
*/
read(bytes) {
let mypos = 0;
// A one-octet version number. The current version is 3.
this.version = bytes[mypos++];
if (this.version !== VERSION) {
throw new UnsupportedError(`Version ${this.version} of the one-pass signature packet is unsupported.`);
}
// A one-octet signature type. Signature types are described in
// Section 5.2.1.
this.signatureType = bytes[mypos++];
// A one-octet number describing the hash algorithm used.
this.hashAlgorithm = bytes[mypos++];
// A one-octet number describing the public-key algorithm used.
this.publicKeyAlgorithm = bytes[mypos++];
// An eight-octet number holding the Key ID of the signing key.
this.issuerKeyID = new KeyID();
this.issuerKeyID.read(bytes.subarray(mypos, mypos + 8));
mypos += 8;
// A one-octet number holding a flag showing whether the signature
// is nested. A zero value indicates that the next packet is
// another One-Pass Signature packet that describes another
// signature to be applied to the same message data.
this.flags = bytes[mypos++];
return this;
}
/**
* creates a string representation of a one-pass signature packet
* @returns {Uint8Array} A Uint8Array representation of a one-pass signature packet.
*/
write() {
const start = new Uint8Array([VERSION, this.signatureType, this.hashAlgorithm, this.publicKeyAlgorithm]);
const end = new Uint8Array([this.flags]);
return util.concatUint8Array([start, this.issuerKeyID.write(), end]);
}
calculateTrailer(...args) {
return fromAsync(async () => SignaturePacket.prototype.calculateTrailer.apply(await this.correspondingSig, args));
}
async verify() {
const correspondingSig = await this.correspondingSig;
if (!correspondingSig || correspondingSig.constructor.tag !== enums.packet.signature) {
throw new Error('Corresponding signature packet missing');
}
if (
correspondingSig.signatureType !== this.signatureType ||
correspondingSig.hashAlgorithm !== this.hashAlgorithm ||
correspondingSig.publicKeyAlgorithm !== this.publicKeyAlgorithm ||
!correspondingSig.issuerKeyID.equals(this.issuerKeyID)
) {
throw new Error('Corresponding signature packet does not match one-pass signature packet');
}
correspondingSig.hashed = this.hashed;
return correspondingSig.verify.apply(correspondingSig, arguments);
}
}
OnePassSignaturePacket.prototype.hash = SignaturePacket.prototype.hash;
OnePassSignaturePacket.prototype.toHash = SignaturePacket.prototype.toHash;
OnePassSignaturePacket.prototype.toSign = SignaturePacket.prototype.toSign;
/**
* Instantiate a new packet given its tag
* @function newPacketFromTag
* @param {module:enums.packet} tag - Property value from {@link module:enums.packet}
* @param {Object} allowedPackets - mapping where keys are allowed packet tags, pointing to their Packet class
* @returns {Object} New packet object with type based on tag
* @throws {Error|UnsupportedError} for disallowed or unknown packets
*/
function newPacketFromTag(tag, allowedPackets) {
if (!allowedPackets[tag]) {
// distinguish between disallowed packets and unknown ones
let packetType;
try {
packetType = enums.read(enums.packet, tag);
} catch (e) {
throw new UnsupportedError(`Unknown packet type with tag: ${tag}`);
}
throw new Error(`Packet not allowed in this context: ${packetType}`);
}
return new allowedPackets[tag]();
}
/**
* This class represents a list of openpgp packets.
* Take care when iterating over it - the packets themselves
* are stored as numerical indices.
* @extends Array
*/
class PacketList extends Array {
/**
* Parses the given binary data and returns a list of packets.
* Equivalent to calling `read` on an empty PacketList instance.
* @param {Uint8Array | ReadableStream} bytes - binary data to parse
* @param {Object} allowedPackets - mapping where keys are allowed packet tags, pointing to their Packet class
* @param {Object} [config] - full configuration, defaults to openpgp.config
* @returns {PacketList} parsed list of packets
* @throws on parsing errors
* @async
*/
static async fromBinary(bytes, allowedPackets, config$1 = config) {
const packets = new PacketList();
await packets.read(bytes, allowedPackets, config$1);
return packets;
}
/**
* Reads a stream of binary data and interprets it as a list of packets.
* @param {Uint8Array | ReadableStream} bytes - binary data to parse
* @param {Object} allowedPackets - mapping where keys are allowed packet tags, pointing to their Packet class
* @param {Object} [config] - full configuration, defaults to openpgp.config
* @throws on parsing errors
* @async
*/
async read(bytes, allowedPackets, config$1 = config) {
if (config$1.additionalAllowedPackets.length) {
allowedPackets = { ...allowedPackets, ...util.constructAllowedPackets(config$1.additionalAllowedPackets) };
}
this.stream = transformPair(bytes, async (readable, writable) => {
const writer = getWriter(writable);
try {
while (true) {
await writer.ready;
const done = await readPackets(readable, async parsed => {
try {
if (parsed.tag === enums.packet.marker || parsed.tag === enums.packet.trust) {
// According to the spec, these packet types should be ignored and not cause parsing errors, even if not esplicitly allowed:
// - Marker packets MUST be ignored when received: https://github.com/openpgpjs/openpgpjs/issues/1145
// - Trust packets SHOULD be ignored outside of keyrings (unsupported): https://datatracker.ietf.org/doc/html/rfc4880#section-5.10
return;
}
const packet = newPacketFromTag(parsed.tag, allowedPackets);
packet.packets = new PacketList();
packet.fromStream = util.isStream(parsed.packet);
await packet.read(parsed.packet, config$1);
await writer.write(packet);
} catch (e) {
const throwUnsupportedError = !config$1.ignoreUnsupportedPackets && e instanceof UnsupportedError;
const throwMalformedError = !config$1.ignoreMalformedPackets && !(e instanceof UnsupportedError);
if (throwUnsupportedError || throwMalformedError || supportsStreaming(parsed.tag)) {
// The packets that support streaming are the ones that contain message data.
// Those are also the ones we want to be more strict about and throw on parse errors
// (since we likely cannot process the message without these packets anyway).
await writer.abort(e);
} else {
const unparsedPacket = new UnparseablePacket(parsed.tag, parsed.packet);
await writer.write(unparsedPacket);
}
util.printDebugError(e);
}
});
if (done) {
await writer.ready;
await writer.close();
return;
}
}
} catch (e) {
await writer.abort(e);
}
});
// Wait until first few packets have been read
const reader = getReader(this.stream);
while (true) {
const { done, value } = await reader.read();
if (!done) {
this.push(value);
} else {
this.stream = null;
}
if (done || supportsStreaming(value.constructor.tag)) {
break;
}
}
reader.releaseLock();
}
/**
* Creates a binary representation of openpgp objects contained within the
* class instance.
* @returns {Uint8Array} A Uint8Array containing valid openpgp packets.
*/
write() {
const arr = [];
for (let i = 0; i < this.length; i++) {
const tag = this[i] instanceof UnparseablePacket ? this[i].tag : this[i].constructor.tag;
const packetbytes = this[i].write();
if (util.isStream(packetbytes) && supportsStreaming(this[i].constructor.tag)) {
let buffer = [];
let bufferLength = 0;
const minLength = 512;
arr.push(writeTag(tag));
arr.push(transform(packetbytes, value => {
buffer.push(value);
bufferLength += value.length;
if (bufferLength >= minLength) {
const powerOf2 = Math.min(Math.log(bufferLength) / Math.LN2 | 0, 30);
const chunkSize = 2 ** powerOf2;
const bufferConcat = util.concat([writePartialLength(powerOf2)].concat(buffer));
buffer = [bufferConcat.subarray(1 + chunkSize)];
bufferLength = buffer[0].length;
return bufferConcat.subarray(0, 1 + chunkSize);
}
}, () => util.concat([writeSimpleLength(bufferLength)].concat(buffer))));
} else {
if (util.isStream(packetbytes)) {
let length = 0;
arr.push(transform(clone(packetbytes), value => {
length += value.length;
}, () => writeHeader(tag, length)));
} else {
arr.push(writeHeader(tag, packetbytes.length));
}
arr.push(packetbytes);
}
}
return util.concat(arr);
}
/**
* Creates a new PacketList with all packets matching the given tag(s)
* @param {...module:enums.packet} tags - packet tags to look for
* @returns {PacketList}
*/
filterByTag(...tags) {
const filtered = new PacketList();
const handle = tag => packetType => tag === packetType;
for (let i = 0; i < this.length; i++) {
if (tags.some(handle(this[i].constructor.tag))) {
filtered.push(this[i]);
}
}
return filtered;
}
/**
* Traverses packet list and returns first packet with matching tag
* @param {module:enums.packet} tag - The packet tag
* @returns {Packet|undefined}
*/
findPacket(tag) {
return this.find(packet => packet.constructor.tag === tag);
}
/**
* Find indices of packets with the given tag(s)
* @param {...module:enums.packet} tags - packet tags to look for
* @returns {Integer[]} packet indices
*/
indexOfTag(...tags) {
const tagIndex = [];
const that = this;
const handle = tag => packetType => tag === packetType;
for (let i = 0; i < this.length; i++) {
if (tags.some(handle(that[i].constructor.tag))) {
tagIndex.push(i);
}
}
return tagIndex;
}
}
// GPG4Browsers - An OpenPGP implementation in javascript
// A Compressed Data packet can contain the following packet types
const allowedPackets = /*#__PURE__*/ util.constructAllowedPackets([
LiteralDataPacket,
OnePassSignaturePacket,
SignaturePacket
]);
/**
* Implementation of the Compressed Data Packet (Tag 8)
*
* {@link https://tools.ietf.org/html/rfc4880#section-5.6|RFC4880 5.6}:
* The Compressed Data packet contains compressed data. Typically,
* this packet is found as the contents of an encrypted packet, or following
* a Signature or One-Pass Signature packet, and contains a literal data packet.
*/
class CompressedDataPacket {
static get tag() {
return enums.packet.compressedData;
}
/**
* @param {Object} [config] - Full configuration, defaults to openpgp.config
*/
constructor(config$1 = config) {
/**
* List of packets
* @type {PacketList}
*/
this.packets = null;
/**
* Compression algorithm
* @type {enums.compression}
*/
this.algorithm = config$1.preferredCompressionAlgorithm;
/**
* Compressed packet data
* @type {Uint8Array | ReadableStream}
*/
this.compressed = null;
/**
* zip/zlib compression level, between 1 and 9
*/
this.deflateLevel = config$1.deflateLevel;
}
/**
* Parsing function for the packet.
* @param {Uint8Array | ReadableStream} bytes - Payload of a tag 8 packet
* @param {Object} [config] - Full configuration, defaults to openpgp.config
*/
async read(bytes, config$1 = config) {
await parse(bytes, async reader => {
// One octet that gives the algorithm used to compress the packet.
this.algorithm = await reader.readByte();
// Compressed data, which makes up the remainder of the packet.
this.compressed = reader.remainder();
await this.decompress(config$1);
});
}
/**
* Return the compressed packet.
* @returns {Uint8Array | ReadableStream} Binary compressed packet.
*/
write() {
if (this.compressed === null) {
this.compress();
}
return util.concat([new Uint8Array([this.algorithm]), this.compressed]);
}
/**
* Decompression method for decompressing the compressed data
* read by read_packet
* @param {Object} [config] - Full configuration, defaults to openpgp.config
*/
async decompress(config$1 = config) {
const compressionName = enums.read(enums.compression, this.algorithm);
const decompressionFn = decompress_fns[compressionName];
if (!decompressionFn) {
throw new Error(`${compressionName} decompression not supported`);
}
this.packets = await PacketList.fromBinary(decompressionFn(this.compressed), allowedPackets, config$1);
}
/**
* Compress the packet data (member decompressedData)
*/
compress() {
const compressionName = enums.read(enums.compression, this.algorithm);
const compressionFn = compress_fns[compressionName];
if (!compressionFn) {
throw new Error(`${compressionName} compression not supported`);
}
this.compressed = compressionFn(this.packets.write(), this.deflateLevel);
}
}
//////////////////////////
// //
// Helper functions //
// //
//////////////////////////
const nodeZlib = util.getNodeZlib();
function uncompressed(data) {
return data;
}
function node_zlib(func, create, options = {}) {
return function (data) {
if (!util.isStream(data) || isArrayStream(data)) {
return fromAsync(() => readToEnd(data).then(data => {
return new Promise((resolve, reject) => {
func(data, options, (err, result) => {
if (err) return reject(err);
resolve(result);
});
});
}));
}
return nodeToWeb(webToNode(data).pipe(create(options)));
};
}
function pako_zlib(constructor, options = {}) {
return function(data) {
const obj = new constructor(options);
return transform(data, value => {
if (value.length) {
obj.push(value, Z_SYNC_FLUSH);
return obj.result;
}
}, () => {
if (constructor === Deflate) {
obj.push([], Z_FINISH);
return obj.result;
}
});
};
}
function bzip2(func) {
return function(data) {
return fromAsync(async () => func(await readToEnd(data)));
};
}
const compress_fns = nodeZlib ? {
zip: /*#__PURE__*/ (compressed, level) => node_zlib(nodeZlib.deflateRaw, nodeZlib.createDeflateRaw, { level })(compressed),
zlib: /*#__PURE__*/ (compressed, level) => node_zlib(nodeZlib.deflate, nodeZlib.createDeflate, { level })(compressed)
} : {
zip: /*#__PURE__*/ (compressed, level) => pako_zlib(Deflate, { raw: true, level })(compressed),
zlib: /*#__PURE__*/ (compressed, level) => pako_zlib(Deflate, { level })(compressed)
};
const decompress_fns = nodeZlib ? {
uncompressed: uncompressed,
zip: /*#__PURE__*/ node_zlib(nodeZlib.inflateRaw, nodeZlib.createInflateRaw),
zlib: /*#__PURE__*/ node_zlib(nodeZlib.inflate, nodeZlib.createInflate),
bzip2: /*#__PURE__*/ bzip2(lib_4)
} : {
uncompressed: uncompressed,
zip: /*#__PURE__*/ pako_zlib(Inflate, { raw: true }),
zlib: /*#__PURE__*/ pako_zlib(Inflate),
bzip2: /*#__PURE__*/ bzip2(lib_4)
};
// GPG4Browsers - An OpenPGP implementation in javascript
// A SEIP packet can contain the following packet types
const allowedPackets$1 = /*#__PURE__*/ util.constructAllowedPackets([
LiteralDataPacket,
CompressedDataPacket,
OnePassSignaturePacket,
SignaturePacket
]);
const VERSION$1 = 1; // A one-octet version number of the data packet.
/**
* Implementation of the Sym. Encrypted Integrity Protected Data Packet (Tag 18)
*
* {@link https://tools.ietf.org/html/rfc4880#section-5.13|RFC4880 5.13}:
* The Symmetrically Encrypted Integrity Protected Data packet is
* a variant of the Symmetrically Encrypted Data packet. It is a new feature
* created for OpenPGP that addresses the problem of detecting a modification to
* encrypted data. It is used in combination with a Modification Detection Code
* packet.
*/
class SymEncryptedIntegrityProtectedDataPacket {
static get tag() {
return enums.packet.symEncryptedIntegrityProtectedData;
}
constructor() {
this.version = VERSION$1;
this.encrypted = null;
this.packets = null;
}
async read(bytes) {
await parse(bytes, async reader => {
const version = await reader.readByte();
// - A one-octet version number. The only currently defined value is 1.
if (version !== VERSION$1) {
throw new UnsupportedError(`Version ${version} of the SEIP packet is unsupported.`);
}
// - Encrypted data, the output of the selected symmetric-key cipher
// operating in Cipher Feedback mode with shift amount equal to the
// block size of the cipher (CFB-n where n is the block size).
this.encrypted = reader.remainder();
});
}
write() {
return util.concat([new Uint8Array([VERSION$1]), this.encrypted]);
}
/**
* Encrypt the payload in the packet.
* @param {enums.symmetric} sessionKeyAlgorithm - The symmetric encryption algorithm to use
* @param {Uint8Array} key - The key of cipher blocksize length to be used
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise}
* @throws {Error} on encryption failure
* @async
*/
async encrypt(sessionKeyAlgorithm, key, config$1 = config) {
const { blockSize } = mod.getCipher(sessionKeyAlgorithm);
let bytes = this.packets.write();
if (isArrayStream(bytes)) bytes = await readToEnd(bytes);
const prefix = await mod.getPrefixRandom(sessionKeyAlgorithm);
const mdc = new Uint8Array([0xD3, 0x14]); // modification detection code packet
const tohash = util.concat([prefix, bytes, mdc]);
const hash = await mod.hash.sha1(passiveClone(tohash));
const plaintext = util.concat([tohash, hash]);
this.encrypted = await mod.mode.cfb.encrypt(sessionKeyAlgorithm, key, plaintext, new Uint8Array(blockSize), config$1);
return true;
}
/**
* Decrypts the encrypted data contained in the packet.
* @param {enums.symmetric} sessionKeyAlgorithm - The selected symmetric encryption algorithm to be used
* @param {Uint8Array} key - The key of cipher blocksize length to be used
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise}
* @throws {Error} on decryption failure
* @async
*/
async decrypt(sessionKeyAlgorithm, key, config$1 = config) {
const { blockSize } = mod.getCipher(sessionKeyAlgorithm);
let encrypted = clone(this.encrypted);
if (isArrayStream(encrypted)) encrypted = await readToEnd(encrypted);
const decrypted = await mod.mode.cfb.decrypt(sessionKeyAlgorithm, key, encrypted, new Uint8Array(blockSize));
// there must be a modification detection code packet as the
// last packet and everything gets hashed except the hash itself
const realHash = slice(passiveClone(decrypted), -20);
const tohash = slice(decrypted, 0, -20);
const verifyHash = Promise.all([
readToEnd(await mod.hash.sha1(passiveClone(tohash))),
readToEnd(realHash)
]).then(([hash, mdc]) => {
if (!util.equalsUint8Array(hash, mdc)) {
throw new Error('Modification detected.');
}
return new Uint8Array();
});
const bytes = slice(tohash, blockSize + 2); // Remove random prefix
let packetbytes = slice(bytes, 0, -2); // Remove MDC packet
packetbytes = concat([packetbytes, fromAsync(() => verifyHash)]);
if (!util.isStream(encrypted) || !config$1.allowUnauthenticatedStream) {
packetbytes = await readToEnd(packetbytes);
}
this.packets = await PacketList.fromBinary(packetbytes, allowedPackets$1, config$1);
return true;
}
}
// OpenPGP.js - An OpenPGP implementation in javascript
// An AEAD-encrypted Data packet can contain the following packet types
const allowedPackets$2 = /*#__PURE__*/ util.constructAllowedPackets([
LiteralDataPacket,
CompressedDataPacket,
OnePassSignaturePacket,
SignaturePacket
]);
const VERSION$2 = 1; // A one-octet version number of the data packet.
/**
* Implementation of the Symmetrically Encrypted Authenticated Encryption with
* Additional Data (AEAD) Protected Data Packet
*
* {@link https://tools.ietf.org/html/draft-ford-openpgp-format-00#section-2.1}:
* AEAD Protected Data Packet
*/
class AEADEncryptedDataPacket {
static get tag() {
return enums.packet.aeadEncryptedData;
}
constructor() {
this.version = VERSION$2;
/** @type {enums.symmetric} */
this.cipherAlgorithm = null;
/** @type {enums.aead} */
this.aeadAlgorithm = enums.aead.eax;
this.chunkSizeByte = null;
this.iv = null;
this.encrypted = null;
this.packets = null;
}
/**
* Parse an encrypted payload of bytes in the order: version, IV, ciphertext (see specification)
* @param {Uint8Array | ReadableStream} bytes
* @throws {Error} on parsing failure
*/
async read(bytes) {
await parse(bytes, async reader => {
const version = await reader.readByte();
if (version !== VERSION$2) { // The only currently defined value is 1.
throw new UnsupportedError(`Version ${version} of the AEAD-encrypted data packet is not supported.`);
}
this.cipherAlgorithm = await reader.readByte();
this.aeadAlgorithm = await reader.readByte();
this.chunkSizeByte = await reader.readByte();
const mode = mod.getAEADMode(this.aeadAlgorithm);
this.iv = await reader.readBytes(mode.ivLength);
this.encrypted = reader.remainder();
});
}
/**
* Write the encrypted payload of bytes in the order: version, IV, ciphertext (see specification)
* @returns {Uint8Array | ReadableStream} The encrypted payload.
*/
write() {
return util.concat([new Uint8Array([this.version, this.cipherAlgorithm, this.aeadAlgorithm, this.chunkSizeByte]), this.iv, this.encrypted]);
}
/**
* Decrypt the encrypted payload.
* @param {enums.symmetric} sessionKeyAlgorithm - The session key's cipher algorithm
* @param {Uint8Array} key - The session key used to encrypt the payload
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @throws {Error} if decryption was not successful
* @async
*/
async decrypt(sessionKeyAlgorithm, key, config$1 = config) {
this.packets = await PacketList.fromBinary(
await this.crypt('decrypt', key, clone(this.encrypted)),
allowedPackets$2,
config$1
);
}
/**
* Encrypt the packet payload.
* @param {enums.symmetric} sessionKeyAlgorithm - The session key's cipher algorithm
* @param {Uint8Array} key - The session key used to encrypt the payload
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @throws {Error} if encryption was not successful
* @async
*/
async encrypt(sessionKeyAlgorithm, key, config$1 = config) {
this.cipherAlgorithm = sessionKeyAlgorithm;
const { ivLength } = mod.getAEADMode(this.aeadAlgorithm);
this.iv = mod.random.getRandomBytes(ivLength); // generate new random IV
this.chunkSizeByte = config$1.aeadChunkSizeByte;
const data = this.packets.write();
this.encrypted = await this.crypt('encrypt', key, data);
}
/**
* En/decrypt the payload.
* @param {encrypt|decrypt} fn - Whether to encrypt or decrypt
* @param {Uint8Array} key - The session key used to en/decrypt the payload
* @param {Uint8Array | ReadableStream} data - The data to en/decrypt
* @returns {Promise>}
* @async
*/
async crypt(fn, key, data) {
const mode = mod.getAEADMode(this.aeadAlgorithm);
const modeInstance = await mode(this.cipherAlgorithm, key);
const tagLengthIfDecrypting = fn === 'decrypt' ? mode.tagLength : 0;
const tagLengthIfEncrypting = fn === 'encrypt' ? mode.tagLength : 0;
const chunkSize = 2 ** (this.chunkSizeByte + 6) + tagLengthIfDecrypting; // ((uint64_t)1 << (c + 6))
const adataBuffer = new ArrayBuffer(21);
const adataArray = new Uint8Array(adataBuffer, 0, 13);
const adataTagArray = new Uint8Array(adataBuffer);
const adataView = new DataView(adataBuffer);
const chunkIndexArray = new Uint8Array(adataBuffer, 5, 8);
adataArray.set([0xC0 | AEADEncryptedDataPacket.tag, this.version, this.cipherAlgorithm, this.aeadAlgorithm, this.chunkSizeByte], 0);
let chunkIndex = 0;
let latestPromise = Promise.resolve();
let cryptedBytes = 0;
let queuedBytes = 0;
const iv = this.iv;
return transformPair(data, async (readable, writable) => {
if (util.isStream(readable) !== 'array') {
const buffer = new TransformStream({}, {
highWaterMark: util.getHardwareConcurrency() * 2 ** (this.chunkSizeByte + 6),
size: array => array.length
});
pipe(buffer.readable, writable);
writable = buffer.writable;
}
const reader = getReader(readable);
const writer = getWriter(writable);
try {
while (true) {
let chunk = await reader.readBytes(chunkSize + tagLengthIfDecrypting) || new Uint8Array();
const finalChunk = chunk.subarray(chunk.length - tagLengthIfDecrypting);
chunk = chunk.subarray(0, chunk.length - tagLengthIfDecrypting);
let cryptedPromise;
let done;
if (!chunkIndex || chunk.length) {
reader.unshift(finalChunk);
cryptedPromise = modeInstance[fn](chunk, mode.getNonce(iv, chunkIndexArray), adataArray);
queuedBytes += chunk.length - tagLengthIfDecrypting + tagLengthIfEncrypting;
} else {
// After the last chunk, we either encrypt a final, empty
// data chunk to get the final authentication tag or
// validate that final authentication tag.
adataView.setInt32(13 + 4, cryptedBytes); // Should be setInt64(13, ...)
cryptedPromise = modeInstance[fn](finalChunk, mode.getNonce(iv, chunkIndexArray), adataTagArray);
queuedBytes += tagLengthIfEncrypting;
done = true;
}
cryptedBytes += chunk.length - tagLengthIfDecrypting;
// eslint-disable-next-line no-loop-func
latestPromise = latestPromise.then(() => cryptedPromise).then(async crypted => {
await writer.ready;
await writer.write(crypted);
queuedBytes -= crypted.length;
}).catch(err => writer.abort(err));
if (done || queuedBytes > writer.desiredSize) {
await latestPromise; // Respect backpressure
}
if (!done) {
adataView.setInt32(5 + 4, ++chunkIndex); // Should be setInt64(5, ...)
} else {
await writer.close();
break;
}
}
} catch (e) {
await writer.abort(e);
}
});
}
}
// GPG4Browsers - An OpenPGP implementation in javascript
const VERSION$3 = 3;
/**
* Public-Key Encrypted Session Key Packets (Tag 1)
*
* {@link https://tools.ietf.org/html/rfc4880#section-5.1|RFC4880 5.1}:
* A Public-Key Encrypted Session Key packet holds the session key
* used to encrypt a message. Zero or more Public-Key Encrypted Session Key
* packets and/or Symmetric-Key Encrypted Session Key packets may precede a
* Symmetrically Encrypted Data Packet, which holds an encrypted message. The
* message is encrypted with the session key, and the session key is itself
* encrypted and stored in the Encrypted Session Key packet(s). The
* Symmetrically Encrypted Data Packet is preceded by one Public-Key Encrypted
* Session Key packet for each OpenPGP key to which the message is encrypted.
* The recipient of the message finds a session key that is encrypted to their
* public key, decrypts the session key, and then uses the session key to
* decrypt the message.
*/
class PublicKeyEncryptedSessionKeyPacket {
static get tag() {
return enums.packet.publicKeyEncryptedSessionKey;
}
constructor() {
this.version = 3;
this.publicKeyID = new KeyID();
this.publicKeyAlgorithm = null;
this.sessionKey = null;
/**
* Algorithm to encrypt the message with
* @type {enums.symmetric}
*/
this.sessionKeyAlgorithm = null;
/** @type {Object} */
this.encrypted = {};
}
/**
* Parsing function for a publickey encrypted session key packet (tag 1).
*
* @param {Uint8Array} bytes - Payload of a tag 1 packet
*/
read(bytes) {
this.version = bytes[0];
if (this.version !== VERSION$3) {
throw new UnsupportedError(`Version ${this.version} of the PKESK packet is unsupported.`);
}
this.publicKeyID.read(bytes.subarray(1, bytes.length));
this.publicKeyAlgorithm = bytes[9];
this.encrypted = mod.parseEncSessionKeyParams(this.publicKeyAlgorithm, bytes.subarray(10));
}
/**
* Create a binary representation of a tag 1 packet
*
* @returns {Uint8Array} The Uint8Array representation.
*/
write() {
const arr = [
new Uint8Array([this.version]),
this.publicKeyID.write(),
new Uint8Array([this.publicKeyAlgorithm]),
mod.serializeParams(this.publicKeyAlgorithm, this.encrypted)
];
return util.concatUint8Array(arr);
}
/**
* Encrypt session key packet
* @param {PublicKeyPacket} key - Public key
* @throws {Error} if encryption failed
* @async
*/
async encrypt(key) {
const data = util.concatUint8Array([
new Uint8Array([enums.write(enums.symmetric, this.sessionKeyAlgorithm)]),
this.sessionKey,
util.writeChecksum(this.sessionKey)
]);
const algo = enums.write(enums.publicKey, this.publicKeyAlgorithm);
this.encrypted = await mod.publicKeyEncrypt(
algo, key.publicParams, data, key.getFingerprintBytes());
}
/**
* Decrypts the session key (only for public key encrypted session key packets (tag 1)
* @param {SecretKeyPacket} key - decrypted private key
* @param {Object} [randomSessionKey] - Bogus session key to use in case of sensitive decryption error, or if the decrypted session key is of a different type/size.
* This is needed for constant-time processing. Expected object of the form: { sessionKey: Uint8Array, sessionKeyAlgorithm: enums.symmetric }
* @throws {Error} if decryption failed, unless `randomSessionKey` is given
* @async
*/
async decrypt(key, randomSessionKey) {
// check that session key algo matches the secret key algo
if (this.publicKeyAlgorithm !== key.algorithm) {
throw new Error('Decryption error');
}
const randomPayload = randomSessionKey ? util.concatUint8Array([
new Uint8Array([randomSessionKey.sessionKeyAlgorithm]),
randomSessionKey.sessionKey,
util.writeChecksum(randomSessionKey.sessionKey)
]) : null;
const decoded = await mod.publicKeyDecrypt(this.publicKeyAlgorithm, key.publicParams, key.privateParams, this.encrypted, key.getFingerprintBytes(), randomPayload);
const symmetricAlgoByte = decoded[0];
const sessionKey = decoded.subarray(1, decoded.length - 2);
const checksum = decoded.subarray(decoded.length - 2);
const computedChecksum = util.writeChecksum(sessionKey);
const isValidChecksum = computedChecksum[0] === checksum[0] & computedChecksum[1] === checksum[1];
if (randomSessionKey) {
// We must not leak info about the validity of the decrypted checksum or cipher algo.
// The decrypted session key must be of the same algo and size as the random session key, otherwise we discard it and use the random data.
const isValidPayload = isValidChecksum & symmetricAlgoByte === randomSessionKey.sessionKeyAlgorithm & sessionKey.length === randomSessionKey.sessionKey.length;
this.sessionKeyAlgorithm = util.selectUint8(isValidPayload, symmetricAlgoByte, randomSessionKey.sessionKeyAlgorithm);
this.sessionKey = util.selectUint8Array(isValidPayload, sessionKey, randomSessionKey.sessionKey);
} else {
const isValidPayload = isValidChecksum && enums.read(enums.symmetric, symmetricAlgoByte);
if (isValidPayload) {
this.sessionKey = sessionKey;
this.sessionKeyAlgorithm = symmetricAlgoByte;
} else {
throw new Error('Decryption error');
}
}
}
}
// GPG4Browsers - An OpenPGP implementation in javascript
class S2K {
/**
* @param {Object} [config] - Full configuration, defaults to openpgp.config
*/
constructor(config$1 = config) {
/**
* Hash function identifier, or 0 for gnu-dummy keys
* @type {module:enums.hash | 0}
*/
this.algorithm = enums.hash.sha256;
/**
* enums.s2k identifier or 'gnu-dummy'
* @type {String}
*/
this.type = 'iterated';
/** @type {Integer} */
this.c = config$1.s2kIterationCountByte;
/** Eight bytes of salt in a binary string.
* @type {Uint8Array}
*/
this.salt = null;
}
getCount() {
// Exponent bias, defined in RFC4880
const expbias = 6;
return (16 + (this.c & 15)) << ((this.c >> 4) + expbias);
}
/**
* Parsing function for a string-to-key specifier ({@link https://tools.ietf.org/html/rfc4880#section-3.7|RFC 4880 3.7}).
* @param {Uint8Array} bytes - Payload of string-to-key specifier
* @returns {Integer} Actual length of the object.
*/
read(bytes) {
let i = 0;
this.type = enums.read(enums.s2k, bytes[i++]);
this.algorithm = bytes[i++];
switch (this.type) {
case 'simple':
break;
case 'salted':
this.salt = bytes.subarray(i, i + 8);
i += 8;
break;
case 'iterated':
this.salt = bytes.subarray(i, i + 8);
i += 8;
// Octet 10: count, a one-octet, coded value
this.c = bytes[i++];
break;
case 'gnu':
if (util.uint8ArrayToString(bytes.subarray(i, i + 3)) === 'GNU') {
i += 3; // GNU
const gnuExtType = 1000 + bytes[i++];
if (gnuExtType === 1001) {
this.type = 'gnu-dummy';
// GnuPG extension mode 1001 -- don't write secret key at all
} else {
throw new Error('Unknown s2k gnu protection mode.');
}
} else {
throw new Error('Unknown s2k type.');
}
break;
default:
throw new Error('Unknown s2k type.');
}
return i;
}
/**
* Serializes s2k information
* @returns {Uint8Array} Binary representation of s2k.
*/
write() {
if (this.type === 'gnu-dummy') {
return new Uint8Array([101, 0, ...util.stringToUint8Array('GNU'), 1]);
}
const arr = [new Uint8Array([enums.write(enums.s2k, this.type), this.algorithm])];
switch (this.type) {
case 'simple':
break;
case 'salted':
arr.push(this.salt);
break;
case 'iterated':
arr.push(this.salt);
arr.push(new Uint8Array([this.c]));
break;
case 'gnu':
throw new Error('GNU s2k type not supported.');
default:
throw new Error('Unknown s2k type.');
}
return util.concatUint8Array(arr);
}
/**
* Produces a key using the specified passphrase and the defined
* hashAlgorithm
* @param {String} passphrase - Passphrase containing user input
* @returns {Promise} Produced key with a length corresponding to.
* hashAlgorithm hash length
* @async
*/
async produceKey(passphrase, numBytes) {
passphrase = util.encodeUTF8(passphrase);
const arr = [];
let rlength = 0;
let prefixlen = 0;
while (rlength < numBytes) {
let toHash;
switch (this.type) {
case 'simple':
toHash = util.concatUint8Array([new Uint8Array(prefixlen), passphrase]);
break;
case 'salted':
toHash = util.concatUint8Array([new Uint8Array(prefixlen), this.salt, passphrase]);
break;
case 'iterated': {
const data = util.concatUint8Array([this.salt, passphrase]);
let datalen = data.length;
const count = Math.max(this.getCount(), datalen);
toHash = new Uint8Array(prefixlen + count);
toHash.set(data, prefixlen);
for (let pos = prefixlen + datalen; pos < count; pos += datalen, datalen *= 2) {
toHash.copyWithin(pos, prefixlen, pos);
}
break;
}
case 'gnu':
throw new Error('GNU s2k type not supported.');
default:
throw new Error('Unknown s2k type.');
}
const result = await mod.hash.digest(this.algorithm, toHash);
arr.push(result);
rlength += result.length;
prefixlen++;
}
return util.concatUint8Array(arr).subarray(0, numBytes);
}
}
// GPG4Browsers - An OpenPGP implementation in javascript
/**
* Symmetric-Key Encrypted Session Key Packets (Tag 3)
*
* {@link https://tools.ietf.org/html/rfc4880#section-5.3|RFC4880 5.3}:
* The Symmetric-Key Encrypted Session Key packet holds the
* symmetric-key encryption of a session key used to encrypt a message.
* Zero or more Public-Key Encrypted Session Key packets and/or
* Symmetric-Key Encrypted Session Key packets may precede a
* Symmetrically Encrypted Data packet that holds an encrypted message.
* The message is encrypted with a session key, and the session key is
* itself encrypted and stored in the Encrypted Session Key packet or
* the Symmetric-Key Encrypted Session Key packet.
*/
class SymEncryptedSessionKeyPacket {
static get tag() {
return enums.packet.symEncryptedSessionKey;
}
/**
* @param {Object} [config] - Full configuration, defaults to openpgp.config
*/
constructor(config$1 = config) {
this.version = config$1.aeadProtect ? 5 : 4;
this.sessionKey = null;
/**
* Algorithm to encrypt the session key with
* @type {enums.symmetric}
*/
this.sessionKeyEncryptionAlgorithm = null;
/**
* Algorithm to encrypt the message with
* @type {enums.symmetric}
*/
this.sessionKeyAlgorithm = enums.symmetric.aes256;
/**
* AEAD mode to encrypt the session key with (if AEAD protection is enabled)
* @type {enums.aead}
*/
this.aeadAlgorithm = enums.write(enums.aead, config$1.preferredAEADAlgorithm);
this.encrypted = null;
this.s2k = null;
this.iv = null;
}
/**
* Parsing function for a symmetric encrypted session key packet (tag 3).
*
* @param {Uint8Array} bytes - Payload of a tag 3 packet
*/
read(bytes) {
let offset = 0;
// A one-octet version number. The only currently defined version is 4.
this.version = bytes[offset++];
if (this.version !== 4 && this.version !== 5) {
throw new UnsupportedError(`Version ${this.version} of the SKESK packet is unsupported.`);
}
// A one-octet number describing the symmetric algorithm used.
const algo = bytes[offset++];
if (this.version === 5) {
// A one-octet AEAD algorithm.
this.aeadAlgorithm = bytes[offset++];
}
// A string-to-key (S2K) specifier, length as defined above.
this.s2k = new S2K();
offset += this.s2k.read(bytes.subarray(offset, bytes.length));
if (this.version === 5) {
const mode = mod.getAEADMode(this.aeadAlgorithm);
// A starting initialization vector of size specified by the AEAD
// algorithm.
this.iv = bytes.subarray(offset, offset += mode.ivLength);
}
// The encrypted session key itself, which is decrypted with the
// string-to-key object. This is optional in version 4.
if (this.version === 5 || offset < bytes.length) {
this.encrypted = bytes.subarray(offset, bytes.length);
this.sessionKeyEncryptionAlgorithm = algo;
} else {
this.sessionKeyAlgorithm = algo;
}
}
/**
* Create a binary representation of a tag 3 packet
*
* @returns {Uint8Array} The Uint8Array representation.
*/
write() {
const algo = this.encrypted === null ?
this.sessionKeyAlgorithm :
this.sessionKeyEncryptionAlgorithm;
let bytes;
if (this.version === 5) {
bytes = util.concatUint8Array([new Uint8Array([this.version, algo, this.aeadAlgorithm]), this.s2k.write(), this.iv, this.encrypted]);
} else {
bytes = util.concatUint8Array([new Uint8Array([this.version, algo]), this.s2k.write()]);
if (this.encrypted !== null) {
bytes = util.concatUint8Array([bytes, this.encrypted]);
}
}
return bytes;
}
/**
* Decrypts the session key with the given passphrase
* @param {String} passphrase - The passphrase in string form
* @throws {Error} if decryption was not successful
* @async
*/
async decrypt(passphrase) {
const algo = this.sessionKeyEncryptionAlgorithm !== null ?
this.sessionKeyEncryptionAlgorithm :
this.sessionKeyAlgorithm;
const { blockSize, keySize } = mod.getCipher(algo);
const key = await this.s2k.produceKey(passphrase, keySize);
if (this.version === 5) {
const mode = mod.getAEADMode(this.aeadAlgorithm);
const adata = new Uint8Array([0xC0 | SymEncryptedSessionKeyPacket.tag, this.version, this.sessionKeyEncryptionAlgorithm, this.aeadAlgorithm]);
const modeInstance = await mode(algo, key);
this.sessionKey = await modeInstance.decrypt(this.encrypted, this.iv, adata);
} else if (this.encrypted !== null) {
const decrypted = await mod.mode.cfb.decrypt(algo, key, this.encrypted, new Uint8Array(blockSize));
this.sessionKeyAlgorithm = enums.write(enums.symmetric, decrypted[0]);
this.sessionKey = decrypted.subarray(1, decrypted.length);
} else {
this.sessionKey = key;
}
}
/**
* Encrypts the session key with the given passphrase
* @param {String} passphrase - The passphrase in string form
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @throws {Error} if encryption was not successful
* @async
*/
async encrypt(passphrase, config$1 = config) {
const algo = this.sessionKeyEncryptionAlgorithm !== null ?
this.sessionKeyEncryptionAlgorithm :
this.sessionKeyAlgorithm;
this.sessionKeyEncryptionAlgorithm = algo;
this.s2k = new S2K(config$1);
this.s2k.salt = mod.random.getRandomBytes(8);
const { blockSize, keySize } = mod.getCipher(algo);
const encryptionKey = await this.s2k.produceKey(passphrase, keySize);
if (this.sessionKey === null) {
this.sessionKey = mod.generateSessionKey(this.sessionKeyAlgorithm);
}
if (this.version === 5) {
const mode = mod.getAEADMode(this.aeadAlgorithm);
this.iv = mod.random.getRandomBytes(mode.ivLength); // generate new random IV
const associatedData = new Uint8Array([0xC0 | SymEncryptedSessionKeyPacket.tag, this.version, this.sessionKeyEncryptionAlgorithm, this.aeadAlgorithm]);
const modeInstance = await mode(algo, encryptionKey);
this.encrypted = await modeInstance.encrypt(this.sessionKey, this.iv, associatedData);
} else {
const toEncrypt = util.concatUint8Array([
new Uint8Array([this.sessionKeyAlgorithm]),
this.sessionKey
]);
this.encrypted = await mod.mode.cfb.encrypt(algo, encryptionKey, toEncrypt, new Uint8Array(blockSize), config$1);
}
}
}
// GPG4Browsers - An OpenPGP implementation in javascript
/**
* Implementation of the Key Material Packet (Tag 5,6,7,14)
*
* {@link https://tools.ietf.org/html/rfc4880#section-5.5|RFC4480 5.5}:
* A key material packet contains all the information about a public or
* private key. There are four variants of this packet type, and two
* major versions.
*
* A Public-Key packet starts a series of packets that forms an OpenPGP
* key (sometimes called an OpenPGP certificate).
*/
class PublicKeyPacket {
static get tag() {
return enums.packet.publicKey;
}
/**
* @param {Date} [date] - Creation date
* @param {Object} [config] - Full configuration, defaults to openpgp.config
*/
constructor(date = new Date(), config$1 = config) {
/**
* Packet version
* @type {Integer}
*/
this.version = config$1.v5Keys ? 5 : 4;
/**
* Key creation date.
* @type {Date}
*/
this.created = util.normalizeDate(date);
/**
* Public key algorithm.
* @type {enums.publicKey}
*/
this.algorithm = null;
/**
* Algorithm specific public params
* @type {Object}
*/
this.publicParams = null;
/**
* Time until expiration in days (V3 only)
* @type {Integer}
*/
this.expirationTimeV3 = 0;
/**
* Fingerprint bytes
* @type {Uint8Array}
*/
this.fingerprint = null;
/**
* KeyID
* @type {module:type/keyid~KeyID}
*/
this.keyID = null;
}
/**
* Create a PublicKeyPacket from a SecretKeyPacket
* @param {SecretKeyPacket} secretKeyPacket - key packet to convert
* @returns {PublicKeyPacket} public key packet
* @static
*/
static fromSecretKeyPacket(secretKeyPacket) {
const keyPacket = new PublicKeyPacket();
const { version, created, algorithm, publicParams, keyID, fingerprint } = secretKeyPacket;
keyPacket.version = version;
keyPacket.created = created;
keyPacket.algorithm = algorithm;
keyPacket.publicParams = publicParams;
keyPacket.keyID = keyID;
keyPacket.fingerprint = fingerprint;
return keyPacket;
}
/**
* Internal Parser for public keys as specified in {@link https://tools.ietf.org/html/rfc4880#section-5.5.2|RFC 4880 section 5.5.2 Public-Key Packet Formats}
* @param {Uint8Array} bytes - Input array to read the packet from
* @returns {Object} This object with attributes set by the parser
* @async
*/
async read(bytes) {
let pos = 0;
// A one-octet version number (3, 4 or 5).
this.version = bytes[pos++];
if (this.version === 4 || this.version === 5) {
// - A four-octet number denoting the time that the key was created.
this.created = util.readDate(bytes.subarray(pos, pos + 4));
pos += 4;
// - A one-octet number denoting the public-key algorithm of this key.
this.algorithm = bytes[pos++];
if (this.version === 5) {
// - A four-octet scalar octet count for the following key material.
pos += 4;
}
// - A series of values comprising the key material.
const { read, publicParams } = mod.parsePublicKeyParams(this.algorithm, bytes.subarray(pos));
this.publicParams = publicParams;
pos += read;
// we set the fingerprint and keyID already to make it possible to put together the key packets directly in the Key constructor
await this.computeFingerprintAndKeyID();
return pos;
}
throw new UnsupportedError(`Version ${this.version} of the key packet is unsupported.`);
}
/**
* Creates an OpenPGP public key packet for the given key.
* @returns {Uint8Array} Bytes encoding the public key OpenPGP packet.
*/
write() {
const arr = [];
// Version
arr.push(new Uint8Array([this.version]));
arr.push(util.writeDate(this.created));
// A one-octet number denoting the public-key algorithm of this key
arr.push(new Uint8Array([this.algorithm]));
const params = mod.serializeParams(this.algorithm, this.publicParams);
if (this.version === 5) {
// A four-octet scalar octet count for the following key material
arr.push(util.writeNumber(params.length, 4));
}
// Algorithm-specific params
arr.push(params);
return util.concatUint8Array(arr);
}
/**
* Write packet in order to be hashed; either for a signature or a fingerprint
* @param {Integer} version - target version of signature or key
*/
writeForHash(version) {
const bytes = this.writePublicKey();
if (version === 5) {
return util.concatUint8Array([new Uint8Array([0x9A]), util.writeNumber(bytes.length, 4), bytes]);
}
return util.concatUint8Array([new Uint8Array([0x99]), util.writeNumber(bytes.length, 2), bytes]);
}
/**
* Check whether secret-key data is available in decrypted form. Returns null for public keys.
* @returns {Boolean|null}
*/
isDecrypted() {
return null;
}
/**
* Returns the creation time of the key
* @returns {Date}
*/
getCreationTime() {
return this.created;
}
/**
* Return the key ID of the key
* @returns {module:type/keyid~KeyID} The 8-byte key ID
*/
getKeyID() {
return this.keyID;
}
/**
* Computes and set the key ID and fingerprint of the key
* @async
*/
async computeFingerprintAndKeyID() {
await this.computeFingerprint();
this.keyID = new KeyID();
if (this.version === 5) {
this.keyID.read(this.fingerprint.subarray(0, 8));
} else if (this.version === 4) {
this.keyID.read(this.fingerprint.subarray(12, 20));
} else {
throw new Error('Unsupported key version');
}
}
/**
* Computes and set the fingerprint of the key
*/
async computeFingerprint() {
const toHash = this.writeForHash(this.version);
if (this.version === 5) {
this.fingerprint = await mod.hash.sha256(toHash);
} else if (this.version === 4) {
this.fingerprint = await mod.hash.sha1(toHash);
} else {
throw new Error('Unsupported key version');
}
}
/**
* Returns the fingerprint of the key, as an array of bytes
* @returns {Uint8Array} A Uint8Array containing the fingerprint
*/
getFingerprintBytes() {
return this.fingerprint;
}
/**
* Calculates and returns the fingerprint of the key, as a string
* @returns {String} A string containing the fingerprint in lowercase hex
*/
getFingerprint() {
return util.uint8ArrayToHex(this.getFingerprintBytes());
}
/**
* Calculates whether two keys have the same fingerprint without actually calculating the fingerprint
* @returns {Boolean} Whether the two keys have the same version and public key data.
*/
hasSameFingerprintAs(other) {
return this.version === other.version && util.equalsUint8Array(this.writePublicKey(), other.writePublicKey());
}
/**
* Returns algorithm information
* @returns {Object} An object of the form {algorithm: String, bits:int, curve:String}.
*/
getAlgorithmInfo() {
const result = {};
result.algorithm = enums.read(enums.publicKey, this.algorithm);
// RSA, DSA or ElGamal public modulo
const modulo = this.publicParams.n || this.publicParams.p;
if (modulo) {
result.bits = util.uint8ArrayBitLength(modulo);
} else {
result.curve = this.publicParams.oid.getName();
}
return result;
}
}
/**
* Alias of read()
* @see PublicKeyPacket#read
*/
PublicKeyPacket.prototype.readPublicKey = PublicKeyPacket.prototype.read;
/**
* Alias of write()
* @see PublicKeyPacket#write
*/
PublicKeyPacket.prototype.writePublicKey = PublicKeyPacket.prototype.write;
// GPG4Browsers - An OpenPGP implementation in javascript
// A SE packet can contain the following packet types
const allowedPackets$3 = /*#__PURE__*/ util.constructAllowedPackets([
LiteralDataPacket,
CompressedDataPacket,
OnePassSignaturePacket,
SignaturePacket
]);
/**
* Implementation of the Symmetrically Encrypted Data Packet (Tag 9)
*
* {@link https://tools.ietf.org/html/rfc4880#section-5.7|RFC4880 5.7}:
* The Symmetrically Encrypted Data packet contains data encrypted with a
* symmetric-key algorithm. When it has been decrypted, it contains other
* packets (usually a literal data packet or compressed data packet, but in
* theory other Symmetrically Encrypted Data packets or sequences of packets
* that form whole OpenPGP messages).
*/
class SymmetricallyEncryptedDataPacket {
static get tag() {
return enums.packet.symmetricallyEncryptedData;
}
constructor() {
/**
* Encrypted secret-key data
*/
this.encrypted = null;
/**
* Decrypted packets contained within.
* @type {PacketList}
*/
this.packets = null;
}
read(bytes) {
this.encrypted = bytes;
}
write() {
return this.encrypted;
}
/**
* Decrypt the symmetrically-encrypted packet data
* See {@link https://tools.ietf.org/html/rfc4880#section-9.2|RFC 4880 9.2} for algorithms.
* @param {module:enums.symmetric} sessionKeyAlgorithm - Symmetric key algorithm to use
* @param {Uint8Array} key - The key of cipher blocksize length to be used
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @throws {Error} if decryption was not successful
* @async
*/
async decrypt(sessionKeyAlgorithm, key, config$1 = config) {
// If MDC errors are not being ignored, all missing MDC packets in symmetrically encrypted data should throw an error
if (!config$1.allowUnauthenticatedMessages) {
throw new Error('Message is not authenticated.');
}
const { blockSize } = mod.getCipher(sessionKeyAlgorithm);
const encrypted = await readToEnd(clone(this.encrypted));
const decrypted = await mod.mode.cfb.decrypt(sessionKeyAlgorithm, key,
encrypted.subarray(blockSize + 2),
encrypted.subarray(2, blockSize + 2)
);
this.packets = await PacketList.fromBinary(decrypted, allowedPackets$3, config$1);
}
/**
* Encrypt the symmetrically-encrypted packet data
* See {@link https://tools.ietf.org/html/rfc4880#section-9.2|RFC 4880 9.2} for algorithms.
* @param {module:enums.symmetric} sessionKeyAlgorithm - Symmetric key algorithm to use
* @param {Uint8Array} key - The key of cipher blocksize length to be used
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @throws {Error} if encryption was not successful
* @async
*/
async encrypt(sessionKeyAlgorithm, key, config$1 = config) {
const data = this.packets.write();
const { blockSize } = mod.getCipher(sessionKeyAlgorithm);
const prefix = await mod.getPrefixRandom(sessionKeyAlgorithm);
const FRE = await mod.mode.cfb.encrypt(sessionKeyAlgorithm, key, prefix, new Uint8Array(blockSize), config$1);
const ciphertext = await mod.mode.cfb.encrypt(sessionKeyAlgorithm, key, data, FRE.subarray(2), config$1);
this.encrypted = util.concat([FRE, ciphertext]);
}
}
// GPG4Browsers - An OpenPGP implementation in javascript
/**
* Implementation of the strange "Marker packet" (Tag 10)
*
* {@link https://tools.ietf.org/html/rfc4880#section-5.8|RFC4880 5.8}:
* An experimental version of PGP used this packet as the Literal
* packet, but no released version of PGP generated Literal packets with this
* tag. With PGP 5.x, this packet has been reassigned and is reserved for use as
* the Marker packet.
*
* The body of this packet consists of:
* The three octets 0x50, 0x47, 0x50 (which spell "PGP" in UTF-8).
*
* Such a packet MUST be ignored when received. It may be placed at the
* beginning of a message that uses features not available in PGP
* version 2.6 in order to cause that version to report that newer
* software is necessary to process the message.
*/
class MarkerPacket {
static get tag() {
return enums.packet.marker;
}
/**
* Parsing function for a marker data packet (tag 10).
* @param {Uint8Array} bytes - Payload of a tag 10 packet
* @returns {Boolean} whether the packet payload contains "PGP"
*/
read(bytes) {
if (bytes[0] === 0x50 && // P
bytes[1] === 0x47 && // G
bytes[2] === 0x50) { // P
return true;
}
return false;
}
write() {
return new Uint8Array([0x50, 0x47, 0x50]);
}
}
// GPG4Browsers - An OpenPGP implementation in javascript
/**
* A Public-Subkey packet (tag 14) has exactly the same format as a
* Public-Key packet, but denotes a subkey. One or more subkeys may be
* associated with a top-level key. By convention, the top-level key
* provides signature services, and the subkeys provide encryption
* services.
* @extends PublicKeyPacket
*/
class PublicSubkeyPacket extends PublicKeyPacket {
static get tag() {
return enums.packet.publicSubkey;
}
/**
* @param {Date} [date] - Creation date
* @param {Object} [config] - Full configuration, defaults to openpgp.config
*/
// eslint-disable-next-line no-useless-constructor
constructor(date, config) {
super(date, config);
}
/**
* Create a PublicSubkeyPacket from a SecretSubkeyPacket
* @param {SecretSubkeyPacket} secretSubkeyPacket - subkey packet to convert
* @returns {SecretSubkeyPacket} public key packet
* @static
*/
static fromSecretSubkeyPacket(secretSubkeyPacket) {
const keyPacket = new PublicSubkeyPacket();
const { version, created, algorithm, publicParams, keyID, fingerprint } = secretSubkeyPacket;
keyPacket.version = version;
keyPacket.created = created;
keyPacket.algorithm = algorithm;
keyPacket.publicParams = publicParams;
keyPacket.keyID = keyID;
keyPacket.fingerprint = fingerprint;
return keyPacket;
}
}
// GPG4Browsers - An OpenPGP implementation in javascript
/**
* Implementation of the User Attribute Packet (Tag 17)
*
* The User Attribute packet is a variation of the User ID packet. It
* is capable of storing more types of data than the User ID packet,
* which is limited to text. Like the User ID packet, a User Attribute
* packet may be certified by the key owner ("self-signed") or any other
* key owner who cares to certify it. Except as noted, a User Attribute
* packet may be used anywhere that a User ID packet may be used.
*
* While User Attribute packets are not a required part of the OpenPGP
* standard, implementations SHOULD provide at least enough
* compatibility to properly handle a certification signature on the
* User Attribute packet. A simple way to do this is by treating the
* User Attribute packet as a User ID packet with opaque contents, but
* an implementation may use any method desired.
*/
class UserAttributePacket {
static get tag() {
return enums.packet.userAttribute;
}
constructor() {
this.attributes = [];
}
/**
* parsing function for a user attribute packet (tag 17).
* @param {Uint8Array} input - Payload of a tag 17 packet
*/
read(bytes) {
let i = 0;
while (i < bytes.length) {
const len = readSimpleLength(bytes.subarray(i, bytes.length));
i += len.offset;
this.attributes.push(util.uint8ArrayToString(bytes.subarray(i, i + len.len)));
i += len.len;
}
}
/**
* Creates a binary representation of the user attribute packet
* @returns {Uint8Array} String representation.
*/
write() {
const arr = [];
for (let i = 0; i < this.attributes.length; i++) {
arr.push(writeSimpleLength(this.attributes[i].length));
arr.push(util.stringToUint8Array(this.attributes[i]));
}
return util.concatUint8Array(arr);
}
/**
* Compare for equality
* @param {UserAttributePacket} usrAttr
* @returns {Boolean} True if equal.
*/
equals(usrAttr) {
if (!usrAttr || !(usrAttr instanceof UserAttributePacket)) {
return false;
}
return this.attributes.every(function(attr, index) {
return attr === usrAttr.attributes[index];
});
}
}
// GPG4Browsers - An OpenPGP implementation in javascript
/**
* A Secret-Key packet contains all the information that is found in a
* Public-Key packet, including the public-key material, but also
* includes the secret-key material after all the public-key fields.
* @extends PublicKeyPacket
*/
class SecretKeyPacket extends PublicKeyPacket {
static get tag() {
return enums.packet.secretKey;
}
/**
* @param {Date} [date] - Creation date
* @param {Object} [config] - Full configuration, defaults to openpgp.config
*/
constructor(date = new Date(), config$1 = config) {
super(date, config$1);
/**
* Secret-key data
*/
this.keyMaterial = null;
/**
* Indicates whether secret-key data is encrypted. `this.isEncrypted === false` means data is available in decrypted form.
*/
this.isEncrypted = null;
/**
* S2K usage
* @type {enums.symmetric}
*/
this.s2kUsage = 0;
/**
* S2K object
* @type {type/s2k}
*/
this.s2k = null;
/**
* Symmetric algorithm to encrypt the key with
* @type {enums.symmetric}
*/
this.symmetric = null;
/**
* AEAD algorithm to encrypt the key with (if AEAD protection is enabled)
* @type {enums.aead}
*/
this.aead = null;
/**
* Decrypted private parameters, referenced by name
* @type {Object}
*/
this.privateParams = null;
}
// 5.5.3. Secret-Key Packet Formats
/**
* Internal parser for private keys as specified in
* {@link https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-04#section-5.5.3|RFC4880bis-04 section 5.5.3}
* @param {Uint8Array} bytes - Input string to read the packet from
* @async
*/
async read(bytes) {
// - A Public-Key or Public-Subkey packet, as described above.
let i = await this.readPublicKey(bytes);
// - One octet indicating string-to-key usage conventions. Zero
// indicates that the secret-key data is not encrypted. 255 or 254
// indicates that a string-to-key specifier is being given. Any
// other value is a symmetric-key encryption algorithm identifier.
this.s2kUsage = bytes[i++];
// - Only for a version 5 packet, a one-octet scalar octet count of
// the next 4 optional fields.
if (this.version === 5) {
i++;
}
// - [Optional] If string-to-key usage octet was 255, 254, or 253, a
// one-octet symmetric encryption algorithm.
if (this.s2kUsage === 255 || this.s2kUsage === 254 || this.s2kUsage === 253) {
this.symmetric = bytes[i++];
// - [Optional] If string-to-key usage octet was 253, a one-octet
// AEAD algorithm.
if (this.s2kUsage === 253) {
this.aead = bytes[i++];
}
// - [Optional] If string-to-key usage octet was 255, 254, or 253, a
// string-to-key specifier. The length of the string-to-key
// specifier is implied by its type, as described above.
this.s2k = new S2K();
i += this.s2k.read(bytes.subarray(i, bytes.length));
if (this.s2k.type === 'gnu-dummy') {
return;
}
} else if (this.s2kUsage) {
this.symmetric = this.s2kUsage;
}
// - [Optional] If secret data is encrypted (string-to-key usage octet
// not zero), an Initial Vector (IV) of the same length as the
// cipher's block size.
if (this.s2kUsage) {
this.iv = bytes.subarray(
i,
i + mod.getCipher(this.symmetric).blockSize
);
i += this.iv.length;
}
// - Only for a version 5 packet, a four-octet scalar octet count for
// the following key material.
if (this.version === 5) {
i += 4;
}
// - Plain or encrypted multiprecision integers comprising the secret
// key data. These algorithm-specific fields are as described
// below.
this.keyMaterial = bytes.subarray(i);
this.isEncrypted = !!this.s2kUsage;
if (!this.isEncrypted) {
const cleartext = this.keyMaterial.subarray(0, -2);
if (!util.equalsUint8Array(util.writeChecksum(cleartext), this.keyMaterial.subarray(-2))) {
throw new Error('Key checksum mismatch');
}
try {
const { privateParams } = mod.parsePrivateKeyParams(this.algorithm, cleartext, this.publicParams);
this.privateParams = privateParams;
} catch (err) {
if (err instanceof UnsupportedError) throw err;
// avoid throwing potentially sensitive errors
throw new Error('Error reading MPIs');
}
}
}
/**
* Creates an OpenPGP key packet for the given key.
* @returns {Uint8Array} A string of bytes containing the secret key OpenPGP packet.
*/
write() {
const arr = [this.writePublicKey()];
arr.push(new Uint8Array([this.s2kUsage]));
const optionalFieldsArr = [];
// - [Optional] If string-to-key usage octet was 255, 254, or 253, a
// one- octet symmetric encryption algorithm.
if (this.s2kUsage === 255 || this.s2kUsage === 254 || this.s2kUsage === 253) {
optionalFieldsArr.push(this.symmetric);
// - [Optional] If string-to-key usage octet was 253, a one-octet
// AEAD algorithm.
if (this.s2kUsage === 253) {
optionalFieldsArr.push(this.aead);
}
// - [Optional] If string-to-key usage octet was 255, 254, or 253, a
// string-to-key specifier. The length of the string-to-key
// specifier is implied by its type, as described above.
optionalFieldsArr.push(...this.s2k.write());
}
// - [Optional] If secret data is encrypted (string-to-key usage octet
// not zero), an Initial Vector (IV) of the same length as the
// cipher's block size.
if (this.s2kUsage && this.s2k.type !== 'gnu-dummy') {
optionalFieldsArr.push(...this.iv);
}
if (this.version === 5) {
arr.push(new Uint8Array([optionalFieldsArr.length]));
}
arr.push(new Uint8Array(optionalFieldsArr));
if (!this.isDummy()) {
if (!this.s2kUsage) {
this.keyMaterial = mod.serializeParams(this.algorithm, this.privateParams);
}
if (this.version === 5) {
arr.push(util.writeNumber(this.keyMaterial.length, 4));
}
arr.push(this.keyMaterial);
if (!this.s2kUsage) {
arr.push(util.writeChecksum(this.keyMaterial));
}
}
return util.concatUint8Array(arr);
}
/**
* Check whether secret-key data is available in decrypted form.
* Returns false for gnu-dummy keys and null for public keys.
* @returns {Boolean|null}
*/
isDecrypted() {
return this.isEncrypted === false;
}
/**
* Check whether this is a gnu-dummy key
* @returns {Boolean}
*/
isDummy() {
return !!(this.s2k && this.s2k.type === 'gnu-dummy');
}
/**
* Remove private key material, converting the key to a dummy one.
* The resulting key cannot be used for signing/decrypting but can still verify signatures.
* @param {Object} [config] - Full configuration, defaults to openpgp.config
*/
makeDummy(config$1 = config) {
if (this.isDummy()) {
return;
}
if (this.isDecrypted()) {
this.clearPrivateParams();
}
this.isEncrypted = null;
this.keyMaterial = null;
this.s2k = new S2K(config$1);
this.s2k.algorithm = 0;
this.s2k.c = 0;
this.s2k.type = 'gnu-dummy';
this.s2kUsage = 254;
this.symmetric = enums.symmetric.aes256;
}
/**
* Encrypt the payload. By default, we use aes256 and iterated, salted string
* to key specifier. If the key is in a decrypted state (isEncrypted === false)
* and the passphrase is empty or undefined, the key will be set as not encrypted.
* This can be used to remove passphrase protection after calling decrypt().
* @param {String} passphrase
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @throws {Error} if encryption was not successful
* @async
*/
async encrypt(passphrase, config$1 = config) {
if (this.isDummy()) {
return;
}
if (!this.isDecrypted()) {
throw new Error('Key packet is already encrypted');
}
if (!passphrase) {
throw new Error('A non-empty passphrase is required for key encryption.');
}
this.s2k = new S2K(config$1);
this.s2k.salt = mod.random.getRandomBytes(8);
const cleartext = mod.serializeParams(this.algorithm, this.privateParams);
this.symmetric = enums.symmetric.aes256;
const key = await produceEncryptionKey(this.s2k, passphrase, this.symmetric);
const { blockSize } = mod.getCipher(this.symmetric);
this.iv = mod.random.getRandomBytes(blockSize);
if (config$1.aeadProtect) {
this.s2kUsage = 253;
this.aead = enums.aead.eax;
const mode = mod.getAEADMode(this.aead);
const modeInstance = await mode(this.symmetric, key);
this.keyMaterial = await modeInstance.encrypt(cleartext, this.iv.subarray(0, mode.ivLength), new Uint8Array());
} else {
this.s2kUsage = 254;
this.keyMaterial = await mod.mode.cfb.encrypt(this.symmetric, key, util.concatUint8Array([
cleartext,
await mod.hash.sha1(cleartext, config$1)
]), this.iv, config$1);
}
}
/**
* Decrypts the private key params which are needed to use the key.
* Successful decryption does not imply key integrity, call validate() to confirm that.
* {@link SecretKeyPacket.isDecrypted} should be false, as
* otherwise calls to this function will throw an error.
* @param {String} passphrase - The passphrase for this private key as string
* @throws {Error} if the key is already decrypted, or if decryption was not successful
* @async
*/
async decrypt(passphrase) {
if (this.isDummy()) {
return false;
}
if (this.isDecrypted()) {
throw new Error('Key packet is already decrypted.');
}
let key;
if (this.s2kUsage === 254 || this.s2kUsage === 253) {
key = await produceEncryptionKey(this.s2k, passphrase, this.symmetric);
} else if (this.s2kUsage === 255) {
throw new Error('Encrypted private key is authenticated using an insecure two-byte hash');
} else {
throw new Error('Private key is encrypted using an insecure S2K function: unsalted MD5');
}
let cleartext;
if (this.s2kUsage === 253) {
const mode = mod.getAEADMode(this.aead);
const modeInstance = await mode(this.symmetric, key);
try {
cleartext = await modeInstance.decrypt(this.keyMaterial, this.iv.subarray(0, mode.ivLength), new Uint8Array());
} catch (err) {
if (err.message === 'Authentication tag mismatch') {
throw new Error('Incorrect key passphrase: ' + err.message);
}
throw err;
}
} else {
const cleartextWithHash = await mod.mode.cfb.decrypt(this.symmetric, key, this.keyMaterial, this.iv);
cleartext = cleartextWithHash.subarray(0, -20);
const hash = await mod.hash.sha1(cleartext);
if (!util.equalsUint8Array(hash, cleartextWithHash.subarray(-20))) {
throw new Error('Incorrect key passphrase');
}
}
try {
const { privateParams } = mod.parsePrivateKeyParams(this.algorithm, cleartext, this.publicParams);
this.privateParams = privateParams;
} catch (err) {
throw new Error('Error reading MPIs');
}
this.isEncrypted = false;
this.keyMaterial = null;
this.s2kUsage = 0;
}
/**
* Checks that the key parameters are consistent
* @throws {Error} if validation was not successful
* @async
*/
async validate() {
if (this.isDummy()) {
return;
}
if (!this.isDecrypted()) {
throw new Error('Key is not decrypted');
}
let validParams;
try {
// this can throw if some parameters are undefined
validParams = await mod.validateParams(this.algorithm, this.publicParams, this.privateParams);
} catch (_) {
validParams = false;
}
if (!validParams) {
throw new Error('Key is invalid');
}
}
async generate(bits, curve) {
const { privateParams, publicParams } = await mod.generateParams(this.algorithm, bits, curve);
this.privateParams = privateParams;
this.publicParams = publicParams;
this.isEncrypted = false;
}
/**
* Clear private key parameters
*/
clearPrivateParams() {
if (this.isDummy()) {
return;
}
Object.keys(this.privateParams).forEach(name => {
const param = this.privateParams[name];
param.fill(0);
delete this.privateParams[name];
});
this.privateParams = null;
this.isEncrypted = true;
}
}
async function produceEncryptionKey(s2k, passphrase, algorithm) {
const { keySize } = mod.getCipher(algorithm);
return s2k.produceKey(passphrase, keySize);
}
var emailAddresses = createCommonjsModule(function (module) {
// email-addresses.js - RFC 5322 email address parser
// v 3.1.0
//
// http://tools.ietf.org/html/rfc5322
//
// This library does not validate email addresses.
// emailAddresses attempts to parse addresses using the (fairly liberal)
// grammar specified in RFC 5322.
//
// email-addresses returns {
// ast: ,
// addresses: [{
// node: ,
// name: ,
// address: ,
// local: ,
// domain:
// }, ...]
// }
//
// emailAddresses.parseOneAddress and emailAddresses.parseAddressList
// work as you might expect. Try it out.
//
// Many thanks to Dominic Sayers and his documentation on the is_email function,
// http://code.google.com/p/isemail/ , which helped greatly in writing this parser.
(function (global) {
function parse5322(opts) {
// tokenizing functions
function inStr() { return pos < len; }
function curTok() { return parseString[pos]; }
function getPos() { return pos; }
function setPos(i) { pos = i; }
function nextTok() { pos += 1; }
function initialize() {
pos = 0;
len = parseString.length;
}
// parser helper functions
function o(name, value) {
return {
name: name,
tokens: value || "",
semantic: value || "",
children: []
};
}
function wrap(name, ast) {
var n;
if (ast === null) { return null; }
n = o(name);
n.tokens = ast.tokens;
n.semantic = ast.semantic;
n.children.push(ast);
return n;
}
function add(parent, child) {
if (child !== null) {
parent.tokens += child.tokens;
parent.semantic += child.semantic;
}
parent.children.push(child);
return parent;
}
function compareToken(fxnCompare) {
var tok;
if (!inStr()) { return null; }
tok = curTok();
if (fxnCompare(tok)) {
nextTok();
return o('token', tok);
}
return null;
}
function literal(lit) {
return function literalFunc() {
return wrap('literal', compareToken(function (tok) {
return tok === lit;
}));
};
}
function and() {
var args = arguments;
return function andFunc() {
var i, s, result, start;
start = getPos();
s = o('and');
for (i = 0; i < args.length; i += 1) {
result = args[i]();
if (result === null) {
setPos(start);
return null;
}
add(s, result);
}
return s;
};
}
function or() {
var args = arguments;
return function orFunc() {
var i, result, start;
start = getPos();
for (i = 0; i < args.length; i += 1) {
result = args[i]();
if (result !== null) {
return result;
}
setPos(start);
}
return null;
};
}
function opt(prod) {
return function optFunc() {
var result, start;
start = getPos();
result = prod();
if (result !== null) {
return result;
}
else {
setPos(start);
return o('opt');
}
};
}
function invis(prod) {
return function invisFunc() {
var result = prod();
if (result !== null) {
result.semantic = "";
}
return result;
};
}
function colwsp(prod) {
return function collapseSemanticWhitespace() {
var result = prod();
if (result !== null && result.semantic.length > 0) {
result.semantic = " ";
}
return result;
};
}
function star(prod, minimum) {
return function starFunc() {
var s, result, count, start, min;
start = getPos();
s = o('star');
count = 0;
min = minimum === undefined ? 0 : minimum;
while ((result = prod()) !== null) {
count = count + 1;
add(s, result);
}
if (count >= min) {
return s;
}
else {
setPos(start);
return null;
}
};
}
// One expects names to get normalized like this:
// " First Last " -> "First Last"
// "First Last" -> "First Last"
// "First Last" -> "First Last"
function collapseWhitespace(s) {
return s.replace(/([ \t]|\r\n)+/g, ' ').replace(/^\s*/, '').replace(/\s*$/, '');
}
// UTF-8 pseudo-production (RFC 6532)
// RFC 6532 extends RFC 5322 productions to include UTF-8
// using the following productions:
// UTF8-non-ascii = UTF8-2 / UTF8-3 / UTF8-4
// UTF8-2 =
// UTF8-3 =
// UTF8-4 =
//
// For reference, the extended RFC 5322 productions are:
// VCHAR =/ UTF8-non-ascii
// ctext =/ UTF8-non-ascii
// atext =/ UTF8-non-ascii
// qtext =/ UTF8-non-ascii
// dtext =/ UTF8-non-ascii
function isUTF8NonAscii(tok) {
// In JavaScript, we just deal directly with Unicode code points,
// so we aren't checking individual bytes for UTF-8 encoding.
// Just check that the character is non-ascii.
return tok.charCodeAt(0) >= 128;
}
// common productions (RFC 5234)
// http://tools.ietf.org/html/rfc5234
// B.1. Core Rules
// CR = %x0D
// ; carriage return
function cr() { return wrap('cr', literal('\r')()); }
// CRLF = CR LF
// ; Internet standard newline
function crlf() { return wrap('crlf', and(cr, lf)()); }
// DQUOTE = %x22
// ; " (Double Quote)
function dquote() { return wrap('dquote', literal('"')()); }
// HTAB = %x09
// ; horizontal tab
function htab() { return wrap('htab', literal('\t')()); }
// LF = %x0A
// ; linefeed
function lf() { return wrap('lf', literal('\n')()); }
// SP = %x20
function sp() { return wrap('sp', literal(' ')()); }
// VCHAR = %x21-7E
// ; visible (printing) characters
function vchar() {
return wrap('vchar', compareToken(function vcharFunc(tok) {
var code = tok.charCodeAt(0);
var accept = (0x21 <= code && code <= 0x7E);
if (opts.rfc6532) {
accept = accept || isUTF8NonAscii(tok);
}
return accept;
}));
}
// WSP = SP / HTAB
// ; white space
function wsp() { return wrap('wsp', or(sp, htab)()); }
// email productions (RFC 5322)
// http://tools.ietf.org/html/rfc5322
// 3.2.1. Quoted characters
// quoted-pair = ("\" (VCHAR / WSP)) / obs-qp
function quotedPair() {
var qp = wrap('quoted-pair',
or(
and(literal('\\'), or(vchar, wsp)),
obsQP
)());
if (qp === null) { return null; }
// a quoted pair will be two characters, and the "\" character
// should be semantically "invisible" (RFC 5322 3.2.1)
qp.semantic = qp.semantic[1];
return qp;
}
// 3.2.2. Folding White Space and Comments
// FWS = ([*WSP CRLF] 1*WSP) / obs-FWS
function fws() {
return wrap('fws', or(
obsFws,
and(
opt(and(
star(wsp),
invis(crlf)
)),
star(wsp, 1)
)
)());
}
// ctext = %d33-39 / ; Printable US-ASCII
// %d42-91 / ; characters not including
// %d93-126 / ; "(", ")", or "\"
// obs-ctext
function ctext() {
return wrap('ctext', or(
function ctextFunc1() {
return compareToken(function ctextFunc2(tok) {
var code = tok.charCodeAt(0);
var accept =
(33 <= code && code <= 39) ||
(42 <= code && code <= 91) ||
(93 <= code && code <= 126);
if (opts.rfc6532) {
accept = accept || isUTF8NonAscii(tok);
}
return accept;
});
},
obsCtext
)());
}
// ccontent = ctext / quoted-pair / comment
function ccontent() {
return wrap('ccontent', or(ctext, quotedPair, comment)());
}
// comment = "(" *([FWS] ccontent) [FWS] ")"
function comment() {
return wrap('comment', and(
literal('('),
star(and(opt(fws), ccontent)),
opt(fws),
literal(')')
)());
}
// CFWS = (1*([FWS] comment) [FWS]) / FWS
function cfws() {
return wrap('cfws', or(
and(
star(
and(opt(fws), comment),
1
),
opt(fws)
),
fws
)());
}
// 3.2.3. Atom
//atext = ALPHA / DIGIT / ; Printable US-ASCII
// "!" / "#" / ; characters not including
// "$" / "%" / ; specials. Used for atoms.
// "&" / "'" /
// "*" / "+" /
// "-" / "/" /
// "=" / "?" /
// "^" / "_" /
// "`" / "{" /
// "|" / "}" /
// "~"
function atext() {
return wrap('atext', compareToken(function atextFunc(tok) {
var accept =
('a' <= tok && tok <= 'z') ||
('A' <= tok && tok <= 'Z') ||
('0' <= tok && tok <= '9') ||
(['!', '#', '$', '%', '&', '\'', '*', '+', '-', '/',
'=', '?', '^', '_', '`', '{', '|', '}', '~'].indexOf(tok) >= 0);
if (opts.rfc6532) {
accept = accept || isUTF8NonAscii(tok);
}
return accept;
}));
}
// atom = [CFWS] 1*atext [CFWS]
function atom() {
return wrap('atom', and(colwsp(opt(cfws)), star(atext, 1), colwsp(opt(cfws)))());
}
// dot-atom-text = 1*atext *("." 1*atext)
function dotAtomText() {
var s, maybeText;
s = wrap('dot-atom-text', star(atext, 1)());
if (s === null) { return s; }
maybeText = star(and(literal('.'), star(atext, 1)))();
if (maybeText !== null) {
add(s, maybeText);
}
return s;
}
// dot-atom = [CFWS] dot-atom-text [CFWS]
function dotAtom() {
return wrap('dot-atom', and(invis(opt(cfws)), dotAtomText, invis(opt(cfws)))());
}
// 3.2.4. Quoted Strings
// qtext = %d33 / ; Printable US-ASCII
// %d35-91 / ; characters not including
// %d93-126 / ; "\" or the quote character
// obs-qtext
function qtext() {
return wrap('qtext', or(
function qtextFunc1() {
return compareToken(function qtextFunc2(tok) {
var code = tok.charCodeAt(0);
var accept =
(33 === code) ||
(35 <= code && code <= 91) ||
(93 <= code && code <= 126);
if (opts.rfc6532) {
accept = accept || isUTF8NonAscii(tok);
}
return accept;
});
},
obsQtext
)());
}
// qcontent = qtext / quoted-pair
function qcontent() {
return wrap('qcontent', or(qtext, quotedPair)());
}
// quoted-string = [CFWS]
// DQUOTE *([FWS] qcontent) [FWS] DQUOTE
// [CFWS]
function quotedString() {
return wrap('quoted-string', and(
invis(opt(cfws)),
invis(dquote), star(and(opt(colwsp(fws)), qcontent)), opt(invis(fws)), invis(dquote),
invis(opt(cfws))
)());
}
// 3.2.5 Miscellaneous Tokens
// word = atom / quoted-string
function word() {
return wrap('word', or(atom, quotedString)());
}
// phrase = 1*word / obs-phrase
function phrase() {
return wrap('phrase', or(obsPhrase, star(word, 1))());
}
// 3.4. Address Specification
// address = mailbox / group
function address() {
return wrap('address', or(mailbox, group)());
}
// mailbox = name-addr / addr-spec
function mailbox() {
return wrap('mailbox', or(nameAddr, addrSpec)());
}
// name-addr = [display-name] angle-addr
function nameAddr() {
return wrap('name-addr', and(opt(displayName), angleAddr)());
}
// angle-addr = [CFWS] "<" addr-spec ">" [CFWS] /
// obs-angle-addr
function angleAddr() {
return wrap('angle-addr', or(
and(
invis(opt(cfws)),
literal('<'),
addrSpec,
literal('>'),
invis(opt(cfws))
),
obsAngleAddr
)());
}
// group = display-name ":" [group-list] ";" [CFWS]
function group() {
return wrap('group', and(
displayName,
literal(':'),
opt(groupList),
literal(';'),
invis(opt(cfws))
)());
}
// display-name = phrase
function displayName() {
return wrap('display-name', function phraseFixedSemantic() {
var result = phrase();
if (result !== null) {
result.semantic = collapseWhitespace(result.semantic);
}
return result;
}());
}
// mailbox-list = (mailbox *("," mailbox)) / obs-mbox-list
function mailboxList() {
return wrap('mailbox-list', or(
and(
mailbox,
star(and(literal(','), mailbox))
),
obsMboxList
)());
}
// address-list = (address *("," address)) / obs-addr-list
function addressList() {
return wrap('address-list', or(
and(
address,
star(and(literal(','), address))
),
obsAddrList
)());
}
// group-list = mailbox-list / CFWS / obs-group-list
function groupList() {
return wrap('group-list', or(
mailboxList,
invis(cfws),
obsGroupList
)());
}
// 3.4.1 Addr-Spec Specification
// local-part = dot-atom / quoted-string / obs-local-part
function localPart() {
// note: quoted-string, dotAtom are proper subsets of obs-local-part
// so we really just have to look for obsLocalPart, if we don't care about the exact parse tree
return wrap('local-part', or(obsLocalPart, dotAtom, quotedString)());
}
// dtext = %d33-90 / ; Printable US-ASCII
// %d94-126 / ; characters not including
// obs-dtext ; "[", "]", or "\"
function dtext() {
return wrap('dtext', or(
function dtextFunc1() {
return compareToken(function dtextFunc2(tok) {
var code = tok.charCodeAt(0);
var accept =
(33 <= code && code <= 90) ||
(94 <= code && code <= 126);
if (opts.rfc6532) {
accept = accept || isUTF8NonAscii(tok);
}
return accept;
});
},
obsDtext
)()
);
}
// domain-literal = [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS]
function domainLiteral() {
return wrap('domain-literal', and(
invis(opt(cfws)),
literal('['),
star(and(opt(fws), dtext)),
opt(fws),
literal(']'),
invis(opt(cfws))
)());
}
// domain = dot-atom / domain-literal / obs-domain
function domain() {
return wrap('domain', function domainCheckTLD() {
var result = or(obsDomain, dotAtom, domainLiteral)();
if (opts.rejectTLD) {
if (result && result.semantic && result.semantic.indexOf('.') < 0) {
return null;
}
}
// strip all whitespace from domains
if (result) {
result.semantic = result.semantic.replace(/\s+/g, '');
}
return result;
}());
}
// addr-spec = local-part "@" domain
function addrSpec() {
return wrap('addr-spec', and(
localPart, literal('@'), domain
)());
}
// 3.6.2 Originator Fields
// Below we only parse the field body, not the name of the field
// like "From:", "Sender:", or "Reply-To:". Other libraries that
// parse email headers can parse those and defer to these productions
// for the "RFC 5322" part.
// RFC 6854 2.1. Replacement of RFC 5322, Section 3.6.2. Originator Fields
// from = "From:" (mailbox-list / address-list) CRLF
function fromSpec() {
return wrap('from', or(
mailboxList,
addressList
)());
}
// RFC 6854 2.1. Replacement of RFC 5322, Section 3.6.2. Originator Fields
// sender = "Sender:" (mailbox / address) CRLF
function senderSpec() {
return wrap('sender', or(
mailbox,
address
)());
}
// RFC 6854 2.1. Replacement of RFC 5322, Section 3.6.2. Originator Fields
// reply-to = "Reply-To:" address-list CRLF
function replyToSpec() {
return wrap('reply-to', addressList());
}
// 4.1. Miscellaneous Obsolete Tokens
// obs-NO-WS-CTL = %d1-8 / ; US-ASCII control
// %d11 / ; characters that do not
// %d12 / ; include the carriage
// %d14-31 / ; return, line feed, and
// %d127 ; white space characters
function obsNoWsCtl() {
return opts.strict ? null : wrap('obs-NO-WS-CTL', compareToken(function (tok) {
var code = tok.charCodeAt(0);
return ((1 <= code && code <= 8) ||
(11 === code || 12 === code) ||
(14 <= code && code <= 31) ||
(127 === code));
}));
}
// obs-ctext = obs-NO-WS-CTL
function obsCtext() { return opts.strict ? null : wrap('obs-ctext', obsNoWsCtl()); }
// obs-qtext = obs-NO-WS-CTL
function obsQtext() { return opts.strict ? null : wrap('obs-qtext', obsNoWsCtl()); }
// obs-qp = "\" (%d0 / obs-NO-WS-CTL / LF / CR)
function obsQP() {
return opts.strict ? null : wrap('obs-qp', and(
literal('\\'),
or(literal('\0'), obsNoWsCtl, lf, cr)
)());
}
// obs-phrase = word *(word / "." / CFWS)
function obsPhrase() {
if (opts.strict ) return null;
return opts.atInDisplayName ? wrap('obs-phrase', and(
word,
star(or(word, literal('.'), literal('@'), colwsp(cfws)))
)()) :
wrap('obs-phrase', and(
word,
star(or(word, literal('.'), colwsp(cfws)))
)());
}
// 4.2. Obsolete Folding White Space
// NOTE: read the errata http://www.rfc-editor.org/errata_search.php?rfc=5322&eid=1908
// obs-FWS = 1*([CRLF] WSP)
function obsFws() {
return opts.strict ? null : wrap('obs-FWS', star(
and(invis(opt(crlf)), wsp),
1
)());
}
// 4.4. Obsolete Addressing
// obs-angle-addr = [CFWS] "<" obs-route addr-spec ">" [CFWS]
function obsAngleAddr() {
return opts.strict ? null : wrap('obs-angle-addr', and(
invis(opt(cfws)),
literal('<'),
obsRoute,
addrSpec,
literal('>'),
invis(opt(cfws))
)());
}
// obs-route = obs-domain-list ":"
function obsRoute() {
return opts.strict ? null : wrap('obs-route', and(
obsDomainList,
literal(':')
)());
}
// obs-domain-list = *(CFWS / ",") "@" domain
// *("," [CFWS] ["@" domain])
function obsDomainList() {
return opts.strict ? null : wrap('obs-domain-list', and(
star(or(invis(cfws), literal(','))),
literal('@'),
domain,
star(and(
literal(','),
invis(opt(cfws)),
opt(and(literal('@'), domain))
))
)());
}
// obs-mbox-list = *([CFWS] ",") mailbox *("," [mailbox / CFWS])
function obsMboxList() {
return opts.strict ? null : wrap('obs-mbox-list', and(
star(and(
invis(opt(cfws)),
literal(',')
)),
mailbox,
star(and(
literal(','),
opt(and(
mailbox,
invis(cfws)
))
))
)());
}
// obs-addr-list = *([CFWS] ",") address *("," [address / CFWS])
function obsAddrList() {
return opts.strict ? null : wrap('obs-addr-list', and(
star(and(
invis(opt(cfws)),
literal(',')
)),
address,
star(and(
literal(','),
opt(and(
address,
invis(cfws)
))
))
)());
}
// obs-group-list = 1*([CFWS] ",") [CFWS]
function obsGroupList() {
return opts.strict ? null : wrap('obs-group-list', and(
star(and(
invis(opt(cfws)),
literal(',')
), 1),
invis(opt(cfws))
)());
}
// obs-local-part = word *("." word)
function obsLocalPart() {
return opts.strict ? null : wrap('obs-local-part', and(word, star(and(literal('.'), word)))());
}
// obs-domain = atom *("." atom)
function obsDomain() {
return opts.strict ? null : wrap('obs-domain', and(atom, star(and(literal('.'), atom)))());
}
// obs-dtext = obs-NO-WS-CTL / quoted-pair
function obsDtext() {
return opts.strict ? null : wrap('obs-dtext', or(obsNoWsCtl, quotedPair)());
}
/////////////////////////////////////////////////////
// ast analysis
function findNode(name, root) {
var i, stack, node;
if (root === null || root === undefined) { return null; }
stack = [root];
while (stack.length > 0) {
node = stack.pop();
if (node.name === name) {
return node;
}
for (i = node.children.length - 1; i >= 0; i -= 1) {
stack.push(node.children[i]);
}
}
return null;
}
function findAllNodes(name, root) {
var i, stack, node, result;
if (root === null || root === undefined) { return null; }
stack = [root];
result = [];
while (stack.length > 0) {
node = stack.pop();
if (node.name === name) {
result.push(node);
}
for (i = node.children.length - 1; i >= 0; i -= 1) {
stack.push(node.children[i]);
}
}
return result;
}
function findAllNodesNoChildren(names, root) {
var i, stack, node, result, namesLookup;
if (root === null || root === undefined) { return null; }
stack = [root];
result = [];
namesLookup = {};
for (i = 0; i < names.length; i += 1) {
namesLookup[names[i]] = true;
}
while (stack.length > 0) {
node = stack.pop();
if (node.name in namesLookup) {
result.push(node);
// don't look at children (hence findAllNodesNoChildren)
} else {
for (i = node.children.length - 1; i >= 0; i -= 1) {
stack.push(node.children[i]);
}
}
}
return result;
}
function giveResult(ast) {
var addresses, groupsAndMailboxes, i, groupOrMailbox, result;
if (ast === null) {
return null;
}
addresses = [];
// An address is a 'group' (i.e. a list of mailboxes) or a 'mailbox'.
groupsAndMailboxes = findAllNodesNoChildren(['group', 'mailbox'], ast);
for (i = 0; i < groupsAndMailboxes.length; i += 1) {
groupOrMailbox = groupsAndMailboxes[i];
if (groupOrMailbox.name === 'group') {
addresses.push(giveResultGroup(groupOrMailbox));
} else if (groupOrMailbox.name === 'mailbox') {
addresses.push(giveResultMailbox(groupOrMailbox));
}
}
result = {
ast: ast,
addresses: addresses,
};
if (opts.simple) {
result = simplifyResult(result);
}
if (opts.oneResult) {
return oneResult(result);
}
if (opts.simple) {
return result && result.addresses;
} else {
return result;
}
}
function giveResultGroup(group) {
var i;
var groupName = findNode('display-name', group);
var groupResultMailboxes = [];
var mailboxes = findAllNodesNoChildren(['mailbox'], group);
for (i = 0; i < mailboxes.length; i += 1) {
groupResultMailboxes.push(giveResultMailbox(mailboxes[i]));
}
return {
node: group,
parts: {
name: groupName,
},
type: group.name, // 'group'
name: grabSemantic(groupName),
addresses: groupResultMailboxes,
};
}
function giveResultMailbox(mailbox) {
var name = findNode('display-name', mailbox);
var aspec = findNode('addr-spec', mailbox);
var cfws = findAllNodes('cfws', mailbox);
var comments = findAllNodesNoChildren(['comment'], mailbox);
var local = findNode('local-part', aspec);
var domain = findNode('domain', aspec);
return {
node: mailbox,
parts: {
name: name,
address: aspec,
local: local,
domain: domain,
comments: cfws
},
type: mailbox.name, // 'mailbox'
name: grabSemantic(name),
address: grabSemantic(aspec),
local: grabSemantic(local),
domain: grabSemantic(domain),
comments: concatComments(comments),
groupName: grabSemantic(mailbox.groupName),
};
}
function grabSemantic(n) {
return n !== null && n !== undefined ? n.semantic : null;
}
function simplifyResult(result) {
var i;
if (result && result.addresses) {
for (i = 0; i < result.addresses.length; i += 1) {
delete result.addresses[i].node;
}
}
return result;
}
function concatComments(comments) {
var result = '';
if (comments) {
for (var i = 0; i < comments.length; i += 1) {
result += grabSemantic(comments[i]);
}
}
return result;
}
function oneResult(result) {
if (!result) { return null; }
if (!opts.partial && result.addresses.length > 1) { return null; }
return result.addresses && result.addresses[0];
}
/////////////////////////////////////////////////////
var parseString, pos, len, parsed, startProduction;
opts = handleOpts(opts, {});
if (opts === null) { return null; }
parseString = opts.input;
startProduction = {
'address': address,
'address-list': addressList,
'angle-addr': angleAddr,
'from': fromSpec,
'group': group,
'mailbox': mailbox,
'mailbox-list': mailboxList,
'reply-to': replyToSpec,
'sender': senderSpec,
}[opts.startAt] || addressList;
if (!opts.strict) {
initialize();
opts.strict = true;
parsed = startProduction(parseString);
if (opts.partial || !inStr()) {
return giveResult(parsed);
}
opts.strict = false;
}
initialize();
parsed = startProduction(parseString);
if (!opts.partial && inStr()) { return null; }
return giveResult(parsed);
}
function parseOneAddressSimple(opts) {
return parse5322(handleOpts(opts, {
oneResult: true,
rfc6532: true,
simple: true,
startAt: 'address-list',
}));
}
function parseAddressListSimple(opts) {
return parse5322(handleOpts(opts, {
rfc6532: true,
simple: true,
startAt: 'address-list',
}));
}
function parseFromSimple(opts) {
return parse5322(handleOpts(opts, {
rfc6532: true,
simple: true,
startAt: 'from',
}));
}
function parseSenderSimple(opts) {
return parse5322(handleOpts(opts, {
oneResult: true,
rfc6532: true,
simple: true,
startAt: 'sender',
}));
}
function parseReplyToSimple(opts) {
return parse5322(handleOpts(opts, {
rfc6532: true,
simple: true,
startAt: 'reply-to',
}));
}
function handleOpts(opts, defs) {
function isString(str) {
return Object.prototype.toString.call(str) === '[object String]';
}
function isObject(o) {
return o === Object(o);
}
function isNullUndef(o) {
return o === null || o === undefined;
}
var defaults, o;
if (isString(opts)) {
opts = { input: opts };
} else if (!isObject(opts)) {
return null;
}
if (!isString(opts.input)) { return null; }
if (!defs) { return null; }
defaults = {
oneResult: false,
partial: false,
rejectTLD: false,
rfc6532: false,
simple: false,
startAt: 'address-list',
strict: false,
atInDisplayName: false
};
for (o in defaults) {
if (isNullUndef(opts[o])) {
opts[o] = !isNullUndef(defs[o]) ? defs[o] : defaults[o];
}
}
return opts;
}
parse5322.parseOneAddress = parseOneAddressSimple;
parse5322.parseAddressList = parseAddressListSimple;
parse5322.parseFrom = parseFromSimple;
parse5322.parseSender = parseSenderSimple;
parse5322.parseReplyTo = parseReplyToSimple;
{
module.exports = parse5322;
}
}());
});
// GPG4Browsers - An OpenPGP implementation in javascript
/**
* Implementation of the User ID Packet (Tag 13)
*
* A User ID packet consists of UTF-8 text that is intended to represent
* the name and email address of the key holder. By convention, it
* includes an RFC 2822 [RFC2822] mail name-addr, but there are no
* restrictions on its content. The packet length in the header
* specifies the length of the User ID.
*/
class UserIDPacket {
static get tag() {
return enums.packet.userID;
}
constructor() {
/** A string containing the user id. Usually in the form
* John Doe
* @type {String}
*/
this.userID = '';
this.name = '';
this.email = '';
this.comment = '';
}
/**
* Create UserIDPacket instance from object
* @param {Object} userID - Object specifying userID name, email and comment
* @returns {UserIDPacket}
* @static
*/
static fromObject(userID) {
if (util.isString(userID) ||
(userID.name && !util.isString(userID.name)) ||
(userID.email && !util.isEmailAddress(userID.email)) ||
(userID.comment && !util.isString(userID.comment))) {
throw new Error('Invalid user ID format');
}
const packet = new UserIDPacket();
Object.assign(packet, userID);
const components = [];
if (packet.name) components.push(packet.name);
if (packet.comment) components.push(`(${packet.comment})`);
if (packet.email) components.push(`<${packet.email}>`);
packet.userID = components.join(' ');
return packet;
}
/**
* Parsing function for a user id packet (tag 13).
* @param {Uint8Array} input - Payload of a tag 13 packet
*/
read(bytes, config$1 = config) {
const userID = util.decodeUTF8(bytes);
if (userID.length > config$1.maxUserIDLength) {
throw new Error('User ID string is too long');
}
try {
const { name, address: email, comments } = emailAddresses.parseOneAddress({ input: userID, atInDisplayName: true });
this.comment = comments.replace(/^\(|\)$/g, '');
this.name = name;
this.email = email;
} catch (e) {}
this.userID = userID;
}
/**
* Creates a binary representation of the user id packet
* @returns {Uint8Array} Binary representation.
*/
write() {
return util.encodeUTF8(this.userID);
}
equals(otherUserID) {
return otherUserID && otherUserID.userID === this.userID;
}
}
// GPG4Browsers - An OpenPGP implementation in javascript
/**
* A Secret-Subkey packet (tag 7) is the subkey analog of the Secret
* Key packet and has exactly the same format.
* @extends SecretKeyPacket
*/
class SecretSubkeyPacket extends SecretKeyPacket {
static get tag() {
return enums.packet.secretSubkey;
}
/**
* @param {Date} [date] - Creation date
* @param {Object} [config] - Full configuration, defaults to openpgp.config
*/
constructor(date = new Date(), config$1 = config) {
super(date, config$1);
}
}
/**
* Implementation of the Trust Packet (Tag 12)
*
* {@link https://tools.ietf.org/html/rfc4880#section-5.10|RFC4880 5.10}:
* The Trust packet is used only within keyrings and is not normally
* exported. Trust packets contain data that record the user's
* specifications of which key holders are trustworthy introducers,
* along with other information that implementing software uses for
* trust information. The format of Trust packets is defined by a given
* implementation.
*
* Trust packets SHOULD NOT be emitted to output streams that are
* transferred to other users, and they SHOULD be ignored on any input
* other than local keyring files.
*/
class TrustPacket {
static get tag() {
return enums.packet.trust;
}
/**
* Parsing function for a trust packet (tag 12).
* Currently not implemented as we ignore trust packets
*/
read() {
throw new UnsupportedError('Trust packets are not supported');
}
write() {
throw new UnsupportedError('Trust packets are not supported');
}
}
// GPG4Browsers - An OpenPGP implementation in javascript
// A Signature can contain the following packets
const allowedPackets$4 = /*#__PURE__*/ util.constructAllowedPackets([SignaturePacket]);
/**
* Class that represents an OpenPGP signature.
*/
class Signature {
/**
* @param {PacketList} packetlist - The signature packets
*/
constructor(packetlist) {
this.packets = packetlist || new PacketList();
}
/**
* Returns binary encoded signature
* @returns {ReadableStream} Binary signature.
*/
write() {
return this.packets.write();
}
/**
* Returns ASCII armored text of signature
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {ReadableStream} ASCII armor.
*/
armor(config$1 = config) {
return armor(enums.armor.signature, this.write(), undefined, undefined, undefined, config$1);
}
/**
* Returns an array of KeyIDs of all of the issuers who created this signature
* @returns {Array} The Key IDs of the signing keys
*/
getSigningKeyIDs() {
return this.packets.map(packet => packet.issuerKeyID);
}
}
/**
* reads an (optionally armored) OpenPGP signature and returns a signature object
* @param {Object} options
* @param {String} [options.armoredSignature] - Armored signature to be parsed
* @param {Uint8Array} [options.binarySignature] - Binary signature to be parsed
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
* @returns {Promise} New signature object.
* @async
* @static
*/
async function readSignature({ armoredSignature, binarySignature, config: config$1, ...rest }) {
config$1 = { ...config, ...config$1 };
let input = armoredSignature || binarySignature;
if (!input) {
throw new Error('readSignature: must pass options object containing `armoredSignature` or `binarySignature`');
}
if (armoredSignature && !util.isString(armoredSignature)) {
throw new Error('readSignature: options.armoredSignature must be a string');
}
if (binarySignature && !util.isUint8Array(binarySignature)) {
throw new Error('readSignature: options.binarySignature must be a Uint8Array');
}
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
if (armoredSignature) {
const { type, data } = await unarmor(input, config$1);
if (type !== enums.armor.signature) {
throw new Error('Armored text not of type signature');
}
input = data;
}
const packetlist = await PacketList.fromBinary(input, allowedPackets$4, config$1);
return new Signature(packetlist);
}
/**
* @fileoverview Provides helpers methods for key module
* @module key/helper
* @private
*/
async function generateSecretSubkey(options, config) {
const secretSubkeyPacket = new SecretSubkeyPacket(options.date, config);
secretSubkeyPacket.packets = null;
secretSubkeyPacket.algorithm = enums.write(enums.publicKey, options.algorithm);
await secretSubkeyPacket.generate(options.rsaBits, options.curve);
await secretSubkeyPacket.computeFingerprintAndKeyID();
return secretSubkeyPacket;
}
async function generateSecretKey(options, config) {
const secretKeyPacket = new SecretKeyPacket(options.date, config);
secretKeyPacket.packets = null;
secretKeyPacket.algorithm = enums.write(enums.publicKey, options.algorithm);
await secretKeyPacket.generate(options.rsaBits, options.curve, options.config);
await secretKeyPacket.computeFingerprintAndKeyID();
return secretKeyPacket;
}
/**
* Returns the valid and non-expired signature that has the latest creation date, while ignoring signatures created in the future.
* @param {Array} signatures - List of signatures
* @param {PublicKeyPacket|PublicSubkeyPacket} publicKey - Public key packet to verify the signature
* @param {Date} date - Use the given date instead of the current time
* @param {Object} config - full configuration
* @returns {Promise} The latest valid signature.
* @async
*/
async function getLatestValidSignature(signatures, publicKey, signatureType, dataToVerify, date = new Date(), config) {
let latestValid;
let exception;
for (let i = signatures.length - 1; i >= 0; i--) {
try {
if (
(!latestValid || signatures[i].created >= latestValid.created)
) {
await signatures[i].verify(publicKey, signatureType, dataToVerify, date, undefined, config);
latestValid = signatures[i];
}
} catch (e) {
exception = e;
}
}
if (!latestValid) {
throw util.wrapError(
`Could not find valid ${enums.read(enums.signature, signatureType)} signature in key ${publicKey.getKeyID().toHex()}`
.replace('certGeneric ', 'self-')
.replace(/([a-z])([A-Z])/g, (_, $1, $2) => $1 + ' ' + $2.toLowerCase()),
exception);
}
return latestValid;
}
function isDataExpired(keyPacket, signature, date = new Date()) {
const normDate = util.normalizeDate(date);
if (normDate !== null) {
const expirationTime = getKeyExpirationTime(keyPacket, signature);
return !(keyPacket.created <= normDate && normDate < expirationTime);
}
return false;
}
/**
* Create Binding signature to the key according to the {@link https://tools.ietf.org/html/rfc4880#section-5.2.1}
* @param {SecretSubkeyPacket} subkey - Subkey key packet
* @param {SecretKeyPacket} primaryKey - Primary key packet
* @param {Object} options
* @param {Object} config - Full configuration
*/
async function createBindingSignature(subkey, primaryKey, options, config) {
const dataToSign = {};
dataToSign.key = primaryKey;
dataToSign.bind = subkey;
const subkeySignaturePacket = new SignaturePacket();
subkeySignaturePacket.signatureType = enums.signature.subkeyBinding;
subkeySignaturePacket.publicKeyAlgorithm = primaryKey.algorithm;
subkeySignaturePacket.hashAlgorithm = await getPreferredHashAlgo$1(null, subkey, undefined, undefined, config);
if (options.sign) {
subkeySignaturePacket.keyFlags = [enums.keyFlags.signData];
subkeySignaturePacket.embeddedSignature = await createSignaturePacket(dataToSign, null, subkey, {
signatureType: enums.signature.keyBinding
}, options.date, undefined, undefined, undefined, config);
} else {
subkeySignaturePacket.keyFlags = [enums.keyFlags.encryptCommunication | enums.keyFlags.encryptStorage];
}
if (options.keyExpirationTime > 0) {
subkeySignaturePacket.keyExpirationTime = options.keyExpirationTime;
subkeySignaturePacket.keyNeverExpires = false;
}
await subkeySignaturePacket.sign(primaryKey, dataToSign, options.date);
return subkeySignaturePacket;
}
/**
* Returns the preferred signature hash algorithm of a key
* @param {Key} [key] - The key to get preferences from
* @param {SecretKeyPacket|SecretSubkeyPacket} keyPacket - key packet used for signing
* @param {Date} [date] - Use the given date for verification instead of the current time
* @param {Object} [userID] - User ID
* @param {Object} config - full configuration
* @returns {Promise}
* @async
*/
async function getPreferredHashAlgo$1(key, keyPacket, date = new Date(), userID = {}, config) {
let hashAlgo = config.preferredHashAlgorithm;
let prefAlgo = hashAlgo;
if (key) {
const primaryUser = await key.getPrimaryUser(date, userID, config);
if (primaryUser.selfCertification.preferredHashAlgorithms) {
[prefAlgo] = primaryUser.selfCertification.preferredHashAlgorithms;
hashAlgo = mod.hash.getHashByteLength(hashAlgo) <= mod.hash.getHashByteLength(prefAlgo) ?
prefAlgo : hashAlgo;
}
}
switch (Object.getPrototypeOf(keyPacket)) {
case SecretKeyPacket.prototype:
case PublicKeyPacket.prototype:
case SecretSubkeyPacket.prototype:
case PublicSubkeyPacket.prototype:
switch (keyPacket.algorithm) {
case enums.publicKey.ecdh:
case enums.publicKey.ecdsa:
case enums.publicKey.eddsa:
prefAlgo = mod.publicKey.elliptic.getPreferredHashAlgo(keyPacket.publicParams.oid);
}
}
return mod.hash.getHashByteLength(hashAlgo) <= mod.hash.getHashByteLength(prefAlgo) ?
prefAlgo : hashAlgo;
}
/**
* Returns the preferred symmetric/aead/compression algorithm for a set of keys
* @param {'symmetric'|'aead'|'compression'} type - Type of preference to return
* @param {Array} [keys] - Set of keys
* @param {Date} [date] - Use the given date for verification instead of the current time
* @param {Array} [userIDs] - User IDs
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise} Preferred algorithm
* @async
*/
async function getPreferredAlgo(type, keys = [], date = new Date(), userIDs = [], config$1 = config) {
const defaultAlgo = { // these are all must-implement in rfc4880bis
'symmetric': enums.symmetric.aes128,
'aead': enums.aead.eax,
'compression': enums.compression.uncompressed
}[type];
const preferredSenderAlgo = {
'symmetric': config$1.preferredSymmetricAlgorithm,
'aead': config$1.preferredAEADAlgorithm,
'compression': config$1.preferredCompressionAlgorithm
}[type];
const prefPropertyName = {
'symmetric': 'preferredSymmetricAlgorithms',
'aead': 'preferredAEADAlgorithms',
'compression': 'preferredCompressionAlgorithms'
}[type];
// if preferredSenderAlgo appears in the prefs of all recipients, we pick it
// otherwise we use the default algo
// if no keys are available, preferredSenderAlgo is returned
const senderAlgoSupport = await Promise.all(keys.map(async function(key, i) {
const primaryUser = await key.getPrimaryUser(date, userIDs[i], config$1);
const recipientPrefs = primaryUser.selfCertification[prefPropertyName];
return !!recipientPrefs && recipientPrefs.indexOf(preferredSenderAlgo) >= 0;
}));
return senderAlgoSupport.every(Boolean) ? preferredSenderAlgo : defaultAlgo;
}
/**
* Create signature packet
* @param {Object} dataToSign - Contains packets to be signed
* @param {PrivateKey} privateKey - key to get preferences from
* @param {SecretKeyPacket|
* SecretSubkeyPacket} signingKeyPacket secret key packet for signing
* @param {Object} [signatureProperties] - Properties to write on the signature packet before signing
* @param {Date} [date] - Override the creationtime of the signature
* @param {Object} [userID] - User ID
* @param {Array} [notations] - Notation Data to add to the signature, e.g. [{ name: 'test@example.org', value: new TextEncoder().encode('test'), humanReadable: true, critical: false }]
* @param {Object} [detached] - Whether to create a detached signature packet
* @param {Object} config - full configuration
* @returns {Promise} Signature packet.
*/
async function createSignaturePacket(dataToSign, privateKey, signingKeyPacket, signatureProperties, date, userID, notations = [], detached = false, config) {
if (signingKeyPacket.isDummy()) {
throw new Error('Cannot sign with a gnu-dummy key.');
}
if (!signingKeyPacket.isDecrypted()) {
throw new Error('Signing key is not decrypted.');
}
const signaturePacket = new SignaturePacket();
Object.assign(signaturePacket, signatureProperties);
signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm;
signaturePacket.hashAlgorithm = await getPreferredHashAlgo$1(privateKey, signingKeyPacket, date, userID, config);
signaturePacket.rawNotations = notations;
await signaturePacket.sign(signingKeyPacket, dataToSign, date, detached);
return signaturePacket;
}
/**
* Merges signatures from source[attr] to dest[attr]
* @param {Object} source
* @param {Object} dest
* @param {String} attr
* @param {Date} [date] - date to use for signature expiration check, instead of the current time
* @param {Function} [checkFn] - signature only merged if true
*/
async function mergeSignatures(source, dest, attr, date = new Date(), checkFn) {
source = source[attr];
if (source) {
if (!dest[attr].length) {
dest[attr] = source;
} else {
await Promise.all(source.map(async function(sourceSig) {
if (!sourceSig.isExpired(date) && (!checkFn || await checkFn(sourceSig)) &&
!dest[attr].some(function(destSig) {
return util.equalsUint8Array(destSig.writeParams(), sourceSig.writeParams());
})) {
dest[attr].push(sourceSig);
}
}));
}
}
}
/**
* Checks if a given certificate or binding signature is revoked
* @param {SecretKeyPacket|
* PublicKeyPacket} primaryKey The primary key packet
* @param {Object} dataToVerify - The data to check
* @param {Array} revocations - The revocation signatures to check
* @param {SignaturePacket} signature - The certificate or signature to check
* @param {PublicSubkeyPacket|
* SecretSubkeyPacket|
* PublicKeyPacket|
* SecretKeyPacket} key, optional The key packet to verify the signature, instead of the primary key
* @param {Date} date - Use the given date instead of the current time
* @param {Object} config - Full configuration
* @returns {Promise} True if the signature revokes the data.
* @async
*/
async function isDataRevoked(primaryKey, signatureType, dataToVerify, revocations, signature, key, date = new Date(), config) {
key = key || primaryKey;
const revocationKeyIDs = [];
await Promise.all(revocations.map(async function(revocationSignature) {
try {
if (
// Note: a third-party revocation signature could legitimately revoke a
// self-signature if the signature has an authorized revocation key.
// However, we don't support passing authorized revocation keys, nor
// verifying such revocation signatures. Instead, we indicate an error
// when parsing a key with an authorized revocation key, and ignore
// third-party revocation signatures here. (It could also be revoking a
// third-party key certification, which should only affect
// `verifyAllCertifications`.)
!signature || revocationSignature.issuerKeyID.equals(signature.issuerKeyID)
) {
await revocationSignature.verify(
key, signatureType, dataToVerify, config.revocationsExpire ? date : null, false, config
);
// TODO get an identifier of the revoked object instead
revocationKeyIDs.push(revocationSignature.issuerKeyID);
}
} catch (e) {}
}));
// TODO further verify that this is the signature that should be revoked
if (signature) {
signature.revoked = revocationKeyIDs.some(keyID => keyID.equals(signature.issuerKeyID)) ? true :
signature.revoked || false;
return signature.revoked;
}
return revocationKeyIDs.length > 0;
}
/**
* Returns key expiration time based on the given certification signature.
* The expiration time of the signature is ignored.
* @param {PublicSubkeyPacket|PublicKeyPacket} keyPacket - key to check
* @param {SignaturePacket} signature - signature to process
* @returns {Date|Infinity} expiration time or infinity if the key does not expire
*/
function getKeyExpirationTime(keyPacket, signature) {
let expirationTime;
// check V4 expiration time
if (signature.keyNeverExpires === false) {
expirationTime = keyPacket.created.getTime() + signature.keyExpirationTime * 1000;
}
return expirationTime ? new Date(expirationTime) : Infinity;
}
/**
* Returns whether aead is supported by all keys in the set
* @param {Array} keys - Set of keys
* @param {Date} [date] - Use the given date for verification instead of the current time
* @param {Array} [userIDs] - User IDs
* @param {Object} config - full configuration
* @returns {Promise}
* @async
*/
async function isAEADSupported(keys, date = new Date(), userIDs = [], config$1 = config) {
let supported = true;
// TODO replace when Promise.some or Promise.any are implemented
await Promise.all(keys.map(async function(key, i) {
const primaryUser = await key.getPrimaryUser(date, userIDs[i], config$1);
if (!primaryUser.selfCertification.features ||
!(primaryUser.selfCertification.features[0] & enums.features.aead)) {
supported = false;
}
}));
return supported;
}
function sanitizeKeyOptions(options, subkeyDefaults = {}) {
options.type = options.type || subkeyDefaults.type;
options.curve = options.curve || subkeyDefaults.curve;
options.rsaBits = options.rsaBits || subkeyDefaults.rsaBits;
options.keyExpirationTime = options.keyExpirationTime !== undefined ? options.keyExpirationTime : subkeyDefaults.keyExpirationTime;
options.passphrase = util.isString(options.passphrase) ? options.passphrase : subkeyDefaults.passphrase;
options.date = options.date || subkeyDefaults.date;
options.sign = options.sign || false;
switch (options.type) {
case 'ecc':
try {
options.curve = enums.write(enums.curve, options.curve);
} catch (e) {
throw new Error('Unknown curve');
}
if (options.curve === enums.curve.ed25519 || options.curve === enums.curve.curve25519) {
options.curve = options.sign ? enums.curve.ed25519 : enums.curve.curve25519;
}
if (options.sign) {
options.algorithm = options.curve === enums.curve.ed25519 ? enums.publicKey.eddsa : enums.publicKey.ecdsa;
} else {
options.algorithm = enums.publicKey.ecdh;
}
break;
case 'rsa':
options.algorithm = enums.publicKey.rsaEncryptSign;
break;
default:
throw new Error(`Unsupported key type ${options.type}`);
}
return options;
}
function isValidSigningKeyPacket(keyPacket, signature) {
const keyAlgo = keyPacket.algorithm;
return keyAlgo !== enums.publicKey.rsaEncrypt &&
keyAlgo !== enums.publicKey.elgamal &&
keyAlgo !== enums.publicKey.ecdh &&
(!signature.keyFlags ||
(signature.keyFlags[0] & enums.keyFlags.signData) !== 0);
}
function isValidEncryptionKeyPacket(keyPacket, signature) {
const keyAlgo = keyPacket.algorithm;
return keyAlgo !== enums.publicKey.dsa &&
keyAlgo !== enums.publicKey.rsaSign &&
keyAlgo !== enums.publicKey.ecdsa &&
keyAlgo !== enums.publicKey.eddsa &&
(!signature.keyFlags ||
(signature.keyFlags[0] & enums.keyFlags.encryptCommunication) !== 0 ||
(signature.keyFlags[0] & enums.keyFlags.encryptStorage) !== 0);
}
function isValidDecryptionKeyPacket(signature, config) {
if (config.allowInsecureDecryptionWithSigningKeys) {
// This is only relevant for RSA keys, all other signing algorithms cannot decrypt
return true;
}
return !signature.keyFlags ||
(signature.keyFlags[0] & enums.keyFlags.encryptCommunication) !== 0 ||
(signature.keyFlags[0] & enums.keyFlags.encryptStorage) !== 0;
}
/**
* Check key against blacklisted algorithms and minimum strength requirements.
* @param {SecretKeyPacket|PublicKeyPacket|
* SecretSubkeyPacket|PublicSubkeyPacket} keyPacket
* @param {Config} config
* @throws {Error} if the key packet does not meet the requirements
*/
function checkKeyRequirements(keyPacket, config) {
const keyAlgo = enums.write(enums.publicKey, keyPacket.algorithm);
const algoInfo = keyPacket.getAlgorithmInfo();
if (config.rejectPublicKeyAlgorithms.has(keyAlgo)) {
throw new Error(`${algoInfo.algorithm} keys are considered too weak.`);
}
switch (keyAlgo) {
case enums.publicKey.rsaEncryptSign:
case enums.publicKey.rsaSign:
case enums.publicKey.rsaEncrypt:
if (algoInfo.bits < config.minRSABits) {
throw new Error(`RSA keys shorter than ${config.minRSABits} bits are considered too weak.`);
}
break;
case enums.publicKey.ecdsa:
case enums.publicKey.eddsa:
case enums.publicKey.ecdh:
if (config.rejectCurves.has(algoInfo.curve)) {
throw new Error(`Support for ${algoInfo.algorithm} keys using curve ${algoInfo.curve} is disabled.`);
}
break;
}
}
/**
* @module key/User
* @private
*/
/**
* Class that represents an user ID or attribute packet and the relevant signatures.
* @param {UserIDPacket|UserAttributePacket} userPacket - packet containing the user info
* @param {Key} mainKey - reference to main Key object containing the primary key and subkeys that the user is associated with
*/
class User {
constructor(userPacket, mainKey) {
this.userID = userPacket.constructor.tag === enums.packet.userID ? userPacket : null;
this.userAttribute = userPacket.constructor.tag === enums.packet.userAttribute ? userPacket : null;
this.selfCertifications = [];
this.otherCertifications = [];
this.revocationSignatures = [];
this.mainKey = mainKey;
}
/**
* Transforms structured user data to packetlist
* @returns {PacketList}
*/
toPacketList() {
const packetlist = new PacketList();
packetlist.push(this.userID || this.userAttribute);
packetlist.push(...this.revocationSignatures);
packetlist.push(...this.selfCertifications);
packetlist.push(...this.otherCertifications);
return packetlist;
}
/**
* Shallow clone
* @returns {User}
*/
clone() {
const user = new User(this.userID || this.userAttribute, this.mainKey);
user.selfCertifications = [...this.selfCertifications];
user.otherCertifications = [...this.otherCertifications];
user.revocationSignatures = [...this.revocationSignatures];
return user;
}
/**
* Generate third-party certifications over this user and its primary key
* @param {Array} signingKeys - Decrypted private keys for signing
* @param {Date} [date] - Date to use as creation date of the certificate, instead of the current time
* @param {Object} config - Full configuration
* @returns {Promise} New user with new certifications.
* @async
*/
async certify(signingKeys, date, config) {
const primaryKey = this.mainKey.keyPacket;
const dataToSign = {
userID: this.userID,
userAttribute: this.userAttribute,
key: primaryKey
};
const user = new User(dataToSign.userID || dataToSign.userAttribute, this.mainKey);
user.otherCertifications = await Promise.all(signingKeys.map(async function(privateKey) {
if (!privateKey.isPrivate()) {
throw new Error('Need private key for signing');
}
if (privateKey.hasSameFingerprintAs(primaryKey)) {
throw new Error("The user's own key can only be used for self-certifications");
}
const signingKey = await privateKey.getSigningKey(undefined, date, undefined, config);
return createSignaturePacket(dataToSign, privateKey, signingKey.keyPacket, {
// Most OpenPGP implementations use generic certification (0x10)
signatureType: enums.signature.certGeneric,
keyFlags: [enums.keyFlags.certifyKeys | enums.keyFlags.signData]
}, date, undefined, undefined, undefined, config);
}));
await user.update(this, date, config);
return user;
}
/**
* Checks if a given certificate of the user is revoked
* @param {SignaturePacket} certificate - The certificate to verify
* @param {PublicSubkeyPacket|
* SecretSubkeyPacket|
* PublicKeyPacket|
* SecretKeyPacket} [keyPacket] The key packet to verify the signature, instead of the primary key
* @param {Date} [date] - Use the given date for verification instead of the current time
* @param {Object} config - Full configuration
* @returns {Promise} True if the certificate is revoked.
* @async
*/
async isRevoked(certificate, keyPacket, date = new Date(), config$1 = config) {
const primaryKey = this.mainKey.keyPacket;
return isDataRevoked(primaryKey, enums.signature.certRevocation, {
key: primaryKey,
userID: this.userID,
userAttribute: this.userAttribute
}, this.revocationSignatures, certificate, keyPacket, date, config$1);
}
/**
* Verifies the user certificate.
* @param {SignaturePacket} certificate - A certificate of this user
* @param {Array} verificationKeys - Array of keys to verify certificate signatures
* @param {Date} [date] - Use the given date instead of the current time
* @param {Object} config - Full configuration
* @returns {Promise} true if the certificate could be verified, or null if the verification keys do not correspond to the certificate
* @throws if the user certificate is invalid.
* @async
*/
async verifyCertificate(certificate, verificationKeys, date = new Date(), config) {
const that = this;
const primaryKey = this.mainKey.keyPacket;
const dataToVerify = {
userID: this.userID,
userAttribute: this.userAttribute,
key: primaryKey
};
const { issuerKeyID } = certificate;
const issuerKeys = verificationKeys.filter(key => key.getKeys(issuerKeyID).length > 0);
if (issuerKeys.length === 0) {
return null;
}
await Promise.all(issuerKeys.map(async key => {
const signingKey = await key.getSigningKey(issuerKeyID, certificate.created, undefined, config);
if (certificate.revoked || await that.isRevoked(certificate, signingKey.keyPacket, date, config)) {
throw new Error('User certificate is revoked');
}
try {
await certificate.verify(signingKey.keyPacket, enums.signature.certGeneric, dataToVerify, date, undefined, config);
} catch (e) {
throw util.wrapError('User certificate is invalid', e);
}
}));
return true;
}
/**
* Verifies all user certificates
* @param {Array} verificationKeys - Array of keys to verify certificate signatures
* @param {Date} [date] - Use the given date instead of the current time
* @param {Object} config - Full configuration
* @returns {Promise>} List of signer's keyID and validity of signature.
* Signature validity is null if the verification keys do not correspond to the certificate.
* @async
*/
async verifyAllCertifications(verificationKeys, date = new Date(), config) {
const that = this;
const certifications = this.selfCertifications.concat(this.otherCertifications);
return Promise.all(certifications.map(async certification => ({
keyID: certification.issuerKeyID,
valid: await that.verifyCertificate(certification, verificationKeys, date, config).catch(() => false)
})));
}
/**
* Verify User. Checks for existence of self signatures, revocation signatures
* and validity of self signature.
* @param {Date} date - Use the given date instead of the current time
* @param {Object} config - Full configuration
* @returns {Promise} Status of user.
* @throws {Error} if there are no valid self signatures.
* @async
*/
async verify(date = new Date(), config) {
if (!this.selfCertifications.length) {
throw new Error('No self-certifications found');
}
const that = this;
const primaryKey = this.mainKey.keyPacket;
const dataToVerify = {
userID: this.userID,
userAttribute: this.userAttribute,
key: primaryKey
};
// TODO replace when Promise.some or Promise.any are implemented
let exception;
for (let i = this.selfCertifications.length - 1; i >= 0; i--) {
try {
const selfCertification = this.selfCertifications[i];
if (selfCertification.revoked || await that.isRevoked(selfCertification, undefined, date, config)) {
throw new Error('Self-certification is revoked');
}
try {
await selfCertification.verify(primaryKey, enums.signature.certGeneric, dataToVerify, date, undefined, config);
} catch (e) {
throw util.wrapError('Self-certification is invalid', e);
}
return true;
} catch (e) {
exception = e;
}
}
throw exception;
}
/**
* Update user with new components from specified user
* @param {User} sourceUser - Source user to merge
* @param {Date} date - Date to verify the validity of signatures
* @param {Object} config - Full configuration
* @returns {Promise}
* @async
*/
async update(sourceUser, date, config) {
const primaryKey = this.mainKey.keyPacket;
const dataToVerify = {
userID: this.userID,
userAttribute: this.userAttribute,
key: primaryKey
};
// self signatures
await mergeSignatures(sourceUser, this, 'selfCertifications', date, async function(srcSelfSig) {
try {
await srcSelfSig.verify(primaryKey, enums.signature.certGeneric, dataToVerify, date, false, config);
return true;
} catch (e) {
return false;
}
});
// other signatures
await mergeSignatures(sourceUser, this, 'otherCertifications', date);
// revocation signatures
await mergeSignatures(sourceUser, this, 'revocationSignatures', date, function(srcRevSig) {
return isDataRevoked(primaryKey, enums.signature.certRevocation, dataToVerify, [srcRevSig], undefined, undefined, date, config);
});
}
/**
* Revokes the user
* @param {SecretKeyPacket} primaryKey - decrypted private primary key for revocation
* @param {Object} reasonForRevocation - optional, object indicating the reason for revocation
* @param {module:enums.reasonForRevocation} reasonForRevocation.flag optional, flag indicating the reason for revocation
* @param {String} reasonForRevocation.string optional, string explaining the reason for revocation
* @param {Date} date - optional, override the creationtime of the revocation signature
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise} New user with revocation signature.
* @async
*/
async revoke(
primaryKey,
{
flag: reasonForRevocationFlag = enums.reasonForRevocation.noReason,
string: reasonForRevocationString = ''
} = {},
date = new Date(),
config$1 = config
) {
const dataToSign = {
userID: this.userID,
userAttribute: this.userAttribute,
key: primaryKey
};
const user = new User(dataToSign.userID || dataToSign.userAttribute, this.mainKey);
user.revocationSignatures.push(await createSignaturePacket(dataToSign, null, primaryKey, {
signatureType: enums.signature.certRevocation,
reasonForRevocationFlag: enums.write(enums.reasonForRevocation, reasonForRevocationFlag),
reasonForRevocationString
}, date, undefined, undefined, false, config$1));
await user.update(this);
return user;
}
}
/**
* @module key/Subkey
* @private
*/
/**
* Class that represents a subkey packet and the relevant signatures.
* @borrows PublicSubkeyPacket#getKeyID as Subkey#getKeyID
* @borrows PublicSubkeyPacket#getFingerprint as Subkey#getFingerprint
* @borrows PublicSubkeyPacket#hasSameFingerprintAs as Subkey#hasSameFingerprintAs
* @borrows PublicSubkeyPacket#getAlgorithmInfo as Subkey#getAlgorithmInfo
* @borrows PublicSubkeyPacket#getCreationTime as Subkey#getCreationTime
* @borrows PublicSubkeyPacket#isDecrypted as Subkey#isDecrypted
*/
class Subkey {
/**
* @param {SecretSubkeyPacket|PublicSubkeyPacket} subkeyPacket - subkey packet to hold in the Subkey
* @param {Key} mainKey - reference to main Key object, containing the primary key packet corresponding to the subkey
*/
constructor(subkeyPacket, mainKey) {
this.keyPacket = subkeyPacket;
this.bindingSignatures = [];
this.revocationSignatures = [];
this.mainKey = mainKey;
}
/**
* Transforms structured subkey data to packetlist
* @returns {PacketList}
*/
toPacketList() {
const packetlist = new PacketList();
packetlist.push(this.keyPacket);
packetlist.push(...this.revocationSignatures);
packetlist.push(...this.bindingSignatures);
return packetlist;
}
/**
* Shallow clone
* @return {Subkey}
*/
clone() {
const subkey = new Subkey(this.keyPacket, this.mainKey);
subkey.bindingSignatures = [...this.bindingSignatures];
subkey.revocationSignatures = [...this.revocationSignatures];
return subkey;
}
/**
* Checks if a binding signature of a subkey is revoked
* @param {SignaturePacket} signature - The binding signature to verify
* @param {PublicSubkeyPacket|
* SecretSubkeyPacket|
* PublicKeyPacket|
* SecretKeyPacket} key, optional The key to verify the signature
* @param {Date} [date] - Use the given date for verification instead of the current time
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise} True if the binding signature is revoked.
* @async
*/
async isRevoked(signature, key, date = new Date(), config$1 = config) {
const primaryKey = this.mainKey.keyPacket;
return isDataRevoked(
primaryKey, enums.signature.subkeyRevocation, {
key: primaryKey,
bind: this.keyPacket
}, this.revocationSignatures, signature, key, date, config$1
);
}
/**
* Verify subkey. Checks for revocation signatures, expiration time
* and valid binding signature.
* @param {Date} date - Use the given date instead of the current time
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise}
* @throws {Error} if the subkey is invalid.
* @async
*/
async verify(date = new Date(), config$1 = config) {
const primaryKey = this.mainKey.keyPacket;
const dataToVerify = { key: primaryKey, bind: this.keyPacket };
// check subkey binding signatures
const bindingSignature = await getLatestValidSignature(this.bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date, config$1);
// check binding signature is not revoked
if (bindingSignature.revoked || await this.isRevoked(bindingSignature, null, date, config$1)) {
throw new Error('Subkey is revoked');
}
// check for expiration time
if (isDataExpired(this.keyPacket, bindingSignature, date)) {
throw new Error('Subkey is expired');
}
return bindingSignature;
}
/**
* Returns the expiration time of the subkey or Infinity if key does not expire.
* Returns null if the subkey is invalid.
* @param {Date} date - Use the given date instead of the current time
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise}
* @async
*/
async getExpirationTime(date = new Date(), config$1 = config) {
const primaryKey = this.mainKey.keyPacket;
const dataToVerify = { key: primaryKey, bind: this.keyPacket };
let bindingSignature;
try {
bindingSignature = await getLatestValidSignature(this.bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date, config$1);
} catch (e) {
return null;
}
const keyExpiry = getKeyExpirationTime(this.keyPacket, bindingSignature);
const sigExpiry = bindingSignature.getExpirationTime();
return keyExpiry < sigExpiry ? keyExpiry : sigExpiry;
}
/**
* Update subkey with new components from specified subkey
* @param {Subkey} subkey - Source subkey to merge
* @param {Date} [date] - Date to verify validity of signatures
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @throws {Error} if update failed
* @async
*/
async update(subkey, date = new Date(), config$1 = config) {
const primaryKey = this.mainKey.keyPacket;
if (!this.hasSameFingerprintAs(subkey)) {
throw new Error('Subkey update method: fingerprints of subkeys not equal');
}
// key packet
if (this.keyPacket.constructor.tag === enums.packet.publicSubkey &&
subkey.keyPacket.constructor.tag === enums.packet.secretSubkey) {
this.keyPacket = subkey.keyPacket;
}
// update missing binding signatures
const that = this;
const dataToVerify = { key: primaryKey, bind: that.keyPacket };
await mergeSignatures(subkey, this, 'bindingSignatures', date, async function(srcBindSig) {
for (let i = 0; i < that.bindingSignatures.length; i++) {
if (that.bindingSignatures[i].issuerKeyID.equals(srcBindSig.issuerKeyID)) {
if (srcBindSig.created > that.bindingSignatures[i].created) {
that.bindingSignatures[i] = srcBindSig;
}
return false;
}
}
try {
await srcBindSig.verify(primaryKey, enums.signature.subkeyBinding, dataToVerify, date, undefined, config$1);
return true;
} catch (e) {
return false;
}
});
// revocation signatures
await mergeSignatures(subkey, this, 'revocationSignatures', date, function(srcRevSig) {
return isDataRevoked(primaryKey, enums.signature.subkeyRevocation, dataToVerify, [srcRevSig], undefined, undefined, date, config$1);
});
}
/**
* Revokes the subkey
* @param {SecretKeyPacket} primaryKey - decrypted private primary key for revocation
* @param {Object} reasonForRevocation - optional, object indicating the reason for revocation
* @param {module:enums.reasonForRevocation} reasonForRevocation.flag optional, flag indicating the reason for revocation
* @param {String} reasonForRevocation.string optional, string explaining the reason for revocation
* @param {Date} date - optional, override the creationtime of the revocation signature
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise} New subkey with revocation signature.
* @async
*/
async revoke(
primaryKey,
{
flag: reasonForRevocationFlag = enums.reasonForRevocation.noReason,
string: reasonForRevocationString = ''
} = {},
date = new Date(),
config$1 = config
) {
const dataToSign = { key: primaryKey, bind: this.keyPacket };
const subkey = new Subkey(this.keyPacket, this.mainKey);
subkey.revocationSignatures.push(await createSignaturePacket(dataToSign, null, primaryKey, {
signatureType: enums.signature.subkeyRevocation,
reasonForRevocationFlag: enums.write(enums.reasonForRevocation, reasonForRevocationFlag),
reasonForRevocationString
}, date, undefined, undefined, false, config$1));
await subkey.update(this);
return subkey;
}
hasSameFingerprintAs(other) {
return this.keyPacket.hasSameFingerprintAs(other.keyPacket || other);
}
}
['getKeyID', 'getFingerprint', 'getAlgorithmInfo', 'getCreationTime', 'isDecrypted'].forEach(name => {
Subkey.prototype[name] =
function() {
return this.keyPacket[name]();
};
});
// GPG4Browsers - An OpenPGP implementation in javascript
// A key revocation certificate can contain the following packets
const allowedRevocationPackets = /*#__PURE__*/ util.constructAllowedPackets([SignaturePacket]);
const mainKeyPacketTags = new Set([enums.packet.publicKey, enums.packet.privateKey]);
const keyPacketTags = new Set([
enums.packet.publicKey, enums.packet.privateKey,
enums.packet.publicSubkey, enums.packet.privateSubkey
]);
/**
* Abstract class that represents an OpenPGP key. Must contain a primary key.
* Can contain additional subkeys, signatures, user ids, user attributes.
* @borrows PublicKeyPacket#getKeyID as Key#getKeyID
* @borrows PublicKeyPacket#getFingerprint as Key#getFingerprint
* @borrows PublicKeyPacket#hasSameFingerprintAs as Key#hasSameFingerprintAs
* @borrows PublicKeyPacket#getAlgorithmInfo as Key#getAlgorithmInfo
* @borrows PublicKeyPacket#getCreationTime as Key#getCreationTime
*/
class Key {
/**
* Transforms packetlist to structured key data
* @param {PacketList} packetlist - The packets that form a key
* @param {Set} disallowedPackets - disallowed packet tags
*/
packetListToStructure(packetlist, disallowedPackets = new Set()) {
let user;
let primaryKeyID;
let subkey;
let ignoreUntil;
for (const packet of packetlist) {
if (packet instanceof UnparseablePacket) {
const isUnparseableKeyPacket = keyPacketTags.has(packet.tag);
if (isUnparseableKeyPacket && !ignoreUntil) {
// Since non-key packets apply to the preceding key packet, if a (sub)key is Unparseable we must
// discard all non-key packets that follow, until another (sub)key packet is found.
if (mainKeyPacketTags.has(packet.tag)) {
ignoreUntil = mainKeyPacketTags;
} else {
ignoreUntil = keyPacketTags;
}
}
continue;
}
const tag = packet.constructor.tag;
if (ignoreUntil) {
if (!ignoreUntil.has(tag)) continue;
ignoreUntil = null;
}
if (disallowedPackets.has(tag)) {
throw new Error(`Unexpected packet type: ${tag}`);
}
switch (tag) {
case enums.packet.publicKey:
case enums.packet.secretKey:
if (this.keyPacket) {
throw new Error('Key block contains multiple keys');
}
this.keyPacket = packet;
primaryKeyID = this.getKeyID();
if (!primaryKeyID) {
throw new Error('Missing Key ID');
}
break;
case enums.packet.userID:
case enums.packet.userAttribute:
user = new User(packet, this);
this.users.push(user);
break;
case enums.packet.publicSubkey:
case enums.packet.secretSubkey:
user = null;
subkey = new Subkey(packet, this);
this.subkeys.push(subkey);
break;
case enums.packet.signature:
switch (packet.signatureType) {
case enums.signature.certGeneric:
case enums.signature.certPersona:
case enums.signature.certCasual:
case enums.signature.certPositive:
if (!user) {
util.printDebug('Dropping certification signatures without preceding user packet');
continue;
}
if (packet.issuerKeyID.equals(primaryKeyID)) {
user.selfCertifications.push(packet);
} else {
user.otherCertifications.push(packet);
}
break;
case enums.signature.certRevocation:
if (user) {
user.revocationSignatures.push(packet);
} else {
this.directSignatures.push(packet);
}
break;
case enums.signature.key:
this.directSignatures.push(packet);
break;
case enums.signature.subkeyBinding:
if (!subkey) {
util.printDebug('Dropping subkey binding signature without preceding subkey packet');
continue;
}
subkey.bindingSignatures.push(packet);
break;
case enums.signature.keyRevocation:
this.revocationSignatures.push(packet);
break;
case enums.signature.subkeyRevocation:
if (!subkey) {
util.printDebug('Dropping subkey revocation signature without preceding subkey packet');
continue;
}
subkey.revocationSignatures.push(packet);
break;
}
break;
}
}
}
/**
* Transforms structured key data to packetlist
* @returns {PacketList} The packets that form a key.
*/
toPacketList() {
const packetlist = new PacketList();
packetlist.push(this.keyPacket);
packetlist.push(...this.revocationSignatures);
packetlist.push(...this.directSignatures);
this.users.map(user => packetlist.push(...user.toPacketList()));
this.subkeys.map(subkey => packetlist.push(...subkey.toPacketList()));
return packetlist;
}
/**
* Clones the key object. The copy is shallow, as it references the same packet objects as the original. However, if the top-level API is used, the two key instances are effectively independent.
* @param {Boolean} [clonePrivateParams=false] Only relevant for private keys: whether the secret key paramenters should be deeply copied. This is needed if e.g. `encrypt()` is to be called either on the clone or the original key.
* @returns {Promise} Clone of the key.
*/
clone(clonePrivateParams = false) {
const key = new this.constructor(this.toPacketList());
if (clonePrivateParams) {
key.getKeys().forEach(k => {
// shallow clone the key packets
k.keyPacket = Object.create(
Object.getPrototypeOf(k.keyPacket),
Object.getOwnPropertyDescriptors(k.keyPacket)
);
if (!k.keyPacket.isDecrypted()) return;
// deep clone the private params, which are cleared during encryption
const privateParams = {};
Object.keys(k.keyPacket.privateParams).forEach(name => {
privateParams[name] = new Uint8Array(k.keyPacket.privateParams[name]);
});
k.keyPacket.privateParams = privateParams;
});
}
return key;
}
/**
* Returns an array containing all public or private subkeys matching keyID;
* If no keyID is given, returns all subkeys.
* @param {type/keyID} [keyID] - key ID to look for
* @returns {Array} array of subkeys
*/
getSubkeys(keyID = null) {
const subkeys = this.subkeys.filter(subkey => (
!keyID || subkey.getKeyID().equals(keyID, true)
));
return subkeys;
}
/**
* Returns an array containing all public or private keys matching keyID.
* If no keyID is given, returns all keys, starting with the primary key.
* @param {type/keyid~KeyID} [keyID] - key ID to look for
* @returns {Array} array of keys
*/
getKeys(keyID = null) {
const keys = [];
if (!keyID || this.getKeyID().equals(keyID, true)) {
keys.push(this);
}
return keys.concat(this.getSubkeys(keyID));
}
/**
* Returns key IDs of all keys
* @returns {Array}
*/
getKeyIDs() {
return this.getKeys().map(key => key.getKeyID());
}
/**
* Returns userIDs
* @returns {Array} Array of userIDs.
*/
getUserIDs() {
return this.users.map(user => {
return user.userID ? user.userID.userID : null;
}).filter(userID => userID !== null);
}
/**
* Returns binary encoded key
* @returns {Uint8Array} Binary key.
*/
write() {
return this.toPacketList().write();
}
/**
* Returns last created key or key by given keyID that is available for signing and verification
* @param {module:type/keyid~KeyID} [keyID] - key ID of a specific key to retrieve
* @param {Date} [date] - use the fiven date date to to check key validity instead of the current date
* @param {Object} [userID] - filter keys for the given user ID
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise} signing key
* @throws if no valid signing key was found
* @async
*/
async getSigningKey(keyID = null, date = new Date(), userID = {}, config$1 = config) {
await this.verifyPrimaryKey(date, userID, config$1);
const primaryKey = this.keyPacket;
const subkeys = this.subkeys.slice().sort((a, b) => b.keyPacket.created - a.keyPacket.created);
let exception;
for (const subkey of subkeys) {
if (!keyID || subkey.getKeyID().equals(keyID)) {
try {
await subkey.verify(date, config$1);
const dataToVerify = { key: primaryKey, bind: subkey.keyPacket };
const bindingSignature = await getLatestValidSignature(
subkey.bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date, config$1
);
if (!isValidSigningKeyPacket(subkey.keyPacket, bindingSignature)) {
continue;
}
if (!bindingSignature.embeddedSignature) {
throw new Error('Missing embedded signature');
}
// verify embedded signature
await getLatestValidSignature(
[bindingSignature.embeddedSignature], subkey.keyPacket, enums.signature.keyBinding, dataToVerify, date, config$1
);
checkKeyRequirements(subkey.keyPacket, config$1);
return subkey;
} catch (e) {
exception = e;
}
}
}
try {
const primaryUser = await this.getPrimaryUser(date, userID, config$1);
if ((!keyID || primaryKey.getKeyID().equals(keyID)) &&
isValidSigningKeyPacket(primaryKey, primaryUser.selfCertification, config$1)) {
checkKeyRequirements(primaryKey, config$1);
return this;
}
} catch (e) {
exception = e;
}
throw util.wrapError('Could not find valid signing key packet in key ' + this.getKeyID().toHex(), exception);
}
/**
* Returns last created key or key by given keyID that is available for encryption or decryption
* @param {module:type/keyid~KeyID} [keyID] - key ID of a specific key to retrieve
* @param {Date} [date] - use the fiven date date to to check key validity instead of the current date
* @param {Object} [userID] - filter keys for the given user ID
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise} encryption key
* @throws if no valid encryption key was found
* @async
*/
async getEncryptionKey(keyID, date = new Date(), userID = {}, config$1 = config) {
await this.verifyPrimaryKey(date, userID, config$1);
const primaryKey = this.keyPacket;
// V4: by convention subkeys are preferred for encryption service
const subkeys = this.subkeys.slice().sort((a, b) => b.keyPacket.created - a.keyPacket.created);
let exception;
for (const subkey of subkeys) {
if (!keyID || subkey.getKeyID().equals(keyID)) {
try {
await subkey.verify(date, config$1);
const dataToVerify = { key: primaryKey, bind: subkey.keyPacket };
const bindingSignature = await getLatestValidSignature(subkey.bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date, config$1);
if (isValidEncryptionKeyPacket(subkey.keyPacket, bindingSignature)) {
checkKeyRequirements(subkey.keyPacket, config$1);
return subkey;
}
} catch (e) {
exception = e;
}
}
}
try {
// if no valid subkey for encryption, evaluate primary key
const primaryUser = await this.getPrimaryUser(date, userID, config$1);
if ((!keyID || primaryKey.getKeyID().equals(keyID)) &&
isValidEncryptionKeyPacket(primaryKey, primaryUser.selfCertification)) {
checkKeyRequirements(primaryKey, config$1);
return this;
}
} catch (e) {
exception = e;
}
throw util.wrapError('Could not find valid encryption key packet in key ' + this.getKeyID().toHex(), exception);
}
/**
* Checks if a signature on a key is revoked
* @param {SignaturePacket} signature - The signature to verify
* @param {PublicSubkeyPacket|
* SecretSubkeyPacket|
* PublicKeyPacket|
* SecretKeyPacket} key, optional The key to verify the signature
* @param {Date} [date] - Use the given date for verification, instead of the current time
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise} True if the certificate is revoked.
* @async
*/
async isRevoked(signature, key, date = new Date(), config$1 = config) {
return isDataRevoked(
this.keyPacket, enums.signature.keyRevocation, { key: this.keyPacket }, this.revocationSignatures, signature, key, date, config$1
);
}
/**
* Verify primary key. Checks for revocation signatures, expiration time
* and valid self signature. Throws if the primary key is invalid.
* @param {Date} [date] - Use the given date for verification instead of the current time
* @param {Object} [userID] - User ID
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @throws {Error} If key verification failed
* @async
*/
async verifyPrimaryKey(date = new Date(), userID = {}, config$1 = config) {
const primaryKey = this.keyPacket;
// check for key revocation signatures
if (await this.isRevoked(null, null, date, config$1)) {
throw new Error('Primary key is revoked');
}
// check for valid, unrevoked, unexpired self signature
const { selfCertification } = await this.getPrimaryUser(date, userID, config$1);
// check for expiration time in binding signatures
if (isDataExpired(primaryKey, selfCertification, date)) {
throw new Error('Primary key is expired');
}
// check for expiration time in direct signatures
const directSignature = await getLatestValidSignature(
this.directSignatures, primaryKey, enums.signature.key, { key: primaryKey }, date, config$1
).catch(() => {}); // invalid signatures are discarded, to avoid breaking the key
if (directSignature && isDataExpired(primaryKey, directSignature, date)) {
throw new Error('Primary key is expired');
}
}
/**
* Returns the expiration date of the primary key, considering self-certifications and direct-key signatures.
* Returns `Infinity` if the key doesn't expire, or `null` if the key is revoked or invalid.
* @param {Object} [userID] - User ID to consider instead of the primary user
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise}
* @async
*/
async getExpirationTime(userID, config$1 = config) {
let primaryKeyExpiry;
try {
const { selfCertification } = await this.getPrimaryUser(null, userID, config$1);
const selfSigKeyExpiry = getKeyExpirationTime(this.keyPacket, selfCertification);
const selfSigExpiry = selfCertification.getExpirationTime();
const directSignature = await getLatestValidSignature(
this.directSignatures, this.keyPacket, enums.signature.key, { key: this.keyPacket }, null, config$1
).catch(() => {});
if (directSignature) {
const directSigKeyExpiry = getKeyExpirationTime(this.keyPacket, directSignature);
// We do not support the edge case where the direct signature expires, since it would invalidate the corresponding key expiration,
// causing a discountinous validy period for the key
primaryKeyExpiry = Math.min(selfSigKeyExpiry, selfSigExpiry, directSigKeyExpiry);
} else {
primaryKeyExpiry = selfSigKeyExpiry < selfSigExpiry ? selfSigKeyExpiry : selfSigExpiry;
}
} catch (e) {
primaryKeyExpiry = null;
}
return util.normalizeDate(primaryKeyExpiry);
}
/**
* Returns primary user and most significant (latest valid) self signature
* - if multiple primary users exist, returns the one with the latest self signature
* - otherwise, returns the user with the latest self signature
* @param {Date} [date] - Use the given date for verification instead of the current time
* @param {Object} [userID] - User ID to get instead of the primary user, if it exists
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise<{
* user: User,
* selfCertification: SignaturePacket
* }>} The primary user and the self signature
* @async
*/
async getPrimaryUser(date = new Date(), userID = {}, config$1 = config) {
const primaryKey = this.keyPacket;
const users = [];
let exception;
for (let i = 0; i < this.users.length; i++) {
try {
const user = this.users[i];
if (!user.userID) {
continue;
}
if (
(userID.name !== undefined && user.userID.name !== userID.name) ||
(userID.email !== undefined && user.userID.email !== userID.email) ||
(userID.comment !== undefined && user.userID.comment !== userID.comment)
) {
throw new Error('Could not find user that matches that user ID');
}
const dataToVerify = { userID: user.userID, key: primaryKey };
const selfCertification = await getLatestValidSignature(user.selfCertifications, primaryKey, enums.signature.certGeneric, dataToVerify, date, config$1);
users.push({ index: i, user, selfCertification });
} catch (e) {
exception = e;
}
}
if (!users.length) {
throw exception || new Error('Could not find primary user');
}
await Promise.all(users.map(async function (a) {
return a.selfCertification.revoked || a.user.isRevoked(a.selfCertification, null, date, config$1);
}));
// sort by primary user flag and signature creation time
const primaryUser = users.sort(function(a, b) {
const A = a.selfCertification;
const B = b.selfCertification;
return B.revoked - A.revoked || A.isPrimaryUserID - B.isPrimaryUserID || A.created - B.created;
}).pop();
const { user, selfCertification: cert } = primaryUser;
if (cert.revoked || await user.isRevoked(cert, null, date, config$1)) {
throw new Error('Primary user is revoked');
}
return primaryUser;
}
/**
* Update key with new components from specified key with same key ID:
* users, subkeys, certificates are merged into the destination key,
* duplicates and expired signatures are ignored.
*
* If the source key is a private key and the destination key is public,
* a private key is returned.
* @param {Key} sourceKey - Source key to merge
* @param {Date} [date] - Date to verify validity of signatures and keys
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise} updated key
* @async
*/
async update(sourceKey, date = new Date(), config$1 = config) {
if (!this.hasSameFingerprintAs(sourceKey)) {
throw new Error('Primary key fingerprints must be equal to update the key');
}
if (!this.isPrivate() && sourceKey.isPrivate()) {
// check for equal subkey packets
const equal = (this.subkeys.length === sourceKey.subkeys.length) &&
(this.subkeys.every(destSubkey => {
return sourceKey.subkeys.some(srcSubkey => {
return destSubkey.hasSameFingerprintAs(srcSubkey);
});
}));
if (!equal) {
throw new Error('Cannot update public key with private key if subkeys mismatch');
}
return sourceKey.update(this, config$1);
}
// from here on, either:
// - destination key is private, source key is public
// - the keys are of the same type
// hence we don't need to convert the destination key type
const updatedKey = this.clone();
// revocation signatures
await mergeSignatures(sourceKey, updatedKey, 'revocationSignatures', date, srcRevSig => {
return isDataRevoked(updatedKey.keyPacket, enums.signature.keyRevocation, updatedKey, [srcRevSig], null, sourceKey.keyPacket, date, config$1);
});
// direct signatures
await mergeSignatures(sourceKey, updatedKey, 'directSignatures', date);
// update users
await Promise.all(sourceKey.users.map(async srcUser => {
// multiple users with the same ID/attribute are not explicitly disallowed by the spec
// hence we support them, just in case
const usersToUpdate = updatedKey.users.filter(dstUser => (
(srcUser.userID && srcUser.userID.equals(dstUser.userID)) ||
(srcUser.userAttribute && srcUser.userAttribute.equals(dstUser.userAttribute))
));
if (usersToUpdate.length > 0) {
await Promise.all(
usersToUpdate.map(userToUpdate => userToUpdate.update(srcUser, date, config$1))
);
} else {
const newUser = srcUser.clone();
newUser.mainKey = updatedKey;
updatedKey.users.push(newUser);
}
}));
// update subkeys
await Promise.all(sourceKey.subkeys.map(async srcSubkey => {
// multiple subkeys with same fingerprint might be preset
const subkeysToUpdate = updatedKey.subkeys.filter(dstSubkey => (
dstSubkey.hasSameFingerprintAs(srcSubkey)
));
if (subkeysToUpdate.length > 0) {
await Promise.all(
subkeysToUpdate.map(subkeyToUpdate => subkeyToUpdate.update(srcSubkey, date, config$1))
);
} else {
const newSubkey = srcSubkey.clone();
newSubkey.mainKey = updatedKey;
updatedKey.subkeys.push(newSubkey);
}
}));
return updatedKey;
}
/**
* Get revocation certificate from a revoked key.
* (To get a revocation certificate for an unrevoked key, call revoke() first.)
* @param {Date} date - Use the given date instead of the current time
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise} Armored revocation certificate.
* @async
*/
async getRevocationCertificate(date = new Date(), config$1 = config) {
const dataToVerify = { key: this.keyPacket };
const revocationSignature = await getLatestValidSignature(this.revocationSignatures, this.keyPacket, enums.signature.keyRevocation, dataToVerify, date, config$1);
const packetlist = new PacketList();
packetlist.push(revocationSignature);
return armor(enums.armor.publicKey, packetlist.write(), null, null, 'This is a revocation certificate');
}
/**
* Applies a revocation certificate to a key
* This adds the first signature packet in the armored text to the key,
* if it is a valid revocation signature.
* @param {String} revocationCertificate - armored revocation certificate
* @param {Date} [date] - Date to verify the certificate
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise} Revoked key.
* @async
*/
async applyRevocationCertificate(revocationCertificate, date = new Date(), config$1 = config) {
const input = await unarmor(revocationCertificate, config$1);
const packetlist = await PacketList.fromBinary(input.data, allowedRevocationPackets, config$1);
const revocationSignature = packetlist.findPacket(enums.packet.signature);
if (!revocationSignature || revocationSignature.signatureType !== enums.signature.keyRevocation) {
throw new Error('Could not find revocation signature packet');
}
if (!revocationSignature.issuerKeyID.equals(this.getKeyID())) {
throw new Error('Revocation signature does not match key');
}
try {
await revocationSignature.verify(this.keyPacket, enums.signature.keyRevocation, { key: this.keyPacket }, date, undefined, config$1);
} catch (e) {
throw util.wrapError('Could not verify revocation signature', e);
}
const key = this.clone();
key.revocationSignatures.push(revocationSignature);
return key;
}
/**
* Signs primary user of key
* @param {Array} privateKeys - decrypted private keys for signing
* @param {Date} [date] - Use the given date for verification instead of the current time
* @param {Object} [userID] - User ID to get instead of the primary user, if it exists
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise} Key with new certificate signature.
* @async
*/
async signPrimaryUser(privateKeys, date, userID, config$1 = config) {
const { index, user } = await this.getPrimaryUser(date, userID, config$1);
const userSign = await user.certify(privateKeys, date, config$1);
const key = this.clone();
key.users[index] = userSign;
return key;
}
/**
* Signs all users of key
* @param {Array} privateKeys - decrypted private keys for signing
* @param {Date} [date] - Use the given date for signing, instead of the current time
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise} Key with new certificate signature.
* @async
*/
async signAllUsers(privateKeys, date = new Date(), config$1 = config) {
const key = this.clone();
key.users = await Promise.all(this.users.map(function(user) {
return user.certify(privateKeys, date, config$1);
}));
return key;
}
/**
* Verifies primary user of key
* - if no arguments are given, verifies the self certificates;
* - otherwise, verifies all certificates signed with given keys.
* @param {Array} [verificationKeys] - array of keys to verify certificate signatures, instead of the primary key
* @param {Date} [date] - Use the given date for verification instead of the current time
* @param {Object} [userID] - User ID to get instead of the primary user, if it exists
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise>} List of signer's keyID and validity of signature.
* Signature validity is null if the verification keys do not correspond to the certificate.
* @async
*/
async verifyPrimaryUser(verificationKeys, date = new Date(), userID, config$1 = config) {
const primaryKey = this.keyPacket;
const { user } = await this.getPrimaryUser(date, userID, config$1);
const results = verificationKeys ?
await user.verifyAllCertifications(verificationKeys, date, config$1) :
[{ keyID: primaryKey.getKeyID(), valid: await user.verify(date, config$1).catch(() => false) }];
return results;
}
/**
* Verifies all users of key
* - if no arguments are given, verifies the self certificates;
* - otherwise, verifies all certificates signed with given keys.
* @param {Array} [verificationKeys] - array of keys to verify certificate signatures
* @param {Date} [date] - Use the given date for verification instead of the current time
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise>} List of userID, signer's keyID and validity of signature.
* Signature validity is null if the verification keys do not correspond to the certificate.
* @async
*/
async verifyAllUsers(verificationKeys, date = new Date(), config$1 = config) {
const primaryKey = this.keyPacket;
const results = [];
await Promise.all(this.users.map(async user => {
const signatures = verificationKeys ?
await user.verifyAllCertifications(verificationKeys, date, config$1) :
[{ keyID: primaryKey.getKeyID(), valid: await user.verify(date, config$1).catch(() => false) }];
results.push(...signatures.map(
signature => ({
userID: user.userID.userID,
keyID: signature.keyID,
valid: signature.valid
}))
);
}));
return results;
}
}
['getKeyID', 'getFingerprint', 'getAlgorithmInfo', 'getCreationTime', 'hasSameFingerprintAs'].forEach(name => {
Key.prototype[name] =
Subkey.prototype[name];
});
// This library is free software; you can redistribute it and/or
/**
* Class that represents an OpenPGP Public Key
*/
class PublicKey extends Key {
/**
* @param {PacketList} packetlist - The packets that form this key
*/
constructor(packetlist) {
super();
this.keyPacket = null;
this.revocationSignatures = [];
this.directSignatures = [];
this.users = [];
this.subkeys = [];
if (packetlist) {
this.packetListToStructure(packetlist, new Set([enums.packet.secretKey, enums.packet.secretSubkey]));
if (!this.keyPacket) {
throw new Error('Invalid key: missing public-key packet');
}
}
}
/**
* Returns true if this is a private key
* @returns {false}
*/
isPrivate() {
return false;
}
/**
* Returns key as public key (shallow copy)
* @returns {PublicKey} New public Key
*/
toPublic() {
return this;
}
/**
* Returns ASCII armored text of key
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {ReadableStream} ASCII armor.
*/
armor(config$1 = config) {
return armor(enums.armor.publicKey, this.toPacketList().write(), undefined, undefined, undefined, config$1);
}
}
/**
* Class that represents an OpenPGP Private key
*/
class PrivateKey extends PublicKey {
/**
* @param {PacketList} packetlist - The packets that form this key
*/
constructor(packetlist) {
super();
this.packetListToStructure(packetlist, new Set([enums.packet.publicKey, enums.packet.publicSubkey]));
if (!this.keyPacket) {
throw new Error('Invalid key: missing private-key packet');
}
}
/**
* Returns true if this is a private key
* @returns {Boolean}
*/
isPrivate() {
return true;
}
/**
* Returns key as public key (shallow copy)
* @returns {PublicKey} New public Key
*/
toPublic() {
const packetlist = new PacketList();
const keyPackets = this.toPacketList();
for (const keyPacket of keyPackets) {
switch (keyPacket.constructor.tag) {
case enums.packet.secretKey: {
const pubKeyPacket = PublicKeyPacket.fromSecretKeyPacket(keyPacket);
packetlist.push(pubKeyPacket);
break;
}
case enums.packet.secretSubkey: {
const pubSubkeyPacket = PublicSubkeyPacket.fromSecretSubkeyPacket(keyPacket);
packetlist.push(pubSubkeyPacket);
break;
}
default:
packetlist.push(keyPacket);
}
}
return new PublicKey(packetlist);
}
/**
* Returns ASCII armored text of key
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {ReadableStream} ASCII armor.
*/
armor(config$1 = config) {
return armor(enums.armor.privateKey, this.toPacketList().write(), undefined, undefined, undefined, config$1);
}
/**
* Returns all keys that are available for decryption, matching the keyID when given
* This is useful to retrieve keys for session key decryption
* @param {module:type/keyid~KeyID} keyID, optional
* @param {Date} date, optional
* @param {String} userID, optional
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise>} Array of decryption keys.
* @async
*/
async getDecryptionKeys(keyID, date = new Date(), userID = {}, config$1 = config) {
const primaryKey = this.keyPacket;
const keys = [];
for (let i = 0; i < this.subkeys.length; i++) {
if (!keyID || this.subkeys[i].getKeyID().equals(keyID, true)) {
try {
const dataToVerify = { key: primaryKey, bind: this.subkeys[i].keyPacket };
const bindingSignature = await getLatestValidSignature(this.subkeys[i].bindingSignatures, primaryKey, enums.signature.subkeyBinding, dataToVerify, date, config$1);
if (isValidDecryptionKeyPacket(bindingSignature, config$1)) {
keys.push(this.subkeys[i]);
}
} catch (e) {}
}
}
// evaluate primary key
const primaryUser = await this.getPrimaryUser(date, userID, config$1);
if ((!keyID || primaryKey.getKeyID().equals(keyID, true)) &&
isValidDecryptionKeyPacket(primaryUser.selfCertification, config$1)) {
keys.push(this);
}
return keys;
}
/**
* Returns true if the primary key or any subkey is decrypted.
* A dummy key is considered encrypted.
*/
isDecrypted() {
return this.getKeys().some(({ keyPacket }) => keyPacket.isDecrypted());
}
/**
* Check whether the private and public primary key parameters correspond
* Together with verification of binding signatures, this guarantees key integrity
* In case of gnu-dummy primary key, it is enough to validate any signing subkeys
* otherwise all encryption subkeys are validated
* If only gnu-dummy keys are found, we cannot properly validate so we throw an error
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @throws {Error} if validation was not successful and the key cannot be trusted
* @async
*/
async validate(config$1 = config) {
if (!this.isPrivate()) {
throw new Error('Cannot validate a public key');
}
let signingKeyPacket;
if (!this.keyPacket.isDummy()) {
signingKeyPacket = this.keyPacket;
} else {
/**
* It is enough to validate any signing keys
* since its binding signatures are also checked
*/
const signingKey = await this.getSigningKey(null, null, undefined, { ...config$1, rejectPublicKeyAlgorithms: new Set(), minRSABits: 0 });
// This could again be a dummy key
if (signingKey && !signingKey.keyPacket.isDummy()) {
signingKeyPacket = signingKey.keyPacket;
}
}
if (signingKeyPacket) {
return signingKeyPacket.validate();
} else {
const keys = this.getKeys();
const allDummies = keys.map(key => key.keyPacket.isDummy()).every(Boolean);
if (allDummies) {
throw new Error('Cannot validate an all-gnu-dummy key');
}
return Promise.all(keys.map(async key => key.keyPacket.validate()));
}
}
/**
* Clear private key parameters
*/
clearPrivateParams() {
this.getKeys().forEach(({ keyPacket }) => {
if (keyPacket.isDecrypted()) {
keyPacket.clearPrivateParams();
}
});
}
/**
* Revokes the key
* @param {Object} reasonForRevocation - optional, object indicating the reason for revocation
* @param {module:enums.reasonForRevocation} reasonForRevocation.flag optional, flag indicating the reason for revocation
* @param {String} reasonForRevocation.string optional, string explaining the reason for revocation
* @param {Date} date - optional, override the creationtime of the revocation signature
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise} New key with revocation signature.
* @async
*/
async revoke(
{
flag: reasonForRevocationFlag = enums.reasonForRevocation.noReason,
string: reasonForRevocationString = ''
} = {},
date = new Date(),
config$1 = config
) {
if (!this.isPrivate()) {
throw new Error('Need private key for revoking');
}
const dataToSign = { key: this.keyPacket };
const key = this.clone();
key.revocationSignatures.push(await createSignaturePacket(dataToSign, null, this.keyPacket, {
signatureType: enums.signature.keyRevocation,
reasonForRevocationFlag: enums.write(enums.reasonForRevocation, reasonForRevocationFlag),
reasonForRevocationString
}, date, undefined, undefined, undefined, config$1));
return key;
}
/**
* Generates a new OpenPGP subkey, and returns a clone of the Key object with the new subkey added.
* Supports RSA and ECC keys. Defaults to the algorithm and bit size/curve of the primary key. DSA primary keys default to RSA subkeys.
* @param {ecc|rsa} options.type The subkey algorithm: ECC or RSA
* @param {String} options.curve (optional) Elliptic curve for ECC keys
* @param {Integer} options.rsaBits (optional) Number of bits for RSA subkeys
* @param {Number} options.keyExpirationTime (optional) Number of seconds from the key creation time after which the key expires
* @param {Date} options.date (optional) Override the creation date of the key and the key signatures
* @param {Boolean} options.sign (optional) Indicates whether the subkey should sign rather than encrypt. Defaults to false
* @param {Object} options.config (optional) custom configuration settings to overwrite those in [config]{@link module:config}
* @returns {Promise}
* @async
*/
async addSubkey(options = {}) {
const config$1 = { ...config, ...options.config };
if (options.passphrase) {
throw new Error('Subkey could not be encrypted here, please encrypt whole key');
}
if (options.rsaBits < config$1.minRSABits) {
throw new Error(`rsaBits should be at least ${config$1.minRSABits}, got: ${options.rsaBits}`);
}
const secretKeyPacket = this.keyPacket;
if (secretKeyPacket.isDummy()) {
throw new Error('Cannot add subkey to gnu-dummy primary key');
}
if (!secretKeyPacket.isDecrypted()) {
throw new Error('Key is not decrypted');
}
const defaultOptions = secretKeyPacket.getAlgorithmInfo();
defaultOptions.type = defaultOptions.curve ? 'ecc' : 'rsa'; // DSA keys default to RSA
defaultOptions.rsaBits = defaultOptions.bits || 4096;
defaultOptions.curve = defaultOptions.curve || 'curve25519';
options = sanitizeKeyOptions(options, defaultOptions);
const keyPacket = await generateSecretSubkey(options);
checkKeyRequirements(keyPacket, config$1);
const bindingSignature = await createBindingSignature(keyPacket, secretKeyPacket, options, config$1);
const packetList = this.toPacketList();
packetList.push(keyPacket, bindingSignature);
return new PrivateKey(packetList);
}
}
// OpenPGP.js - An OpenPGP implementation in javascript
// A Key can contain the following packets
const allowedKeyPackets = /*#__PURE__*/ util.constructAllowedPackets([
PublicKeyPacket,
PublicSubkeyPacket,
SecretKeyPacket,
SecretSubkeyPacket,
UserIDPacket,
UserAttributePacket,
SignaturePacket
]);
/**
* Creates a PublicKey or PrivateKey depending on the packetlist in input
* @param {PacketList} - packets to parse
* @return {Key} parsed key
* @throws if no key packet was found
*/
function createKey(packetlist) {
for (const packet of packetlist) {
switch (packet.constructor.tag) {
case enums.packet.secretKey:
return new PrivateKey(packetlist);
case enums.packet.publicKey:
return new PublicKey(packetlist);
}
}
throw new Error('No key packet found');
}
/**
* Generates a new OpenPGP key. Supports RSA and ECC keys.
* By default, primary and subkeys will be of same type.
* @param {ecc|rsa} options.type The primary key algorithm type: ECC or RSA
* @param {String} options.curve Elliptic curve for ECC keys
* @param {Integer} options.rsaBits Number of bits for RSA keys
* @param {Array} options.userIDs User IDs as strings or objects: 'Jo Doe ' or { name:'Jo Doe', email:'info@jo.com' }
* @param {String} options.passphrase Passphrase used to encrypt the resulting private key
* @param {Number} options.keyExpirationTime (optional) Number of seconds from the key creation time after which the key expires
* @param {Date} options.date Creation date of the key and the key signatures
* @param {Object} config - Full configuration
* @param {Array} options.subkeys (optional) options for each subkey, default to main key options. e.g. [{sign: true, passphrase: '123'}]
* sign parameter defaults to false, and indicates whether the subkey should sign rather than encrypt
* @returns {Promise<{{ key: PrivateKey, revocationCertificate: String }}>}
* @async
* @static
* @private
*/
async function generate$2(options, config) {
options.sign = true; // primary key is always a signing key
options = sanitizeKeyOptions(options);
options.subkeys = options.subkeys.map((subkey, index) => sanitizeKeyOptions(options.subkeys[index], options));
let promises = [generateSecretKey(options, config)];
promises = promises.concat(options.subkeys.map(options => generateSecretSubkey(options, config)));
const packets = await Promise.all(promises);
const key = await wrapKeyObject(packets[0], packets.slice(1), options, config);
const revocationCertificate = await key.getRevocationCertificate(options.date, config);
key.revocationSignatures = [];
return { key, revocationCertificate };
}
/**
* Reformats and signs an OpenPGP key with a given User ID. Currently only supports RSA keys.
* @param {PrivateKey} options.privateKey The private key to reformat
* @param {Array} options.userIDs User IDs as strings or objects: 'Jo Doe ' or { name:'Jo Doe', email:'info@jo.com' }
* @param {String} options.passphrase Passphrase used to encrypt the resulting private key
* @param {Number} options.keyExpirationTime Number of seconds from the key creation time after which the key expires
* @param {Date} options.date Override the creation date of the key signatures
* @param {Array} options.subkeys (optional) options for each subkey, default to main key options. e.g. [{sign: true, passphrase: '123'}]
* @param {Object} config - Full configuration
*
* @returns {Promise<{{ key: PrivateKey, revocationCertificate: String }}>}
* @async
* @static
* @private
*/
async function reformat(options, config) {
options = sanitize(options);
const { privateKey } = options;
if (!privateKey.isPrivate()) {
throw new Error('Cannot reformat a public key');
}
if (privateKey.keyPacket.isDummy()) {
throw new Error('Cannot reformat a gnu-dummy primary key');
}
const isDecrypted = privateKey.getKeys().every(({ keyPacket }) => keyPacket.isDecrypted());
if (!isDecrypted) {
throw new Error('Key is not decrypted');
}
const secretKeyPacket = privateKey.keyPacket;
if (!options.subkeys) {
options.subkeys = await Promise.all(privateKey.subkeys.map(async subkey => {
const secretSubkeyPacket = subkey.keyPacket;
const dataToVerify = { key: secretKeyPacket, bind: secretSubkeyPacket };
const bindingSignature = await (
getLatestValidSignature(subkey.bindingSignatures, secretKeyPacket, enums.signature.subkeyBinding, dataToVerify, null, config)
).catch(() => ({}));
return {
sign: bindingSignature.keyFlags && (bindingSignature.keyFlags[0] & enums.keyFlags.signData)
};
}));
}
const secretSubkeyPackets = privateKey.subkeys.map(subkey => subkey.keyPacket);
if (options.subkeys.length !== secretSubkeyPackets.length) {
throw new Error('Number of subkey options does not match number of subkeys');
}
options.subkeys = options.subkeys.map(subkeyOptions => sanitize(subkeyOptions, options));
const key = await wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, config);
const revocationCertificate = await key.getRevocationCertificate(options.date, config);
key.revocationSignatures = [];
return { key, revocationCertificate };
function sanitize(options, subkeyDefaults = {}) {
options.keyExpirationTime = options.keyExpirationTime || subkeyDefaults.keyExpirationTime;
options.passphrase = util.isString(options.passphrase) ? options.passphrase : subkeyDefaults.passphrase;
options.date = options.date || subkeyDefaults.date;
return options;
}
}
/**
* Construct PrivateKey object from the given key packets, add certification signatures and set passphrase protection
* The new key includes a revocation certificate that must be removed before returning the key, otherwise the key is considered revoked.
* @param {SecretKeyPacket} secretKeyPacket
* @param {SecretSubkeyPacket} secretSubkeyPackets
* @param {Object} options
* @param {Object} config - Full configuration
* @returns {PrivateKey}
*/
async function wrapKeyObject(secretKeyPacket, secretSubkeyPackets, options, config) {
// set passphrase protection
if (options.passphrase) {
await secretKeyPacket.encrypt(options.passphrase, config);
}
await Promise.all(secretSubkeyPackets.map(async function(secretSubkeyPacket, index) {
const subkeyPassphrase = options.subkeys[index].passphrase;
if (subkeyPassphrase) {
await secretSubkeyPacket.encrypt(subkeyPassphrase, config);
}
}));
const packetlist = new PacketList();
packetlist.push(secretKeyPacket);
await Promise.all(options.userIDs.map(async function(userID, index) {
function createPreferredAlgos(algos, preferredAlgo) {
return [preferredAlgo, ...algos.filter(algo => algo !== preferredAlgo)];
}
const userIDPacket = UserIDPacket.fromObject(userID);
const dataToSign = {};
dataToSign.userID = userIDPacket;
dataToSign.key = secretKeyPacket;
const signaturePacket = new SignaturePacket();
signaturePacket.signatureType = enums.signature.certGeneric;
signaturePacket.publicKeyAlgorithm = secretKeyPacket.algorithm;
signaturePacket.hashAlgorithm = await getPreferredHashAlgo$1(null, secretKeyPacket, undefined, undefined, config);
signaturePacket.keyFlags = [enums.keyFlags.certifyKeys | enums.keyFlags.signData];
signaturePacket.preferredSymmetricAlgorithms = createPreferredAlgos([
// prefer aes256, aes128, then aes192 (no WebCrypto support: https://www.chromium.org/blink/webcrypto#TOC-AES-support)
enums.symmetric.aes256,
enums.symmetric.aes128,
enums.symmetric.aes192
], config.preferredSymmetricAlgorithm);
if (config.aeadProtect) {
signaturePacket.preferredAEADAlgorithms = createPreferredAlgos([
enums.aead.eax,
enums.aead.ocb
], config.preferredAEADAlgorithm);
}
signaturePacket.preferredHashAlgorithms = createPreferredAlgos([
// prefer fast asm.js implementations (SHA-256)
enums.hash.sha256,
enums.hash.sha512
], config.preferredHashAlgorithm);
signaturePacket.preferredCompressionAlgorithms = createPreferredAlgos([
enums.compression.zlib,
enums.compression.zip,
enums.compression.uncompressed
], config.preferredCompressionAlgorithm);
if (index === 0) {
signaturePacket.isPrimaryUserID = true;
}
// integrity protection always enabled
signaturePacket.features = [0];
signaturePacket.features[0] |= enums.features.modificationDetection;
if (config.aeadProtect) {
signaturePacket.features[0] |= enums.features.aead;
}
if (config.v5Keys) {
signaturePacket.features[0] |= enums.features.v5Keys;
}
if (options.keyExpirationTime > 0) {
signaturePacket.keyExpirationTime = options.keyExpirationTime;
signaturePacket.keyNeverExpires = false;
}
await signaturePacket.sign(secretKeyPacket, dataToSign, options.date);
return { userIDPacket, signaturePacket };
})).then(list => {
list.forEach(({ userIDPacket, signaturePacket }) => {
packetlist.push(userIDPacket);
packetlist.push(signaturePacket);
});
});
await Promise.all(secretSubkeyPackets.map(async function(secretSubkeyPacket, index) {
const subkeyOptions = options.subkeys[index];
const subkeySignaturePacket = await createBindingSignature(secretSubkeyPacket, secretKeyPacket, subkeyOptions, config);
return { secretSubkeyPacket, subkeySignaturePacket };
})).then(packets => {
packets.forEach(({ secretSubkeyPacket, subkeySignaturePacket }) => {
packetlist.push(secretSubkeyPacket);
packetlist.push(subkeySignaturePacket);
});
});
// Add revocation signature packet for creating a revocation certificate.
// This packet should be removed before returning the key.
const dataToSign = { key: secretKeyPacket };
packetlist.push(await createSignaturePacket(dataToSign, null, secretKeyPacket, {
signatureType: enums.signature.keyRevocation,
reasonForRevocationFlag: enums.reasonForRevocation.noReason,
reasonForRevocationString: ''
}, options.date, undefined, undefined, undefined, config));
if (options.passphrase) {
secretKeyPacket.clearPrivateParams();
}
await Promise.all(secretSubkeyPackets.map(async function(secretSubkeyPacket, index) {
const subkeyPassphrase = options.subkeys[index].passphrase;
if (subkeyPassphrase) {
secretSubkeyPacket.clearPrivateParams();
}
}));
return new PrivateKey(packetlist);
}
/**
* Reads an (optionally armored) OpenPGP key and returns a key object
* @param {Object} options
* @param {String} [options.armoredKey] - Armored key to be parsed
* @param {Uint8Array} [options.binaryKey] - Binary key to be parsed
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
* @returns {Promise} Key object.
* @async
* @static
*/
async function readKey({ armoredKey, binaryKey, config: config$1, ...rest }) {
config$1 = { ...config, ...config$1 };
if (!armoredKey && !binaryKey) {
throw new Error('readKey: must pass options object containing `armoredKey` or `binaryKey`');
}
if (armoredKey && !util.isString(armoredKey)) {
throw new Error('readKey: options.armoredKey must be a string');
}
if (binaryKey && !util.isUint8Array(binaryKey)) {
throw new Error('readKey: options.binaryKey must be a Uint8Array');
}
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
let input;
if (armoredKey) {
const { type, data } = await unarmor(armoredKey, config$1);
if (!(type === enums.armor.publicKey || type === enums.armor.privateKey)) {
throw new Error('Armored text not of type key');
}
input = data;
} else {
input = binaryKey;
}
const packetlist = await PacketList.fromBinary(input, allowedKeyPackets, config$1);
return createKey(packetlist);
}
/**
* Reads an (optionally armored) OpenPGP private key and returns a PrivateKey object
* @param {Object} options
* @param {String} [options.armoredKey] - Armored key to be parsed
* @param {Uint8Array} [options.binaryKey] - Binary key to be parsed
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
* @returns {Promise} Key object.
* @async
* @static
*/
async function readPrivateKey({ armoredKey, binaryKey, config: config$1, ...rest }) {
config$1 = { ...config, ...config$1 };
if (!armoredKey && !binaryKey) {
throw new Error('readPrivateKey: must pass options object containing `armoredKey` or `binaryKey`');
}
if (armoredKey && !util.isString(armoredKey)) {
throw new Error('readPrivateKey: options.armoredKey must be a string');
}
if (binaryKey && !util.isUint8Array(binaryKey)) {
throw new Error('readPrivateKey: options.binaryKey must be a Uint8Array');
}
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
let input;
if (armoredKey) {
const { type, data } = await unarmor(armoredKey, config$1);
if (!(type === enums.armor.privateKey)) {
throw new Error('Armored text not of type private key');
}
input = data;
} else {
input = binaryKey;
}
const packetlist = await PacketList.fromBinary(input, allowedKeyPackets, config$1);
return new PrivateKey(packetlist);
}
/**
* Reads an (optionally armored) OpenPGP key block and returns a list of key objects
* @param {Object} options
* @param {String} [options.armoredKeys] - Armored keys to be parsed
* @param {Uint8Array} [options.binaryKeys] - Binary keys to be parsed
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
* @returns {Promise>} Key objects.
* @async
* @static
*/
async function readKeys({ armoredKeys, binaryKeys, config: config$1, ...rest }) {
config$1 = { ...config, ...config$1 };
let input = armoredKeys || binaryKeys;
if (!input) {
throw new Error('readKeys: must pass options object containing `armoredKeys` or `binaryKeys`');
}
if (armoredKeys && !util.isString(armoredKeys)) {
throw new Error('readKeys: options.armoredKeys must be a string');
}
if (binaryKeys && !util.isUint8Array(binaryKeys)) {
throw new Error('readKeys: options.binaryKeys must be a Uint8Array');
}
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
if (armoredKeys) {
const { type, data } = await unarmor(armoredKeys, config$1);
if (type !== enums.armor.publicKey && type !== enums.armor.privateKey) {
throw new Error('Armored text not of type key');
}
input = data;
}
const keys = [];
const packetlist = await PacketList.fromBinary(input, allowedKeyPackets, config$1);
const keyIndex = packetlist.indexOfTag(enums.packet.publicKey, enums.packet.secretKey);
if (keyIndex.length === 0) {
throw new Error('No key packet found');
}
for (let i = 0; i < keyIndex.length; i++) {
const oneKeyList = packetlist.slice(keyIndex[i], keyIndex[i + 1]);
const newKey = createKey(oneKeyList);
keys.push(newKey);
}
return keys;
}
/**
* Reads an (optionally armored) OpenPGP private key block and returns a list of PrivateKey objects
* @param {Object} options
* @param {String} [options.armoredKeys] - Armored keys to be parsed
* @param {Uint8Array} [options.binaryKeys] - Binary keys to be parsed
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
* @returns {Promise>} Key objects.
* @async
* @static
*/
async function readPrivateKeys({ armoredKeys, binaryKeys, config: config$1 }) {
config$1 = { ...config, ...config$1 };
let input = armoredKeys || binaryKeys;
if (!input) {
throw new Error('readPrivateKeys: must pass options object containing `armoredKeys` or `binaryKeys`');
}
if (armoredKeys && !util.isString(armoredKeys)) {
throw new Error('readPrivateKeys: options.armoredKeys must be a string');
}
if (binaryKeys && !util.isUint8Array(binaryKeys)) {
throw new Error('readPrivateKeys: options.binaryKeys must be a Uint8Array');
}
if (armoredKeys) {
const { type, data } = await unarmor(armoredKeys, config$1);
if (type !== enums.armor.privateKey) {
throw new Error('Armored text not of type private key');
}
input = data;
}
const keys = [];
const packetlist = await PacketList.fromBinary(input, allowedKeyPackets, config$1);
const keyIndex = packetlist.indexOfTag(enums.packet.secretKey);
if (keyIndex.length === 0) {
throw new Error('No secret key packet found');
}
for (let i = 0; i < keyIndex.length; i++) {
const oneKeyList = packetlist.slice(keyIndex[i], keyIndex[i + 1]);
const newKey = new PrivateKey(oneKeyList);
keys.push(newKey);
}
return keys;
}
// GPG4Browsers - An OpenPGP implementation in javascript
// A Message can contain the following packets
const allowedMessagePackets = /*#__PURE__*/ util.constructAllowedPackets([
LiteralDataPacket,
CompressedDataPacket,
AEADEncryptedDataPacket,
SymEncryptedIntegrityProtectedDataPacket,
SymmetricallyEncryptedDataPacket,
PublicKeyEncryptedSessionKeyPacket,
SymEncryptedSessionKeyPacket,
OnePassSignaturePacket,
SignaturePacket
]);
// A SKESK packet can contain the following packets
const allowedSymSessionKeyPackets = /*#__PURE__*/ util.constructAllowedPackets([SymEncryptedSessionKeyPacket]);
// A detached signature can contain the following packets
const allowedDetachedSignaturePackets = /*#__PURE__*/ util.constructAllowedPackets([SignaturePacket]);
/**
* Class that represents an OpenPGP message.
* Can be an encrypted message, signed message, compressed message or literal message
* See {@link https://tools.ietf.org/html/rfc4880#section-11.3}
*/
class Message {
/**
* @param {PacketList} packetlist - The packets that form this message
*/
constructor(packetlist) {
this.packets = packetlist || new PacketList();
}
/**
* Returns the key IDs of the keys to which the session key is encrypted
* @returns {Array} Array of keyID objects.
*/
getEncryptionKeyIDs() {
const keyIDs = [];
const pkESKeyPacketlist = this.packets.filterByTag(enums.packet.publicKeyEncryptedSessionKey);
pkESKeyPacketlist.forEach(function(packet) {
keyIDs.push(packet.publicKeyID);
});
return keyIDs;
}
/**
* Returns the key IDs of the keys that signed the message
* @returns {Array} Array of keyID objects.
*/
getSigningKeyIDs() {
const msg = this.unwrapCompressed();
// search for one pass signatures
const onePassSigList = msg.packets.filterByTag(enums.packet.onePassSignature);
if (onePassSigList.length > 0) {
return onePassSigList.map(packet => packet.issuerKeyID);
}
// if nothing found look for signature packets
const signatureList = msg.packets.filterByTag(enums.packet.signature);
return signatureList.map(packet => packet.issuerKeyID);
}
/**
* Decrypt the message. Either a private key, a session key, or a password must be specified.
* @param {Array} [decryptionKeys] - Private keys with decrypted secret data
* @param {Array} [passwords] - Passwords used to decrypt
* @param {Array} [sessionKeys] - Session keys in the form: { data:Uint8Array, algorithm:String, [aeadAlgorithm:String] }
* @param {Date} [date] - Use the given date for key verification instead of the current time
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise} New message with decrypted content.
* @async
*/
async decrypt(decryptionKeys, passwords, sessionKeys, date = new Date(), config$1 = config) {
const sessionKeyObjects = sessionKeys || await this.decryptSessionKeys(decryptionKeys, passwords, date, config$1);
const symEncryptedPacketlist = this.packets.filterByTag(
enums.packet.symmetricallyEncryptedData,
enums.packet.symEncryptedIntegrityProtectedData,
enums.packet.aeadEncryptedData
);
if (symEncryptedPacketlist.length === 0) {
throw new Error('No encrypted data found');
}
const symEncryptedPacket = symEncryptedPacketlist[0];
let exception = null;
const decryptedPromise = Promise.all(sessionKeyObjects.map(async ({ algorithm: algorithmName, data }) => {
if (!util.isUint8Array(data) || !util.isString(algorithmName)) {
throw new Error('Invalid session key for decryption.');
}
try {
const algo = enums.write(enums.symmetric, algorithmName);
await symEncryptedPacket.decrypt(algo, data, config$1);
} catch (e) {
util.printDebugError(e);
exception = e;
}
}));
// We don't await stream.cancel here because it only returns when the other copy is canceled too.
cancel(symEncryptedPacket.encrypted); // Don't keep copy of encrypted data in memory.
symEncryptedPacket.encrypted = null;
await decryptedPromise;
if (!symEncryptedPacket.packets || !symEncryptedPacket.packets.length) {
throw exception || new Error('Decryption failed.');
}
const resultMsg = new Message(symEncryptedPacket.packets);
symEncryptedPacket.packets = new PacketList(); // remove packets after decryption
return resultMsg;
}
/**
* Decrypt encrypted session keys either with private keys or passwords.
* @param {Array} [decryptionKeys] - Private keys with decrypted secret data
* @param {Array} [passwords] - Passwords used to decrypt
* @param {Date} [date] - Use the given date for key verification, instead of current time
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise>} array of object with potential sessionKey, algorithm pairs
* @async
*/
async decryptSessionKeys(decryptionKeys, passwords, date = new Date(), config$1 = config) {
let decryptedSessionKeyPackets = [];
let exception;
if (passwords) {
const skeskPackets = this.packets.filterByTag(enums.packet.symEncryptedSessionKey);
if (skeskPackets.length === 0) {
throw new Error('No symmetrically encrypted session key packet found.');
}
await Promise.all(passwords.map(async function(password, i) {
let packets;
if (i) {
packets = await PacketList.fromBinary(skeskPackets.write(), allowedSymSessionKeyPackets, config$1);
} else {
packets = skeskPackets;
}
await Promise.all(packets.map(async function(skeskPacket) {
try {
await skeskPacket.decrypt(password);
decryptedSessionKeyPackets.push(skeskPacket);
} catch (err) {
util.printDebugError(err);
}
}));
}));
} else if (decryptionKeys) {
const pkeskPackets = this.packets.filterByTag(enums.packet.publicKeyEncryptedSessionKey);
if (pkeskPackets.length === 0) {
throw new Error('No public key encrypted session key packet found.');
}
await Promise.all(pkeskPackets.map(async function(pkeskPacket) {
await Promise.all(decryptionKeys.map(async function(decryptionKey) {
let algos = [
enums.symmetric.aes256, // Old OpenPGP.js default fallback
enums.symmetric.aes128, // RFC4880bis fallback
enums.symmetric.tripledes, // RFC4880 fallback
enums.symmetric.cast5 // Golang OpenPGP fallback
];
try {
const primaryUser = await decryptionKey.getPrimaryUser(date, undefined, config$1); // TODO: Pass userID from somewhere.
if (primaryUser.selfCertification.preferredSymmetricAlgorithms) {
algos = algos.concat(primaryUser.selfCertification.preferredSymmetricAlgorithms);
}
} catch (e) {}
// do not check key expiration to allow decryption of old messages
const decryptionKeyPackets = (await decryptionKey.getDecryptionKeys(pkeskPacket.publicKeyID, null, undefined, config$1)).map(key => key.keyPacket);
await Promise.all(decryptionKeyPackets.map(async function(decryptionKeyPacket) {
if (!decryptionKeyPacket || decryptionKeyPacket.isDummy()) {
return;
}
if (!decryptionKeyPacket.isDecrypted()) {
throw new Error('Decryption key is not decrypted.');
}
// To hinder CCA attacks against PKCS1, we carry out a constant-time decryption flow if the `constantTimePKCS1Decryption` config option is set.
const doConstantTimeDecryption = config$1.constantTimePKCS1Decryption && (
pkeskPacket.publicKeyAlgorithm === enums.publicKey.rsaEncrypt ||
pkeskPacket.publicKeyAlgorithm === enums.publicKey.rsaEncryptSign ||
pkeskPacket.publicKeyAlgorithm === enums.publicKey.rsaSign ||
pkeskPacket.publicKeyAlgorithm === enums.publicKey.elgamal
);
if (doConstantTimeDecryption) {
// The goal is to not reveal whether PKESK decryption (specifically the PKCS1 decoding step) failed, hence, we always proceed to decrypt the message,
// either with the successfully decrypted session key, or with a randomly generated one.
// Since the SEIP/AEAD's symmetric algorithm and key size are stored in the encrypted portion of the PKESK, and the execution flow cannot depend on
// the decrypted payload, we always assume the message to be encrypted with one of the symmetric algorithms specified in `config.constantTimePKCS1DecryptionSupportedSymmetricAlgorithms`:
// - If the PKESK decryption succeeds, and the session key cipher is in the supported set, then we try to decrypt the data with the decrypted session key as well as with the
// randomly generated keys of the remaining key types.
// - If the PKESK decryptions fails, or if it succeeds but support for the cipher is not enabled, then we discard the session key and try to decrypt the data using only the randomly
// generated session keys.
// NB: as a result, if the data is encrypted with a non-suported cipher, decryption will always fail.
const serialisedPKESK = pkeskPacket.write(); // make copies to be able to decrypt the PKESK packet multiple times
await Promise.all(Array.from(config$1.constantTimePKCS1DecryptionSupportedSymmetricAlgorithms).map(async sessionKeyAlgorithm => {
const pkeskPacketCopy = new PublicKeyEncryptedSessionKeyPacket();
pkeskPacketCopy.read(serialisedPKESK);
const randomSessionKey = {
sessionKeyAlgorithm,
sessionKey: mod.generateSessionKey(sessionKeyAlgorithm)
};
try {
await pkeskPacketCopy.decrypt(decryptionKeyPacket, randomSessionKey);
decryptedSessionKeyPackets.push(pkeskPacketCopy);
} catch (err) {
// `decrypt` can still throw some non-security-sensitive errors
util.printDebugError(err);
exception = err;
}
}));
} else {
try {
await pkeskPacket.decrypt(decryptionKeyPacket);
if (!algos.includes(enums.write(enums.symmetric, pkeskPacket.sessionKeyAlgorithm))) {
throw new Error('A non-preferred symmetric algorithm was used.');
}
decryptedSessionKeyPackets.push(pkeskPacket);
} catch (err) {
util.printDebugError(err);
exception = err;
}
}
}));
}));
cancel(pkeskPacket.encrypted); // Don't keep copy of encrypted data in memory.
pkeskPacket.encrypted = null;
}));
} else {
throw new Error('No key or password specified.');
}
if (decryptedSessionKeyPackets.length > 0) {
// Return only unique session keys
if (decryptedSessionKeyPackets.length > 1) {
const seen = new Set();
decryptedSessionKeyPackets = decryptedSessionKeyPackets.filter(item => {
const k = item.sessionKeyAlgorithm + util.uint8ArrayToString(item.sessionKey);
if (seen.has(k)) {
return false;
}
seen.add(k);
return true;
});
}
return decryptedSessionKeyPackets.map(packet => ({
data: packet.sessionKey,
algorithm: enums.read(enums.symmetric, packet.sessionKeyAlgorithm)
}));
}
throw exception || new Error('Session key decryption failed.');
}
/**
* Get literal data that is the body of the message
* @returns {(Uint8Array|null)} Literal body of the message as Uint8Array.
*/
getLiteralData() {
const msg = this.unwrapCompressed();
const literal = msg.packets.findPacket(enums.packet.literalData);
return (literal && literal.getBytes()) || null;
}
/**
* Get filename from literal data packet
* @returns {(String|null)} Filename of literal data packet as string.
*/
getFilename() {
const msg = this.unwrapCompressed();
const literal = msg.packets.findPacket(enums.packet.literalData);
return (literal && literal.getFilename()) || null;
}
/**
* Get literal data as text
* @returns {(String|null)} Literal body of the message interpreted as text.
*/
getText() {
const msg = this.unwrapCompressed();
const literal = msg.packets.findPacket(enums.packet.literalData);
if (literal) {
return literal.getText();
}
return null;
}
/**
* Generate a new session key object, taking the algorithm preferences of the passed encryption keys into account, if any.
* @param {Array} [encryptionKeys] - Public key(s) to select algorithm preferences for
* @param {Date} [date] - Date to select algorithm preferences at
* @param {Array} [userIDs] - User IDs to select algorithm preferences for
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise<{ data: Uint8Array, algorithm: String, aeadAlgorithm: undefined|String }>} Object with session key data and algorithms.
* @async
*/
static async generateSessionKey(encryptionKeys = [], date = new Date(), userIDs = [], config$1 = config) {
const algo = await getPreferredAlgo('symmetric', encryptionKeys, date, userIDs, config$1);
const algorithmName = enums.read(enums.symmetric, algo);
const aeadAlgorithmName = config$1.aeadProtect && await isAEADSupported(encryptionKeys, date, userIDs, config$1) ?
enums.read(enums.aead, await getPreferredAlgo('aead', encryptionKeys, date, userIDs, config$1)) :
undefined;
const sessionKeyData = mod.generateSessionKey(algo);
return { data: sessionKeyData, algorithm: algorithmName, aeadAlgorithm: aeadAlgorithmName };
}
/**
* Encrypt the message either with public keys, passwords, or both at once.
* @param {Array} [encryptionKeys] - Public key(s) for message encryption
* @param {Array} [passwords] - Password(s) for message encryption
* @param {Object} [sessionKey] - Session key in the form: { data:Uint8Array, algorithm:String, [aeadAlgorithm:String] }
* @param {Boolean} [wildcard] - Use a key ID of 0 instead of the public key IDs
* @param {Array} [encryptionKeyIDs] - Array of key IDs to use for encryption. Each encryptionKeyIDs[i] corresponds to keys[i]
* @param {Date} [date] - Override the creation date of the literal package
* @param {Array} [userIDs] - User IDs to encrypt for, e.g. [{ name:'Robert Receiver', email:'robert@openpgp.org' }]
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise} New message with encrypted content.
* @async
*/
async encrypt(encryptionKeys, passwords, sessionKey, wildcard = false, encryptionKeyIDs = [], date = new Date(), userIDs = [], config$1 = config) {
if (sessionKey) {
if (!util.isUint8Array(sessionKey.data) || !util.isString(sessionKey.algorithm)) {
throw new Error('Invalid session key for encryption.');
}
} else if (encryptionKeys && encryptionKeys.length) {
sessionKey = await Message.generateSessionKey(encryptionKeys, date, userIDs, config$1);
} else if (passwords && passwords.length) {
sessionKey = await Message.generateSessionKey(undefined, undefined, undefined, config$1);
} else {
throw new Error('No keys, passwords, or session key provided.');
}
const { data: sessionKeyData, algorithm: algorithmName, aeadAlgorithm: aeadAlgorithmName } = sessionKey;
const msg = await Message.encryptSessionKey(sessionKeyData, algorithmName, aeadAlgorithmName, encryptionKeys, passwords, wildcard, encryptionKeyIDs, date, userIDs, config$1);
let symEncryptedPacket;
if (aeadAlgorithmName) {
symEncryptedPacket = new AEADEncryptedDataPacket();
symEncryptedPacket.aeadAlgorithm = enums.write(enums.aead, aeadAlgorithmName);
} else {
symEncryptedPacket = new SymEncryptedIntegrityProtectedDataPacket();
}
symEncryptedPacket.packets = this.packets;
const algorithm = enums.write(enums.symmetric, algorithmName);
await symEncryptedPacket.encrypt(algorithm, sessionKeyData, config$1);
msg.packets.push(symEncryptedPacket);
symEncryptedPacket.packets = new PacketList(); // remove packets after encryption
return msg;
}
/**
* Encrypt a session key either with public keys, passwords, or both at once.
* @param {Uint8Array} sessionKey - session key for encryption
* @param {String} algorithmName - session key algorithm
* @param {String} [aeadAlgorithmName] - AEAD algorithm, e.g. 'eax' or 'ocb'
* @param {Array} [encryptionKeys] - Public key(s) for message encryption
* @param {Array} [passwords] - For message encryption
* @param {Boolean} [wildcard] - Use a key ID of 0 instead of the public key IDs
* @param {Array} [encryptionKeyIDs] - Array of key IDs to use for encryption. Each encryptionKeyIDs[i] corresponds to encryptionKeys[i]
* @param {Date} [date] - Override the date
* @param {Array} [userIDs] - User IDs to encrypt for, e.g. [{ name:'Robert Receiver', email:'robert@openpgp.org' }]
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise} New message with encrypted content.
* @async
*/
static async encryptSessionKey(sessionKey, algorithmName, aeadAlgorithmName, encryptionKeys, passwords, wildcard = false, encryptionKeyIDs = [], date = new Date(), userIDs = [], config$1 = config) {
const packetlist = new PacketList();
const algorithm = enums.write(enums.symmetric, algorithmName);
const aeadAlgorithm = aeadAlgorithmName && enums.write(enums.aead, aeadAlgorithmName);
if (encryptionKeys) {
const results = await Promise.all(encryptionKeys.map(async function(primaryKey, i) {
const encryptionKey = await primaryKey.getEncryptionKey(encryptionKeyIDs[i], date, userIDs, config$1);
const pkESKeyPacket = new PublicKeyEncryptedSessionKeyPacket();
pkESKeyPacket.publicKeyID = wildcard ? KeyID.wildcard() : encryptionKey.getKeyID();
pkESKeyPacket.publicKeyAlgorithm = encryptionKey.keyPacket.algorithm;
pkESKeyPacket.sessionKey = sessionKey;
pkESKeyPacket.sessionKeyAlgorithm = algorithm;
await pkESKeyPacket.encrypt(encryptionKey.keyPacket);
delete pkESKeyPacket.sessionKey; // delete plaintext session key after encryption
return pkESKeyPacket;
}));
packetlist.push(...results);
}
if (passwords) {
const testDecrypt = async function(keyPacket, password) {
try {
await keyPacket.decrypt(password);
return 1;
} catch (e) {
return 0;
}
};
const sum = (accumulator, currentValue) => accumulator + currentValue;
const encryptPassword = async function(sessionKey, algorithm, aeadAlgorithm, password) {
const symEncryptedSessionKeyPacket = new SymEncryptedSessionKeyPacket(config$1);
symEncryptedSessionKeyPacket.sessionKey = sessionKey;
symEncryptedSessionKeyPacket.sessionKeyAlgorithm = algorithm;
if (aeadAlgorithm) {
symEncryptedSessionKeyPacket.aeadAlgorithm = aeadAlgorithm;
}
await symEncryptedSessionKeyPacket.encrypt(password, config$1);
if (config$1.passwordCollisionCheck) {
const results = await Promise.all(passwords.map(pwd => testDecrypt(symEncryptedSessionKeyPacket, pwd)));
if (results.reduce(sum) !== 1) {
return encryptPassword(sessionKey, algorithm, password);
}
}
delete symEncryptedSessionKeyPacket.sessionKey; // delete plaintext session key after encryption
return symEncryptedSessionKeyPacket;
};
const results = await Promise.all(passwords.map(pwd => encryptPassword(sessionKey, algorithm, aeadAlgorithm, pwd)));
packetlist.push(...results);
}
return new Message(packetlist);
}
/**
* Sign the message (the literal data packet of the message)
* @param {Array} signingKeys - private keys with decrypted secret key data for signing
* @param {Signature} [signature] - Any existing detached signature to add to the message
* @param {Array} [signingKeyIDs] - Array of key IDs to use for signing. Each signingKeyIDs[i] corresponds to signingKeys[i]
* @param {Date} [date] - Override the creation time of the signature
* @param {Array} [userIDs] - User IDs to sign with, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
* @param {Array} [notations] - Notation Data to add to the signatures, e.g. [{ name: 'test@example.org', value: new TextEncoder().encode('test'), humanReadable: true, critical: false }]
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise} New message with signed content.
* @async
*/
async sign(signingKeys = [], signature = null, signingKeyIDs = [], date = new Date(), userIDs = [], notations = [], config$1 = config) {
const packetlist = new PacketList();
const literalDataPacket = this.packets.findPacket(enums.packet.literalData);
if (!literalDataPacket) {
throw new Error('No literal data packet to sign.');
}
let i;
let existingSigPacketlist;
// If data packet was created from Uint8Array, use binary, otherwise use text
const signatureType = literalDataPacket.text === null ?
enums.signature.binary : enums.signature.text;
if (signature) {
existingSigPacketlist = signature.packets.filterByTag(enums.packet.signature);
for (i = existingSigPacketlist.length - 1; i >= 0; i--) {
const signaturePacket = existingSigPacketlist[i];
const onePassSig = new OnePassSignaturePacket();
onePassSig.signatureType = signaturePacket.signatureType;
onePassSig.hashAlgorithm = signaturePacket.hashAlgorithm;
onePassSig.publicKeyAlgorithm = signaturePacket.publicKeyAlgorithm;
onePassSig.issuerKeyID = signaturePacket.issuerKeyID;
if (!signingKeys.length && i === 0) {
onePassSig.flags = 1;
}
packetlist.push(onePassSig);
}
}
await Promise.all(Array.from(signingKeys).reverse().map(async function (primaryKey, i) {
if (!primaryKey.isPrivate()) {
throw new Error('Need private key for signing');
}
const signingKeyID = signingKeyIDs[signingKeys.length - 1 - i];
const signingKey = await primaryKey.getSigningKey(signingKeyID, date, userIDs, config$1);
const onePassSig = new OnePassSignaturePacket();
onePassSig.signatureType = signatureType;
onePassSig.hashAlgorithm = await getPreferredHashAlgo$1(primaryKey, signingKey.keyPacket, date, userIDs, config$1);
onePassSig.publicKeyAlgorithm = signingKey.keyPacket.algorithm;
onePassSig.issuerKeyID = signingKey.getKeyID();
if (i === signingKeys.length - 1) {
onePassSig.flags = 1;
}
return onePassSig;
})).then(onePassSignatureList => {
onePassSignatureList.forEach(onePassSig => packetlist.push(onePassSig));
});
packetlist.push(literalDataPacket);
packetlist.push(...(await createSignaturePackets(literalDataPacket, signingKeys, signature, signingKeyIDs, date, userIDs, notations, false, config$1)));
return new Message(packetlist);
}
/**
* Compresses the message (the literal and -if signed- signature data packets of the message)
* @param {module:enums.compression} algo - compression algorithm
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Message} New message with compressed content.
*/
compress(algo, config$1 = config) {
if (algo === enums.compression.uncompressed) {
return this;
}
const compressed = new CompressedDataPacket(config$1);
compressed.algorithm = algo;
compressed.packets = this.packets;
const packetList = new PacketList();
packetList.push(compressed);
return new Message(packetList);
}
/**
* Create a detached signature for the message (the literal data packet of the message)
* @param {Array} signingKeys - private keys with decrypted secret key data for signing
* @param {Signature} [signature] - Any existing detached signature
* @param {Array} [signingKeyIDs] - Array of key IDs to use for signing. Each signingKeyIDs[i] corresponds to signingKeys[i]
* @param {Date} [date] - Override the creation time of the signature
* @param {Array} [userIDs] - User IDs to sign with, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
* @param {Array} [notations] - Notation Data to add to the signatures, e.g. [{ name: 'test@example.org', value: new TextEncoder().encode('test'), humanReadable: true, critical: false }]
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise} New detached signature of message content.
* @async
*/
async signDetached(signingKeys = [], signature = null, signingKeyIDs = [], date = new Date(), userIDs = [], notations = [], config$1 = config) {
const literalDataPacket = this.packets.findPacket(enums.packet.literalData);
if (!literalDataPacket) {
throw new Error('No literal data packet to sign.');
}
return new Signature(await createSignaturePackets(literalDataPacket, signingKeys, signature, signingKeyIDs, date, userIDs, notations, true, config$1));
}
/**
* Verify message signatures
* @param {Array} verificationKeys - Array of public keys to verify signatures
* @param {Date} [date] - Verify the signature against the given date, i.e. check signature creation time < date < expiration time
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise,
* verified: Promise
* }>>} List of signer's keyID and validity of signatures.
* @async
*/
async verify(verificationKeys, date = new Date(), config$1 = config) {
const msg = this.unwrapCompressed();
const literalDataList = msg.packets.filterByTag(enums.packet.literalData);
if (literalDataList.length !== 1) {
throw new Error('Can only verify message with one literal data packet.');
}
if (isArrayStream(msg.packets.stream)) {
msg.packets.push(...await readToEnd(msg.packets.stream, _ => _ || []));
}
const onePassSigList = msg.packets.filterByTag(enums.packet.onePassSignature).reverse();
const signatureList = msg.packets.filterByTag(enums.packet.signature);
if (onePassSigList.length && !signatureList.length && util.isStream(msg.packets.stream) && !isArrayStream(msg.packets.stream)) {
await Promise.all(onePassSigList.map(async onePassSig => {
onePassSig.correspondingSig = new Promise((resolve, reject) => {
onePassSig.correspondingSigResolve = resolve;
onePassSig.correspondingSigReject = reject;
});
onePassSig.signatureData = fromAsync(async () => (await onePassSig.correspondingSig).signatureData);
onePassSig.hashed = readToEnd(await onePassSig.hash(onePassSig.signatureType, literalDataList[0], undefined, false));
onePassSig.hashed.catch(() => {});
}));
msg.packets.stream = transformPair(msg.packets.stream, async (readable, writable) => {
const reader = getReader(readable);
const writer = getWriter(writable);
try {
for (let i = 0; i < onePassSigList.length; i++) {
const { value: signature } = await reader.read();
onePassSigList[i].correspondingSigResolve(signature);
}
await reader.readToEnd();
await writer.ready;
await writer.close();
} catch (e) {
onePassSigList.forEach(onePassSig => {
onePassSig.correspondingSigReject(e);
});
await writer.abort(e);
}
});
return createVerificationObjects(onePassSigList, literalDataList, verificationKeys, date, false, config$1);
}
return createVerificationObjects(signatureList, literalDataList, verificationKeys, date, false, config$1);
}
/**
* Verify detached message signature
* @param {Array} verificationKeys - Array of public keys to verify signatures
* @param {Signature} signature
* @param {Date} date - Verify the signature against the given date, i.e. check signature creation time < date < expiration time
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise,
* verified: Promise
* }>>} List of signer's keyID and validity of signature.
* @async
*/
verifyDetached(signature, verificationKeys, date = new Date(), config$1 = config) {
const msg = this.unwrapCompressed();
const literalDataList = msg.packets.filterByTag(enums.packet.literalData);
if (literalDataList.length !== 1) {
throw new Error('Can only verify message with one literal data packet.');
}
const signatureList = signature.packets;
return createVerificationObjects(signatureList, literalDataList, verificationKeys, date, true, config$1);
}
/**
* Unwrap compressed message
* @returns {Message} Message Content of compressed message.
*/
unwrapCompressed() {
const compressed = this.packets.filterByTag(enums.packet.compressedData);
if (compressed.length) {
return new Message(compressed[0].packets);
}
return this;
}
/**
* Append signature to unencrypted message object
* @param {String|Uint8Array} detachedSignature - The detached ASCII-armored or Uint8Array PGP signature
* @param {Object} [config] - Full configuration, defaults to openpgp.config
*/
async appendSignature(detachedSignature, config$1 = config) {
await this.packets.read(
util.isUint8Array(detachedSignature) ? detachedSignature : (await unarmor(detachedSignature)).data,
allowedDetachedSignaturePackets,
config$1
);
}
/**
* Returns binary encoded message
* @returns {ReadableStream} Binary message.
*/
write() {
return this.packets.write();
}
/**
* Returns ASCII armored text of message
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {ReadableStream} ASCII armor.
*/
armor(config$1 = config) {
return armor(enums.armor.message, this.write(), null, null, null, config$1);
}
}
/**
* Create signature packets for the message
* @param {LiteralDataPacket} literalDataPacket - the literal data packet to sign
* @param {Array} [signingKeys] - private keys with decrypted secret key data for signing
* @param {Signature} [signature] - Any existing detached signature to append
* @param {Array} [signingKeyIDs] - Array of key IDs to use for signing. Each signingKeyIDs[i] corresponds to signingKeys[i]
* @param {Date} [date] - Override the creationtime of the signature
* @param {Array} [userIDs] - User IDs to sign with, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
* @param {Array} [notations] - Notation Data to add to the signatures, e.g. [{ name: 'test@example.org', value: new TextEncoder().encode('test'), humanReadable: true, critical: false }]
* @param {Boolean} [detached] - Whether to create detached signature packets
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise} List of signature packets.
* @async
* @private
*/
async function createSignaturePackets(literalDataPacket, signingKeys, signature = null, signingKeyIDs = [], date = new Date(), userIDs = [], notations = [], detached = false, config$1 = config) {
const packetlist = new PacketList();
// If data packet was created from Uint8Array, use binary, otherwise use text
const signatureType = literalDataPacket.text === null ?
enums.signature.binary : enums.signature.text;
await Promise.all(signingKeys.map(async (primaryKey, i) => {
const userID = userIDs[i];
if (!primaryKey.isPrivate()) {
throw new Error('Need private key for signing');
}
const signingKey = await primaryKey.getSigningKey(signingKeyIDs[i], date, userID, config$1);
return createSignaturePacket(literalDataPacket, primaryKey, signingKey.keyPacket, { signatureType }, date, userID, notations, detached, config$1);
})).then(signatureList => {
packetlist.push(...signatureList);
});
if (signature) {
const existingSigPacketlist = signature.packets.filterByTag(enums.packet.signature);
packetlist.push(...existingSigPacketlist);
}
return packetlist;
}
/**
* Create object containing signer's keyID and validity of signature
* @param {SignaturePacket} signature - Signature packet
* @param {Array} literalDataList - Array of literal data packets
* @param {Array} verificationKeys - Array of public keys to verify signatures
* @param {Date} [date] - Check signature validity with respect to the given date
* @param {Boolean} [detached] - Whether to verify detached signature packets
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise<{
* keyID: module:type/keyid~KeyID,
* signature: Promise,
* verified: Promise
* }>} signer's keyID and validity of signature
* @async
* @private
*/
async function createVerificationObject(signature, literalDataList, verificationKeys, date = new Date(), detached = false, config$1 = config) {
let primaryKey;
let unverifiedSigningKey;
for (const key of verificationKeys) {
const issuerKeys = key.getKeys(signature.issuerKeyID);
if (issuerKeys.length > 0) {
primaryKey = key;
unverifiedSigningKey = issuerKeys[0];
break;
}
}
const isOnePassSignature = signature instanceof OnePassSignaturePacket;
const signaturePacketPromise = isOnePassSignature ? signature.correspondingSig : signature;
const verifiedSig = {
keyID: signature.issuerKeyID,
verified: (async () => {
if (!unverifiedSigningKey) {
throw new Error(`Could not find signing key with key ID ${signature.issuerKeyID.toHex()}`);
}
await signature.verify(unverifiedSigningKey.keyPacket, signature.signatureType, literalDataList[0], date, detached, config$1);
const signaturePacket = await signaturePacketPromise;
if (unverifiedSigningKey.getCreationTime() > signaturePacket.created) {
throw new Error('Key is newer than the signature');
}
// We pass the signature creation time to check whether the key was expired at the time of signing.
// We check this after signature verification because for streamed one-pass signatures, the creation time is not available before
try {
await primaryKey.getSigningKey(unverifiedSigningKey.getKeyID(), signaturePacket.created, undefined, config$1);
} catch (e) {
// If a key was reformatted then the self-signatures of the signing key might be in the future compared to the message signature,
// making the key invalid at the time of signing.
// However, if the key is valid at the given `date`, we still allow using it provided the relevant `config` setting is enabled.
// Note: we do not support the edge case of a key that was reformatted and it has expired.
if (config$1.allowInsecureVerificationWithReformattedKeys && e.message.match(/Signature creation time is in the future/)) {
await primaryKey.getSigningKey(unverifiedSigningKey.getKeyID(), date, undefined, config$1);
} else {
throw e;
}
}
return true;
})(),
signature: (async () => {
const signaturePacket = await signaturePacketPromise;
const packetlist = new PacketList();
signaturePacket && packetlist.push(signaturePacket);
return new Signature(packetlist);
})()
};
// Mark potential promise rejections as "handled". This is needed because in
// some cases, we reject them before the user has a reasonable chance to
// handle them (e.g. `await readToEnd(result.data); await result.verified` and
// the data stream errors).
verifiedSig.signature.catch(() => {});
verifiedSig.verified.catch(() => {});
return verifiedSig;
}
/**
* Create list of objects containing signer's keyID and validity of signature
* @param {Array} signatureList - Array of signature packets
* @param {Array} literalDataList - Array of literal data packets
* @param {Array} verificationKeys - Array of public keys to verify signatures
* @param {Date} date - Verify the signature against the given date,
* i.e. check signature creation time < date < expiration time
* @param {Boolean} [detached] - Whether to verify detached signature packets
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise,
* verified: Promise
* }>>} list of signer's keyID and validity of signatures (one entry per signature packet in input)
* @async
* @private
*/
async function createVerificationObjects(signatureList, literalDataList, verificationKeys, date = new Date(), detached = false, config$1 = config) {
return Promise.all(signatureList.filter(function(signature) {
return ['text', 'binary'].includes(enums.read(enums.signature, signature.signatureType));
}).map(async function(signature) {
return createVerificationObject(signature, literalDataList, verificationKeys, date, detached, config$1);
}));
}
/**
* Reads an (optionally armored) OpenPGP message and returns a Message object
* @param {Object} options
* @param {String | ReadableStream} [options.armoredMessage] - Armored message to be parsed
* @param {Uint8Array | ReadableStream} [options.binaryMessage] - Binary to be parsed
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
* @returns {Promise} New message object.
* @async
* @static
*/
async function readMessage({ armoredMessage, binaryMessage, config: config$1, ...rest }) {
config$1 = { ...config, ...config$1 };
let input = armoredMessage || binaryMessage;
if (!input) {
throw new Error('readMessage: must pass options object containing `armoredMessage` or `binaryMessage`');
}
if (armoredMessage && !util.isString(armoredMessage) && !util.isStream(armoredMessage)) {
throw new Error('readMessage: options.armoredMessage must be a string or stream');
}
if (binaryMessage && !util.isUint8Array(binaryMessage) && !util.isStream(binaryMessage)) {
throw new Error('readMessage: options.binaryMessage must be a Uint8Array or stream');
}
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
const streamType = util.isStream(input);
if (streamType) {
await loadStreamsPonyfill();
input = toStream(input);
}
if (armoredMessage) {
const { type, data } = await unarmor(input, config$1);
if (type !== enums.armor.message) {
throw new Error('Armored text not of type message');
}
input = data;
}
const packetlist = await PacketList.fromBinary(input, allowedMessagePackets, config$1);
const message = new Message(packetlist);
message.fromStream = streamType;
return message;
}
/**
* Creates new message object from text or binary data.
* @param {Object} options
* @param {String | ReadableStream} [options.text] - The text message contents
* @param {Uint8Array | ReadableStream} [options.binary] - The binary message contents
* @param {String} [options.filename=""] - Name of the file (if any)
* @param {Date} [options.date=current date] - Date of the message, or modification date of the file
* @param {'utf8'|'binary'|'text'|'mime'} [options.format='utf8' if text is passed, 'binary' otherwise] - Data packet type
* @returns {Promise} New message object.
* @async
* @static
*/
async function createMessage({ text, binary, filename, date = new Date(), format = text !== undefined ? 'utf8' : 'binary', ...rest }) {
let input = text !== undefined ? text : binary;
if (input === undefined) {
throw new Error('createMessage: must pass options object containing `text` or `binary`');
}
if (text && !util.isString(text) && !util.isStream(text)) {
throw new Error('createMessage: options.text must be a string or stream');
}
if (binary && !util.isUint8Array(binary) && !util.isStream(binary)) {
throw new Error('createMessage: options.binary must be a Uint8Array or stream');
}
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
const streamType = util.isStream(input);
if (streamType) {
await loadStreamsPonyfill();
input = toStream(input);
}
const literalDataPacket = new LiteralDataPacket(date);
if (text !== undefined) {
literalDataPacket.setText(input, enums.write(enums.literal, format));
} else {
literalDataPacket.setBytes(input, enums.write(enums.literal, format));
}
if (filename !== undefined) {
literalDataPacket.setFilename(filename);
}
const literalDataPacketlist = new PacketList();
literalDataPacketlist.push(literalDataPacket);
const message = new Message(literalDataPacketlist);
message.fromStream = streamType;
return message;
}
// GPG4Browsers - An OpenPGP implementation in javascript
// A Cleartext message can contain the following packets
const allowedPackets$5 = /*#__PURE__*/ util.constructAllowedPackets([SignaturePacket]);
/**
* Class that represents an OpenPGP cleartext signed message.
* See {@link https://tools.ietf.org/html/rfc4880#section-7}
*/
class CleartextMessage {
/**
* @param {String} text - The cleartext of the signed message
* @param {Signature} signature - The detached signature or an empty signature for unsigned messages
*/
constructor(text, signature) {
// remove trailing whitespace and normalize EOL to canonical form
this.text = util.removeTrailingSpaces(text).replace(/\r?\n/g, '\r\n');
if (signature && !(signature instanceof Signature)) {
throw new Error('Invalid signature input');
}
this.signature = signature || new Signature(new PacketList());
}
/**
* Returns the key IDs of the keys that signed the cleartext message
* @returns {Array} Array of keyID objects.
*/
getSigningKeyIDs() {
const keyIDs = [];
const signatureList = this.signature.packets;
signatureList.forEach(function(packet) {
keyIDs.push(packet.issuerKeyID);
});
return keyIDs;
}
/**
* Sign the cleartext message
* @param {Array} privateKeys - private keys with decrypted secret key data for signing
* @param {Signature} [signature] - Any existing detached signature
* @param {Array} [signingKeyIDs] - Array of key IDs to use for signing. Each signingKeyIDs[i] corresponds to privateKeys[i]
* @param {Date} [date] - The creation time of the signature that should be created
* @param {Array} [userIDs] - User IDs to sign with, e.g. [{ name:'Steve Sender', email:'steve@openpgp.org' }]
* @param {Array} [notations] - Notation Data to add to the signatures, e.g. [{ name: 'test@example.org', value: new TextEncoder().encode('test'), humanReadable: true, critical: false }]
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise} New cleartext message with signed content.
* @async
*/
async sign(privateKeys, signature = null, signingKeyIDs = [], date = new Date(), userIDs = [], notations = [], config$1 = config) {
const literalDataPacket = new LiteralDataPacket();
literalDataPacket.setText(this.text);
const newSignature = new Signature(await createSignaturePackets(literalDataPacket, privateKeys, signature, signingKeyIDs, date, userIDs, notations, true, config$1));
return new CleartextMessage(this.text, newSignature);
}
/**
* Verify signatures of cleartext signed message
* @param {Array} keys - Array of keys to verify signatures
* @param {Date} [date] - Verify the signature against the given date, i.e. check signature creation time < date < expiration time
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {Promise,
* verified: Promise
* }>>} List of signer's keyID and validity of signature.
* @async
*/
verify(keys, date = new Date(), config$1 = config) {
const signatureList = this.signature.packets;
const literalDataPacket = new LiteralDataPacket();
// we assume that cleartext signature is generated based on UTF8 cleartext
literalDataPacket.setText(this.text);
return createVerificationObjects(signatureList, [literalDataPacket], keys, date, true, config$1);
}
/**
* Get cleartext
* @returns {String} Cleartext of message.
*/
getText() {
// normalize end of line to \n
return this.text.replace(/\r\n/g, '\n');
}
/**
* Returns ASCII armored text of cleartext signed message
* @param {Object} [config] - Full configuration, defaults to openpgp.config
* @returns {String | ReadableStream} ASCII armor.
*/
armor(config$1 = config) {
let hashes = this.signature.packets.map(function(packet) {
return enums.read(enums.hash, packet.hashAlgorithm).toUpperCase();
});
hashes = hashes.filter(function(item, i, ar) { return ar.indexOf(item) === i; });
const body = {
hash: hashes.join(),
text: this.text,
data: this.signature.packets.write()
};
return armor(enums.armor.signed, body, undefined, undefined, undefined, config$1);
}
}
/**
* Reads an OpenPGP cleartext signed message and returns a CleartextMessage object
* @param {Object} options
* @param {String} options.cleartextMessage - Text to be parsed
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
* @returns {Promise} New cleartext message object.
* @async
* @static
*/
async function readCleartextMessage({ cleartextMessage, config: config$1, ...rest }) {
config$1 = { ...config, ...config$1 };
if (!cleartextMessage) {
throw new Error('readCleartextMessage: must pass options object containing `cleartextMessage`');
}
if (!util.isString(cleartextMessage)) {
throw new Error('readCleartextMessage: options.cleartextMessage must be a string');
}
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
const input = await unarmor(cleartextMessage);
if (input.type !== enums.armor.signed) {
throw new Error('No cleartext signed message.');
}
const packetlist = await PacketList.fromBinary(input.data, allowedPackets$5, config$1);
verifyHeaders$1(input.headers, packetlist);
const signature = new Signature(packetlist);
return new CleartextMessage(input.text, signature);
}
/**
* Compare hash algorithm specified in the armor header with signatures
* @param {Array} headers - Armor headers
* @param {PacketList} packetlist - The packetlist with signature packets
* @private
*/
function verifyHeaders$1(headers, packetlist) {
const checkHashAlgos = function(hashAlgos) {
const check = packet => algo => packet.hashAlgorithm === algo;
for (let i = 0; i < packetlist.length; i++) {
if (packetlist[i].constructor.tag === enums.packet.signature && !hashAlgos.some(check(packetlist[i]))) {
return false;
}
}
return true;
};
let oneHeader = null;
let hashAlgos = [];
headers.forEach(function(header) {
oneHeader = header.match(/Hash: (.+)/); // get header value
if (oneHeader) {
oneHeader = oneHeader[1].replace(/\s/g, ''); // remove whitespace
oneHeader = oneHeader.split(',');
oneHeader = oneHeader.map(function(hash) {
hash = hash.toLowerCase();
try {
return enums.write(enums.hash, hash);
} catch (e) {
throw new Error('Unknown hash algorithm in armor header: ' + hash);
}
});
hashAlgos = hashAlgos.concat(oneHeader);
} else {
throw new Error('Only "Hash" header allowed in cleartext signed message');
}
});
if (!hashAlgos.length && !checkHashAlgos([enums.hash.md5])) {
throw new Error('If no "Hash" header in cleartext signed message, then only MD5 signatures allowed');
} else if (hashAlgos.length && !checkHashAlgos(hashAlgos)) {
throw new Error('Hash algorithm mismatch in armor header and signature');
}
}
/**
* Creates a new CleartextMessage object from text
* @param {Object} options
* @param {String} options.text
* @static
* @async
*/
async function createCleartextMessage({ text, ...rest }) {
if (!text) {
throw new Error('createCleartextMessage: must pass options object containing `text`');
}
if (!util.isString(text)) {
throw new Error('createCleartextMessage: options.text must be a string');
}
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
return new CleartextMessage(text);
}
// OpenPGP.js - An OpenPGP implementation in javascript
//////////////////////
// //
// Key handling //
// //
//////////////////////
/**
* Generates a new OpenPGP key pair. Supports RSA and ECC keys. By default, primary and subkeys will be of same type.
* The generated primary key will have signing capabilities. By default, one subkey with encryption capabilities is also generated.
* @param {Object} options
* @param {Object|Array} options.userIDs - User IDs as objects: `{ name: 'Jo Doe', email: 'info@jo.com' }`
* @param {'ecc'|'rsa'} [options.type='ecc'] - The primary key algorithm type: ECC (default) or RSA
* @param {String} [options.passphrase=(not protected)] - The passphrase used to encrypt the generated private key. If omitted or empty, the key won't be encrypted.
* @param {Number} [options.rsaBits=4096] - Number of bits for RSA keys
* @param {String} [options.curve='curve25519'] - Elliptic curve for ECC keys:
* curve25519 (default), p256, p384, p521, secp256k1,
* brainpoolP256r1, brainpoolP384r1, or brainpoolP512r1
* @param {Date} [options.date=current date] - Override the creation date of the key and the key signatures
* @param {Number} [options.keyExpirationTime=0 (never expires)] - Number of seconds from the key creation time after which the key expires
* @param {Array} [options.subkeys=a single encryption subkey] - Options for each subkey e.g. `[{sign: true, passphrase: '123'}]`
* default to main key options, except for `sign` parameter that defaults to false, and indicates whether the subkey should sign rather than encrypt
* @param {'armored'|'binary'|'object'} [options.format='armored'] - format of the output keys
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
* @returns {Promise} The generated key object in the form:
* { privateKey:PrivateKey|Uint8Array|String, publicKey:PublicKey|Uint8Array|String, revocationCertificate:String }
* @async
* @static
*/
async function generateKey({ userIDs = [], passphrase, type = 'ecc', rsaBits = 4096, curve = 'curve25519', keyExpirationTime = 0, date = new Date(), subkeys = [{}], format = 'armored', config: config$1, ...rest }) {
config$1 = { ...config, ...config$1 }; checkConfig(config$1);
userIDs = toArray$1(userIDs);
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
if (userIDs.length === 0) {
throw new Error('UserIDs are required for key generation');
}
if (type === 'rsa' && rsaBits < config$1.minRSABits) {
throw new Error(`rsaBits should be at least ${config$1.minRSABits}, got: ${rsaBits}`);
}
const options = { userIDs, passphrase, type, rsaBits, curve, keyExpirationTime, date, subkeys };
try {
const { key, revocationCertificate } = await generate$2(options, config$1);
key.getKeys().forEach(({ keyPacket }) => checkKeyRequirements(keyPacket, config$1));
return {
privateKey: formatObject(key, format, config$1),
publicKey: formatObject(key.toPublic(), format, config$1),
revocationCertificate
};
} catch (err) {
throw util.wrapError('Error generating keypair', err);
}
}
/**
* Reformats signature packets for a key and rewraps key object.
* @param {Object} options
* @param {PrivateKey} options.privateKey - Private key to reformat
* @param {Object|Array} options.userIDs - User IDs as objects: `{ name: 'Jo Doe', email: 'info@jo.com' }`
* @param {String} [options.passphrase=(not protected)] - The passphrase used to encrypt the reformatted private key. If omitted or empty, the key won't be encrypted.
* @param {Number} [options.keyExpirationTime=0 (never expires)] - Number of seconds from the key creation time after which the key expires
* @param {Date} [options.date] - Override the creation date of the key signatures. If the key was previously used to sign messages, it is recommended
* to set the same date as the key creation time to ensure that old message signatures will still be verifiable using the reformatted key.
* @param {'armored'|'binary'|'object'} [options.format='armored'] - format of the output keys
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
* @returns {Promise} The generated key object in the form:
* { privateKey:PrivateKey|Uint8Array|String, publicKey:PublicKey|Uint8Array|String, revocationCertificate:String }
* @async
* @static
*/
async function reformatKey({ privateKey, userIDs = [], passphrase, keyExpirationTime = 0, date, format = 'armored', config: config$1, ...rest }) {
config$1 = { ...config, ...config$1 }; checkConfig(config$1);
userIDs = toArray$1(userIDs);
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
if (userIDs.length === 0) {
throw new Error('UserIDs are required for key reformat');
}
const options = { privateKey, userIDs, passphrase, keyExpirationTime, date };
try {
const { key: reformattedKey, revocationCertificate } = await reformat(options, config$1);
return {
privateKey: formatObject(reformattedKey, format, config$1),
publicKey: formatObject(reformattedKey.toPublic(), format, config$1),
revocationCertificate
};
} catch (err) {
throw util.wrapError('Error reformatting keypair', err);
}
}
/**
* Revokes a key. Requires either a private key or a revocation certificate.
* If a revocation certificate is passed, the reasonForRevocation parameter will be ignored.
* @param {Object} options
* @param {Key} options.key - Public or private key to revoke
* @param {String} [options.revocationCertificate] - Revocation certificate to revoke the key with
* @param {Object} [options.reasonForRevocation] - Object indicating the reason for revocation
* @param {module:enums.reasonForRevocation} [options.reasonForRevocation.flag=[noReason]{@link module:enums.reasonForRevocation}] - Flag indicating the reason for revocation
* @param {String} [options.reasonForRevocation.string=""] - String explaining the reason for revocation
* @param {Date} [options.date] - Use the given date instead of the current time to verify validity of revocation certificate (if provided), or as creation time of the revocation signature
* @param {'armored'|'binary'|'object'} [options.format='armored'] - format of the output key(s)
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
* @returns {Promise} The revoked key in the form:
* { privateKey:PrivateKey|Uint8Array|String, publicKey:PublicKey|Uint8Array|String } if private key is passed, or
* { privateKey: null, publicKey:PublicKey|Uint8Array|String } otherwise
* @async
* @static
*/
async function revokeKey({ key, revocationCertificate, reasonForRevocation, date = new Date(), format = 'armored', config: config$1, ...rest }) {
config$1 = { ...config, ...config$1 }; checkConfig(config$1);
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
try {
const revokedKey = revocationCertificate ?
await key.applyRevocationCertificate(revocationCertificate, date, config$1) :
await key.revoke(reasonForRevocation, date, config$1);
return revokedKey.isPrivate() ? {
privateKey: formatObject(revokedKey, format, config$1),
publicKey: formatObject(revokedKey.toPublic(), format, config$1)
} : {
privateKey: null,
publicKey: formatObject(revokedKey, format, config$1)
};
} catch (err) {
throw util.wrapError('Error revoking key', err);
}
}
/**
* Unlock a private key with the given passphrase.
* This method does not change the original key.
* @param {Object} options
* @param {PrivateKey} options.privateKey - The private key to decrypt
* @param {String|Array} options.passphrase - The user's passphrase(s)
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
* @returns {Promise} The unlocked key object.
* @async
*/
async function decryptKey({ privateKey, passphrase, config: config$1, ...rest }) {
config$1 = { ...config, ...config$1 }; checkConfig(config$1);
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
if (!privateKey.isPrivate()) {
throw new Error('Cannot decrypt a public key');
}
const clonedPrivateKey = privateKey.clone(true);
const passphrases = util.isArray(passphrase) ? passphrase : [passphrase];
try {
await Promise.all(clonedPrivateKey.getKeys().map(key => (
// try to decrypt each key with any of the given passphrases
util.anyPromise(passphrases.map(passphrase => key.keyPacket.decrypt(passphrase)))
)));
await clonedPrivateKey.validate(config$1);
return clonedPrivateKey;
} catch (err) {
clonedPrivateKey.clearPrivateParams();
throw util.wrapError('Error decrypting private key', err);
}
}
/**
* Lock a private key with the given passphrase.
* This method does not change the original key.
* @param {Object} options
* @param {PrivateKey} options.privateKey - The private key to encrypt
* @param {String|Array} options.passphrase - If multiple passphrases, they should be in the same order as the packets each should encrypt
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
* @returns {Promise} The locked key object.
* @async
*/
async function encryptKey({ privateKey, passphrase, config: config$1, ...rest }) {
config$1 = { ...config, ...config$1 }; checkConfig(config$1);
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
if (!privateKey.isPrivate()) {
throw new Error('Cannot encrypt a public key');
}
const clonedPrivateKey = privateKey.clone(true);
const keys = clonedPrivateKey.getKeys();
const passphrases = util.isArray(passphrase) ? passphrase : new Array(keys.length).fill(passphrase);
if (passphrases.length !== keys.length) {
throw new Error('Invalid number of passphrases given for key encryption');
}
try {
await Promise.all(keys.map(async (key, i) => {
const { keyPacket } = key;
await keyPacket.encrypt(passphrases[i], config$1);
keyPacket.clearPrivateParams();
}));
return clonedPrivateKey;
} catch (err) {
clonedPrivateKey.clearPrivateParams();
throw util.wrapError('Error encrypting private key', err);
}
}
///////////////////////////////////////////
// //
// Message encryption and decryption //
// //
///////////////////////////////////////////
/**
* Encrypts a message using public keys, passwords or both at once. At least one of `encryptionKeys`, `passwords` or `sessionKeys`
* must be specified. If signing keys are specified, those will be used to sign the message.
* @param {Object} options
* @param {Message} options.message - Message to be encrypted as created by {@link createMessage}
* @param {PublicKey|PublicKey[]} [options.encryptionKeys] - Array of keys or single key, used to encrypt the message
* @param {PrivateKey|PrivateKey[]} [options.signingKeys] - Private keys for signing. If omitted message will not be signed
* @param {String|String[]} [options.passwords] - Array of passwords or a single password to encrypt the message
* @param {Object} [options.sessionKey] - Session key in the form: `{ data:Uint8Array, algorithm:String }`
* @param {'armored'|'binary'|'object'} [options.format='armored'] - Format of the returned message
* @param {Signature} [options.signature] - A detached signature to add to the encrypted message
* @param {Boolean} [options.wildcard=false] - Use a key ID of 0 instead of the public key IDs
* @param {KeyID|KeyID[]} [options.signingKeyIDs=latest-created valid signing (sub)keys] - Array of key IDs to use for signing. Each `signingKeyIDs[i]` corresponds to `signingKeys[i]`
* @param {KeyID|KeyID[]} [options.encryptionKeyIDs=latest-created valid encryption (sub)keys] - Array of key IDs to use for encryption. Each `encryptionKeyIDs[i]` corresponds to `encryptionKeys[i]`
* @param {Date} [options.date=current date] - Override the creation date of the message signature
* @param {Object|Object[]} [options.signingUserIDs=primary user IDs] - Array of user IDs to sign with, one per key in `signingKeys`, e.g. `[{ name: 'Steve Sender', email: 'steve@openpgp.org' }]`
* @param {Object|Object[]} [options.encryptionUserIDs=primary user IDs] - Array of user IDs to encrypt for, one per key in `encryptionKeys`, e.g. `[{ name: 'Robert Receiver', email: 'robert@openpgp.org' }]`
* @param {Object|Object[]} [options.signatureNotations=[]] - Array of notations to add to the signatures, e.g. `[{ name: 'test@example.org', value: new TextEncoder().encode('test'), humanReadable: true, critical: false }]`
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
* @returns {Promise|MaybeStream>} Encrypted message (string if `armor` was true, the default; Uint8Array if `armor` was false).
* @async
* @static
*/
async function encrypt$4({ message, encryptionKeys, signingKeys, passwords, sessionKey, format = 'armored', signature = null, wildcard = false, signingKeyIDs = [], encryptionKeyIDs = [], date = new Date(), signingUserIDs = [], encryptionUserIDs = [], signatureNotations = [], config: config$1, ...rest }) {
config$1 = { ...config, ...config$1 }; checkConfig(config$1);
checkMessage(message); checkOutputMessageFormat(format);
encryptionKeys = toArray$1(encryptionKeys); signingKeys = toArray$1(signingKeys); passwords = toArray$1(passwords);
signingKeyIDs = toArray$1(signingKeyIDs); encryptionKeyIDs = toArray$1(encryptionKeyIDs); signingUserIDs = toArray$1(signingUserIDs); encryptionUserIDs = toArray$1(encryptionUserIDs); signatureNotations = toArray$1(signatureNotations);
if (rest.detached) {
throw new Error("The `detached` option has been removed from openpgp.encrypt, separately call openpgp.sign instead. Don't forget to remove the `privateKeys` option as well.");
}
if (rest.publicKeys) throw new Error('The `publicKeys` option has been removed from openpgp.encrypt, pass `encryptionKeys` instead');
if (rest.privateKeys) throw new Error('The `privateKeys` option has been removed from openpgp.encrypt, pass `signingKeys` instead');
if (rest.armor !== undefined) throw new Error('The `armor` option has been removed from openpgp.encrypt, pass `format` instead.');
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
if (!signingKeys) {
signingKeys = [];
}
const streaming = message.fromStream;
try {
if (signingKeys.length || signature) { // sign the message only if signing keys or signature is specified
message = await message.sign(signingKeys, signature, signingKeyIDs, date, signingUserIDs, signatureNotations, config$1);
}
message = message.compress(
await getPreferredAlgo('compression', encryptionKeys, date, encryptionUserIDs, config$1),
config$1
);
message = await message.encrypt(encryptionKeys, passwords, sessionKey, wildcard, encryptionKeyIDs, date, encryptionUserIDs, config$1);
if (format === 'object') return message;
// serialize data
const armor = format === 'armored';
const data = armor ? message.armor(config$1) : message.write();
return convertStream(data, streaming, armor ? 'utf8' : 'binary');
} catch (err) {
throw util.wrapError('Error encrypting message', err);
}
}
/**
* Decrypts a message with the user's private key, a session key or a password.
* One of `decryptionKeys`, `sessionkeys` or `passwords` must be specified (passing a combination of these options is not supported).
* @param {Object} options
* @param {Message} options.message - The message object with the encrypted data
* @param {PrivateKey|PrivateKey[]} [options.decryptionKeys] - Private keys with decrypted secret key data or session key
* @param {String|String[]} [options.passwords] - Passwords to decrypt the message
* @param {Object|Object[]} [options.sessionKeys] - Session keys in the form: { data:Uint8Array, algorithm:String }
* @param {PublicKey|PublicKey[]} [options.verificationKeys] - Array of public keys or single key, to verify signatures
* @param {Boolean} [options.expectSigned=false] - If true, data decryption fails if the message is not signed with the provided publicKeys
* @param {'utf8'|'binary'} [options.format='utf8'] - Whether to return data as a string(Stream) or Uint8Array(Stream). If 'utf8' (the default), also normalize newlines.
* @param {Signature} [options.signature] - Detached signature for verification
* @param {Date} [options.date=current date] - Use the given date for verification instead of the current time
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
* @returns {Promise} Object containing decrypted and verified message in the form:
*
* {
* data: MaybeStream, (if format was 'utf8', the default)
* data: MaybeStream, (if format was 'binary')
* filename: String,
* signatures: [
* {
* keyID: module:type/keyid~KeyID,
* verified: Promise,
* signature: Promise
* }, ...
* ]
* }
*
* where `signatures` contains a separate entry for each signature packet found in the input message.
* @async
* @static
*/
async function decrypt$4({ message, decryptionKeys, passwords, sessionKeys, verificationKeys, expectSigned = false, format = 'utf8', signature = null, date = new Date(), config: config$1, ...rest }) {
config$1 = { ...config, ...config$1 }; checkConfig(config$1);
checkMessage(message); verificationKeys = toArray$1(verificationKeys); decryptionKeys = toArray$1(decryptionKeys); passwords = toArray$1(passwords); sessionKeys = toArray$1(sessionKeys);
if (rest.privateKeys) throw new Error('The `privateKeys` option has been removed from openpgp.decrypt, pass `decryptionKeys` instead');
if (rest.publicKeys) throw new Error('The `publicKeys` option has been removed from openpgp.decrypt, pass `verificationKeys` instead');
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
try {
const decrypted = await message.decrypt(decryptionKeys, passwords, sessionKeys, date, config$1);
if (!verificationKeys) {
verificationKeys = [];
}
const result = {};
result.signatures = signature ? await decrypted.verifyDetached(signature, verificationKeys, date, config$1) : await decrypted.verify(verificationKeys, date, config$1);
result.data = format === 'binary' ? decrypted.getLiteralData() : decrypted.getText();
result.filename = decrypted.getFilename();
linkStreams(result, message);
if (expectSigned) {
if (verificationKeys.length === 0) {
throw new Error('Verification keys are required to verify message signatures');
}
if (result.signatures.length === 0) {
throw new Error('Message is not signed');
}
result.data = concat([
result.data,
fromAsync(async () => {
await util.anyPromise(result.signatures.map(sig => sig.verified));
})
]);
}
result.data = await convertStream(result.data, message.fromStream, format);
return result;
} catch (err) {
throw util.wrapError('Error decrypting message', err);
}
}
//////////////////////////////////////////
// //
// Message signing and verification //
// //
//////////////////////////////////////////
/**
* Signs a message.
* @param {Object} options
* @param {CleartextMessage|Message} options.message - (cleartext) message to be signed
* @param {PrivateKey|PrivateKey[]} options.signingKeys - Array of keys or single key with decrypted secret key data to sign cleartext
* @param {'armored'|'binary'|'object'} [options.format='armored'] - Format of the returned message
* @param {Boolean} [options.detached=false] - If the return value should contain a detached signature
* @param {KeyID|KeyID[]} [options.signingKeyIDs=latest-created valid signing (sub)keys] - Array of key IDs to use for signing. Each signingKeyIDs[i] corresponds to signingKeys[i]
* @param {Date} [options.date=current date] - Override the creation date of the signature
* @param {Object|Object[]} [options.signingUserIDs=primary user IDs] - Array of user IDs to sign with, one per key in `signingKeys`, e.g. `[{ name: 'Steve Sender', email: 'steve@openpgp.org' }]`
* @param {Object|Object[]} [options.signatureNotations=[]] - Array of notations to add to the signatures, e.g. `[{ name: 'test@example.org', value: new TextEncoder().encode('test'), humanReadable: true, critical: false }]`
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
* @returns {Promise>} Signed message (string if `armor` was true, the default; Uint8Array if `armor` was false).
* @async
* @static
*/
async function sign$5({ message, signingKeys, format = 'armored', detached = false, signingKeyIDs = [], date = new Date(), signingUserIDs = [], signatureNotations = [], config: config$1, ...rest }) {
config$1 = { ...config, ...config$1 }; checkConfig(config$1);
checkCleartextOrMessage(message); checkOutputMessageFormat(format);
signingKeys = toArray$1(signingKeys); signingKeyIDs = toArray$1(signingKeyIDs); signingUserIDs = toArray$1(signingUserIDs); signatureNotations = toArray$1(signatureNotations);
if (rest.privateKeys) throw new Error('The `privateKeys` option has been removed from openpgp.sign, pass `signingKeys` instead');
if (rest.armor !== undefined) throw new Error('The `armor` option has been removed from openpgp.sign, pass `format` instead.');
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
if (message instanceof CleartextMessage && format === 'binary') throw new Error('Cannot return signed cleartext message in binary format');
if (message instanceof CleartextMessage && detached) throw new Error('Cannot detach-sign a cleartext message');
if (!signingKeys || signingKeys.length === 0) {
throw new Error('No signing keys provided');
}
try {
let signature;
if (detached) {
signature = await message.signDetached(signingKeys, undefined, signingKeyIDs, date, signingUserIDs, signatureNotations, config$1);
} else {
signature = await message.sign(signingKeys, undefined, signingKeyIDs, date, signingUserIDs, signatureNotations, config$1);
}
if (format === 'object') return signature;
const armor = format === 'armored';
signature = armor ? signature.armor(config$1) : signature.write();
if (detached) {
signature = transformPair(message.packets.write(), async (readable, writable) => {
await Promise.all([
pipe(signature, writable),
readToEnd(readable).catch(() => {})
]);
});
}
return convertStream(signature, message.fromStream, armor ? 'utf8' : 'binary');
} catch (err) {
throw util.wrapError('Error signing message', err);
}
}
/**
* Verifies signatures of cleartext signed message
* @param {Object} options
* @param {CleartextMessage|Message} options.message - (cleartext) message object with signatures
* @param {PublicKey|PublicKey[]} options.verificationKeys - Array of publicKeys or single key, to verify signatures
* @param {Boolean} [options.expectSigned=false] - If true, verification throws if the message is not signed with the provided publicKeys
* @param {'utf8'|'binary'} [options.format='utf8'] - Whether to return data as a string(Stream) or Uint8Array(Stream). If 'utf8' (the default), also normalize newlines.
* @param {Signature} [options.signature] - Detached signature for verification
* @param {Date} [options.date=current date] - Use the given date for verification instead of the current time
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
* @returns {Promise} Object containing verified message in the form:
*
* {
* data: MaybeStream, (if `message` was a CleartextMessage)
* data: MaybeStream, (if `message` was a Message)
* signatures: [
* {
* keyID: module:type/keyid~KeyID,
* verified: Promise,
* signature: Promise
* }, ...
* ]
* }
*
* where `signatures` contains a separate entry for each signature packet found in the input message.
* @async
* @static
*/
async function verify$5({ message, verificationKeys, expectSigned = false, format = 'utf8', signature = null, date = new Date(), config: config$1, ...rest }) {
config$1 = { ...config, ...config$1 }; checkConfig(config$1);
checkCleartextOrMessage(message); verificationKeys = toArray$1(verificationKeys);
if (rest.publicKeys) throw new Error('The `publicKeys` option has been removed from openpgp.verify, pass `verificationKeys` instead');
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
if (message instanceof CleartextMessage && format === 'binary') throw new Error("Can't return cleartext message data as binary");
if (message instanceof CleartextMessage && signature) throw new Error("Can't verify detached cleartext signature");
try {
const result = {};
if (signature) {
result.signatures = await message.verifyDetached(signature, verificationKeys, date, config$1);
} else {
result.signatures = await message.verify(verificationKeys, date, config$1);
}
result.data = format === 'binary' ? message.getLiteralData() : message.getText();
if (message.fromStream) linkStreams(result, message);
if (expectSigned) {
if (result.signatures.length === 0) {
throw new Error('Message is not signed');
}
result.data = concat([
result.data,
fromAsync(async () => {
await util.anyPromise(result.signatures.map(sig => sig.verified));
})
]);
}
result.data = await convertStream(result.data, message.fromStream, format);
return result;
} catch (err) {
throw util.wrapError('Error verifying signed message', err);
}
}
///////////////////////////////////////////////
// //
// Session key encryption and decryption //
// //
///////////////////////////////////////////////
/**
* Generate a new session key object, taking the algorithm preferences of the passed public keys into account, if any.
* @param {Object} options
* @param {PublicKey|PublicKey[]} [options.encryptionKeys] - Array of public keys or single key used to select algorithm preferences for. If no keys are given, the algorithm will be [config.preferredSymmetricAlgorithm]{@link module:config.preferredSymmetricAlgorithm}
* @param {Date} [options.date=current date] - Date to select algorithm preferences at
* @param {Object|Object[]} [options.encryptionUserIDs=primary user IDs] - User IDs to select algorithm preferences for
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
* @returns {Promise<{ data: Uint8Array, algorithm: String }>} Object with session key data and algorithm.
* @async
* @static
*/
async function generateSessionKey$1({ encryptionKeys, date = new Date(), encryptionUserIDs = [], config: config$1, ...rest }) {
config$1 = { ...config, ...config$1 }; checkConfig(config$1);
encryptionKeys = toArray$1(encryptionKeys); encryptionUserIDs = toArray$1(encryptionUserIDs);
if (rest.publicKeys) throw new Error('The `publicKeys` option has been removed from openpgp.generateSessionKey, pass `encryptionKeys` instead');
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
try {
const sessionKeys = await Message.generateSessionKey(encryptionKeys, date, encryptionUserIDs, config$1);
return sessionKeys;
} catch (err) {
throw util.wrapError('Error generating session key', err);
}
}
/**
* Encrypt a symmetric session key with public keys, passwords, or both at once.
* At least one of `encryptionKeys` or `passwords` must be specified.
* @param {Object} options
* @param {Uint8Array} options.data - The session key to be encrypted e.g. 16 random bytes (for aes128)
* @param {String} options.algorithm - Algorithm of the symmetric session key e.g. 'aes128' or 'aes256'
* @param {String} [options.aeadAlgorithm] - AEAD algorithm, e.g. 'eax' or 'ocb'
* @param {PublicKey|PublicKey[]} [options.encryptionKeys] - Array of public keys or single key, used to encrypt the key
* @param {String|String[]} [options.passwords] - Passwords for the message
* @param {'armored'|'binary'} [options.format='armored'] - Format of the returned value
* @param {Boolean} [options.wildcard=false] - Use a key ID of 0 instead of the public key IDs
* @param {KeyID|KeyID[]} [options.encryptionKeyIDs=latest-created valid encryption (sub)keys] - Array of key IDs to use for encryption. Each encryptionKeyIDs[i] corresponds to encryptionKeys[i]
* @param {Date} [options.date=current date] - Override the date
* @param {Object|Object[]} [options.encryptionUserIDs=primary user IDs] - Array of user IDs to encrypt for, one per key in `encryptionKeys`, e.g. `[{ name: 'Phil Zimmermann', email: 'phil@openpgp.org' }]`
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
* @returns {Promise} Encrypted session keys (string if `armor` was true, the default; Uint8Array if `armor` was false).
* @async
* @static
*/
async function encryptSessionKey({ data, algorithm, aeadAlgorithm, encryptionKeys, passwords, format = 'armored', wildcard = false, encryptionKeyIDs = [], date = new Date(), encryptionUserIDs = [], config: config$1, ...rest }) {
config$1 = { ...config, ...config$1 }; checkConfig(config$1);
checkBinary(data); checkString(algorithm, 'algorithm'); checkOutputMessageFormat(format);
encryptionKeys = toArray$1(encryptionKeys); passwords = toArray$1(passwords); encryptionKeyIDs = toArray$1(encryptionKeyIDs); encryptionUserIDs = toArray$1(encryptionUserIDs);
if (rest.publicKeys) throw new Error('The `publicKeys` option has been removed from openpgp.encryptSessionKey, pass `encryptionKeys` instead');
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
if ((!encryptionKeys || encryptionKeys.length === 0) && (!passwords || passwords.length === 0)) {
throw new Error('No encryption keys or passwords provided.');
}
try {
const message = await Message.encryptSessionKey(data, algorithm, aeadAlgorithm, encryptionKeys, passwords, wildcard, encryptionKeyIDs, date, encryptionUserIDs, config$1);
return formatObject(message, format, config$1);
} catch (err) {
throw util.wrapError('Error encrypting session key', err);
}
}
/**
* Decrypt symmetric session keys using private keys or passwords (not both).
* One of `decryptionKeys` or `passwords` must be specified.
* @param {Object} options
* @param {Message} options.message - A message object containing the encrypted session key packets
* @param {PrivateKey|PrivateKey[]} [options.decryptionKeys] - Private keys with decrypted secret key data
* @param {String|String[]} [options.passwords] - Passwords to decrypt the session key
* @param {Date} [options.date] - Date to use for key verification instead of the current time
* @param {Object} [options.config] - Custom configuration settings to overwrite those in [config]{@link module:config}
* @returns {Promise} Array of decrypted session key, algorithm pairs in the form:
* { data:Uint8Array, algorithm:String }
* @throws if no session key could be found or decrypted
* @async
* @static
*/
async function decryptSessionKeys({ message, decryptionKeys, passwords, date = new Date(), config: config$1, ...rest }) {
config$1 = { ...config, ...config$1 }; checkConfig(config$1);
checkMessage(message); decryptionKeys = toArray$1(decryptionKeys); passwords = toArray$1(passwords);
if (rest.privateKeys) throw new Error('The `privateKeys` option has been removed from openpgp.decryptSessionKeys, pass `decryptionKeys` instead');
const unknownOptions = Object.keys(rest); if (unknownOptions.length > 0) throw new Error(`Unknown option: ${unknownOptions.join(', ')}`);
try {
const sessionKeys = await message.decryptSessionKeys(decryptionKeys, passwords, date, config$1);
return sessionKeys;
} catch (err) {
throw util.wrapError('Error decrypting session keys', err);
}
}
//////////////////////////
// //
// Helper functions //
// //
//////////////////////////
/**
* Input validation
* @private
*/
function checkString(data, name) {
if (!util.isString(data)) {
throw new Error('Parameter [' + (name || 'data') + '] must be of type String');
}
}
function checkBinary(data, name) {
if (!util.isUint8Array(data)) {
throw new Error('Parameter [' + (name || 'data') + '] must be of type Uint8Array');
}
}
function checkMessage(message) {
if (!(message instanceof Message)) {
throw new Error('Parameter [message] needs to be of type Message');
}
}
function checkCleartextOrMessage(message) {
if (!(message instanceof CleartextMessage) && !(message instanceof Message)) {
throw new Error('Parameter [message] needs to be of type Message or CleartextMessage');
}
}
function checkOutputMessageFormat(format) {
if (format !== 'armored' && format !== 'binary' && format !== 'object') {
throw new Error(`Unsupported format ${format}`);
}
}
const defaultConfigPropsCount = Object.keys(config).length;
function checkConfig(config$1) {
const inputConfigProps = Object.keys(config$1);
if (inputConfigProps.length !== defaultConfigPropsCount) {
for (const inputProp of inputConfigProps) {
if (config[inputProp] === undefined) {
throw new Error(`Unknown config property: ${inputProp}`);
}
}
}
}
/**
* Normalize parameter to an array if it is not undefined.
* @param {Object} param - the parameter to be normalized
* @returns {Array|undefined} The resulting array or undefined.
* @private
*/
function toArray$1(param) {
if (param && !util.isArray(param)) {
param = [param];
}
return param;
}
/**
* Convert data to or from Stream
* @param {Object} data - the data to convert
* @param {'web'|'ponyfill'|'node'|false} streaming - Whether to return a ReadableStream, and of what type
* @param {'utf8'|'binary'} [encoding] - How to return data in Node Readable streams
* @returns {Promise} The data in the respective format.
* @async
* @private
*/
async function convertStream(data, streaming, encoding = 'utf8') {
const streamType = util.isStream(data);
if (streamType === 'array') {
return readToEnd(data);
}
if (streaming === 'node') {
data = webToNode(data);
if (encoding !== 'binary') data.setEncoding(encoding);
return data;
}
if (streaming === 'web' && streamType === 'ponyfill') {
return toNativeReadable(data);
}
return data;
}
/**
* Link result.data to the message stream for cancellation.
* Also, forward errors in the message to result.data.
* @param {Object} result - the data to convert
* @param {Message} message - message object
* @returns {Object}
* @private
*/
function linkStreams(result, message) {
result.data = transformPair(message.packets.stream, async (readable, writable) => {
await pipe(result.data, writable, {
preventClose: true
});
const writer = getWriter(writable);
try {
// Forward errors in the message stream to result.data.
await readToEnd(readable, _ => _);
await writer.close();
} catch (e) {
await writer.abort(e);
}
});
}
/**
* Convert the object to the given format
* @param {Key|Message} object
* @param {'armored'|'binary'|'object'} format
* @param {Object} config - Full configuration
* @returns {String|Uint8Array|Object}
*/
function formatObject(object, format, config) {
switch (format) {
case 'object':
return object;
case 'armored':
return object.armor(config);
case 'binary':
return object.write();
default:
throw new Error(`Unsupported format ${format}`);
}
}
export { AEADEncryptedDataPacket, CleartextMessage, CompressedDataPacket, LiteralDataPacket, MarkerPacket, Message, OnePassSignaturePacket, PacketList, PrivateKey, PublicKey, PublicKeyEncryptedSessionKeyPacket, PublicKeyPacket, PublicSubkeyPacket, SecretKeyPacket, SecretSubkeyPacket, Signature, SignaturePacket, Subkey, SymEncryptedIntegrityProtectedDataPacket, SymEncryptedSessionKeyPacket, SymmetricallyEncryptedDataPacket, TrustPacket, UnparseablePacket, UserAttributePacket, UserIDPacket, _224 as _, commonjsGlobal as a, armor, common$1 as b, createCommonjsModule as c, config, createCleartextMessage, createMessage, common as d, decrypt$4 as decrypt, decryptKey, decryptSessionKeys, _256 as e, encrypt$4 as encrypt, encryptKey, encryptSessionKey, enums, _384 as f, _512 as g, generateKey, generateSessionKey$1 as generateSessionKey, inherits_browser as i, minimalisticAssert as m, ripemd as r, readCleartextMessage, readKey, readKeys, readMessage, readPrivateKey, readPrivateKeys, readSignature, reformatKey, revokeKey, sign$5 as sign, utils as u, unarmor, verify$5 as verify };