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 +91 -0
- package/Makefile +33 -5
- package/README.md +13 -2
- package/dist/zip-module.wasm +0 -0
- package/package.json +3 -2
- package/src/wasm/aes_hmac_wasm.c +377 -0
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:
|
|
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='[
|
|
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='[
|
|
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:
|
|
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='[
|
|
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
|
-
|
|
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.
|
|
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
|
+
}
|