zlib-streams 1.1.0 → 1.2.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/Makefile CHANGED
@@ -148,6 +148,7 @@ WASM_CRC_CFLAGS = -DZ_U4=unsigned -DZ_U8='unsigned long long' -DZ_TESTW=8
148
148
  # USE_ZLIB_RABIN_KARP_ROLLING_HASH turns Chromium's own hash OFF so the deflate stream
149
149
  # stays bit-for-bit what madler's deflate.c produces.
150
150
  WASM_DEFLATE_CFLAGS = -DDEFLATE_COMPARE256_64LE -DUSE_ZLIB_RABIN_KARP_ROLLING_HASH
151
+ WASM_EXPORTED_FUNCTIONS = "_inflate9_new","_inflate9_init","_inflate9_init_raw","_inflate9_process","_inflate9_end","_inflate9_last_consumed","_inflate_new","_inflate_init","_inflate_init_raw","_inflate_init_gzip","_inflate_process","_inflate_end","_inflate_last_consumed","_deflate_new","_deflate_init","_deflate_init_raw","_deflate_init_gzip","_deflate_process","_deflate_end","_deflate_last_consumed","_malloc","_free"
151
152
  WASM_CFLAGS = -Isrc -Isrc/zlib -Isrc/zlib/contrib/infback9 -O2 -flto -DDYNAMIC_CRC_TABLE -DBUILDFIXED -DZ_SOLO $(WASM_CRC_CFLAGS) $(WASM_DEFLATE_CFLAGS) $(INFLATE_CHUNK_CFLAGS)
152
153
 
153
154
  .PHONY: wasm
@@ -160,7 +161,7 @@ dist/zlib-streams_traced.wasm: $(WASM_SRCS)
160
161
  @echo "Building traced $@ using $(EMCC)"
161
162
  @mkdir -p dist
162
163
  $(EMCC) $(WASM_SRCS) $(WASM_CFLAGS) $(DEBUG_DEFINES_TRACED) -s WASM=1 -s STANDALONE_WASM=1 --no-entry \
163
- -s EXPORTED_FUNCTIONS='["_inflate9_new","_inflate9_init","_inflate9_init_raw","_inflate9_process","_inflate9_end","_inflate9_last_consumed","_inflate_new","_inflate_init","_inflate_init_raw","_inflate_init_gzip","_inflate_process","_inflate_end","_inflate_last_consumed","_deflate_new","_deflate_init","_deflate_init_raw","_deflate_init_gzip","_deflate_process","_deflate_end","_deflate_last_consumed","_malloc","_free"]' \
164
+ -s EXPORTED_FUNCTIONS='[$(WASM_EXPORTED_FUNCTIONS)]' \
164
165
  -o $@
165
166
 
166
167
  # Run reference C and WASM test suites over payloads in test/ref-data
@@ -292,13 +293,15 @@ run_all_tests: dist/zlib-streams-dev.wasm
292
293
  # Output buffer filling before any input is consumed, including a deflate64
293
294
  # match longer than the buffer, which no encoder we have can produce
294
295
  @node src/wasm/tests/test_output_buffer_boundary.js dist/zlib-streams-dev.wasm
296
+ # Error codes packed the same way as a success, on both directions
297
+ @node src/wasm/tests/test_process_error_encoding.js dist/zlib-streams-dev.wasm
295
298
  @echo "Completed run_all_tests"
296
299
 
297
300
  dist/zlib-streams-dev.wasm: $(WASM_SRCS)
298
301
  @echo "Building $@ using $(EMCC)"
299
302
  @mkdir -p dist
300
303
  $(EMCC) $(WASM_SRCS) $(WASM_CFLAGS) -s WASM=1 -s STANDALONE_WASM=1 --no-entry \
301
- -s EXPORTED_FUNCTIONS='["_inflate9_new","_inflate9_init","_inflate9_init_raw","_inflate9_process","_inflate9_end","_inflate9_last_consumed","_inflate_new","_inflate_init","_inflate_init_raw","_inflate_init_gzip","_inflate_process","_inflate_end","_inflate_last_consumed","_deflate_new","_deflate_init","_deflate_init_raw","_deflate_init_gzip","_deflate_process","_deflate_end","_deflate_last_consumed","_malloc","_free"]' \
304
+ -s EXPORTED_FUNCTIONS='[$(WASM_EXPORTED_FUNCTIONS)]' \
302
305
  -o $@
