@amritk/nish-x86_64-linux 0.18.0 → 0.20.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/INSTALL.md +43 -25
- package/bin/nish +0 -0
- package/package.json +2 -2
- package/runtime/nish.d.ts +55 -5
- package/runtime/nish.h +215 -18
- package/runtime/nish.mjs +16 -0
- package/runtime/runtime-aes.c +490 -0
- package/runtime/runtime-cross.c +366 -0
- package/runtime/runtime-host.c +7 -6
- package/runtime/runtime-net.c +93 -34
- package/runtime/runtime-os.c +213 -15
- package/runtime/runtime-parallel.c +590 -107
- package/runtime/runtime-simd.c +4 -4
- package/runtime/runtime-wasm.c +5 -3
- package/runtime/runtime.c +69 -13
- package/runtime/shim.mjs +71 -1
- package/scripts/build.sh +223 -22
- package/std/README.md +81 -51
- package/std/bytes.ts +163 -0
- package/std/crypto/LICENSE-libsecp256k1 +19 -0
- package/std/crypto/aes.ts +238 -76
- package/std/crypto/chacha20poly1305.ts +43 -9
- package/std/crypto/ed25519.ts +840 -0
- package/std/crypto/hkdf.ts +304 -12
- package/std/crypto/hmac.ts +245 -53
- package/std/crypto/p256.ts +932 -61
- package/std/crypto/x25519.ts +55 -37
- package/std/crypto/x509-random.ts +71 -0
- package/std/crypto/x509.ts +9 -9
- package/std/json-tokenizer.ts +1296 -0
- package/std/json-typed.ts +1014 -0
- package/std/json-value.ts +1163 -0
- package/std/json.ts +1120 -34
- package/std/net/buffer-pool.ts +151 -0
- package/std/net/hpack.ts +416 -112
- package/std/net/http-fields.ts +93 -0
- package/std/net/http1-server.ts +417 -55
- package/std/net/http1.ts +31 -6
- package/std/net/http2-tls.ts +112 -24
- package/std/net/http2.ts +333 -75
- package/std/net/http3-server.ts +211 -31
- package/std/net/http3.ts +187 -28
- package/std/net/prefork.ts +412 -0
- package/std/net/quic-listener.ts +88 -7
- package/std/net/quic-packet.ts +243 -82
- package/std/net/quic-recovery.ts +361 -30
- package/std/net/quic-stream.ts +424 -24
- package/std/net/quic.ts +519 -167
- package/std/net/router.ts +676 -0
- package/std/net/tls/codec.ts +426 -27
- package/std/net/tls/record-server.ts +478 -132
- package/std/net/tls/record.ts +133 -42
- package/std/net/tls/schedule.ts +464 -55
- package/std/net/tls/ticket.ts +610 -0
- package/std/net/tls-tcp.ts +196 -53
- package/std/net/tls.ts +1018 -260
- package/std/net/url.ts +571 -0
- package/std/random.ts +94 -0
- package/std/threads.ts +438 -14
package/std/crypto/hmac.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `nish/crypto/hmac` — HMAC as RFC 2104 defines it, over SHA-256
|
|
2
|
+
* `nish/crypto/hmac` — HMAC as RFC 2104 defines it, over SHA-256, SHA-384 and
|
|
3
|
+
* SHA-512.
|
|
3
4
|
*
|
|
4
5
|
* H(K XOR opad, H(K XOR ipad, text))
|
|
5
6
|
*
|
|
@@ -24,6 +25,21 @@
|
|
|
24
25
|
* which HMAC does not keep secret; a received tag is compared with
|
|
25
26
|
* `timingSafeEqual`, never `===`.
|
|
26
27
|
*
|
|
28
|
+
* **What the key reaches is wiped** (CLAUDE.md, "Security"). The key block
|
|
29
|
+
* is wiped once both hashers have absorbed it, and so is the hash
|
|
30
|
+
* of a key longer than a block and the hasher that made it. `digest` wipes
|
|
31
|
+
* the inner digest and both keyed hashers (chaining value, pending block and
|
|
32
|
+
* message schedule) before it answers, so a finished `HmacSha256` holds
|
|
33
|
+
* nothing of the key. The wipes are `wipe`'s volatile stores, which `-O2`
|
|
34
|
+
* keeps (`tests/wipes/crypto.js`, "crypto_hmac crypto_hkdf: the wipes survive -O2").
|
|
35
|
+
* What no wipe here reaches is the caller's own key array, and an
|
|
36
|
+
* `HmacSha256` that is keyed and then dropped without a `digest` keeps its
|
|
37
|
+
* keyed hashers (docs/security/crypto-k1.md, K1-7).
|
|
38
|
+
*
|
|
39
|
+
* A caller that holds its key as a `Secret<u8[]>` (`nish:secret`) MACs with
|
|
40
|
+
* `hmacSha256Secret`, `hmacSha384Secret` or `hmacSha512Secret`, which read the
|
|
41
|
+
* key only inside `exposeWith`; the tag they answer is public and plain.
|
|
42
|
+
*
|
|
27
43
|
* `HmacSha256Scratch` and `HmacSha384Scratch` are the same computation in
|
|
28
44
|
* hashers the caller allocates once: `begin` keys them again in place and
|
|
29
45
|
* `finishInto` writes the tag into the caller's array, so a loop of them
|
|
@@ -32,9 +48,10 @@
|
|
|
32
48
|
*
|
|
33
49
|
* Written from RFC 2104, not ported from another implementation.
|
|
34
50
|
*/
|
|
35
|
-
import { SHA256_BLOCK, SHA256_SIZE, Sha256
|
|
36
|
-
import { SHA384_SIZE, SHA512_BLOCK, Sha384,
|
|
51
|
+
import { SHA256_BLOCK, SHA256_SIZE, Sha256 } from "nish/crypto/sha256"
|
|
52
|
+
import { SHA384_SIZE, SHA512_BLOCK, SHA512_SIZE, Sha384, Sha512 } from "nish/crypto/sha512"
|
|
37
53
|
import { timingSafeEqual } from "nish/crypto/ct"
|
|
54
|
+
import { Secret, exposeWith, wipe } from "nish:secret"
|
|
38
55
|
|
|
39
56
|
/** RFC 2104 §2's `ipad`, the byte XORed into the key for the inner hash. */
|
|
40
57
|
const HMAC_IPAD: i32 = 0x36
|
|
@@ -76,6 +93,141 @@ const hmacPadBlock = (key: u8[], blockSize: i32, pad: i32): u8[] => {
|
|
|
76
93
|
return out
|
|
77
94
|
}
|
|
78
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Zeroes everything `h` holds of the key and the message it was fed: its hash
|
|
98
|
+
* value, its pending block and its message schedule, with `wipe`'s volatile
|
|
99
|
+
* stores, which no optimiser removes however dead the hasher is about to be.
|
|
100
|
+
* The hasher is left finished, so that feeding it before it is started again
|
|
101
|
+
* panics, as feeding a spent one always has.
|
|
102
|
+
*/
|
|
103
|
+
const hmacWipeSha256 = (h: Sha256): void => {
|
|
104
|
+
wipe(h.state)
|
|
105
|
+
wipe(h.block)
|
|
106
|
+
wipe(h.schedule)
|
|
107
|
+
h.fill = 0
|
|
108
|
+
h.total = 0
|
|
109
|
+
h.finished = true
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** `hmacWipeSha256` for SHA-384. */
|
|
113
|
+
const hmacWipeSha384 = (h: Sha384): void => {
|
|
114
|
+
wipe(h.engine.state)
|
|
115
|
+
wipe(h.engine.block)
|
|
116
|
+
wipe(h.engine.schedule)
|
|
117
|
+
h.engine.filled = 0
|
|
118
|
+
h.engine.count = toU64(0)
|
|
119
|
+
h.engine.finished = true
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** `hmacWipeSha256` for SHA-512. */
|
|
123
|
+
const hmacWipeSha512 = (h: Sha512): void => {
|
|
124
|
+
wipe(h.engine.state)
|
|
125
|
+
wipe(h.engine.block)
|
|
126
|
+
wipe(h.engine.schedule)
|
|
127
|
+
h.engine.filled = 0
|
|
128
|
+
h.engine.count = toU64(0)
|
|
129
|
+
h.engine.finished = true
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Panics on a key longer than 2^31 - 1 bytes, before any `toI32` of its
|
|
134
|
+
* length: under `--number-mode f64` that would saturate, and the key hashed
|
|
135
|
+
* would be a prefix, so two keys sharing it would MAC alike (K1-1).
|
|
136
|
+
*/
|
|
137
|
+
const hmacCheckKey = (key: u8[]): void => {
|
|
138
|
+
if (key.length > 2147483647) {
|
|
139
|
+
panic("hmac: a key longer than 2^31 - 1 bytes")
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Keys `inner` with `k XOR ipad` and `outer` with `k XOR opad`, `k` no longer
|
|
145
|
+
* than SHA-256's block, in one block that is rewritten between the two and
|
|
146
|
+
* wiped once both have absorbed it.
|
|
147
|
+
*/
|
|
148
|
+
const hmacPadsSha256 = (inner: Sha256, outer: Sha256, k: u8[]): void => {
|
|
149
|
+
const pad: u8[] = hmacPadBlock(k, SHA256_BLOCK, HMAC_IPAD)
|
|
150
|
+
inner.update(pad, HMAC_FROM, SHA256_BLOCK)
|
|
151
|
+
hmacPadInto(pad, k, HMAC_FROM, toI32(k.length), HMAC_OPAD)
|
|
152
|
+
outer.update(pad, HMAC_FROM, SHA256_BLOCK)
|
|
153
|
+
wipe(pad)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Keys `inner` and `outer` with `key` as RFC 2104 §2 says: a key longer than
|
|
158
|
+
* the block is replaced by its hash, in a hasher of its own, and that hash
|
|
159
|
+
* and that hasher are wiped once the key blocks are absorbed.
|
|
160
|
+
*/
|
|
161
|
+
const hmacKeySha256 = (inner: Sha256, outer: Sha256, key: u8[]): void => {
|
|
162
|
+
hmacCheckKey(key)
|
|
163
|
+
if (toI32(key.length) <= SHA256_BLOCK) {
|
|
164
|
+
hmacPadsSha256(inner, outer, key)
|
|
165
|
+
return
|
|
166
|
+
}
|
|
167
|
+
const hasher = new Sha256()
|
|
168
|
+
hasher.update(key, HMAC_FROM, toI32(key.length))
|
|
169
|
+
const hashed: u8[] = hasher.digest()
|
|
170
|
+
hmacWipeSha256(hasher)
|
|
171
|
+
hmacPadsSha256(inner, outer, hashed)
|
|
172
|
+
wipe(hashed)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** `hmacPadsSha256` for SHA-384's 128-byte block. */
|
|
176
|
+
const hmacPadsSha384 = (inner: Sha384, outer: Sha384, k: u8[]): void => {
|
|
177
|
+
const pad: u8[] = hmacPadBlock(k, SHA512_BLOCK, HMAC_IPAD)
|
|
178
|
+
inner.update(pad, HMAC_FROM, SHA512_BLOCK)
|
|
179
|
+
hmacPadInto(pad, k, HMAC_FROM, toI32(k.length), HMAC_OPAD)
|
|
180
|
+
outer.update(pad, HMAC_FROM, SHA512_BLOCK)
|
|
181
|
+
wipe(pad)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Keys `inner` and `outer` with `key` as RFC 2104 §2 says: a key longer than
|
|
186
|
+
* the block is replaced by its hash, in a hasher of its own, and that hash
|
|
187
|
+
* and that hasher are wiped once the key blocks are absorbed.
|
|
188
|
+
*/
|
|
189
|
+
const hmacKeySha384 = (inner: Sha384, outer: Sha384, key: u8[]): void => {
|
|
190
|
+
hmacCheckKey(key)
|
|
191
|
+
if (toI32(key.length) <= SHA512_BLOCK) {
|
|
192
|
+
hmacPadsSha384(inner, outer, key)
|
|
193
|
+
return
|
|
194
|
+
}
|
|
195
|
+
const hasher = new Sha384()
|
|
196
|
+
hasher.update(key, HMAC_FROM, toI32(key.length))
|
|
197
|
+
const hashed: u8[] = hasher.digest()
|
|
198
|
+
hmacWipeSha384(hasher)
|
|
199
|
+
hmacPadsSha384(inner, outer, hashed)
|
|
200
|
+
wipe(hashed)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** `hmacPadsSha256` for SHA-512's 128-byte block. */
|
|
204
|
+
const hmacPadsSha512 = (inner: Sha512, outer: Sha512, k: u8[]): void => {
|
|
205
|
+
const pad: u8[] = hmacPadBlock(k, SHA512_BLOCK, HMAC_IPAD)
|
|
206
|
+
inner.update(pad, HMAC_FROM, SHA512_BLOCK)
|
|
207
|
+
hmacPadInto(pad, k, HMAC_FROM, toI32(k.length), HMAC_OPAD)
|
|
208
|
+
outer.update(pad, HMAC_FROM, SHA512_BLOCK)
|
|
209
|
+
wipe(pad)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Keys `inner` and `outer` with `key` as RFC 2104 §2 says: a key longer than
|
|
214
|
+
* the block is replaced by its hash, in a hasher of its own, and that hash
|
|
215
|
+
* and that hasher are wiped once the key blocks are absorbed.
|
|
216
|
+
*/
|
|
217
|
+
const hmacKeySha512 = (inner: Sha512, outer: Sha512, key: u8[]): void => {
|
|
218
|
+
hmacCheckKey(key)
|
|
219
|
+
if (toI32(key.length) <= SHA512_BLOCK) {
|
|
220
|
+
hmacPadsSha512(inner, outer, key)
|
|
221
|
+
return
|
|
222
|
+
}
|
|
223
|
+
const hasher = new Sha512()
|
|
224
|
+
hasher.update(key, HMAC_FROM, toI32(key.length))
|
|
225
|
+
const hashed: u8[] = hasher.digest()
|
|
226
|
+
hmacWipeSha512(hasher)
|
|
227
|
+
hmacPadsSha512(inner, outer, hashed)
|
|
228
|
+
wipe(hashed)
|
|
229
|
+
}
|
|
230
|
+
|
|
79
231
|
/**
|
|
80
232
|
* HMAC-SHA-256 in progress (RFC 2104 with RFC 4231's SHA-256): feed the
|
|
81
233
|
* message with `update`, as many windows as it takes, and take the 32-byte
|
|
@@ -87,13 +239,14 @@ export class HmacSha256 {
|
|
|
87
239
|
/** H(K XOR opad, …), fed the key block in the constructor and the inner digest last. */
|
|
88
240
|
outer: Sha256
|
|
89
241
|
|
|
90
|
-
/**
|
|
242
|
+
/**
|
|
243
|
+
* Keys the computation. A key longer than 64 bytes is replaced by its
|
|
244
|
+
* SHA-256 (RFC 2104 §2), which is wiped once used (`hmacKeySha256`).
|
|
245
|
+
*/
|
|
91
246
|
constructor(key: u8[]) {
|
|
92
|
-
const k: u8[] = toI32(key.length) > SHA256_BLOCK ? sha256(key) : key
|
|
93
247
|
this.inner = new Sha256()
|
|
94
|
-
this.inner.update(hmacPadBlock(k, SHA256_BLOCK, HMAC_IPAD), HMAC_FROM, SHA256_BLOCK)
|
|
95
248
|
this.outer = new Sha256()
|
|
96
|
-
this.
|
|
249
|
+
hmacKeySha256(this.inner, this.outer, key)
|
|
97
250
|
}
|
|
98
251
|
|
|
99
252
|
/** Absorbs `data[off .. off + len)`; a window outside `data` panics in `Sha256.update`. */
|
|
@@ -101,11 +254,15 @@ export class HmacSha256 {
|
|
|
101
254
|
this.inner.update(data, off, len)
|
|
102
255
|
}
|
|
103
256
|
|
|
104
|
-
/** The 32-byte tag, in a fresh array. Ends the computation. */
|
|
257
|
+
/** The 32-byte tag, in a fresh array. Ends the computation, and wipes both hashers. */
|
|
105
258
|
digest(): u8[] {
|
|
106
259
|
const innerDigest: u8[] = this.inner.digest()
|
|
107
260
|
this.outer.update(innerDigest, HMAC_FROM, SHA256_SIZE)
|
|
108
|
-
|
|
261
|
+
wipe(innerDigest)
|
|
262
|
+
const tag: u8[] = this.outer.digest()
|
|
263
|
+
hmacWipeSha256(this.inner)
|
|
264
|
+
hmacWipeSha256(this.outer)
|
|
265
|
+
return tag
|
|
109
266
|
}
|
|
110
267
|
}
|
|
111
268
|
|
|
@@ -121,11 +278,9 @@ export class HmacSha384 {
|
|
|
121
278
|
|
|
122
279
|
/** Keys the computation. A key longer than 128 bytes is replaced by its SHA-384 (RFC 2104 §2). */
|
|
123
280
|
constructor(key: u8[]) {
|
|
124
|
-
const k: u8[] = toI32(key.length) > SHA512_BLOCK ? sha384(key) : key
|
|
125
281
|
this.inner = new Sha384()
|
|
126
|
-
this.inner.update(hmacPadBlock(k, SHA512_BLOCK, HMAC_IPAD), HMAC_FROM, SHA512_BLOCK)
|
|
127
282
|
this.outer = new Sha384()
|
|
128
|
-
this.
|
|
283
|
+
hmacKeySha384(this.inner, this.outer, key)
|
|
129
284
|
}
|
|
130
285
|
|
|
131
286
|
/** Absorbs `data[off .. off + len)`; a window outside `data` panics in `Sha384.update`. */
|
|
@@ -133,11 +288,49 @@ export class HmacSha384 {
|
|
|
133
288
|
this.inner.update(data, off, len)
|
|
134
289
|
}
|
|
135
290
|
|
|
136
|
-
/** The 48-byte tag, in a fresh array. Ends the computation. */
|
|
291
|
+
/** The 48-byte tag, in a fresh array. Ends the computation, and wipes both hashers. */
|
|
137
292
|
digest(): u8[] {
|
|
138
293
|
const innerDigest: u8[] = this.inner.digest()
|
|
139
294
|
this.outer.update(innerDigest, HMAC_FROM, SHA384_SIZE)
|
|
140
|
-
|
|
295
|
+
wipe(innerDigest)
|
|
296
|
+
const tag: u8[] = this.outer.digest()
|
|
297
|
+
hmacWipeSha384(this.inner)
|
|
298
|
+
hmacWipeSha384(this.outer)
|
|
299
|
+
return tag
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* HMAC-SHA-512 in progress (RFC 2104 with RFC 4231's SHA-512), with
|
|
305
|
+
* `HmacSha256`'s methods. The block is SHA-512's 128 bytes and the tag 64.
|
|
306
|
+
*/
|
|
307
|
+
export class HmacSha512 {
|
|
308
|
+
/** H(K XOR ipad, …), fed the key block in the constructor and the message after. */
|
|
309
|
+
inner: Sha512
|
|
310
|
+
/** H(K XOR opad, …), fed the key block in the constructor and the inner digest last. */
|
|
311
|
+
outer: Sha512
|
|
312
|
+
|
|
313
|
+
/** Keys the computation. A key longer than 128 bytes is replaced by its SHA-512 (RFC 2104 §2). */
|
|
314
|
+
constructor(key: u8[]) {
|
|
315
|
+
this.inner = new Sha512()
|
|
316
|
+
this.outer = new Sha512()
|
|
317
|
+
hmacKeySha512(this.inner, this.outer, key)
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/** Absorbs `data[off .. off + len)`; a window outside `data` panics in `Sha512.update`. */
|
|
321
|
+
update(data: u8[], off: i32, len: i32): void {
|
|
322
|
+
this.inner.update(data, off, len)
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/** The 64-byte tag, in a fresh array. Ends the computation, and wipes both hashers. */
|
|
326
|
+
digest(): u8[] {
|
|
327
|
+
const innerDigest: u8[] = this.inner.digest()
|
|
328
|
+
this.outer.update(innerDigest, HMAC_FROM, SHA512_SIZE)
|
|
329
|
+
wipe(innerDigest)
|
|
330
|
+
const tag: u8[] = this.outer.digest()
|
|
331
|
+
hmacWipeSha512(this.inner)
|
|
332
|
+
hmacWipeSha512(this.outer)
|
|
333
|
+
return tag
|
|
141
334
|
}
|
|
142
335
|
}
|
|
143
336
|
|
|
@@ -147,7 +340,7 @@ export class HmacSha384 {
|
|
|
147
340
|
* `data` longer than 2^31 - 1 bytes panics, as `sha256` does and for its
|
|
148
341
|
* reason: under `--number-mode f64` the tag would be of a prefix, and a tag
|
|
149
342
|
* that verifies every message sharing that prefix is a forgery. A key that
|
|
150
|
-
* long
|
|
343
|
+
* long panics in the constructor for the same reason.
|
|
151
344
|
*/
|
|
152
345
|
export const hmacSha256 = (key: u8[], data: u8[]): u8[] => {
|
|
153
346
|
if (data.length > 2147483647) {
|
|
@@ -171,6 +364,31 @@ export const hmacSha384 = (key: u8[], data: u8[]): u8[] => {
|
|
|
171
364
|
return mac.digest()
|
|
172
365
|
}
|
|
173
366
|
|
|
367
|
+
/**
|
|
368
|
+
* The HMAC-SHA-512 of all of `data` under `key`, as a fresh 64-byte array.
|
|
369
|
+
* `data` longer than 2^31 - 1 bytes panics, as in `hmacSha256`.
|
|
370
|
+
*/
|
|
371
|
+
export const hmacSha512 = (key: u8[], data: u8[]): u8[] => {
|
|
372
|
+
if (data.length > 2147483647) {
|
|
373
|
+
panic("hmacSha512: a message longer than 2^31 - 1 bytes")
|
|
374
|
+
}
|
|
375
|
+
const mac = new HmacSha512(key)
|
|
376
|
+
mac.update(data, HMAC_FROM, toI32(data.length))
|
|
377
|
+
return mac.digest()
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* `hmacSha256` under a key held as a `Secret`, read only inside `exposeWith`.
|
|
382
|
+
* The tag is public, so it is answered plain; the caller still wipes the key.
|
|
383
|
+
*/
|
|
384
|
+
export const hmacSha256Secret = (key: Secret<u8[]>, data: u8[]): u8[] => exposeWith(key, data, hmacSha256)
|
|
385
|
+
|
|
386
|
+
/** `hmacSha384` under a key held as a `Secret`, as `hmacSha256Secret` is. */
|
|
387
|
+
export const hmacSha384Secret = (key: Secret<u8[]>, data: u8[]): u8[] => exposeWith(key, data, hmacSha384)
|
|
388
|
+
|
|
389
|
+
/** `hmacSha512` under a key held as a `Secret`, as `hmacSha256Secret` is. */
|
|
390
|
+
export const hmacSha512Secret = (key: Secret<u8[]>, data: u8[]): u8[] => exposeWith(key, data, hmacSha512)
|
|
391
|
+
|
|
174
392
|
/**
|
|
175
393
|
* Whether `tag` is the HMAC-SHA-256 of `data` under `key`, compared by
|
|
176
394
|
* `timingSafeEqual`. A tag that is not 32 bytes answers `false` without a
|
|
@@ -184,6 +402,10 @@ export const hmacSha256Verify = (key: u8[], data: u8[], tag: u8[]): boolean =>
|
|
|
184
402
|
export const hmacSha384Verify = (key: u8[], data: u8[], tag: u8[]): boolean =>
|
|
185
403
|
timingSafeEqual(hmacSha384(key, data), tag)
|
|
186
404
|
|
|
405
|
+
/** Whether `tag` is the HMAC-SHA-512 of `data` under `key`, compared as `hmacSha256Verify` does. */
|
|
406
|
+
export const hmacSha512Verify = (key: u8[], data: u8[], tag: u8[]): boolean =>
|
|
407
|
+
timingSafeEqual(hmacSha512(key, data), tag)
|
|
408
|
+
|
|
187
409
|
// ---- Caller-owned scratch --------------------------------------------------
|
|
188
410
|
//
|
|
189
411
|
// `HmacSha256` makes its two hashers in its constructor, and the one-shot
|
|
@@ -241,44 +463,6 @@ export const hmacCopySha384 = (from: Sha384, to: Sha384): void => {
|
|
|
241
463
|
to.engine.finished = from.engine.finished
|
|
242
464
|
}
|
|
243
465
|
|
|
244
|
-
/**
|
|
245
|
-
* Zeroes everything `h` holds of the message it was fed: the pending block
|
|
246
|
-
* with `secureZero`, and the hash value and message schedule, which are words
|
|
247
|
-
* `secureZero` does not take, with ordinary stores. Those stand because the
|
|
248
|
-
* hasher stays reachable for the next `begin`. The hasher is left finished, so
|
|
249
|
-
* that feeding it before it is started again panics.
|
|
250
|
-
*/
|
|
251
|
-
const hmacWipeSha256 = (h: Sha256): void => {
|
|
252
|
-
secureZero(h.block)
|
|
253
|
-
const state: u32[] = h.state
|
|
254
|
-
for (let i: i32 = 0; i < toI32(state.length); i += 1) {
|
|
255
|
-
state[i] = toU32(0)
|
|
256
|
-
}
|
|
257
|
-
const schedule: u32[] = h.schedule
|
|
258
|
-
for (let i: i32 = 0; i < toI32(schedule.length); i += 1) {
|
|
259
|
-
schedule[i] = toU32(0)
|
|
260
|
-
}
|
|
261
|
-
h.fill = 0
|
|
262
|
-
h.total = 0
|
|
263
|
-
h.finished = true
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/** `hmacWipeSha256` for SHA-384. */
|
|
267
|
-
const hmacWipeSha384 = (h: Sha384): void => {
|
|
268
|
-
secureZero(h.engine.block)
|
|
269
|
-
const state: u64[] = h.engine.state
|
|
270
|
-
for (let i: i32 = 0; i < toI32(state.length); i += 1) {
|
|
271
|
-
state[i] = toU64(0)
|
|
272
|
-
}
|
|
273
|
-
const schedule: u64[] = h.engine.schedule
|
|
274
|
-
for (let i: i32 = 0; i < toI32(schedule.length); i += 1) {
|
|
275
|
-
schedule[i] = toU64(0)
|
|
276
|
-
}
|
|
277
|
-
h.engine.filled = 0
|
|
278
|
-
h.engine.count = toU64(0)
|
|
279
|
-
h.engine.finished = true
|
|
280
|
-
}
|
|
281
|
-
|
|
282
466
|
/** Whether `[off, off + len)` is a window inside an array of `length` elements. */
|
|
283
467
|
const hmacWindowFits = (length: i32, off: i32, len: i32): boolean =>
|
|
284
468
|
off >= 0 && len >= 0 && off <= length - len
|
|
@@ -346,6 +530,10 @@ export class HmacSha256Scratch {
|
|
|
346
530
|
* stored to the arena analysis.
|
|
347
531
|
*/
|
|
348
532
|
keyBlocks(key: u8[], off: i32, len: i32): void {
|
|
533
|
+
// Starting a hasher again copies only the live part of `fresh`, so the
|
|
534
|
+
// last computation's block and schedule are wiped first (K1-7).
|
|
535
|
+
hmacWipeSha256(this.inner)
|
|
536
|
+
hmacWipeSha256(this.outer)
|
|
349
537
|
hmacPadInto(this.pad, key, off, len, HMAC_IPAD)
|
|
350
538
|
hmacCopySha256(this.fresh, this.inner)
|
|
351
539
|
this.inner.update(this.pad, HMAC_FROM, SHA256_BLOCK)
|
|
@@ -434,6 +622,10 @@ export class HmacSha384Scratch {
|
|
|
434
622
|
* stored to the arena analysis.
|
|
435
623
|
*/
|
|
436
624
|
keyBlocks(key: u8[], off: i32, len: i32): void {
|
|
625
|
+
// Starting a hasher again copies only the live part of `fresh`, so the
|
|
626
|
+
// last computation's block and schedule are wiped first (K1-7).
|
|
627
|
+
hmacWipeSha384(this.inner)
|
|
628
|
+
hmacWipeSha384(this.outer)
|
|
437
629
|
hmacPadInto(this.pad, key, off, len, HMAC_IPAD)
|
|
438
630
|
hmacCopySha384(this.fresh, this.inner)
|
|
439
631
|
this.inner.update(this.pad, HMAC_FROM, SHA512_BLOCK)
|