@zip.js/zip.js 2.13.0 → 2.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BENCHMARKS.md +46 -1
- package/deno.json +1 -1
- package/dist/zip-core-external.js +594 -935
- package/dist/zip-core-external.min.js +1 -1
- package/dist/zip-core.js +461 -908
- package/dist/zip-core.min.js +1 -1
- package/dist/zip-fs-core-external.js +601 -938
- package/dist/zip-fs-core-external.min.js +1 -1
- package/dist/zip-fs-core.js +468 -911
- package/dist/zip-fs-core.min.js +1 -1
- package/dist/zip-fs-external.js +601 -938
- package/dist/zip-fs-external.min.js +1 -1
- package/dist/zip-fs-native.js +470 -913
- package/dist/zip-fs-native.min.js +1 -1
- package/dist/zip-fs.js +604 -941
- package/dist/zip-fs.min.js +1 -1
- package/dist/zip-legacy.js +463 -910
- package/dist/zip-legacy.min.js +1 -1
- package/dist/zip-module.wasm +0 -0
- package/dist/zip-native.js +463 -910
- package/dist/zip-native.min.js +1 -1
- package/dist/zip-web-worker-native.js +1 -1
- package/dist/zip-web-worker.js +1 -1
- package/dist/zip.js +597 -938
- package/dist/zip.min.js +1 -1
- package/index-native.cjs +470 -913
- package/index-native.min.js +1 -1
- package/index.cjs +604 -941
- package/index.d.cts +58 -12
- package/index.d.ts +58 -12
- package/index.min.js +1 -1
- package/lib/core/codec-worker-web.js +35 -11
- package/lib/core/codec-worker.js +33 -23
- package/lib/core/io.js +29 -21
- package/lib/core/streams/aes-crypto-stream.js +58 -99
- package/lib/core/streams/codecs/aes-hmac-sha1.js +348 -0
- package/lib/core/streams/zlib-wasm/aes-hmac-sha1-wasm.js +106 -0
- package/lib/core/streams/zlib-wasm/zlib-streams-loader.js +4 -0
- package/lib/core/streams/zlib-wasm/zlib-streams.wasm +0 -0
- package/lib/core/version.js +1 -1
- package/lib/core/web-worker-base.js +15 -9
- package/lib/core/web-worker-inline-native.js +1 -1
- package/lib/core/web-worker-inline-wasm.js +1 -1
- package/lib/core/web-worker-wasm.js +2 -0
- package/lib/core/zip-fs.js +7 -3
- package/lib/core/zip-writer.js +1 -2
- package/lib/core/zlib-streams-inline.js +1 -1
- package/lib/zip-module-wasm-base.js +3 -1
- package/package.json +1 -1
- package/lib/core/streams/codecs/sjcl.js +0 -795
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2026 Gildas Lormeau. All rights reserved.
|
|
3
|
+
|
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
|
6
|
+
|
|
7
|
+
1. Redistributions of source code must retain the above copyright notice,
|
|
8
|
+
this list of conditions and the following disclaimer.
|
|
9
|
+
|
|
10
|
+
2. Redistributions in binary form must reproduce the above copyright
|
|
11
|
+
notice, this list of conditions and the following disclaimer in
|
|
12
|
+
the documentation and/or other materials provided with the distribution.
|
|
13
|
+
|
|
14
|
+
3. The names of the authors may not be used to endorse or promote products
|
|
15
|
+
derived from this software without specific prior written permission.
|
|
16
|
+
|
|
17
|
+
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
18
|
+
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
20
|
+
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
21
|
+
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
22
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
23
|
+
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
24
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
25
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
26
|
+
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
const BLOCK_LENGTH = 16;
|
|
30
|
+
const ROUND_KEYS_LENGTH = 60;
|
|
31
|
+
const SHA1_BLOCK_LENGTH = 64;
|
|
32
|
+
const SHA1_DIGEST_LENGTH = 20;
|
|
33
|
+
const SHA1_SCHEDULE_LENGTH = 80;
|
|
34
|
+
const SHA1_LENGTH_OFFSET = 56;
|
|
35
|
+
const SHA1_PADDING = new Uint8Array([0x80]);
|
|
36
|
+
const SHA1_ZERO = new Uint8Array(1);
|
|
37
|
+
const SHA1_INITIAL_STATE = new Int32Array([0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0]);
|
|
38
|
+
const HMAC_INNER_PADDING = 0x36;
|
|
39
|
+
const HMAC_OUTER_PADDING = 0x5c;
|
|
40
|
+
const S_BOX = new Uint8Array(256);
|
|
41
|
+
const T0 = new Int32Array(256);
|
|
42
|
+
const T1 = new Int32Array(256);
|
|
43
|
+
const T2 = new Int32Array(256);
|
|
44
|
+
const T3 = new Int32Array(256);
|
|
45
|
+
|
|
46
|
+
let tablesInitialized = false;
|
|
47
|
+
|
|
48
|
+
export {
|
|
49
|
+
createEngine,
|
|
50
|
+
pbkdf2
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
function createEngine(key, authenticationKey) {
|
|
54
|
+
initTables();
|
|
55
|
+
const roundKeys = new Int32Array(ROUND_KEYS_LENGTH);
|
|
56
|
+
const rounds = expandKey(key, roundKeys);
|
|
57
|
+
const counter = new Uint8Array(BLOCK_LENGTH);
|
|
58
|
+
const keystream = new Int32Array(BLOCK_LENGTH / 4);
|
|
59
|
+
const hmac = createHmac(authenticationKey);
|
|
60
|
+
return {
|
|
61
|
+
process(data, decrypt) {
|
|
62
|
+
if (decrypt) {
|
|
63
|
+
hmac.update(data, 0, data.length);
|
|
64
|
+
}
|
|
65
|
+
encrypt(data);
|
|
66
|
+
if (!decrypt) {
|
|
67
|
+
hmac.update(data, 0, data.length);
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
digest() {
|
|
71
|
+
return hmac.digest();
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
function encrypt(data) {
|
|
76
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
77
|
+
const length = data.length;
|
|
78
|
+
let offset = 0;
|
|
79
|
+
for (; offset + BLOCK_LENGTH <= length; offset += BLOCK_LENGTH) {
|
|
80
|
+
nextKeystream();
|
|
81
|
+
view.setInt32(offset, view.getInt32(offset) ^ keystream[0]);
|
|
82
|
+
view.setInt32(offset + 4, view.getInt32(offset + 4) ^ keystream[1]);
|
|
83
|
+
view.setInt32(offset + 8, view.getInt32(offset + 8) ^ keystream[2]);
|
|
84
|
+
view.setInt32(offset + 12, view.getInt32(offset + 12) ^ keystream[3]);
|
|
85
|
+
}
|
|
86
|
+
if (offset < length) {
|
|
87
|
+
nextKeystream();
|
|
88
|
+
for (let indexByte = 0; offset < length; offset++, indexByte++) {
|
|
89
|
+
data[offset] ^= keystream[indexByte >> 2] >>> (24 - 8 * (indexByte & 3));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function nextKeystream() {
|
|
95
|
+
for (let indexByte = 0; indexByte < BLOCK_LENGTH; indexByte++) {
|
|
96
|
+
counter[indexByte]++;
|
|
97
|
+
if (counter[indexByte] !== 0) {
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
let s0 = ((counter[0] << 24) | (counter[1] << 16) | (counter[2] << 8) | counter[3]) ^ roundKeys[0];
|
|
102
|
+
let s1 = ((counter[4] << 24) | (counter[5] << 16) | (counter[6] << 8) | counter[7]) ^ roundKeys[1];
|
|
103
|
+
let s2 = ((counter[8] << 24) | (counter[9] << 16) | (counter[10] << 8) | counter[11]) ^ roundKeys[2];
|
|
104
|
+
let s3 = ((counter[12] << 24) | (counter[13] << 16) | (counter[14] << 8) | counter[15]) ^ roundKeys[3];
|
|
105
|
+
let indexKey = 4;
|
|
106
|
+
for (let round = 1; round < rounds; round++, indexKey += 4) {
|
|
107
|
+
const t0 = T0[s0 >>> 24] ^ T1[(s1 >>> 16) & 255] ^ T2[(s2 >>> 8) & 255] ^ T3[s3 & 255] ^ roundKeys[indexKey];
|
|
108
|
+
const t1 = T0[s1 >>> 24] ^ T1[(s2 >>> 16) & 255] ^ T2[(s3 >>> 8) & 255] ^ T3[s0 & 255] ^ roundKeys[indexKey + 1];
|
|
109
|
+
const t2 = T0[s2 >>> 24] ^ T1[(s3 >>> 16) & 255] ^ T2[(s0 >>> 8) & 255] ^ T3[s1 & 255] ^ roundKeys[indexKey + 2];
|
|
110
|
+
const t3 = T0[s3 >>> 24] ^ T1[(s0 >>> 16) & 255] ^ T2[(s1 >>> 8) & 255] ^ T3[s2 & 255] ^ roundKeys[indexKey + 3];
|
|
111
|
+
s0 = t0;
|
|
112
|
+
s1 = t1;
|
|
113
|
+
s2 = t2;
|
|
114
|
+
s3 = t3;
|
|
115
|
+
}
|
|
116
|
+
keystream[0] = ((S_BOX[s0 >>> 24] << 24) | (S_BOX[(s1 >>> 16) & 255] << 16) | (S_BOX[(s2 >>> 8) & 255] << 8) | S_BOX[s3 & 255]) ^ roundKeys[indexKey];
|
|
117
|
+
keystream[1] = ((S_BOX[s1 >>> 24] << 24) | (S_BOX[(s2 >>> 16) & 255] << 16) | (S_BOX[(s3 >>> 8) & 255] << 8) | S_BOX[s0 & 255]) ^ roundKeys[indexKey + 1];
|
|
118
|
+
keystream[2] = ((S_BOX[s2 >>> 24] << 24) | (S_BOX[(s3 >>> 16) & 255] << 16) | (S_BOX[(s0 >>> 8) & 255] << 8) | S_BOX[s1 & 255]) ^ roundKeys[indexKey + 2];
|
|
119
|
+
keystream[3] = ((S_BOX[s3 >>> 24] << 24) | (S_BOX[(s0 >>> 16) & 255] << 16) | (S_BOX[(s1 >>> 8) & 255] << 8) | S_BOX[s2 & 255]) ^ roundKeys[indexKey + 3];
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function pbkdf2(password, salt, iterations, length) {
|
|
124
|
+
const hmac = createHmac(password);
|
|
125
|
+
const result = new Uint8Array(length);
|
|
126
|
+
const block = new Uint8Array(salt.length + 4);
|
|
127
|
+
const blockView = new DataView(block.buffer);
|
|
128
|
+
block.set(salt);
|
|
129
|
+
for (let indexBlock = 1, offset = 0; offset < length; indexBlock++, offset += SHA1_DIGEST_LENGTH) {
|
|
130
|
+
blockView.setUint32(salt.length, indexBlock);
|
|
131
|
+
hmac.update(block, 0, block.length);
|
|
132
|
+
let previous = hmac.digest();
|
|
133
|
+
const output = previous.slice();
|
|
134
|
+
for (let iteration = 1; iteration < iterations; iteration++) {
|
|
135
|
+
hmac.update(previous, 0, SHA1_DIGEST_LENGTH);
|
|
136
|
+
previous = hmac.digest();
|
|
137
|
+
for (let indexByte = 0; indexByte < SHA1_DIGEST_LENGTH; indexByte++) {
|
|
138
|
+
output[indexByte] ^= previous[indexByte];
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
result.set(output.subarray(0, Math.min(SHA1_DIGEST_LENGTH, length - offset)), offset);
|
|
142
|
+
}
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function createHmac(key) {
|
|
147
|
+
const sha1 = createSha1();
|
|
148
|
+
const innerKey = new Uint8Array(SHA1_BLOCK_LENGTH);
|
|
149
|
+
const outerKey = new Uint8Array(SHA1_BLOCK_LENGTH);
|
|
150
|
+
if (key.length > SHA1_BLOCK_LENGTH) {
|
|
151
|
+
sha1.update(key, 0, key.length);
|
|
152
|
+
key = sha1.digest();
|
|
153
|
+
}
|
|
154
|
+
for (let indexByte = 0; indexByte < SHA1_BLOCK_LENGTH; indexByte++) {
|
|
155
|
+
const keyByte = indexByte < key.length ? key[indexByte] : 0;
|
|
156
|
+
innerKey[indexByte] = keyByte ^ HMAC_INNER_PADDING;
|
|
157
|
+
outerKey[indexByte] = keyByte ^ HMAC_OUTER_PADDING;
|
|
158
|
+
}
|
|
159
|
+
sha1.update(innerKey, 0, SHA1_BLOCK_LENGTH);
|
|
160
|
+
return {
|
|
161
|
+
update(data, offset, length) {
|
|
162
|
+
sha1.update(data, offset, length);
|
|
163
|
+
},
|
|
164
|
+
digest() {
|
|
165
|
+
const innerDigest = sha1.digest();
|
|
166
|
+
sha1.update(outerKey, 0, SHA1_BLOCK_LENGTH);
|
|
167
|
+
sha1.update(innerDigest, 0, SHA1_DIGEST_LENGTH);
|
|
168
|
+
const result = sha1.digest();
|
|
169
|
+
sha1.update(innerKey, 0, SHA1_BLOCK_LENGTH);
|
|
170
|
+
return result;
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function createSha1() {
|
|
176
|
+
const state = new Int32Array(SHA1_INITIAL_STATE);
|
|
177
|
+
const schedule = new Int32Array(SHA1_SCHEDULE_LENGTH);
|
|
178
|
+
const block = new Uint8Array(SHA1_BLOCK_LENGTH);
|
|
179
|
+
const blockView = new DataView(block.buffer);
|
|
180
|
+
const lengthBytes = new Uint8Array(8);
|
|
181
|
+
let blockLength = 0;
|
|
182
|
+
let totalLength = 0;
|
|
183
|
+
return {
|
|
184
|
+
update,
|
|
185
|
+
digest
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
function update(data, offset, length) {
|
|
189
|
+
const end = offset + length;
|
|
190
|
+
totalLength += length;
|
|
191
|
+
if (blockLength) {
|
|
192
|
+
while (offset < end && blockLength < SHA1_BLOCK_LENGTH) {
|
|
193
|
+
block[blockLength++] = data[offset++];
|
|
194
|
+
}
|
|
195
|
+
if (blockLength == SHA1_BLOCK_LENGTH) {
|
|
196
|
+
compress(blockView, 0);
|
|
197
|
+
blockLength = 0;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (offset + SHA1_BLOCK_LENGTH <= end) {
|
|
201
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
202
|
+
for (; offset + SHA1_BLOCK_LENGTH <= end; offset += SHA1_BLOCK_LENGTH) {
|
|
203
|
+
compress(view, offset);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
while (offset < end) {
|
|
207
|
+
block[blockLength++] = data[offset++];
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function digest() {
|
|
212
|
+
const bits = totalLength * 8;
|
|
213
|
+
const high = Math.floor(bits / 0x100000000);
|
|
214
|
+
const low = bits >>> 0;
|
|
215
|
+
update(SHA1_PADDING, 0, 1);
|
|
216
|
+
while (blockLength != SHA1_LENGTH_OFFSET) {
|
|
217
|
+
update(SHA1_ZERO, 0, 1);
|
|
218
|
+
}
|
|
219
|
+
lengthBytes[0] = high >>> 24;
|
|
220
|
+
lengthBytes[1] = high >>> 16;
|
|
221
|
+
lengthBytes[2] = high >>> 8;
|
|
222
|
+
lengthBytes[3] = high;
|
|
223
|
+
lengthBytes[4] = low >>> 24;
|
|
224
|
+
lengthBytes[5] = low >>> 16;
|
|
225
|
+
lengthBytes[6] = low >>> 8;
|
|
226
|
+
lengthBytes[7] = low;
|
|
227
|
+
update(lengthBytes, 0, 8);
|
|
228
|
+
const result = new Uint8Array(SHA1_DIGEST_LENGTH);
|
|
229
|
+
const resultView = new DataView(result.buffer);
|
|
230
|
+
for (let indexWord = 0; indexWord < state.length; indexWord++) {
|
|
231
|
+
resultView.setInt32(4 * indexWord, state[indexWord]);
|
|
232
|
+
}
|
|
233
|
+
state.set(SHA1_INITIAL_STATE);
|
|
234
|
+
blockLength = 0;
|
|
235
|
+
totalLength = 0;
|
|
236
|
+
return result;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function compress(view, offset) {
|
|
240
|
+
for (let index = 0; index < 16; index++) {
|
|
241
|
+
schedule[index] = view.getInt32(offset + 4 * index);
|
|
242
|
+
}
|
|
243
|
+
for (let index = 16; index < SHA1_SCHEDULE_LENGTH; index++) {
|
|
244
|
+
const word = schedule[index - 3] ^ schedule[index - 8] ^ schedule[index - 14] ^ schedule[index - 16];
|
|
245
|
+
schedule[index] = (word << 1) | (word >>> 31);
|
|
246
|
+
}
|
|
247
|
+
let a = state[0];
|
|
248
|
+
let b = state[1];
|
|
249
|
+
let c = state[2];
|
|
250
|
+
let d = state[3];
|
|
251
|
+
let e = state[4];
|
|
252
|
+
let t;
|
|
253
|
+
for (let index = 0; index < 20; index++) {
|
|
254
|
+
t = (((a << 5) | (a >>> 27)) + ((b & c) | (~b & d)) + e + 0x5A827999 + schedule[index]) | 0;
|
|
255
|
+
e = d;
|
|
256
|
+
d = c;
|
|
257
|
+
c = (b << 30) | (b >>> 2);
|
|
258
|
+
b = a;
|
|
259
|
+
a = t;
|
|
260
|
+
}
|
|
261
|
+
for (let index = 20; index < 40; index++) {
|
|
262
|
+
t = (((a << 5) | (a >>> 27)) + (b ^ c ^ d) + e + 0x6ED9EBA1 + schedule[index]) | 0;
|
|
263
|
+
e = d;
|
|
264
|
+
d = c;
|
|
265
|
+
c = (b << 30) | (b >>> 2);
|
|
266
|
+
b = a;
|
|
267
|
+
a = t;
|
|
268
|
+
}
|
|
269
|
+
for (let index = 40; index < 60; index++) {
|
|
270
|
+
t = (((a << 5) | (a >>> 27)) + ((b & c) | (b & d) | (c & d)) + e + 0x8F1BBCDC + schedule[index]) | 0;
|
|
271
|
+
e = d;
|
|
272
|
+
d = c;
|
|
273
|
+
c = (b << 30) | (b >>> 2);
|
|
274
|
+
b = a;
|
|
275
|
+
a = t;
|
|
276
|
+
}
|
|
277
|
+
for (let index = 60; index < SHA1_SCHEDULE_LENGTH; index++) {
|
|
278
|
+
t = (((a << 5) | (a >>> 27)) + (b ^ c ^ d) + e + 0xCA62C1D6 + schedule[index]) | 0;
|
|
279
|
+
e = d;
|
|
280
|
+
d = c;
|
|
281
|
+
c = (b << 30) | (b >>> 2);
|
|
282
|
+
b = a;
|
|
283
|
+
a = t;
|
|
284
|
+
}
|
|
285
|
+
state[0] = (state[0] + a) | 0;
|
|
286
|
+
state[1] = (state[1] + b) | 0;
|
|
287
|
+
state[2] = (state[2] + c) | 0;
|
|
288
|
+
state[3] = (state[3] + d) | 0;
|
|
289
|
+
state[4] = (state[4] + e) | 0;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function initTables() {
|
|
294
|
+
if (!tablesInitialized) {
|
|
295
|
+
let p = 1;
|
|
296
|
+
let q = 1;
|
|
297
|
+
do {
|
|
298
|
+
p = (p ^ (p << 1) ^ ((p & 0x80) ? 0x1b : 0)) & 255;
|
|
299
|
+
q = (q ^ (q << 1)) & 255;
|
|
300
|
+
q = (q ^ (q << 2)) & 255;
|
|
301
|
+
q = (q ^ (q << 4)) & 255;
|
|
302
|
+
if (q & 0x80) {
|
|
303
|
+
q ^= 0x09;
|
|
304
|
+
}
|
|
305
|
+
S_BOX[p] = (q ^ ((q << 1) | (q >> 7)) ^ ((q << 2) | (q >> 6)) ^ ((q << 3) | (q >> 5)) ^ ((q << 4) | (q >> 4)) ^ 0x63) & 255;
|
|
306
|
+
} while (p != 1);
|
|
307
|
+
S_BOX[0] = 0x63;
|
|
308
|
+
for (let index = 0; index < 256; index++) {
|
|
309
|
+
const s = S_BOX[index];
|
|
310
|
+
const s2 = multiplyByTwo(s);
|
|
311
|
+
const t = (s2 << 24) | (s << 16) | (s << 8) | (s2 ^ s);
|
|
312
|
+
T0[index] = t;
|
|
313
|
+
T1[index] = (t >>> 8) | (t << 24);
|
|
314
|
+
T2[index] = (t >>> 16) | (t << 16);
|
|
315
|
+
T3[index] = (t >>> 24) | (t << 8);
|
|
316
|
+
}
|
|
317
|
+
tablesInitialized = true;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function expandKey(key, roundKeys) {
|
|
322
|
+
const keyWords = key.length >> 2;
|
|
323
|
+
const rounds = keyWords + 6;
|
|
324
|
+
const total = 4 * (rounds + 1);
|
|
325
|
+
let roundConstant = 1;
|
|
326
|
+
for (let index = 0; index < keyWords; index++) {
|
|
327
|
+
roundKeys[index] = (key[4 * index] << 24) | (key[4 * index + 1] << 16) | (key[4 * index + 2] << 8) | key[4 * index + 3];
|
|
328
|
+
}
|
|
329
|
+
for (let index = keyWords; index < total; index++) {
|
|
330
|
+
let word = roundKeys[index - 1];
|
|
331
|
+
if (index % keyWords == 0) {
|
|
332
|
+
word = substituteWord((word << 8) | (word >>> 24)) ^ (roundConstant << 24);
|
|
333
|
+
roundConstant = multiplyByTwo(roundConstant);
|
|
334
|
+
} else if (keyWords > 6 && index % keyWords == 4) {
|
|
335
|
+
word = substituteWord(word);
|
|
336
|
+
}
|
|
337
|
+
roundKeys[index] = roundKeys[index - keyWords] ^ word;
|
|
338
|
+
}
|
|
339
|
+
return rounds;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function substituteWord(word) {
|
|
343
|
+
return (S_BOX[word >>> 24] << 24) | (S_BOX[(word >>> 16) & 255] << 16) | (S_BOX[(word >>> 8) & 255] << 8) | S_BOX[word & 255];
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function multiplyByTwo(value) {
|
|
347
|
+
return ((value << 1) ^ ((value >> 7) * 0x1b)) & 255;
|
|
348
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2026 Gildas Lormeau. All rights reserved.
|
|
3
|
+
|
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
|
6
|
+
|
|
7
|
+
1. Redistributions of source code must retain the above copyright notice,
|
|
8
|
+
this list of conditions and the following disclaimer.
|
|
9
|
+
|
|
10
|
+
2. Redistributions in binary form must reproduce the above copyright
|
|
11
|
+
notice, this list of conditions and the following disclaimer in
|
|
12
|
+
the documentation and/or other materials provided with the distribution.
|
|
13
|
+
|
|
14
|
+
3. The names of the authors may not be used to endorse or promote products
|
|
15
|
+
derived from this software without specific prior written permission.
|
|
16
|
+
|
|
17
|
+
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
18
|
+
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
20
|
+
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
21
|
+
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
22
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
23
|
+
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
24
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
25
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
26
|
+
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import { FUNCTION_TYPE } from "../../constants.js";
|
|
30
|
+
import { createEngine as createDefaultEngine } from "../codecs/aes-hmac-sha1.js";
|
|
31
|
+
|
|
32
|
+
const BUFFER_LENGTH = 64 * 1024;
|
|
33
|
+
const DIGEST_LENGTH = 20;
|
|
34
|
+
|
|
35
|
+
let wasm, buffer;
|
|
36
|
+
|
|
37
|
+
export {
|
|
38
|
+
setWasmExports,
|
|
39
|
+
resetWasmExports,
|
|
40
|
+
createEngine
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
function setWasmExports(wasmAPI) {
|
|
44
|
+
// deno-lint-ignore valid-typeof
|
|
45
|
+
if (typeof wasmAPI.aes_hmac_new == FUNCTION_TYPE) {
|
|
46
|
+
wasm = wasmAPI;
|
|
47
|
+
buffer = 0;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function resetWasmExports() {
|
|
52
|
+
wasm = null;
|
|
53
|
+
buffer = 0;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function createEngine(key, authenticationKey) {
|
|
57
|
+
const exports = wasm;
|
|
58
|
+
let context = exports ? createContext(exports, key, authenticationKey) : 0;
|
|
59
|
+
if (!context) {
|
|
60
|
+
return createDefaultEngine(key, authenticationKey);
|
|
61
|
+
}
|
|
62
|
+
const scratch = buffer;
|
|
63
|
+
return {
|
|
64
|
+
process(data, decrypt) {
|
|
65
|
+
for (let offset = 0; offset < data.length; offset += BUFFER_LENGTH) {
|
|
66
|
+
const chunk = data.subarray(offset, offset + BUFFER_LENGTH);
|
|
67
|
+
const heap = getHeap(exports);
|
|
68
|
+
heap.set(chunk, scratch);
|
|
69
|
+
exports.aes_hmac_process(context, scratch, chunk.length, decrypt ? 1 : 0);
|
|
70
|
+
chunk.set(heap.subarray(scratch, scratch + chunk.length));
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
digest() {
|
|
74
|
+
exports.aes_hmac_end(context, scratch);
|
|
75
|
+
context = 0;
|
|
76
|
+
return getHeap(exports).slice(scratch, scratch + DIGEST_LENGTH);
|
|
77
|
+
},
|
|
78
|
+
dispose() {
|
|
79
|
+
if (context) {
|
|
80
|
+
exports.aes_hmac_end(context, 0);
|
|
81
|
+
context = 0;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function createContext(exports, key, authenticationKey) {
|
|
88
|
+
if (!buffer) {
|
|
89
|
+
buffer = exports.malloc(BUFFER_LENGTH);
|
|
90
|
+
}
|
|
91
|
+
const context = buffer ? exports.aes_hmac_new() : 0;
|
|
92
|
+
if (context) {
|
|
93
|
+
const heap = getHeap(exports);
|
|
94
|
+
heap.set(key, buffer);
|
|
95
|
+
heap.set(authenticationKey, buffer + key.length);
|
|
96
|
+
if (exports.aes_hmac_init(context, buffer, key.length, buffer + key.length, authenticationKey.length)) {
|
|
97
|
+
exports.aes_hmac_end(context, 0);
|
|
98
|
+
return 0;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return context;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function getHeap(exports) {
|
|
105
|
+
return new Uint8Array(exports.memory.buffer);
|
|
106
|
+
}
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
/* global WebAssembly, URL, fetch, atob */
|
|
30
30
|
|
|
31
31
|
import { setWasmExports, setInitError, resetWasmExports } from "./zlib-streams.js";
|
|
32
|
+
import { setWasmExports as setEngineWasmExports, resetWasmExports as resetEngineWasmExports } from "./aes-hmac-sha1-wasm.js";
|
|
32
33
|
|
|
33
34
|
let initializedModule = false;
|
|
34
35
|
|
|
@@ -63,11 +64,13 @@ async function instantiateModule(wasmURI, baseURI) {
|
|
|
63
64
|
}
|
|
64
65
|
const wasmInstance = await WebAssembly.instantiate(arrayBuffer);
|
|
65
66
|
setWasmExports(wasmInstance.instance.exports);
|
|
67
|
+
setEngineWasmExports(wasmInstance.instance.exports);
|
|
66
68
|
}
|
|
67
69
|
|
|
68
70
|
function resetWasmModule() {
|
|
69
71
|
initializedModule = false;
|
|
70
72
|
resetWasmExports();
|
|
73
|
+
resetEngineWasmExports();
|
|
71
74
|
}
|
|
72
75
|
|
|
73
76
|
function arrayBufferFromDataURI(dataURI) {
|
|
@@ -85,6 +88,7 @@ export {
|
|
|
85
88
|
CompressionStreamZlib,
|
|
86
89
|
DecompressionStreamZlib
|
|
87
90
|
} from "./zlib-streams.js";
|
|
91
|
+
export { createEngine as createAESEngine } from "./aes-hmac-sha1-wasm.js";
|
|
88
92
|
export {
|
|
89
93
|
initModule,
|
|
90
94
|
resetWasmModule
|
|
Binary file
|
package/lib/core/version.js
CHANGED
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
-
/* global self, addEventListener, postMessage, ReadableStream, WritableStream,
|
|
31
|
+
/* global self, addEventListener, postMessage, ReadableStream, WritableStream, structuredClone */
|
|
32
32
|
|
|
33
33
|
import {
|
|
34
34
|
CODEC_DEFLATE,
|
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
MESSAGE_READY
|
|
45
45
|
} from "./streams/codec-stream.js";
|
|
46
46
|
import { getChunkSize } from "./configuration.js";
|
|
47
|
+
import { setAESEngine } from "./streams/aes-crypto-stream.js";
|
|
47
48
|
import { toCompatibleReadable, toCompatibleWritable } from "./util/compatible-streams.js";
|
|
48
49
|
import { toExactUint8Array } from "./util/array.js";
|
|
49
50
|
import { isErrorObject } from "./util/error.js";
|
|
@@ -54,14 +55,17 @@ const pendingPullMessages = new Map();
|
|
|
54
55
|
const pendingDataMessages = new Map();
|
|
55
56
|
const errorValueSerializable = testErrorValueSerializable();
|
|
56
57
|
|
|
57
|
-
let
|
|
58
|
+
let messageId = 0;
|
|
58
59
|
|
|
59
60
|
export { initWorker };
|
|
60
61
|
|
|
61
62
|
function initWorker(options = {}) {
|
|
62
|
-
const { init } = options;
|
|
63
|
+
const { init, createAESEngine } = options;
|
|
63
64
|
const CompressionStreamFallback = options.CompressionStreamFallback || options.CompressionStreamZlib;
|
|
64
65
|
const DecompressionStreamFallback = options.DecompressionStreamFallback || options.DecompressionStreamZlib;
|
|
66
|
+
if (createAESEngine) {
|
|
67
|
+
setAESEngine(createAESEngine);
|
|
68
|
+
}
|
|
65
69
|
self.initModule = async config => {
|
|
66
70
|
if (init) {
|
|
67
71
|
await init(config);
|
|
@@ -91,9 +95,6 @@ addEventListener(MESSAGE_EVENT_TYPE, ({ data }) => {
|
|
|
91
95
|
pendingDataMessages.delete(messageId);
|
|
92
96
|
resolve();
|
|
93
97
|
}
|
|
94
|
-
if (type == MESSAGE_CLOSE) {
|
|
95
|
-
abortController.abort();
|
|
96
|
-
}
|
|
97
98
|
} catch (error) {
|
|
98
99
|
sendErrorMessage(error);
|
|
99
100
|
}
|
|
@@ -141,6 +142,13 @@ async function init(message) {
|
|
|
141
142
|
}
|
|
142
143
|
}
|
|
143
144
|
}
|
|
145
|
+
if (options.encrypted && !options.zipCrypto) {
|
|
146
|
+
try {
|
|
147
|
+
await self.initModule(message.config);
|
|
148
|
+
} catch {
|
|
149
|
+
// ignored
|
|
150
|
+
}
|
|
151
|
+
}
|
|
144
152
|
if (!config.CompressionStreamFallback && config.CompressionStreamZlib) {
|
|
145
153
|
config.CompressionStreamFallback = config.CompressionStreamZlib;
|
|
146
154
|
}
|
|
@@ -172,12 +180,10 @@ async function init(message) {
|
|
|
172
180
|
}, strategy);
|
|
173
181
|
codecStream = new CodecStream(options, config);
|
|
174
182
|
chunkStream = new ChunkStream(getChunkSize(config));
|
|
175
|
-
abortController = new AbortController();
|
|
176
|
-
const { signal } = abortController;
|
|
177
183
|
await readable
|
|
178
184
|
.pipeThrough(codecStream)
|
|
179
185
|
.pipeThrough(chunkStream)
|
|
180
|
-
.pipeTo(writable, {
|
|
186
|
+
.pipeTo(writable, { preventClose: true, preventAbort: true });
|
|
181
187
|
await writable.getWriter().close();
|
|
182
188
|
const {
|
|
183
189
|
crc32,
|