zlib-streams 1.2.0 → 1.2.2
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 +91 -0
- package/Makefile +6 -3
- package/README.md +7 -3
- package/dist/zip-module.wasm +0 -0
- package/dist/zlib-streams.js +2 -7
- package/package.json +1 -1
- package/src/wasm/aes_hmac_wasm.c +182 -112
- package/src/wasm/api/zlib-streams.js +2 -7
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
|
@@ -152,7 +152,8 @@ WASM_EXPORTED_FUNCTIONS = "_inflate9_new","_inflate9_init","_inflate9_init_raw",
|
|
|
152
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)
|
|
153
153
|
|
|
154
154
|
.PHONY: wasm
|
|
155
|
-
wasm:
|
|
155
|
+
wasm:
|
|
156
|
+
@$(MAKE) -B dist/zlib-streams-dev.wasm
|
|
156
157
|
|
|
157
158
|
.PHONY: wasm_traced
|
|
158
159
|
wasm_traced: dist/zlib-streams_traced.wasm
|
|
@@ -307,7 +308,8 @@ dist/zlib-streams-dev.wasm: $(WASM_SRCS)
|
|
|
307
308
|
|
|
308
309
|
# Production-optimized wasm: smaller build with -Oz and no extra runtime methods.
|
|
309
310
|
.PHONY: wasm_prod
|
|
310
|
-
wasm_prod:
|
|
311
|
+
wasm_prod:
|
|
312
|
+
@$(MAKE) -B dist/zlib-streams.wasm
|
|
311
313
|
|
|
312
314
|
dist/zlib-streams.wasm: $(WASM_SRCS)
|
|
313
315
|
@echo "Building production wasm $@ using $(EMCC)"
|
|
@@ -328,7 +330,8 @@ ZIP_MODULE_SRCS = src/wasm/aes_hmac_wasm.c
|
|
|
328
330
|
ZIP_MODULE_EXPORTED_FUNCTIONS = $(WASM_EXPORTED_FUNCTIONS),"_aes_hmac_new","_aes_hmac_init","_aes_hmac_process","_aes_hmac_end"
|
|
329
331
|
|
|
330
332
|
.PHONY: zip_module
|
|
331
|
-
zip_module:
|
|
333
|
+
zip_module:
|
|
334
|
+
@$(MAKE) -B dist/zip-module.wasm
|
|
332
335
|
|
|
333
336
|
dist/zip-module.wasm: $(WASM_SRCS) $(ZIP_MODULE_SRCS)
|
|
334
337
|
@echo "Building zip.js module $@ using $(EMCC)"
|
package/README.md
CHANGED
|
@@ -19,24 +19,28 @@ git submodule update --init --recursive
|
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
### 2. Build WASM module
|
|
22
|
-
|
|
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
|
|
|
34
|
-
- zip.js module: the codecs plus the AES-CTR/HMAC-SHA1 engine behind the encrypted entries of zip.js
|
|
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`.
|
|
35
37
|
```sh
|
|
36
38
|
make zip_module
|
|
37
39
|
make test_zip_module
|
|
38
40
|
```
|
|
39
41
|
Output: `dist/zip-module.wasm`
|
|
40
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
|
+
|
|
41
45
|
## License
|
|
42
46
|
See LICENSE for details.
|
package/dist/zip-module.wasm
CHANGED
|
Binary file
|
package/dist/zlib-streams.js
CHANGED
|
@@ -72,7 +72,6 @@ function _make(isCompress, type, options = {}) {
|
|
|
72
72
|
if (!this.out || !this.in) {
|
|
73
73
|
throw new Error("allocation failed");
|
|
74
74
|
}
|
|
75
|
-
this._scratch = new Uint8Array(outBufferSize);
|
|
76
75
|
if (isCompress) {
|
|
77
76
|
this._process = wasm.deflate_process;
|
|
78
77
|
this._last_consumed = wasm.deflate_last_consumed;
|
|
@@ -121,7 +120,6 @@ function _make(isCompress, type, options = {}) {
|
|
|
121
120
|
const process = this._process;
|
|
122
121
|
const last_consumed = this._last_consumed;
|
|
123
122
|
const out = this.out;
|
|
124
|
-
const scratch = this._scratch;
|
|
125
123
|
let offset = 0;
|
|
126
124
|
while (offset < buffer.length) {
|
|
127
125
|
const toRead = Math.min(buffer.length - offset, 32 * 1024);
|
|
@@ -146,8 +144,7 @@ function _make(isCompress, type, options = {}) {
|
|
|
146
144
|
}
|
|
147
145
|
const prod = result & 0x00ffffff;
|
|
148
146
|
if (prod) {
|
|
149
|
-
|
|
150
|
-
controller.enqueue(scratch.slice(0, prod));
|
|
147
|
+
controller.enqueue(heap.slice(out, out + prod));
|
|
151
148
|
}
|
|
152
149
|
const consumed = last_consumed(this.streamHandle);
|
|
153
150
|
if (consumed === 0 && prod === 0) {
|
|
@@ -165,7 +162,6 @@ function _make(isCompress, type, options = {}) {
|
|
|
165
162
|
const heap = new Uint8Array(memory.buffer);
|
|
166
163
|
const process = this._process;
|
|
167
164
|
const out = this.out;
|
|
168
|
-
const scratch = this._scratch;
|
|
169
165
|
while (true) {
|
|
170
166
|
const result = process(this.streamHandle, 0, 0, out, outBufferSize, 4);
|
|
171
167
|
const code = (result >> 24) & 0xff;
|
|
@@ -175,8 +171,7 @@ function _make(isCompress, type, options = {}) {
|
|
|
175
171
|
}
|
|
176
172
|
const produced = result & 0x00ffffff;
|
|
177
173
|
if (produced) {
|
|
178
|
-
|
|
179
|
-
controller.enqueue(scratch.slice(0, produced));
|
|
174
|
+
controller.enqueue(heap.slice(out, out + produced));
|
|
180
175
|
}
|
|
181
176
|
if (code === 1 || produced === 0) {
|
|
182
177
|
break;
|
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.2.
|
|
6
|
+
"version": "1.2.2",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"keywords": [
|
|
9
9
|
"deflate",
|
package/src/wasm/aes_hmac_wasm.c
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
little-endian integer starting at 1, and HMAC-SHA1 over the ciphertext. Forward-only T-table
|
|
3
3
|
AES, the aes_core.c layout. One context per stream: init() takes the cipher key and the
|
|
4
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
|
|
5
|
+
call, end() writes the 20-byte MAC when given an output pointer, clears sensitive state, and
|
|
6
|
+
frees the context. */
|
|
6
7
|
#include <stdlib.h>
|
|
7
8
|
#include <string.h>
|
|
8
9
|
#include <stdint.h>
|
|
@@ -15,11 +16,11 @@
|
|
|
15
16
|
struct aes_hmac_ctx {
|
|
16
17
|
uint32_t round_keys[ROUND_KEYS_LENGTH];
|
|
17
18
|
int rounds;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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];
|
|
23
24
|
uint8_t opad[SHA1_BLOCK_LENGTH];
|
|
24
25
|
};
|
|
25
26
|
|
|
@@ -40,6 +41,15 @@ static void store_be32(uint8_t *p, uint32_t v) {
|
|
|
40
41
|
p[3] = (uint8_t)v;
|
|
41
42
|
}
|
|
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
|
+
|
|
43
53
|
static void init_tables(void) {
|
|
44
54
|
uint8_t p = 1, q = 1;
|
|
45
55
|
do {
|
|
@@ -93,122 +103,185 @@ static void encrypt_block(const struct aes_hmac_ctx *c, const uint8_t in[BLOCK_L
|
|
|
93
103
|
uint32_t s0 = load_be32(in) ^ rk[0], s1 = load_be32(in + 4) ^ rk[1];
|
|
94
104
|
uint32_t s2 = load_be32(in + 8) ^ rk[2], s3 = load_be32(in + 12) ^ rk[3];
|
|
95
105
|
uint32_t t0, t1, t2, t3;
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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;
|
|
107
126
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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]);
|
|
112
141
|
}
|
|
113
142
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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;
|
|
160
228
|
}
|
|
161
229
|
|
|
162
230
|
static void sha1_init(struct aes_hmac_ctx *c) {
|
|
163
|
-
c->
|
|
164
|
-
c->
|
|
165
|
-
c->
|
|
166
|
-
c->
|
|
167
|
-
c->
|
|
168
|
-
c->
|
|
169
|
-
c->total_length = 0;
|
|
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;
|
|
170
237
|
}
|
|
171
238
|
|
|
172
|
-
static void sha1_update(struct aes_hmac_ctx *c, const uint8_t *
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
length -= n;
|
|
183
|
-
if (c->block_length == SHA1_BLOCK_LENGTH) {
|
|
184
|
-
sha1_block(c, c->block);
|
|
185
|
-
c->block_length = 0;
|
|
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]);
|
|
186
249
|
}
|
|
250
|
+
j = 0;
|
|
251
|
+
} else {
|
|
252
|
+
i = 0;
|
|
187
253
|
}
|
|
188
|
-
|
|
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
|
-
}
|
|
254
|
+
memcpy(&c->sha1_buffer[j], &data[i], length - i);
|
|
197
255
|
}
|
|
198
256
|
|
|
199
257
|
static void sha1_final(struct aes_hmac_ctx *c, uint8_t out[SHA1_DIGEST_LENGTH]) {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
unsigned
|
|
203
|
-
|
|
204
|
-
|
|
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);
|
|
205
266
|
}
|
|
206
|
-
sha1_update(c,
|
|
207
|
-
for (
|
|
208
|
-
|
|
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);
|
|
209
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;
|
|
210
274
|
}
|
|
211
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
|
+
|
|
212
285
|
static void hmac_init(struct aes_hmac_ctx *c, const uint8_t *key, unsigned length) {
|
|
213
286
|
uint8_t ipad[SHA1_BLOCK_LENGTH], hashed_key[SHA1_DIGEST_LENGTH];
|
|
214
287
|
if (length > SHA1_BLOCK_LENGTH) {
|
|
@@ -254,7 +327,7 @@ int aes_hmac_init(unsigned ctx, unsigned key_ptr, unsigned key_length, unsigned
|
|
|
254
327
|
init_tables();
|
|
255
328
|
}
|
|
256
329
|
expand_key(c, (const uint8_t *)(uintptr_t)key_ptr, key_length);
|
|
257
|
-
memset(c->counter, 0,
|
|
330
|
+
memset(c->counter, 0, sizeof(c->counter));
|
|
258
331
|
hmac_init(c, (const uint8_t *)(uintptr_t)auth_ptr, auth_length);
|
|
259
332
|
return 0;
|
|
260
333
|
}
|
|
@@ -270,12 +343,8 @@ void aes_hmac_process(unsigned ctx, unsigned ptr, unsigned length, int decrypt)
|
|
|
270
343
|
sha1_update(c, p, length);
|
|
271
344
|
}
|
|
272
345
|
for (unsigned i = 0; i < length; i += BLOCK_LENGTH) {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
break;
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
encrypt_block(c, c->counter, (uint8_t *)keystream);
|
|
346
|
+
++c->counter[0];
|
|
347
|
+
encrypt_block(c, (const uint8_t *)c->counter, (uint8_t *)keystream);
|
|
279
348
|
if (length - i >= BLOCK_LENGTH) {
|
|
280
349
|
memcpy(words, p + i, BLOCK_LENGTH);
|
|
281
350
|
words[0] ^= keystream[0];
|
|
@@ -303,5 +372,6 @@ void aes_hmac_end(unsigned ctx, unsigned out_ptr) {
|
|
|
303
372
|
if (out_ptr) {
|
|
304
373
|
hmac_final(c, (uint8_t *)(uintptr_t)out_ptr);
|
|
305
374
|
}
|
|
375
|
+
secure_clear(c, sizeof(*c));
|
|
306
376
|
free(c);
|
|
307
377
|
}
|
|
@@ -72,7 +72,6 @@ function _make(isCompress, type, options = {}) {
|
|
|
72
72
|
if (!this.out || !this.in) {
|
|
73
73
|
throw new Error("allocation failed");
|
|
74
74
|
}
|
|
75
|
-
this._scratch = new Uint8Array(outBufferSize);
|
|
76
75
|
if (isCompress) {
|
|
77
76
|
this._process = wasm.deflate_process;
|
|
78
77
|
this._last_consumed = wasm.deflate_last_consumed;
|
|
@@ -121,7 +120,6 @@ function _make(isCompress, type, options = {}) {
|
|
|
121
120
|
const process = this._process;
|
|
122
121
|
const last_consumed = this._last_consumed;
|
|
123
122
|
const out = this.out;
|
|
124
|
-
const scratch = this._scratch;
|
|
125
123
|
let offset = 0;
|
|
126
124
|
while (offset < buffer.length) {
|
|
127
125
|
const toRead = Math.min(buffer.length - offset, 32 * 1024);
|
|
@@ -146,8 +144,7 @@ function _make(isCompress, type, options = {}) {
|
|
|
146
144
|
}
|
|
147
145
|
const prod = result & 0x00ffffff;
|
|
148
146
|
if (prod) {
|
|
149
|
-
|
|
150
|
-
controller.enqueue(scratch.slice(0, prod));
|
|
147
|
+
controller.enqueue(heap.slice(out, out + prod));
|
|
151
148
|
}
|
|
152
149
|
const consumed = last_consumed(this.streamHandle);
|
|
153
150
|
if (consumed === 0 && prod === 0) {
|
|
@@ -165,7 +162,6 @@ function _make(isCompress, type, options = {}) {
|
|
|
165
162
|
const heap = new Uint8Array(memory.buffer);
|
|
166
163
|
const process = this._process;
|
|
167
164
|
const out = this.out;
|
|
168
|
-
const scratch = this._scratch;
|
|
169
165
|
while (true) {
|
|
170
166
|
const result = process(this.streamHandle, 0, 0, out, outBufferSize, 4);
|
|
171
167
|
const code = (result >> 24) & 0xff;
|
|
@@ -175,8 +171,7 @@ function _make(isCompress, type, options = {}) {
|
|
|
175
171
|
}
|
|
176
172
|
const produced = result & 0x00ffffff;
|
|
177
173
|
if (produced) {
|
|
178
|
-
|
|
179
|
-
controller.enqueue(scratch.slice(0, produced));
|
|
174
|
+
controller.enqueue(heap.slice(out, out + produced));
|
|
180
175
|
}
|
|
181
176
|
if (code === 1 || produced === 0) {
|
|
182
177
|
break;
|