303
306
  cp src/wasm/api/zlib-streams.js dist/zlib-streams.js
304
307
 
@@ -311,11 +314,35 @@ dist/zlib-streams.wasm: $(WASM_SRCS)
311
314
  @mkdir -p dist
312
315
  $(EMCC) $(WASM_SRCS) $(WASM_CFLAGS) -Oz -flto -s WASM=1 -s STANDALONE_WASM=1 --no-entry \
313
316
  -s FILESYSTEM=0 -s DISABLE_EXCEPTION_CATCHING=1 \
314
- -s EXPORTED_FUNCTIONS='["_inflate9_new","_inflate9_init","_inflate9_init_raw","_inflate9_process","_inflate9_end","_inflate9_last_consumed","_inflate_new","_inflate_init","_inflate_init_raw","_inflate_init_gzip","_inflate_process","_inflate_end","_inflate_last_consumed","_deflate_new","_deflate_init","_deflate_init_raw","_deflate_init_gzip","_deflate_process","_deflate_end","_deflate_last_consumed","_malloc","_free"]' \
317
+ -s EXPORTED_FUNCTIONS='[$(WASM_EXPORTED_FUNCTIONS)]' \
315
318
  -o $@
316
319
  cp src/wasm/api/zlib-streams.js dist/zlib-streams.js
317
320
  @test -x $(WASM_OPT) && { echo "Running wasm-opt -Oz --enable-bulk-memory-opt"; $(WASM_OPT) -Oz --enable-bulk-memory-opt -o $@ $@ || true; } || true
318
321
 
322
+ # -----------------------------------------------------------------------------
323
+ # zip.js module: the zlib codecs plus the AES-CTR/HMAC-SHA1 engine behind its
324
+ # encrypted entries (src/wasm/aes_hmac_wasm.c), vendored by zip.js as
325
+ # lib/core/streams/zlib-wasm/zlib-streams.wasm
326
+ # -----------------------------------------------------------------------------
327
+ ZIP_MODULE_SRCS = src/wasm/aes_hmac_wasm.c
328
+ ZIP_MODULE_EXPORTED_FUNCTIONS = $(WASM_EXPORTED_FUNCTIONS),"_aes_hmac_new","_aes_hmac_init","_aes_hmac_process","_aes_hmac_end"
329
+
330
+ .PHONY: zip_module
331
+ zip_module: dist/zip-module.wasm
332
+
333
+ dist/zip-module.wasm: $(WASM_SRCS) $(ZIP_MODULE_SRCS)
334
+ @echo "Building zip.js module $@ using $(EMCC)"
335
+ @mkdir -p dist
336
+ $(EMCC) $(WASM_SRCS) $(ZIP_MODULE_SRCS) $(WASM_CFLAGS) -Oz -flto -s WASM=1 -s STANDALONE_WASM=1 --no-entry \
337
+ -s FILESYSTEM=0 -s DISABLE_EXCEPTION_CATCHING=1 \
338
+ -s EXPORTED_FUNCTIONS='[$(ZIP_MODULE_EXPORTED_FUNCTIONS)]' \
339
+ -o $@
340
+ @test -x $(WASM_OPT) && { echo "Running wasm-opt -Oz --enable-bulk-memory-opt"; $(WASM_OPT) -Oz --enable-bulk-memory-opt -o $@ $@ || true; } || true
341
+
342
+ .PHONY: test_zip_module
343
+ test_zip_module: dist/zip-module.wasm
344
+ @node src/wasm/tests/test_aes_hmac.js dist/zip-module.wasm
345
+
319
346
  # -----------------------------------------------------------------------------
320
347
  # Optional generator: build a C++ tool that creates Deflate64 ZIPs using the
321
348
  # 7-Zip SDK. This target is guarded: it only compiles when the SDK is present
