zlib-streams 1.1.1 → 1.2.1

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/LICENSE ADDED
@@ -0,0 +1,91 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2025-2026, Gildas Lormeau
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+
30
+ ---
31
+
32
+ This software includes zlib (src/zlib) and altered versions of zlib sources
33
+ (src/deflate.c, src/deflate.h, src/inflate.c, src/inflate.h, src/inftrees.c,
34
+ src/inffast.h, src/trees.c, with deflate64 support added), which are
35
+ distributed under the zlib license:
36
+
37
+ Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler
38
+
39
+ This software is provided 'as-is', without any express or implied
40
+ warranty. In no event will the authors be held liable for any damages
41
+ arising from the use of this software.
42
+
43
+ Permission is granted to anyone to use this software for any purpose,
44
+ including commercial applications, and to alter it and redistribute it
45
+ freely, subject to the following restrictions:
46
+
47
+ 1. The origin of this software must not be misrepresented; you must not
48
+ claim that you wrote the original software. If you use this software
49
+ in a product, an acknowledgment in the product documentation would be
50
+ appreciated but is not required.
51
+ 2. Altered source versions must be plainly marked as such, and must not be
52
+ misrepresented as being the original software.
53
+ 3. This notice may not be removed or altered from any source distribution.
54
+
55
+ Jean-loup Gailly Mark Adler
56
+ jloup@gzip.org madler@alumni.caltech.edu
57
+
58
+ ---
59
+
60
+ src/chunkcopy.h, src/compare256.h, src/cpu_features.h, src/inffast_chunk.c,
61
+ src/inffast_chunk.h and src/insert_string.h come from the zlib fork of the
62
+ Chromium project (Copyright 2017 ARM, Inc. for the chunk copy code), and are
63
+ distributed under the Chromium license:
64
+
65
+ Copyright 2015 The Chromium Authors
66
+
67
+ Redistribution and use in source and binary forms, with or without
68
+ modification, are permitted provided that the following conditions are
69
+ met:
70
+
71
+ * Redistributions of source code must retain the above copyright
72
+ notice, this list of conditions and the following disclaimer.
73
+ * Redistributions in binary form must reproduce the above
74
+ copyright notice, this list of conditions and the following disclaimer
75
+ in the documentation and/or other materials provided with the
76
+ distribution.
77
+ * Neither the name of Google LLC nor the names of its
78
+ contributors may be used to endorse or promote products derived from
79
+ this software without specific prior written permission.
80
+
81
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
82
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
83
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
84
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
85
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
86
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
87
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
88
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
89
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
90
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
91
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/Makefile CHANGED
@@ -148,10 +148,12 @@ 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
154
- wasm: dist/zlib-streams-dev.wasm
155
+ wasm:
156
+ @$(MAKE) -B dist/zlib-streams-dev.wasm
155
157
 
156
158
  .PHONY: wasm_traced
157
159
  wasm_traced: dist/zlib-streams_traced.wasm
@@ -160,7 +162,7 @@ dist/zlib-streams_traced.wasm: $(WASM_SRCS)
160
162
  @echo "Building traced $@ using $(EMCC)"
161
163
  @mkdir -p dist
