@amritk/nish-x86_64-linux 0.17.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 +231 -20
- 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 +203 -0
- package/runtime/runtime-wasm.c +16 -3
- package/runtime/runtime.c +89 -23
- package/runtime/shim.mjs +71 -1
- package/scripts/build.sh +225 -20
- package/std/README.md +86 -55
- 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 +1376 -42
- 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 +1412 -70
- 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 +231 -45
- package/std/net/http3.ts +187 -28
- package/std/net/prefork.ts +412 -0
- package/std/net/quic-conn-params.ts +86 -16
- package/std/net/quic-listener.ts +576 -219
- package/std/net/quic-packet.ts +443 -58
- package/std/net/quic-recovery.ts +361 -30
- package/std/net/quic-stream.ts +434 -28
- package/std/net/quic.ts +922 -206
- 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 +204 -57
- package/std/net/tls.ts +1132 -305
- package/std/net/url.ts +571 -0
- package/std/random.ts +94 -0
- package/std/text.ts +77 -0
- package/std/threads.ts +438 -14
package/std/crypto/hkdf.ts
CHANGED
|
@@ -65,6 +65,29 @@
|
|
|
65
65
|
* length other than 32 or 48, or an output window outside its array, is the
|
|
66
66
|
* caller's bug and panics.
|
|
67
67
|
*
|
|
68
|
+
* **What the key reaches is wiped** (CLAUDE.md, "Security"). Every HMAC on
|
|
69
|
+
* the way wipes its key blocks and hashers (`nish/crypto/hmac`), and `expand`
|
|
70
|
+
* wipes each T(i) once the next has replaced it, and the last one before it
|
|
71
|
+
* returns. The PRK `extract` answers and the output `expand` answers are the
|
|
72
|
+
* caller's. A caller that holds its input keying material as a `Secret<u8[]>`
|
|
73
|
+
* (`nish:secret`) derives with `hkdfSha256Secret` or `hkdfSha384Secret`,
|
|
74
|
+
* which run both steps, hand the output back as a `Secret` and wipe the PRK
|
|
75
|
+
* between them, or with the `*Secret` twins of each step, HKDF-Expand-Label's
|
|
76
|
+
* among them:
|
|
77
|
+
*
|
|
78
|
+
* const okm: Secret<u8[]> | null = hkdfSha256Secret(salt, ikm, info, 42);
|
|
79
|
+
* const key: Secret<u8[]> = hkdfExpandLabelSha256Secret(prk, "key", context, 16);
|
|
80
|
+
*
|
|
81
|
+
* A caller that already holds the destination — a field of a long-lived
|
|
82
|
+
* object, say, that keeps one traffic secret and ratchets it — derives into
|
|
83
|
+
* it with the `*Held` forms, which fill as many bytes as the `Secret` holds,
|
|
84
|
+
* in place, and wipe the plain output they copied from. The destination may
|
|
85
|
+
* be the PRK itself; `hkdfExpandLabelHeldInto` writes a plain window instead,
|
|
86
|
+
* for output that is plain by design, a record layer's AEAD key and IV:
|
|
87
|
+
*
|
|
88
|
+
* hkdfExpandLabelSha256Held(secret, secret, "traffic upd", none);
|
|
89
|
+
* hkdfExpandLabelHeldInto(32, secret, "key", none, key, 0, 16);
|
|
90
|
+
*
|
|
68
91
|
* Written from RFC 5869 and RFC 8446 §7.1, not ported from another
|
|
69
92
|
* implementation.
|
|
70
93
|
*/
|
|
@@ -78,6 +101,7 @@ import {
|
|
|
78
101
|
} from "nish/crypto/hmac"
|
|
79
102
|
import { SHA256_SIZE } from "nish/crypto/sha256"
|
|
80
103
|
import { SHA384_SIZE } from "nish/crypto/sha512"
|
|
104
|
+
import { Secret, expose, exposeWith, secret, wipe } from "nish:secret"
|
|
81
105
|
|
|
82
106
|
/** The largest block counter, and so the most blocks `expand` can make (RFC 5869 §2.3). */
|
|
83
107
|
const HKDF_MAX_BLOCKS: i32 = 255
|
|
@@ -145,10 +169,13 @@ export const hkdfExpandSha256 = (prk: u8[], info: u8[], length: i32): u8[] | nul
|
|
|
145
169
|
mac.update(info, HKDF_FROM, toI32(info.length))
|
|
146
170
|
counter[0] = toU8(i)
|
|
147
171
|
mac.update(counter, HKDF_FROM, counterLength)
|
|
148
|
-
|
|
172
|
+
const block: u8[] = mac.digest()
|
|
173
|
+
wipe(previous)
|
|
174
|
+
previous = block
|
|
149
175
|
at = hkdfAppend(out, at, previous)
|
|
150
176
|
i += 1
|
|
151
177
|
}
|
|
178
|
+
wipe(previous)
|
|
152
179
|
return out
|
|
153
180
|
}
|
|
154
181
|
|
|
@@ -179,13 +206,115 @@ export const hkdfExpandSha384 = (prk: u8[], info: u8[], length: i32): u8[] | nul
|
|
|
179
206
|
mac.update(info, HKDF_FROM, toI32(info.length))
|
|
180
207
|
counter[0] = toU8(i)
|
|
181
208
|
mac.update(counter, HKDF_FROM, counterLength)
|
|
182
|
-
|
|
209
|
+
const block: u8[] = mac.digest()
|
|
210
|
+
wipe(previous)
|
|
211
|
+
previous = block
|
|
183
212
|
at = hkdfAppend(out, at, previous)
|
|
184
213
|
i += 1
|
|
185
214
|
}
|
|
215
|
+
wipe(previous)
|
|
186
216
|
return out
|
|
187
217
|
}
|
|
188
218
|
|
|
219
|
+
// ---- Keys held as `Secret`s ------------------------------------------------
|
|
220
|
+
//
|
|
221
|
+
// The `*Secret` functions the module docs name: each reads its key only inside
|
|
222
|
+
// `exposeWith`, and hands the PRK and the output back as `Secret`s.
|
|
223
|
+
|
|
224
|
+
/** What `expand` needs besides the PRK, as one argument, since `exposeWith` hands on only one. */
|
|
225
|
+
interface HkdfExpandRequest {
|
|
226
|
+
info: u8[]
|
|
227
|
+
length: i32
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* HKDF-Extract with HMAC-SHA-256 on the plain IKM, for `exposeWith` to run.
|
|
232
|
+
* It keys HMAC with `salt` itself rather than through `hkdfSalt`, whose answer
|
|
233
|
+
* may be `salt`, because the checker does not credit that path with leaving
|
|
234
|
+
* `salt` unwritten (NL2450). The PRK is the same: an empty salt is padded to
|
|
235
|
+
* the block with zeros, as the HashLen zeros of §2.2 would be.
|
|
236
|
+
*/
|
|
237
|
+
const hkdfExtractSha256Exposed = (ikm: u8[], salt: u8[]): u8[] => hmacSha256(salt, ikm)
|
|
238
|
+
|
|
239
|
+
/** HKDF-Extract with HMAC-SHA-384 on the plain IKM, for `exposeWith` to run, as the SHA-256 one is. */
|
|
240
|
+
const hkdfExtractSha384Exposed = (ikm: u8[], salt: u8[]): u8[] => hmacSha384(salt, ikm)
|
|
241
|
+
|
|
242
|
+
/** HKDF-Expand with HMAC-SHA-256 on the plain PRK, for `exposeWith` to run. */
|
|
243
|
+
const hkdfExpandSha256Exposed = (prk: u8[], request: HkdfExpandRequest): u8[] | null =>
|
|
244
|
+
hkdfExpandSha256(prk, request.info, request.length)
|
|
245
|
+
|
|
246
|
+
/** HKDF-Expand with HMAC-SHA-384 on the plain PRK, for `exposeWith` to run. */
|
|
247
|
+
const hkdfExpandSha384Exposed = (prk: u8[], request: HkdfExpandRequest): u8[] | null =>
|
|
248
|
+
hkdfExpandSha384(prk, request.info, request.length)
|
|
249
|
+
|
|
250
|
+
/** `hkdfExtractSha256` on input keying material held as a `Secret`: the 32-byte PRK, held as one. */
|
|
251
|
+
export const hkdfExtractSha256Secret = (salt: u8[], ikm: Secret<u8[]>): Secret<u8[]> => {
|
|
252
|
+
const prk: u8[] = exposeWith(ikm, salt, hkdfExtractSha256Exposed)
|
|
253
|
+
return secret(prk)
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** `hkdfExtractSha384` on input keying material held as a `Secret`: the 48-byte PRK, held as one. */
|
|
257
|
+
export const hkdfExtractSha384Secret = (salt: u8[], ikm: Secret<u8[]>): Secret<u8[]> => {
|
|
258
|
+
const prk: u8[] = exposeWith(ikm, salt, hkdfExtractSha384Exposed)
|
|
259
|
+
return secret(prk)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* `hkdfExpandSha256` on a PRK held as a `Secret`: the output keying material,
|
|
264
|
+
* held as one, or `null` where `hkdfExpandSha256` answers `null`.
|
|
265
|
+
*/
|
|
266
|
+
export const hkdfExpandSha256Secret = (prk: Secret<u8[]>, info: u8[], length: i32): Secret<u8[]> | null => {
|
|
267
|
+
const request: HkdfExpandRequest = { info: info, length: length }
|
|
268
|
+
const okm: u8[] | null = exposeWith(prk, request, hkdfExpandSha256Exposed)
|
|
269
|
+
if (okm === null) {
|
|
270
|
+
return null
|
|
271
|
+
}
|
|
272
|
+
return secret(okm)
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* `hkdfExpandSha384` on a PRK held as a `Secret`: the output keying material,
|
|
277
|
+
* held as one, or `null` where `hkdfExpandSha384` answers `null`.
|
|
278
|
+
*/
|
|
279
|
+
export const hkdfExpandSha384Secret = (prk: Secret<u8[]>, info: u8[], length: i32): Secret<u8[]> | null => {
|
|
280
|
+
const request: HkdfExpandRequest = { info: info, length: length }
|
|
281
|
+
const okm: u8[] | null = exposeWith(prk, request, hkdfExpandSha384Exposed)
|
|
282
|
+
if (okm === null) {
|
|
283
|
+
return null
|
|
284
|
+
}
|
|
285
|
+
return secret(okm)
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* HKDF with HMAC-SHA-256, both steps (RFC 5869 §2): `length` bytes from `salt`,
|
|
290
|
+
* the `Secret` input keying material and `info`, held as a `Secret`, or `null`
|
|
291
|
+
* where `hkdfExpandSha256` answers `null`. The PRK is wiped before it returns.
|
|
292
|
+
*/
|
|
293
|
+
export const hkdfSha256Secret = (
|
|
294
|
+
salt: u8[],
|
|
295
|
+
ikm: Secret<u8[]>,
|
|
296
|
+
info: u8[],
|
|
297
|
+
length: i32
|
|
298
|
+
): Secret<u8[]> | null => {
|
|
299
|
+
const prk: Secret<u8[]> = hkdfExtractSha256Secret(salt, ikm)
|
|
300
|
+
const okm: Secret<u8[]> | null = hkdfExpandSha256Secret(prk, info, length)
|
|
301
|
+
wipe(prk)
|
|
302
|
+
return okm
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/** `hkdfSha256Secret` with HMAC-SHA-384: the PRK is 48 bytes, and wiped before it returns. */
|
|
306
|
+
export const hkdfSha384Secret = (
|
|
307
|
+
salt: u8[],
|
|
308
|
+
ikm: Secret<u8[]>,
|
|
309
|
+
info: u8[],
|
|
310
|
+
length: i32
|
|
311
|
+
): Secret<u8[]> | null => {
|
|
312
|
+
const prk: Secret<u8[]> = hkdfExtractSha384Secret(salt, ikm)
|
|
313
|
+
const okm: Secret<u8[]> | null = hkdfExpandSha384Secret(prk, info, length)
|
|
314
|
+
wipe(prk)
|
|
315
|
+
return okm
|
|
316
|
+
}
|
|
317
|
+
|
|
189
318
|
/**
|
|
190
319
|
* The `HkdfLabel` struct of RFC 8446 §7.1, the `info` HKDF-Expand-Label hands
|
|
191
320
|
* to `expand`, or a panic naming `caller` when `length`, `label` or `context`
|
|
@@ -212,6 +341,13 @@ const hkdfLabel = (caller: string, label: string, context: u8[], length: i32): u
|
|
|
212
341
|
out[1] = toU8(length & 0xff)
|
|
213
342
|
out[2] = toU8(fullLength)
|
|
214
343
|
for (let k: i32 = 0; k < fullLength; k += 1) {
|
|
344
|
+
// `out` is longer than `3 + fullLength`, but the proof cannot read that
|
|
345
|
+
// off the sum it was allocated with; this test is what proves the store.
|
|
346
|
+
// It sits in the body rather than the loop condition, which stays the
|
|
347
|
+
// plain `k < fullLength` the attribute pass counts as a bounded loop.
|
|
348
|
+
if (3 + k >= toI32(out.length)) {
|
|
349
|
+
panic("hkdfLabel: the label overran its buffer")
|
|
350
|
+
}
|
|
215
351
|
out[3 + k] = toU8(toI32(full.charCodeAt(k)))
|
|
216
352
|
}
|
|
217
353
|
out[3 + fullLength] = toU8(contextLength)
|
|
@@ -221,12 +357,12 @@ const hkdfLabel = (caller: string, label: string, context: u8[], length: i32): u
|
|
|
221
357
|
|
|
222
358
|
/**
|
|
223
359
|
* HKDF-Expand-Label with HMAC-SHA-256 (RFC 8446 §7.1): `length` bytes from
|
|
224
|
-
* `
|
|
360
|
+
* `prk` (RFC 8446's Secret), `"tls13 " + label` and `context`. Panics on an argument out of the
|
|
225
361
|
* range the module docs give, a secret shorter than 32 bytes among them.
|
|
226
362
|
*/
|
|
227
|
-
export const hkdfExpandLabelSha256 = (
|
|
363
|
+
export const hkdfExpandLabelSha256 = (prk: u8[], label: string, context: u8[], length: i32): u8[] => {
|
|
228
364
|
const okm: u8[] | null = hkdfExpandSha256(
|
|
229
|
-
|
|
365
|
+
prk,
|
|
230
366
|
hkdfLabel("hkdfExpandLabelSha256", label, context, length),
|
|
231
367
|
length
|
|
232
368
|
)
|
|
@@ -238,12 +374,12 @@ export const hkdfExpandLabelSha256 = (secret: u8[], label: string, context: u8[]
|
|
|
238
374
|
|
|
239
375
|
/**
|
|
240
376
|
* HKDF-Expand-Label with HMAC-SHA-384 (RFC 8446 §7.1): `length` bytes from
|
|
241
|
-
* `
|
|
377
|
+
* `prk` (RFC 8446's Secret), `"tls13 " + label` and `context`. Panics on an argument out of the
|
|
242
378
|
* range the module docs give, a secret shorter than 48 bytes among them.
|
|
243
379
|
*/
|
|
244
|
-
export const hkdfExpandLabelSha384 = (
|
|
380
|
+
export const hkdfExpandLabelSha384 = (prk: u8[], label: string, context: u8[], length: i32): u8[] => {
|
|
245
381
|
const okm: u8[] | null = hkdfExpandSha384(
|
|
246
|
-
|
|
382
|
+
prk,
|
|
247
383
|
hkdfLabel("hkdfExpandLabelSha384", label, context, length),
|
|
248
384
|
length
|
|
249
385
|
)
|
|
@@ -253,6 +389,47 @@ export const hkdfExpandLabelSha384 = (secret: u8[], label: string, context: u8[]
|
|
|
253
389
|
return okm
|
|
254
390
|
}
|
|
255
391
|
|
|
392
|
+
/**
|
|
393
|
+
* `hkdfExpandLabelSha256` on a secret held as a `Secret`: the `length` bytes,
|
|
394
|
+
* held as one. The label is built outside `expose`, since the label and the
|
|
395
|
+
* context are not secret, and the PRK is read only inside it. Panics as
|
|
396
|
+
* `hkdfExpandLabelSha256` does.
|
|
397
|
+
*/
|
|
398
|
+
export const hkdfExpandLabelSha256Secret = (
|
|
399
|
+
prk: Secret<u8[]>,
|
|
400
|
+
label: string,
|
|
401
|
+
context: u8[],
|
|
402
|
+
length: i32
|
|
403
|
+
): Secret<u8[]> => {
|
|
404
|
+
const okm: Secret<u8[]> | null = hkdfExpandSha256Secret(
|
|
405
|
+
prk,
|
|
406
|
+
hkdfLabel("hkdfExpandLabelSha256Secret", label, context, length),
|
|
407
|
+
length
|
|
408
|
+
)
|
|
409
|
+
if (okm === null) {
|
|
410
|
+
panic("hkdfExpandLabelSha256Secret: a secret shorter than 32 bytes")
|
|
411
|
+
}
|
|
412
|
+
return okm
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/** `hkdfExpandLabelSha256Secret` with HMAC-SHA-384: panics as `hkdfExpandLabelSha384` does. */
|
|
416
|
+
export const hkdfExpandLabelSha384Secret = (
|
|
417
|
+
prk: Secret<u8[]>,
|
|
418
|
+
label: string,
|
|
419
|
+
context: u8[],
|
|
420
|
+
length: i32
|
|
421
|
+
): Secret<u8[]> => {
|
|
422
|
+
const okm: Secret<u8[]> | null = hkdfExpandSha384Secret(
|
|
423
|
+
prk,
|
|
424
|
+
hkdfLabel("hkdfExpandLabelSha384Secret", label, context, length),
|
|
425
|
+
length
|
|
426
|
+
)
|
|
427
|
+
if (okm === null) {
|
|
428
|
+
panic("hkdfExpandLabelSha384Secret: a secret shorter than 48 bytes")
|
|
429
|
+
}
|
|
430
|
+
return okm
|
|
431
|
+
}
|
|
432
|
+
|
|
256
433
|
// ---- Caller-owned scratch ----------------------------------------------------
|
|
257
434
|
|
|
258
435
|
/** The longest `HkdfLabel`: two length bytes, `label<7..255>` and `context<0..255>`, each with its length byte. */
|
|
@@ -435,7 +612,7 @@ export const hkdfExpandInto = (
|
|
|
435
612
|
|
|
436
613
|
/**
|
|
437
614
|
* HKDF-Expand-Label (RFC 8446 §7.1) over the hash `hashLength` names: `length`
|
|
438
|
-
* bytes from `
|
|
615
|
+
* bytes from `prk` (RFC 8446's Secret), `"tls13 " + label` and the context
|
|
439
616
|
* `context[contextOff .. contextOff + contextLen)`, written at `out[at]`. It
|
|
440
617
|
* panics where `hkdfExpandLabelSha256` does — a length outside 0 to 255, a
|
|
441
618
|
* label empty or past 249 bytes, a context past 255, a secret shorter than
|
|
@@ -444,7 +621,7 @@ export const hkdfExpandInto = (
|
|
|
444
621
|
export const hkdfExpandLabelInto = (
|
|
445
622
|
s: HkdfScratch,
|
|
446
623
|
hashLength: i32,
|
|
447
|
-
|
|
624
|
+
prk: u8[],
|
|
448
625
|
label: string,
|
|
449
626
|
context: u8[],
|
|
450
627
|
contextOff: i32,
|
|
@@ -468,7 +645,7 @@ export const hkdfExpandLabelInto = (
|
|
|
468
645
|
) {
|
|
469
646
|
panic("hkdfExpandLabelInto: the context window is outside its array or longer than 255 bytes")
|
|
470
647
|
}
|
|
471
|
-
if (toI32(
|
|
648
|
+
if (toI32(prk.length) < hashLength) {
|
|
472
649
|
panic("hkdfExpandLabelInto: a secret shorter than HashLen")
|
|
473
650
|
}
|
|
474
651
|
hkdfCheckOutput("hkdfExpandLabelInto", out, at, length)
|
|
@@ -491,5 +668,120 @@ export const hkdfExpandLabelInto = (
|
|
|
491
668
|
for (let k: i32 = 0; k < contextLen && contextAt + 1 + k < toI32(info.length); k += 1) {
|
|
492
669
|
info[contextAt + 1 + k] = context[contextOff + k]
|
|
493
670
|
}
|
|
494
|
-
hkdfExpandWindow(s, hashLength,
|
|
671
|
+
hkdfExpandWindow(s, hashLength, prk, info, contextAt + 1 + contextLen, out, at, length)
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// ---- From and into a held `Secret` -----------------------------------------
|
|
675
|
+
//
|
|
676
|
+
// The `*Held` forms derive from a `Secret<u8[]>` the caller already holds, and
|
|
677
|
+
// into one, overwriting its bytes in place, so a key that lives in one place
|
|
678
|
+
// for a connection's life is never handed out as a fresh `Secret`. The output
|
|
679
|
+
// is derived plain inside `exposeWith` of the PRK, by the function the
|
|
680
|
+
// `*Secret` forms run, copied where it goes, and wiped. None of this opens a
|
|
681
|
+
// `using arena()` block: every hasher's constructor stores the arrays it
|
|
682
|
+
// allocates into its fields, which the block refuses (NL2424), and a scratch
|
|
683
|
+
// made before the block could be neither written nor wiped inside `exposeWith`
|
|
684
|
+
// (NL2450, and `secureZero` is C). The function's own scope reclaims the
|
|
685
|
+
// temporaries instead.
|
|
686
|
+
|
|
687
|
+
/** The length of the bytes a `Secret` holds, which is public, for `expose` to read. */
|
|
688
|
+
const hkdfHeldLength = (bytes: u8[]): i32 => toI32(bytes.length)
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* HKDF-Expand-Label of the held `prk` over the hash `hashLength` names: the
|
|
692
|
+
* `length` bytes, plain, for the caller to copy and wipe. Panics naming
|
|
693
|
+
* `caller` where `hkdfExpandLabelSha256` does.
|
|
694
|
+
*/
|
|
695
|
+
const hkdfHeldDerive = (
|
|
696
|
+
caller: string,
|
|
697
|
+
hashLength: i32,
|
|
698
|
+
prk: Secret<u8[]>,
|
|
699
|
+
label: string,
|
|
700
|
+
context: u8[],
|
|
701
|
+
length: i32
|
|
702
|
+
): u8[] => {
|
|
703
|
+
hkdfCheckHash(caller, hashLength)
|
|
704
|
+
const request: HkdfExpandRequest = { info: hkdfLabel(caller, label, context, length), length: length }
|
|
705
|
+
const okm: u8[] | null =
|
|
706
|
+
hashLength === SHA256_SIZE
|
|
707
|
+
? exposeWith(prk, request, hkdfExpandSha256Exposed)
|
|
708
|
+
: exposeWith(prk, request, hkdfExpandSha384Exposed)
|
|
709
|
+
if (okm === null) {
|
|
710
|
+
panic(
|
|
711
|
+
`${caller}: a secret shorter than ${hashLength} bytes, or more than ${255 * hashLength} bytes asked`
|
|
712
|
+
)
|
|
713
|
+
}
|
|
714
|
+
return okm
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
/**
|
|
718
|
+
* Overwrites the bytes a `Secret` holds with `okm`, for `exposeWith` to run on
|
|
719
|
+
* the destination: it writes the value it is shown, never its argument.
|
|
720
|
+
*/
|
|
721
|
+
const hkdfHeldCopy = (held: u8[], okm: u8[]): void => {
|
|
722
|
+
for (let k: i32 = 0; k < toI32(held.length) && k < toI32(okm.length); k++) {
|
|
723
|
+
held[k] = okm[k]
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/** Derives into `dst`, as many bytes as it holds, for the two exported forms. */
|
|
728
|
+
const hkdfHeld = (
|
|
729
|
+
caller: string,
|
|
730
|
+
hashLength: i32,
|
|
731
|
+
dst: Secret<u8[]>,
|
|
732
|
+
prk: Secret<u8[]>,
|
|
733
|
+
label: string,
|
|
734
|
+
context: u8[]
|
|
735
|
+
): void => {
|
|
736
|
+
const okm: u8[] = hkdfHeldDerive(caller, hashLength, prk, label, context, expose(dst, hkdfHeldLength))
|
|
737
|
+
exposeWith(dst, okm, hkdfHeldCopy)
|
|
738
|
+
wipe(okm)
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
/**
|
|
742
|
+
* `hkdfExpandLabelSha256Secret` into `dst`: as many bytes as `dst` holds,
|
|
743
|
+
* derived from `prk`, the label and `context` and written over `dst`'s in
|
|
744
|
+
* place. `dst` may be `prk` itself, since the output is whole before it is
|
|
745
|
+
* copied: that is a ratchet. Panics as `hkdfExpandLabelSha256` does.
|
|
746
|
+
*/
|
|
747
|
+
export const hkdfExpandLabelSha256Held = (
|
|
748
|
+
dst: Secret<u8[]>,
|
|
749
|
+
prk: Secret<u8[]>,
|
|
750
|
+
label: string,
|
|
751
|
+
context: u8[]
|
|
752
|
+
): void => {
|
|
753
|
+
hkdfHeld("hkdfExpandLabelSha256Held", SHA256_SIZE, dst, prk, label, context)
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
/** `hkdfExpandLabelSha256Held` with HMAC-SHA-384: panics as `hkdfExpandLabelSha384` does. */
|
|
757
|
+
export const hkdfExpandLabelSha384Held = (
|
|
758
|
+
dst: Secret<u8[]>,
|
|
759
|
+
prk: Secret<u8[]>,
|
|
760
|
+
label: string,
|
|
761
|
+
context: u8[]
|
|
762
|
+
): void => {
|
|
763
|
+
hkdfHeld("hkdfExpandLabelSha384Held", SHA384_SIZE, dst, prk, label, context)
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
/**
|
|
767
|
+
* HKDF-Expand-Label of the held `prk` over the hash `hashLength` names into a
|
|
768
|
+
* plain array: `length` bytes written at `out[at]`. This is for output that is
|
|
769
|
+
* kept plain by design, a record layer's AEAD key and IV, say, which live in
|
|
770
|
+
* the arrays the cipher reads. Panics as `hkdfExpandLabelInto` does.
|
|
771
|
+
*/
|
|
772
|
+
export const hkdfExpandLabelHeldInto = (
|
|
773
|
+
hashLength: i32,
|
|
774
|
+
prk: Secret<u8[]>,
|
|
775
|
+
label: string,
|
|
776
|
+
context: u8[],
|
|
777
|
+
out: u8[],
|
|
778
|
+
at: i32,
|
|
779
|
+
length: i32
|
|
780
|
+
): void => {
|
|
781
|
+
hkdfCheckOutput("hkdfExpandLabelHeldInto", out, at, length)
|
|
782
|
+
const okm: u8[] = hkdfHeldDerive("hkdfExpandLabelHeldInto", hashLength, prk, label, context, length)
|
|
783
|
+
for (let k: i32 = 0; k < length && k < toI32(okm.length); k++) {
|
|
784
|
+
out[at + k] = okm[k]
|
|
785
|
+
}
|
|
786
|
+
wipe(okm)
|
|
495
787
|
}
|