package/README.md CHANGED
@@ -31,5 +31,12 @@ make wasm_prod
31
31
  ```
32
32
  Output: `dist/zlib-streams.wasm` and `dist/zlib-streams.js`
33
33
 
34
+ - zip.js module: the codecs plus the AES-CTR/HMAC-SHA1 engine behind the encrypted entries of zip.js
35
+ ```sh
36
+ make zip_module
37
+ make test_zip_module
38
+ ```
39
+ Output: `dist/zip-module.wasm`
40
+
34
41
  ## License
35
42
  See LICENSE for details.
Binary file
Binary file
@@ -138,18 +138,17 @@ function _make(isCompress, type, options = {}) {
138
138
  }
139
139
  heap.set(buffer.subarray(offset, offset + toRead), this.in);
140
140
  const result = process(this.streamHandle, this.in, toRead, out, outBufferSize, 0);
141
+ // checked before the byte count is used, so a status code can never be read as one
142
+ const code = (result >> 24) & 0xff;
143
+ const signedCode = (code & 0x80) ? code - 256 : code;
144
+ if (signedCode < 0) {
145
+ throw new Error("process error:" + signedCode);
146
+ }
141
147
  const prod = result & 0x00ffffff;
142
148
  if (prod) {
143
149
  scratch.set(heap.subarray(out, out + prod), 0);
144
150
  controller.enqueue(scratch.slice(0, prod));
145
151
  }
146
- if (!isCompress) {
147
- const code = (result >> 24) & 0xff;
148
- const signedCode = (code & 0x80) ? code - 256 : code;
149
- if (signedCode < 0) {
150
- throw new Error("process error:" + signedCode);
151
- }
152
- }
153
152
  const consumed = last_consumed(this.streamHandle);
154
153
  if (consumed === 0 && prod === 0) {
155
154
  break;
@@ -169,14 +168,12 @@ function _make(isCompress, type, options = {}) {
169
168
  const scratch = this._scratch;
170
169
  while (true) {
171
170
  const result = process(this.streamHandle, 0, 0, out, outBufferSize, 4);
172
- const produced = result & 0x00ffffff;
173
171
  const code = (result >> 24) & 0xff;
174
- if (!isCompress) {
175
- const signedCode = (code & 0x80) ? code - 256 : code;
176
- if (signedCode < 0) {
177
- throw new Error("process error:" + signedCode);
178
- }
172
+ const signedCode = (code & 0x80) ? code - 256 : code;
173
+ if (signedCode < 0) {
174
+ throw new Error("process error:" + signedCode);
179
175
  }
176
+ const produced = result & 0x00ffffff;
180
177
  if (produced) {
181
178
  scratch.set(heap.subarray(out, out + produced), 0);
182
179
  controller.enqueue(scratch.slice(0, produced));
Binary file
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "WASM-based Compression Streams API implementation using zlib, with support for deflate64 decompression.",
4
4
  "author": "Gildas Lormeau",
5
5
  "license": "BSD-3-Clause",
6
- "version": "1.1.0",
6
+ "version": "1.2.0",
7
7
  "type": "module",
8
8
  "keywords": [
9
9
  "deflate",
@@ -15,7 +15,8 @@
15
15
  "exports": {
16
16
  "./package.json": "./package.json",
17
17
  "./zlib-streams.js": "./dist/zlib-streams.js",
18
- "./zlib-streams.wasm": "./dist/zlib-streams.wasm"
18
+ "./zlib-streams.wasm": "./dist/zlib-streams.wasm",
19
+ "./zip-module.wasm": "./dist/zip-module.wasm"
19
20
  },
20
21
  "repository": {
21
22
  "type": "git",
@@ -0,0 +1,307 @@
1
+ /* The engine behind the AES entries of zip.js: AES-CTR with the WinZip counter, a 16-byte
2
+ little-endian integer starting at 1, and HMAC-SHA1 over the ciphertext. Forward-only T-table
3
+ AES, the aes_core.c layout. One context per stream: init() takes the cipher key and the
4
+ authentication key, process() works in place and takes whole 16-byte blocks except for the last
5
+ call, end() writes the 20-byte MAC when given an output pointer and frees the context. */
6
+ #include <stdlib.h>
7
+ #include <string.h>
8
+ #include <stdint.h>
9
+
10
+ #define BLOCK_LENGTH 16
11
+ #define SHA1_BLOCK_LENGTH 64
12
+ #define SHA1_DIGEST_LENGTH 20
13
+ #define ROUND_KEYS_LENGTH 60
14
+
15
+ struct aes_hmac_ctx {
16
+ uint32_t round_keys[ROUND_KEYS_LENGTH];
17
+ int rounds;
18
+ uint8_t counter[BLOCK_LENGTH];
19
+ uint32_t h[5];
20
+ uint8_t block[SHA1_BLOCK_LENGTH];
21
+ unsigned block_length;
22
+ uint64_t total_length;
23
+ uint8_t opad[SHA1_BLOCK_LENGTH];
24
+ };
25
+
26
+ static uint32_t Te0[256], Te1[256], Te2[256], Te3[256];
27
+ static uint8_t sbox[256];
28
+ static int tables_ready;
29
+
30
+ static uint8_t xtime(uint8_t x) { return (uint8_t)((x << 1) ^ ((x >> 7) * 0x1b)); }
31
+ static uint32_t rotr(uint32_t x, int n) { return (x >> n) | (x << (32 - n)); }
32
+ static uint32_t rotl(uint32_t x, int n) { return (x << n) | (x >> (32 - n)); }
33
+ static uint32_t load_be32(const uint8_t *p) {
34
+ return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | p[3];
35
+ }
36
+ static void store_be32(uint8_t *p, uint32_t v) {
37
+ p[0] = (uint8_t)(v >> 24);
38
+ p[1] = (uint8_t)(v >> 16);
39
+ p[2] = (uint8_t)(v >> 8);
40
+ p[3] = (uint8_t)v;
41
+ }
42
+
43
+ static void init_tables(void) {
44
+ uint8_t p = 1, q = 1;
45
+ do {
46
+ p = (uint8_t)(p ^ (p << 1) ^ ((p & 0x80) ? 0x1b : 0));
47
+ q ^= (uint8_t)(q << 1);
48
+ q ^= (uint8_t)(q << 2);
49
+ q ^= (uint8_t)(q << 4);
50
+ q ^= (q & 0x80) ? 0x09 : 0;
51
+ uint8_t x = (uint8_t)(q ^ ((q << 1) | (q >> 7)) ^ ((q << 2) | (q >> 6)) ^ ((q << 3) | (q >> 5)) ^ ((q << 4) | (q >> 4)));
52
+ sbox[p] = (uint8_t)(x ^ 0x63);
53
+ } while (p != 1);
54
+ sbox[0] = 0x63;
55
+ for (int i = 0; i < 256; i++) {
56
+ uint8_t s = sbox[i], s2 = xtime(s), s3 = (uint8_t)(s2 ^ s);
57
+ uint32_t t = ((uint32_t)s2 << 24) | ((uint32_t)s << 16) | ((uint32_t)s << 8) | s3;
58
+ Te0[i] = t;
59
+ Te1[i] = rotr(t, 8);
60
+ Te2[i] = rotr(t, 16);
61
+ Te3[i] = rotr(t, 24);
62
+ }
63
+ tables_ready = 1;
64
+ }
65
+
66
+ static uint32_t sub_word(uint32_t w) {
67
+ return ((uint32_t)sbox[w >> 24] << 24) | ((uint32_t)sbox[(w >> 16) & 255] << 16) |
68
+ ((uint32_t)sbox[(w >> 8) & 255] << 8) | sbox[w & 255];
69
+ }
70
+
71
+ static void expand_key(struct aes_hmac_ctx *c, const uint8_t *key, unsigned key_length) {
72
+ int nk = (int)key_length / 4;
73
+ c->rounds = nk + 6;
74
+ int total = 4 * (c->rounds + 1);
75
+ uint8_t rcon = 1;
76
+ for (int i = 0; i < nk; i++) {
77
+ c->round_keys[i] = load_be32(key + 4 * i);
78
+ }
79
+ for (int i = nk; i < total; i++) {
80
+ uint32_t t = c->round_keys[i - 1];
81
+ if (i % nk == 0) {
82
+ t = sub_word(rotl(t, 8)) ^ ((uint32_t)rcon << 24);
83
+ rcon = xtime(rcon);
84
+ } else if (nk > 6 && i % nk == 4) {
85
+ t = sub_word(t);
86
+ }
87
+ c->round_keys[i] = c->round_keys[i - nk] ^ t;
88
+ }
89
+ }
90
+
91
+ static void encrypt_block(const struct aes_hmac_ctx *c, const uint8_t in[BLOCK_LENGTH], uint8_t out[BLOCK_LENGTH]) {
92
+ const uint32_t *rk = c->round_keys;
93
+ uint32_t s0 = load_be32(in) ^ rk[0], s1 = load_be32(in + 4) ^ rk[1];
94
+ uint32_t s2 = load_be32(in + 8) ^ rk[2], s3 = load_be32(in + 12) ^ rk[3];
95
+ uint32_t t0, t1, t2, t3;
96
+ rk += 4;
97
+ for (int r = 1; r < c->rounds; r++) {
98
+ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 255] ^ Te2[(s2 >> 8) & 255] ^ Te3[s3 & 255] ^ rk[0];
99
+ t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 255] ^ Te2[(s3 >> 8) & 255] ^ Te3[s0 & 255] ^ rk[1];
100
+ t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 255] ^ Te2[(s0 >> 8) & 255] ^ Te3[s1 & 255] ^ rk[2];
101
+ t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 255] ^ Te2[(s1 >> 8) & 255] ^ Te3[s2 & 255] ^ rk[3];
102
+ s0 = t0;
103
+ s1 = t1;
104
+ s2 = t2;
105
+ s3 = t3;
106
+ rk += 4;
107
+ }
108
+ store_be32(out, (((uint32_t)sbox[s0 >> 24] << 24) | ((uint32_t)sbox[(s1 >> 16) & 255] << 16) | ((uint32_t)sbox[(s2 >> 8) & 255] << 8) | sbox[s3 & 255]) ^ rk[0]);
109
+ store_be32(out + 4, (((uint32_t)sbox[s1 >> 24] << 24) | ((uint32_t)sbox[(s2 >> 16) & 255] << 16) | ((uint32_t)sbox[(s3 >> 8) & 255] << 8) | sbox[s0 & 255]) ^ rk[1]);
110
+ store_be32(out + 8, (((uint32_t)sbox[s2 >> 24] << 24) | ((uint32_t)sbox[(s3 >> 16) & 255] << 16) | ((uint32_t)sbox[(s0 >> 8) & 255] << 8) | sbox[s1 & 255]) ^ rk[2]);
111
+ store_be32(out + 12, (((uint32_t)sbox[s3 >> 24] << 24) | ((uint32_t)sbox[(s0 >> 16) & 255] << 16) | ((uint32_t)sbox[(s1 >> 8) & 255] << 8) | sbox[s2 & 255]) ^ rk[3]);
112
+ }
113
+
114
+ static void sha1_block(struct aes_hmac_ctx *c, const uint8_t *p) {
115
+ uint32_t w[80];
116
+ for (int i = 0; i < 16; i++) {
117
+ w[i] = load_be32(p + 4 * i);
118
+ }
119
+ for (int i = 16; i < 80; i++) {
120
+ w[i] = rotl(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);
121
+ }
122
+ uint32_t a = c->h[0], b = c->h[1], cc = c->h[2], d = c->h[3], e = c->h[4], t;
123
+ for (int i = 0; i < 20; i++) {
124
+ t = rotl(a, 5) + ((b & cc) | (~b & d)) + e + 0x5A827999 + w[i];
125
+ e = d;
126
+ d = cc;
127
+ cc = rotl(b, 30);
128
+ b = a;
129
+ a = t;
130
+ }
131
+ for (int i = 20; i < 40; i++) {
132
+ t = rotl(a, 5) + (b ^ cc ^ d) + e + 0x6ED9EBA1 + w[i];
133
+ e = d;
134
+ d = cc;
135
+ cc = rotl(b, 30);
136
+ b = a;
137
+ a = t;
138
+ }
139
+ for (int i = 40; i < 60; i++) {
140
+ t = rotl(a, 5) + ((b & cc) | (b & d) | (cc & d)) + e + 0x8F1BBCDC + w[i];
141
+ e = d;
142
+ d = cc;
143
+ cc = rotl(b, 30);
144
+ b = a;
145
+ a = t;
146
+ }
147
+ for (int i = 60; i < 80; i++) {
148
+ t = rotl(a, 5) + (b ^ cc ^ d) + e + 0xCA62C1D6 + w[i];
149
+ e = d;
150
+ d = cc;
151
+ cc = rotl(b, 30);
152
+ b = a;
153
+ a = t;
154
+ }
155
+ c->h[0] += a;
156
+ c->h[1] += b;
157
+ c->h[2] += cc;
158
+ c->h[3] += d;
159
+ c->h[4] += e;
160
+ }
161
+
162
+ static void sha1_init(struct aes_hmac_ctx *c) {
163
+ c->h[0] = 0x67452301;
164
+ c->h[1] = 0xEFCDAB89;
165
+ c->h[2] = 0x98BADCFE;
166
+ c->h[3] = 0x10325476;
167
+ c->h[4] = 0xC3D2E1F0;
168
+ c->block_length = 0;
169
+ c->total_length = 0;
170
+ }
171
+
172
+ static void sha1_update(struct aes_hmac_ctx *c, const uint8_t *p, unsigned length) {
173
+ c->total_length += length;
174
+ if (c->block_length) {
175
+ unsigned n = SHA1_BLOCK_LENGTH - c->block_length;
176
+ if (n > length) {
177
+ n = length;
178
+ }
179
+ memcpy(c->block + c->block_length, p, n);
180
+ c->block_length += n;
181
+ p += n;
182
+ length -= n;
183
+ if (c->block_length == SHA1_BLOCK_LENGTH) {
184
+ sha1_block(c, c->block);
185
+ c->block_length = 0;
186
+ }
187
+ }
188
+ while (length >= SHA1_BLOCK_LENGTH) {
189
+ sha1_block(c, p);
190
+ p += SHA1_BLOCK_LENGTH;
191
+ length -= SHA1_BLOCK_LENGTH;
192
+ }
193
+ if (length) {
194
+ memcpy(c->block, p, length);
195
+ c->block_length = length;
196
+ }
197
+ }
198
+
199
+ static void sha1_final(struct aes_hmac_ctx *c, uint8_t out[SHA1_DIGEST_LENGTH]) {
200
+ uint64_t bits = c->total_length * 8;
201
+ uint8_t padding[SHA1_BLOCK_LENGTH + 8] = { 0x80 };
202
+ unsigned padding_length = (c->block_length < 56 ? 56 : 120) - c->block_length;
203
+ for (int i = 0; i < 8; i++) {
204
+ padding[padding_length + i] = (uint8_t)(bits >> (56 - 8 * i));
205
+ }
206
+ sha1_update(c, padding, padding_length + 8);
207
+ for (int i = 0; i < 5; i++) {
208
+ store_be32(out + 4 * i, c->h[i]);
209
+ }
210
+ }
211
+
212
+ static void hmac_init(struct aes_hmac_ctx *c, const uint8_t *key, unsigned length) {
213
+ uint8_t ipad[SHA1_BLOCK_LENGTH], hashed_key[SHA1_DIGEST_LENGTH];
214
+ if (length > SHA1_BLOCK_LENGTH) {
215
+ sha1_init(c);
216
+ sha1_update(c, key, length);
217
+ sha1_final(c, hashed_key);
218
+ key = hashed_key;
219
+ length = SHA1_DIGEST_LENGTH;
220
+ }
221
+ for (unsigned i = 0; i < SHA1_BLOCK_LENGTH; i++) {
222
+ uint8_t k = i < length ? key[i] : 0;
223
+ ipad[i] = (uint8_t)(k ^ 0x36);
224
+ c->opad[i] = (uint8_t)(k ^ 0x5c);
225
+ }
226
+ sha1_init(c);
227
+ sha1_update(c, ipad, SHA1_BLOCK_LENGTH);
228
+ }
229
+
230
+ static void hmac_final(struct aes_hmac_ctx *c, uint8_t out[SHA1_DIGEST_LENGTH]) {
231
+ uint8_t inner[SHA1_DIGEST_LENGTH];
232
+ sha1_final(c, inner);
233
+ sha1_init(c);
234
+ sha1_update(c, c->opad, SHA1_BLOCK_LENGTH);
235
+ sha1_update(c, inner, SHA1_DIGEST_LENGTH);
236
+ sha1_final(c, out);
237
+ }
238
+
239
+ unsigned aes_hmac_new(void) {
240
+ struct aes_hmac_ctx *c = (struct aes_hmac_ctx *)malloc(sizeof(*c));
241
+ if (!c) {
242
+ return 0;
243
+ }
244
+ memset(c, 0, sizeof(*c));
245
+ return (unsigned)(uintptr_t)c;
246
+ }
247
+
248
+ int aes_hmac_init(unsigned ctx, unsigned key_ptr, unsigned key_length, unsigned auth_ptr, unsigned auth_length) {
249
+ struct aes_hmac_ctx *c = (struct aes_hmac_ctx *)(uintptr_t)ctx;
250
+ if (!c || (key_length != 16 && key_length != 24 && key_length != 32)) {
251
+ return -1;
252
+ }
253
+ if (!tables_ready) {
254
+ init_tables();
255
+ }
256
+ expand_key(c, (const uint8_t *)(uintptr_t)key_ptr, key_length);
257
+ memset(c->counter, 0, BLOCK_LENGTH);
258
+ hmac_init(c, (const uint8_t *)(uintptr_t)auth_ptr, auth_length);
259
+ return 0;
260
+ }
261
+
262
+ void aes_hmac_process(unsigned ctx, unsigned ptr, unsigned length, int decrypt) {
263
+ struct aes_hmac_ctx *c = (struct aes_hmac_ctx *)(uintptr_t)ctx;
264
+ uint8_t *p = (uint8_t *)(uintptr_t)ptr;
265
+ uint32_t keystream[4], words[4];
266
+ if (!c) {
267
+ return;
268
+ }
269
+ if (decrypt) {
270
+ sha1_update(c, p, length);
271
+ }
272
+ for (unsigned i = 0; i < length; i += BLOCK_LENGTH) {
273
+ for (int j = 0; j < BLOCK_LENGTH; j++) {
274
+ if (++c->counter[j]) {
275
+ break;
276
+ }
277
+ }
278
+ encrypt_block(c, c->counter, (uint8_t *)keystream);
279
+ if (length - i >= BLOCK_LENGTH) {
280
+ memcpy(words, p + i, BLOCK_LENGTH);
281
+ words[0] ^= keystream[0];
282
+ words[1] ^= keystream[1];
283
+ words[2] ^= keystream[2];
284
+ words[3] ^= keystream[3];
285
+ memcpy(p + i, words, BLOCK_LENGTH);
286
+ } else {
287
+ const uint8_t *k = (const uint8_t *)keystream;
288
+ for (unsigned j = 0; j < length - i; j++) {
289
+ p[i + j] ^= k[j];
290
+ }
291
+ }
292
+ }
293
+ if (!decrypt) {
294
+ sha1_update(c, p, length);
295
+ }
296
+ }
297
+
298
+ void aes_hmac_end(unsigned ctx, unsigned out_ptr) {
299
+ struct aes_hmac_ctx *c = (struct aes_hmac_ctx *)(uintptr_t)ctx;
300
+ if (!c) {
301
+ return;
302
+ }
303
+ if (out_ptr) {
304
+ hmac_final(c, (uint8_t *)(uintptr_t)out_ptr);
305
+ }
306
+ free(c);
307
+ }
@@ -138,18 +138,17 @@ function _make(isCompress, type, options = {}) {
138
138
  }
139
139
  heap.set(buffer.subarray(offset, offset + toRead), this.in);
140
140
  const result = process(this.streamHandle, this.in, toRead, out, outBufferSize, 0);
141
+ // checked before the byte count is used, so a status code can never be read as one
142
+ const code = (result >> 24) & 0xff;
143
+ const signedCode = (code & 0x80) ? code - 256 : code;
144
+ if (signedCode < 0) {
145
+ throw new Error("process error:" + signedCode);
146
+ }
141
147
  const prod = result & 0x00ffffff;
142
148
  if (prod) {
143
149
  scratch.set(heap.subarray(out, out + prod), 0);
144
150
  controller.enqueue(scratch.slice(0, prod));
145
151
  }
146
- if (!isCompress) {
147
- const code = (result >> 24) & 0xff;
148
- const signedCode = (code & 0x80) ? code - 256 : code;
149
- if (signedCode < 0) {
150
- throw new Error("process error:" + signedCode);
151
- }
152
- }
153
152
  const consumed = last_consumed(this.streamHandle);
154
153
  if (consumed === 0 && prod === 0) {
155
154
  break;
@@ -169,14 +168,12 @@ function _make(isCompress, type, options = {}) {
169
168
  const scratch = this._scratch;
170
169
  while (true) {
171
170
  const result = process(this.streamHandle, 0, 0, out, outBufferSize, 4);
172
- const produced = result & 0x00ffffff;
173
171
  const code = (result >> 24) & 0xff;
174
- if (!isCompress) {
175
- const signedCode = (code & 0x80) ? code - 256 : code;
176
- if (signedCode < 0) {
177
- throw new Error("process error:" + signedCode);
178
- }
172
+ const signedCode = (code & 0x80) ? code - 256 : code;
173
+ if (signedCode < 0) {
174
+ throw new Error("process error:" + signedCode);
179
175
  }
176
+ const produced = result & 0x00ffffff;
180
177
  if (produced) {
181
178
  scratch.set(heap.subarray(out, out + produced), 0);
182
179
  controller.enqueue(scratch.slice(0, produced));
@@ -34,17 +34,22 @@ unsigned wasm_stream_last_consumed(unsigned zptr) {
34
34
  return c->last_consumed;
35
35
  }
36
36
 
37
+ /* the process functions pack the produced byte count and the zlib status code into one int, so
38
+ every return path has to use this shape: a bare negative code decodes as a huge byte count */
39
+ #define WASM_STREAM_RESULT(produced, code) \
40
+ (((produced) & 0x00ffffff) | (((code) & 0xff) << 24))
41
+
37
42
  int wasm_stream_process_common(unsigned zptr, unsigned in_ptr, unsigned in_len,
38
43
  unsigned out_ptr, unsigned out_len, int flush,
39
44
  int (*process_func)(z_streamp, int)) {
40
45
  struct wasm_stream_ctx *c = (struct wasm_stream_ctx *)(uintptr_t)zptr;
41
46
  if (!c)
42
- return Z_STREAM_ERROR;
47
+ return WASM_STREAM_RESULT(0, Z_STREAM_ERROR);
43
48
 
44
49
  if (in_len > c->inbuf_sz) {
45
50
  unsigned char *nb = (unsigned char *)realloc(c->inbuf, in_len);
46
51
  if (!nb)
47
- return Z_MEM_ERROR;
52
+ return WASM_STREAM_RESULT(0, Z_MEM_ERROR);
48
53
  c->inbuf = nb;
49
54
  c->inbuf_sz = in_len;
50
55
  }
@@ -58,6 +63,5 @@ int wasm_stream_process_common(unsigned zptr, unsigned in_ptr, unsigned in_len,
58
63
  int ret = process_func(&c->strm, flush);
59
64
  int produced = (int)(out_len - c->strm.avail_out);
60
65
  c->last_consumed = (unsigned)(in_len - c->strm.avail_in);
61
- int code = ret & 0xff;
62
- return (produced & 0x00ffffff) | ((code & 0xff) << 24);
66
+ return WASM_STREAM_RESULT(produced, ret);
63
67
  }