162
164
  $(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"]' \
165
+ -s EXPORTED_FUNCTIONS='[$(WASM_EXPORTED_FUNCTIONS)]' \
164
166
  -o $@
165
167
 
166
168
  # Run reference C and WASM test suites over payloads in test/ref-data
@@ -300,24 +302,50 @@ dist/zlib-streams-dev.wasm: $(WASM_SRCS)
300
302
  @echo "Building $@ using $(EMCC)"
301
303
  @mkdir -p dist
302
304
  $(EMCC) $(WASM_SRCS) $(WASM_CFLAGS) -s WASM=1 -s STANDALONE_WASM=1 --no-entry \
303
- -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"]' \
305
+ -s EXPORTED_FUNCTIONS='[$(WASM_EXPORTED_FUNCTIONS)]' \
304
306
  -o $@
305
307
  cp src/wasm/api/zlib-streams.js dist/zlib-streams.js
306
308
 
307
309
  # Production-optimized wasm: smaller build with -Oz and no extra runtime methods.
308
310
  .PHONY: wasm_prod
309
- wasm_prod: dist/zlib-streams.wasm
311
+ wasm_prod:
312
+ @$(MAKE) -B dist/zlib-streams.wasm
310
313
 
311
314
  dist/zlib-streams.wasm: $(WASM_SRCS)
312
315
  @echo "Building production wasm $@ using $(EMCC)"
313
316
  @mkdir -p dist
314
317
  $(EMCC) $(WASM_SRCS) $(WASM_CFLAGS) -Oz -flto -s WASM=1 -s STANDALONE_WASM=1 --no-entry \
315
318
  -s FILESYSTEM=0 -s DISABLE_EXCEPTION_CATCHING=1 \
316
- -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"]' \
319
+ -s EXPORTED_FUNCTIONS='[$(WASM_EXPORTED_FUNCTIONS)]' \
317
320
  -o $@
318
321
  cp src/wasm/api/zlib-streams.js dist/zlib-streams.js
319
322
  @test -x $(WASM_OPT) && { echo "Running wasm-opt -Oz --enable-bulk-memory-opt"; $(WASM_OPT) -Oz --enable-bulk-memory-opt -o $@ $@ || true; } || true
320
323
 
324
+ # -----------------------------------------------------------------------------
325
+ # zip.js module: the zlib codecs plus the AES-CTR/HMAC-SHA1 engine behind its
326
+ # encrypted entries (src/wasm/aes_hmac_wasm.c), vendored by zip.js as
327
+ # lib/core/streams/zlib-wasm/zlib-streams.wasm
328
+ # -----------------------------------------------------------------------------
329
+ ZIP_MODULE_SRCS = src/wasm/aes_hmac_wasm.c
330
+ ZIP_MODULE_EXPORTED_FUNCTIONS = $(WASM_EXPORTED_FUNCTIONS),"_aes_hmac_new","_aes_hmac_init","_aes_hmac_process","_aes_hmac_end"
331
+
332
+ .PHONY: zip_module
333
+ zip_module:
334
+ @$(MAKE) -B dist/zip-module.wasm
335
+
336
+ dist/zip-module.wasm: $(WASM_SRCS) $(ZIP_MODULE_SRCS)
337
+ @echo "Building zip.js module $@ using $(EMCC)"
338
+ @mkdir -p dist
339
+ $(EMCC) $(WASM_SRCS) $(ZIP_MODULE_SRCS) $(WASM_CFLAGS) -Oz -flto -s WASM=1 -s STANDALONE_WASM=1 --no-entry \
340
+ -s FILESYSTEM=0 -s DISABLE_EXCEPTION_CATCHING=1 \
341
+ -s EXPORTED_FUNCTIONS='[$(ZIP_MODULE_EXPORTED_FUNCTIONS)]' \
342
+ -o $@
343
+ @test -x $(WASM_OPT) && { echo "Running wasm-opt -Oz --enable-bulk-memory-opt"; $(WASM_OPT) -Oz --enable-bulk-memory-opt -o $@ $@ || true; } || true
344
+
345
+ .PHONY: test_zip_module
346
+ test_zip_module: dist/zip-module.wasm
347
+ @node src/wasm/tests/test_aes_hmac.js dist/zip-module.wasm
348
+
321
349
  # -----------------------------------------------------------------------------
322
350
  # Optional generator: build a C++ tool that creates Deflate64 ZIPs using the
323
351
  # 7-Zip SDK. This target is guarded: it only compiles when the SDK is present
package/README.md CHANGED
@@ -19,17 +19,28 @@ git submodule update --init --recursive
19
19
  ```
20
20
 
21
21
  ### 2. Build WASM module
22
- - Developmeent
22
+ The build needs the Emscripten SDK. The Makefile looks for it in `emsdk/` at the repository root (ignored by git) and can be pointed elsewhere with `make EMCC=... WASM_OPT=...`.
23
+
24
+ - Development: `-O2`, used by the test targets. Do not benchmark or ship this file.
23
25
  ```sh
24
26
  make wasm
25
27
  ```
26
28
  Output: `dist/zlib-streams-dev.wasm` and `dist/zlib-streams.js`
27
29
 
28
- - Production
30
+ - Production: `-Oz` plus `wasm-opt`. This is the published module.
29
31
  ```sh
30
32
  make wasm_prod
31
33
  ```
32
34
  Output: `dist/zlib-streams.wasm` and `dist/zlib-streams.js`
33
35
 
36
+ - zip.js module: the codecs plus the AES-CTR/HMAC-SHA1 engine behind the encrypted entries of zip.js, vendored by zip.js as `lib/core/streams/zlib-wasm/zlib-streams.wasm`.
37
+ ```sh
38
+ make zip_module
39
+ make test_zip_module
40
+ ```
41
+ Output: `dist/zip-module.wasm`
42
+
43
+ The files in `dist/` are tracked, so a checkout leaves them with the same timestamp as the sources and `make dist/<file>` reports them up to date even when the sources changed. The three targets above always rebuild their file; the test targets depend on the file rules and rebuild only when a source is newer. Rebuild and commit `dist/` in the same commit as a change to `src/`.
44
+
34
45
  ## License
35
46
  See LICENSE for details.
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.1",
6
+ "version": "1.2.1",
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,377 @@
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, clears sensitive state, and
6
+ frees the context. */
7
+ #include <stdlib.h>
8
+ #include <string.h>
9
+ #include <stdint.h>
10
+
11
+ #define BLOCK_LENGTH 16
12
+ #define SHA1_BLOCK_LENGTH 64
13
+ #define SHA1_DIGEST_LENGTH 20
14
+ #define ROUND_KEYS_LENGTH 60
15
+
16
+ struct aes_hmac_ctx {
17
+ uint32_t round_keys[ROUND_KEYS_LENGTH];
18
+ int rounds;
19
+ /* 64-bit WinZip counter followed by eight zero bytes; wasm32 is little-endian. */
20
+ uint64_t counter[2];
21
+ uint32_t sha1_state[5];
22
+ uint64_t sha1_count;
23
+ uint8_t sha1_buffer[SHA1_BLOCK_LENGTH];
24
+ uint8_t opad[SHA1_BLOCK_LENGTH];
25
+ };
26
+
27
+ static uint32_t Te0[256], Te1[256], Te2[256], Te3[256];
28
+ static uint8_t sbox[256];
29
+ static int tables_ready;
30
+
31
+ static uint8_t xtime(uint8_t x) { return (uint8_t)((x << 1) ^ ((x >> 7) * 0x1b)); }
32
+ static uint32_t rotr(uint32_t x, int n) { return (x >> n) | (x << (32 - n)); }
33
+ static uint32_t rotl(uint32_t x, int n) { return (x << n) | (x >> (32 - n)); }
34
+ static uint32_t load_be32(const uint8_t *p) {
35
+ return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | p[3];
36
+ }
37
+ static void store_be32(uint8_t *p, uint32_t v) {
38
+ p[0] = (uint8_t)(v >> 24);
39
+ p[1] = (uint8_t)(v >> 16);
40
+ p[2] = (uint8_t)(v >> 8);
41
+ p[3] = (uint8_t)v;
42
+ }
43
+
44
+ /* Volatile stores keep LTO from removing the wipe before free(). */
45
+ __attribute__((noinline, minsize))
46
+ static void secure_clear(void *ptr, size_t length) {
47
+ volatile uint8_t *p = (volatile uint8_t *)ptr;
48
+ while (length--) {
49
+ *p++ = 0;
50
+ }
51
+ }
52
+
53
+ static void init_tables(void) {
54
+ uint8_t p = 1, q = 1;
55
+ do {
56
+ p = (uint8_t)(p ^ (p << 1) ^ ((p & 0x80) ? 0x1b : 0));
57
+ q ^= (uint8_t)(q << 1);
58
+ q ^= (uint8_t)(q << 2);
59
+ q ^= (uint8_t)(q << 4);
60
+ q ^= (q & 0x80) ? 0x09 : 0;
61
+ uint8_t x = (uint8_t)(q ^ ((q << 1) | (q >> 7)) ^ ((q << 2) | (q >> 6)) ^ ((q << 3) | (q >> 5)) ^ ((q << 4) | (q >> 4)));
62
+ sbox[p] = (uint8_t)(x ^ 0x63);
63
+ } while (p != 1);
64
+ sbox[0] = 0x63;
65
+ for (int i = 0; i < 256; i++) {
66
+ uint8_t s = sbox[i], s2 = xtime(s), s3 = (uint8_t)(s2 ^ s);
67
+ uint32_t t = ((uint32_t)s2 << 24) | ((uint32_t)s << 16) | ((uint32_t)s << 8) | s3;
68
+ Te0[i] = t;
69
+ Te1[i] = rotr(t, 8);
70
+ Te2[i] = rotr(t, 16);
71
+ Te3[i] = rotr(t, 24);
72
+ }
73
+ tables_ready = 1;
74
+ }
75
+
76
+ static uint32_t sub_word(uint32_t w) {
77
+ return ((uint32_t)sbox[w >> 24] << 24) | ((uint32_t)sbox[(w >> 16) & 255] << 16) |
78
+ ((uint32_t)sbox[(w >> 8) & 255] << 8) | sbox[w & 255];
79
+ }
80
+
81
+ static void expand_key(struct aes_hmac_ctx *c, const uint8_t *key, unsigned key_length) {
82
+ int nk = (int)key_length / 4;
83
+ c->rounds = nk + 6;
84
+ int total = 4 * (c->rounds + 1);
85
+ uint8_t rcon = 1;
86
+ for (int i = 0; i < nk; i++) {
87
+ c->round_keys[i] = load_be32(key + 4 * i);
88
+ }
89
+ for (int i = nk; i < total; i++) {
90
+ uint32_t t = c->round_keys[i - 1];
91
+ if (i % nk == 0) {
92
+ t = sub_word(rotl(t, 8)) ^ ((uint32_t)rcon << 24);
93
+ rcon = xtime(rcon);
94
+ } else if (nk > 6 && i % nk == 4) {
95
+ t = sub_word(t);
96
+ }
97
+ c->round_keys[i] = c->round_keys[i - nk] ^ t;
98
+ }
99
+ }
100
+
101
+ static void encrypt_block(const struct aes_hmac_ctx *c, const uint8_t in[BLOCK_LENGTH], uint8_t out[BLOCK_LENGTH]) {
102
+ const uint32_t *rk = c->round_keys;
103
+ uint32_t s0 = load_be32(in) ^ rk[0], s1 = load_be32(in + 4) ^ rk[1];
104
+ uint32_t s2 = load_be32(in + 8) ^ rk[2], s3 = load_be32(in + 12) ^ rk[3];
105
+ uint32_t t0, t1, t2, t3;
106
+ #define AES_ROUND(O0, O1, O2, O3, I0, I1, I2, I3, K) do { \
107
+ (O0) = Te0[(I0) >> 24] ^ Te1[((I1) >> 16) & 255] ^ Te2[((I2) >> 8) & 255] ^ Te3[(I3) & 255] ^ (K)[0]; \
108
+ (O1) = Te0[(I1) >> 24] ^ Te1[((I2) >> 16) & 255] ^ Te2[((I3) >> 8) & 255] ^ Te3[(I0) & 255] ^ (K)[1]; \
109
+ (O2) = Te0[(I2) >> 24] ^ Te1[((I3) >> 16) & 255] ^ Te2[((I0) >> 8) & 255] ^ Te3[(I1) & 255] ^ (K)[2]; \
110
+ (O3) = Te0[(I3) >> 24] ^ Te1[((I0) >> 16) & 255] ^ Te2[((I1) >> 8) & 255] ^ Te3[(I2) & 255] ^ (K)[3]; \
111
+ } while (0)
112
+ AES_ROUND(t0, t1, t2, t3, s0, s1, s2, s3, rk + 4);
113
+ AES_ROUND(s0, s1, s2, s3, t0, t1, t2, t3, rk + 8);
114
+ AES_ROUND(t0, t1, t2, t3, s0, s1, s2, s3, rk + 12);
115
+ AES_ROUND(s0, s1, s2, s3, t0, t1, t2, t3, rk + 16);
116
+ AES_ROUND(t0, t1, t2, t3, s0, s1, s2, s3, rk + 20);
117
+ AES_ROUND(s0, s1, s2, s3, t0, t1, t2, t3, rk + 24);
118
+ AES_ROUND(t0, t1, t2, t3, s0, s1, s2, s3, rk + 28);
119
+ AES_ROUND(s0, s1, s2, s3, t0, t1, t2, t3, rk + 32);
120
+ AES_ROUND(t0, t1, t2, t3, s0, s1, s2, s3, rk + 36);
121
+ rk += 40;
122
+ if (c->rounds > 10) {
123
+ AES_ROUND(s0, s1, s2, s3, t0, t1, t2, t3, rk);
124
+ AES_ROUND(t0, t1, t2, t3, s0, s1, s2, s3, rk + 4);
125
+ rk += 8;
126
+ }
127
+ if (c->rounds > 12) {
128
+ AES_ROUND(s0, s1, s2, s3, t0, t1, t2, t3, rk);
129
+ AES_ROUND(t0, t1, t2, t3, s0, s1, s2, s3, rk + 4);
130
+ rk += 8;
131
+ }
132
+ #undef AES_ROUND
133
+ store_be32(out, (Te2[t0 >> 24] & 0xff000000) ^ (Te3[(t1 >> 16) & 255] & 0x00ff0000) ^
134
+ (Te0[(t2 >> 8) & 255] & 0x0000ff00) ^ (Te1[t3 & 255] & 0x000000ff) ^ rk[0]);
135
+ store_be32(out + 4, (Te2[t1 >> 24] & 0xff000000) ^ (Te3[(t2 >> 16) & 255] & 0x00ff0000) ^
136
+ (Te0[(t3 >> 8) & 255] & 0x0000ff00) ^ (Te1[t0 & 255] & 0x000000ff) ^ rk[1]);
137
+ store_be32(out + 8, (Te2[t2 >> 24] & 0xff000000) ^ (Te3[(t3 >> 16) & 255] & 0x00ff0000) ^
138
+ (Te0[(t0 >> 8) & 255] & 0x0000ff00) ^ (Te1[t1 & 255] & 0x000000ff) ^ rk[2]);
139
+ store_be32(out + 12, (Te2[t3 >> 24] & 0xff000000) ^ (Te3[(t0 >> 16) & 255] & 0x00ff0000) ^
140
+ (Te0[(t1 >> 8) & 255] & 0x0000ff00) ^ (Te1[t2 & 255] & 0x000000ff) ^ rk[3]);
141
+ }
142
+
143
+ /*
144
+ * SHA-1 in C
145
+ * By Steve Reid <steve@edmweb.com>
146
+ * 100% Public Domain
147
+ *
148
+ * Adapted from OpenSSH portable's openbsd-compat/sha1.c for this combined
149
+ * AES/HMAC context and the little-endian wasm32 target.
150
+ */
151
+ typedef union {
152
+ uint8_t c[SHA1_BLOCK_LENGTH];
153
+ uint32_t l[SHA1_BLOCK_LENGTH / sizeof(uint32_t)];
154
+ } sha1_block;
155
+
156
+ #define SHA1_ROL(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
157
+ /* wasm32 is little-endian, so the first 16 words need byte swapping. */
158
+ #define SHA1_BLK0(block, i) ((block).l[i] = \
159
+ (SHA1_ROL((block).l[i], 24) & 0xFF00FF00) | \
160
+ (SHA1_ROL((block).l[i], 8) & 0x00FF00FF))
161
+ #define SHA1_BLK(block, i) ((block).l[(i) & 15] = SHA1_ROL( \
162
+ (block).l[((i) + 13) & 15] ^ (block).l[((i) + 8) & 15] ^ \
163
+ (block).l[((i) + 2) & 15] ^ (block).l[(i) & 15], 1))
164
+ #define SHA1_R0(block, v, w, x, y, z, i) do { \
165
+ (z) += (((w) & ((x) ^ (y))) ^ (y)) + SHA1_BLK0((block), (i)) + \
166
+ 0x5A827999 + SHA1_ROL((v), 5); \
167
+ (w) = SHA1_ROL((w), 30); \
168
+ } while (0)
169
+ #define SHA1_R1(block, v, w, x, y, z, i) do { \
170
+ (z) += (((w) & ((x) ^ (y))) ^ (y)) + SHA1_BLK((block), (i)) + \
171
+ 0x5A827999 + SHA1_ROL((v), 5); \
172
+ (w) = SHA1_ROL((w), 30); \
173
+ } while (0)
174
+ #define SHA1_R2(block, v, w, x, y, z, i) do { \
175
+ (z) += ((w) ^ (x) ^ (y)) + SHA1_BLK((block), (i)) + \
176
+ 0x6ED9EBA1 + SHA1_ROL((v), 5); \
177
+ (w) = SHA1_ROL((w), 30); \
178
+ } while (0)
179
+ #define SHA1_R3(block, v, w, x, y, z, i) do { \
180
+ (z) += ((((w) | (x)) & (y)) | ((w) & (x))) + SHA1_BLK((block), (i)) + \
181
+ 0x8F1BBCDC + SHA1_ROL((v), 5); \
182
+ (w) = SHA1_ROL((w), 30); \
183
+ } while (0)
184
+ #define SHA1_R4(block, v, w, x, y, z, i) do { \
185
+ (z) += ((w) ^ (x) ^ (y)) + SHA1_BLK((block), (i)) + \
186
+ 0xCA62C1D6 + SHA1_ROL((v), 5); \
187
+ (w) = SHA1_ROL((w), 30); \
188
+ } while (0)
189
+
190
+ static void sha1_transform(uint32_t state[5], const uint8_t buffer[SHA1_BLOCK_LENGTH]) {
191
+ uint32_t a, b, c, d, e;
192
+ sha1_block block;
193
+
194
+ memcpy(&block, buffer, sizeof(block));
195
+ a = state[0];
196
+ b = state[1];
197
+ c = state[2];
198
+ d = state[3];
199
+ e = state[4];
200
+
201
+ SHA1_R0(block,a,b,c,d,e, 0); SHA1_R0(block,e,a,b,c,d, 1); SHA1_R0(block,d,e,a,b,c, 2); SHA1_R0(block,c,d,e,a,b, 3);
202
+ SHA1_R0(block,b,c,d,e,a, 4); SHA1_R0(block,a,b,c,d,e, 5); SHA1_R0(block,e,a,b,c,d, 6); SHA1_R0(block,d,e,a,b,c, 7);
203
+ SHA1_R0(block,c,d,e,a,b, 8); SHA1_R0(block,b,c,d,e,a, 9); SHA1_R0(block,a,b,c,d,e,10); SHA1_R0(block,e,a,b,c,d,11);
204
+ SHA1_R0(block,d,e,a,b,c,12); SHA1_R0(block,c,d,e,a,b,13); SHA1_R0(block,b,c,d,e,a,14); SHA1_R0(block,a,b,c,d,e,15);
205
+ SHA1_R1(block,e,a,b,c,d,16); SHA1_R1(block,d,e,a,b,c,17); SHA1_R1(block,c,d,e,a,b,18); SHA1_R1(block,b,c,d,e,a,19);
206
+ SHA1_R2(block,a,b,c,d,e,20); SHA1_R2(block,e,a,b,c,d,21); SHA1_R2(block,d,e,a,b,c,22); SHA1_R2(block,c,d,e,a,b,23);
207
+ SHA1_R2(block,b,c,d,e,a,24); SHA1_R2(block,a,b,c,d,e,25); SHA1_R2(block,e,a,b,c,d,26); SHA1_R2(block,d,e,a,b,c,27);
208
+ SHA1_R2(block,c,d,e,a,b,28); SHA1_R2(block,b,c,d,e,a,29); SHA1_R2(block,a,b,c,d,e,30); SHA1_R2(block,e,a,b,c,d,31);
209
+ SHA1_R2(block,d,e,a,b,c,32); SHA1_R2(block,c,d,e,a,b,33); SHA1_R2(block,b,c,d,e,a,34); SHA1_R2(block,a,b,c,d,e,35);
210
+ SHA1_R2(block,e,a,b,c,d,36); SHA1_R2(block,d,e,a,b,c,37); SHA1_R2(block,c,d,e,a,b,38); SHA1_R2(block,b,c,d,e,a,39);
211
+ SHA1_R3(block,a,b,c,d,e,40); SHA1_R3(block,e,a,b,c,d,41); SHA1_R3(block,d,e,a,b,c,42); SHA1_R3(block,c,d,e,a,b,43);
212
+ SHA1_R3(block,b,c,d,e,a,44); SHA1_R3(block,a,b,c,d,e,45); SHA1_R3(block,e,a,b,c,d,46); SHA1_R3(block,d,e,a,b,c,47);
213
+ SHA1_R3(block,c,d,e,a,b,48); SHA1_R3(block,b,c,d,e,a,49); SHA1_R3(block,a,b,c,d,e,50); SHA1_R3(block,e,a,b,c,d,51);
214
+ SHA1_R3(block,d,e,a,b,c,52); SHA1_R3(block,c,d,e,a,b,53); SHA1_R3(block,b,c,d,e,a,54); SHA1_R3(block,a,b,c,d,e,55);
215
+ SHA1_R3(block,e,a,b,c,d,56); SHA1_R3(block,d,e,a,b,c,57); SHA1_R3(block,c,d,e,a,b,58); SHA1_R3(block,b,c,d,e,a,59);
216
+ SHA1_R4(block,a,b,c,d,e,60); SHA1_R4(block,e,a,b,c,d,61); SHA1_R4(block,d,e,a,b,c,62); SHA1_R4(block,c,d,e,a,b,63);
217
+ SHA1_R4(block,b,c,d,e,a,64); SHA1_R4(block,a,b,c,d,e,65); SHA1_R4(block,e,a,b,c,d,66); SHA1_R4(block,d,e,a,b,c,67);
218
+ SHA1_R4(block,c,d,e,a,b,68); SHA1_R4(block,b,c,d,e,a,69); SHA1_R4(block,a,b,c,d,e,70); SHA1_R4(block,e,a,b,c,d,71);
219
+ SHA1_R4(block,d,e,a,b,c,72); SHA1_R4(block,c,d,e,a,b,73); SHA1_R4(block,b,c,d,e,a,74); SHA1_R4(block,a,b,c,d,e,75);
220
+ SHA1_R4(block,e,a,b,c,d,76); SHA1_R4(block,d,e,a,b,c,77); SHA1_R4(block,c,d,e,a,b,78); SHA1_R4(block,b,c,d,e,a,79);
221
+
222
+ state[0] += a;
223
+ state[1] += b;
224
+ state[2] += c;
225
+ state[3] += d;
226
+ state[4] += e;
227
+ a = b = c = d = e = 0;
228
+ }
229
+
230
+ static void sha1_init(struct aes_hmac_ctx *c) {
231
+ c->sha1_count = 0;
232
+ c->sha1_state[0] = 0x67452301;
233
+ c->sha1_state[1] = 0xEFCDAB89;
234
+ c->sha1_state[2] = 0x98BADCFE;
235
+ c->sha1_state[3] = 0x10325476;
236
+ c->sha1_state[4] = 0xC3D2E1F0;
237
+ }
238
+
239
+ static void sha1_update(struct aes_hmac_ctx *c, const uint8_t *data, size_t length) {
240
+ size_t i, j;
241
+
242
+ j = (size_t)((c->sha1_count >> 3) & 63);
243
+ c->sha1_count += ((uint64_t)length << 3);
244
+ if (j + length > 63) {
245
+ memcpy(&c->sha1_buffer[j], data, (i = SHA1_BLOCK_LENGTH - j));
246
+ sha1_transform(c->sha1_state, c->sha1_buffer);
247
+ for (; i + 63 < length; i += SHA1_BLOCK_LENGTH) {
248
+ sha1_transform(c->sha1_state, &data[i]);
249
+ }
250
+ j = 0;
251
+ } else {
252
+ i = 0;
253
+ }
254
+ memcpy(&c->sha1_buffer[j], &data[i], length - i);
255
+ }
256
+
257
+ static void sha1_final(struct aes_hmac_ctx *c, uint8_t out[SHA1_DIGEST_LENGTH]) {
258
+ uint8_t final_count[8];
259
+
260
+ for (unsigned i = 0; i < 8; i++) {
261
+ final_count[i] = (uint8_t)((c->sha1_count >> ((7 - i) * 8)) & 255);
262
+ }
263
+ sha1_update(c, (const uint8_t *)"\200", 1);
264
+ while ((c->sha1_count & 504) != 448) {
265
+ sha1_update(c, (const uint8_t *)"\0", 1);
266
+ }
267
+ sha1_update(c, final_count, sizeof(final_count));
268
+ for (unsigned i = 0; i < SHA1_DIGEST_LENGTH; i++) {
269
+ out[i] = (uint8_t)((c->sha1_state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
270
+ }
271
+ secure_clear(c->sha1_state, sizeof(c->sha1_state));
272
+ secure_clear(c->sha1_buffer, sizeof(c->sha1_buffer));
273
+ c->sha1_count = 0;
274
+ }
275
+
276
+ #undef SHA1_R4
277
+ #undef SHA1_R3
278
+ #undef SHA1_R2
279
+ #undef SHA1_R1
280
+ #undef SHA1_R0
281
+ #undef SHA1_BLK
282
+ #undef SHA1_BLK0
283
+ #undef SHA1_ROL
284
+
285
+ static void hmac_init(struct aes_hmac_ctx *c, const uint8_t *key, unsigned length) {
286
+ uint8_t ipad[SHA1_BLOCK_LENGTH], hashed_key[SHA1_DIGEST_LENGTH];
287
+ if (length > SHA1_BLOCK_LENGTH) {
288
+ sha1_init(c);
289
+ sha1_update(c, key, length);
290
+ sha1_final(c, hashed_key);
291
+ key = hashed_key;
292
+ length = SHA1_DIGEST_LENGTH;
293
+ }
294
+ for (unsigned i = 0; i < SHA1_BLOCK_LENGTH; i++) {
295
+ uint8_t k = i < length ? key[i] : 0;
296
+ ipad[i] = (uint8_t)(k ^ 0x36);
297
+ c->opad[i] = (uint8_t)(k ^ 0x5c);
298
+ }
299
+ sha1_init(c);
300
+ sha1_update(c, ipad, SHA1_BLOCK_LENGTH);
301
+ }
302
+
303
+ static void hmac_final(struct aes_hmac_ctx *c, uint8_t out[SHA1_DIGEST_LENGTH]) {
304
+ uint8_t inner[SHA1_DIGEST_LENGTH];
305
+ sha1_final(c, inner);
306
+ sha1_init(c);
307
+ sha1_update(c, c->opad, SHA1_BLOCK_LENGTH);
308
+ sha1_update(c, inner, SHA1_DIGEST_LENGTH);
309
+ sha1_final(c, out);
310
+ }
311
+
312
+ unsigned aes_hmac_new(void) {
313
+ struct aes_hmac_ctx *c = (struct aes_hmac_ctx *)malloc(sizeof(*c));
314
+ if (!c) {
315
+ return 0;
316
+ }
317
+ memset(c, 0, sizeof(*c));
318
+ return (unsigned)(uintptr_t)c;
319
+ }
320
+
321
+ int aes_hmac_init(unsigned ctx, unsigned key_ptr, unsigned key_length, unsigned auth_ptr, unsigned auth_length) {
322
+ struct aes_hmac_ctx *c = (struct aes_hmac_ctx *)(uintptr_t)ctx;
323
+ if (!c || (key_length != 16 && key_length != 24 && key_length != 32)) {
324
+ return -1;
325
+ }
326
+ if (!tables_ready) {
327
+ init_tables();
328
+ }
329
+ expand_key(c, (const uint8_t *)(uintptr_t)key_ptr, key_length);
330
+ memset(c->counter, 0, sizeof(c->counter));
331
+ hmac_init(c, (const uint8_t *)(uintptr_t)auth_ptr, auth_length);
332
+ return 0;
333
+ }
334
+
335
+ void aes_hmac_process(unsigned ctx, unsigned ptr, unsigned length, int decrypt) {
336
+ struct aes_hmac_ctx *c = (struct aes_hmac_ctx *)(uintptr_t)ctx;
337
+ uint8_t *p = (uint8_t *)(uintptr_t)ptr;
338
+ uint32_t keystream[4], words[4];
339
+ if (!c) {
340
+ return;
341
+ }
342
+ if (decrypt) {
343
+ sha1_update(c, p, length);
344
+ }
345
+ for (unsigned i = 0; i < length; i += BLOCK_LENGTH) {
346
+ ++c->counter[0];
347
+ encrypt_block(c, (const uint8_t *)c->counter, (uint8_t *)keystream);
348
+ if (length - i >= BLOCK_LENGTH) {
349
+ memcpy(words, p + i, BLOCK_LENGTH);
350
+ words[0] ^= keystream[0];
351
+ words[1] ^= keystream[1];
352
+ words[2] ^= keystream[2];
353
+ words[3] ^= keystream[3];
354
+ memcpy(p + i, words, BLOCK_LENGTH);
355
+ } else {
356
+ const uint8_t *k = (const uint8_t *)keystream;
357
+ for (unsigned j = 0; j < length - i; j++) {
358
+ p[i + j] ^= k[j];
359
+ }
360
+ }
361
+ }
362
+ if (!decrypt) {
363
+ sha1_update(c, p, length);
364
+ }
365
+ }
366
+
367
+ void aes_hmac_end(unsigned ctx, unsigned out_ptr) {
368
+ struct aes_hmac_ctx *c = (struct aes_hmac_ctx *)(uintptr_t)ctx;
369
+ if (!c) {
370
+ return;
371
+ }
372
+ if (out_ptr) {
373
+ hmac_final(c, (uint8_t *)(uintptr_t)out_ptr);
374
+ }
375
+ secure_clear(c, sizeof(*c));
376
+ free(c);
377
+ }