@amritk/nish-x86_64-linux 0.16.0 → 0.18.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.
Files changed (58) hide show
  1. package/INSTALL.md +43 -34
  2. package/bin/nish +0 -0
  3. package/package.json +1 -1
  4. package/runtime/nish.d.ts +117 -8
  5. package/runtime/nish.h +50 -13
  6. package/runtime/nish.mjs +71 -7
  7. package/runtime/runtime-host.c +43 -24
  8. package/runtime/runtime-net.c +57 -10
  9. package/runtime/runtime-os.c +62 -20
  10. package/runtime/runtime-simd.c +203 -0
  11. package/runtime/runtime-wasm.c +12 -0
  12. package/runtime/runtime.c +66 -18
  13. package/runtime/shim.mjs +114 -5
  14. package/scripts/build.sh +14 -12
  15. package/std/README.md +168 -36
  16. package/std/crypto/aes.ts +51 -8
  17. package/std/crypto/base64url.ts +25 -12
  18. package/std/crypto/chacha20poly1305.ts +43 -29
  19. package/std/crypto/ct.ts +6 -1
  20. package/std/crypto/hkdf.ts +364 -3
  21. package/std/crypto/hmac.ts +307 -7
  22. package/std/crypto/p256.ts +618 -34
  23. package/std/crypto/sha1.ts +147 -0
  24. package/std/crypto/sha256.ts +3 -2
  25. package/std/crypto/x25519.ts +88 -36
  26. package/std/crypto/x509.ts +130 -47
  27. package/std/json.ts +297 -41
  28. package/std/net/hpack.ts +1094 -0
  29. package/std/net/http-fields.ts +604 -0
  30. package/std/net/http1-server.ts +1389 -0
  31. package/std/net/http1.ts +1492 -0
  32. package/std/net/http2-frame.ts +745 -0
  33. package/std/net/http2-tls.ts +216 -0
  34. package/std/net/http2.ts +1433 -0
  35. package/std/net/http3-frame.ts +457 -0
  36. package/std/net/http3-server.ts +911 -0
  37. package/std/net/http3.ts +2145 -0
  38. package/std/net/qpack.ts +1163 -0
  39. package/std/net/quic-conn-ack.ts +206 -0
  40. package/std/net/quic-conn-cid.ts +425 -0
  41. package/std/net/quic-conn-params.ts +462 -0
  42. package/std/net/quic-datagram.ts +130 -0
  43. package/std/net/quic-frame.ts +1206 -0
  44. package/std/net/quic-listener.ts +929 -0
  45. package/std/net/quic-packet.ts +1698 -0
  46. package/std/net/quic-recovery.ts +849 -0
  47. package/std/net/quic-stream.ts +1609 -0
  48. package/std/net/quic.ts +3578 -0
  49. package/std/net/tls/codec.ts +1089 -0
  50. package/std/net/tls/record-server.ts +1173 -0
  51. package/std/net/tls/record.ts +621 -0
  52. package/std/net/tls/schedule.ts +429 -0
  53. package/std/net/tls-tcp.ts +414 -0
  54. package/std/net/tls.ts +1437 -0
  55. package/std/net/websocket.ts +823 -0
  56. package/std/net/webtransport.ts +1334 -0
  57. package/std/secret.ts +62 -0
  58. package/std/text.ts +77 -0
@@ -0,0 +1,429 @@
1
+ /**
2
+ * `nish/net/tls/schedule` — the TLS 1.3 key schedule and transcript hash
3
+ * (RFC 8446 §4.4.1, §7.1, §7.3) for the three cipher suites `nish/net/tls`
4
+ * negotiates.
5
+ *
6
+ * The schedule is a chain of HKDF steps over the suite's hash, SHA-256 for
7
+ * `TLS_AES_128_GCM_SHA256` and `TLS_CHACHA20_POLY1305_SHA256` and SHA-384 for
8
+ * `TLS_AES_256_GCM_SHA384`. Without a PSK it runs:
9
+ *
10
+ * early = HKDF-Extract(0, 0)
11
+ * handshake = HKDF-Extract(Derive-Secret(early, "derived", ""), ECDHE)
12
+ * c/s hs traffic = Derive-Secret(handshake, "c hs traffic" / "s hs traffic", CH..SH)
13
+ * master = HKDF-Extract(Derive-Secret(handshake, "derived", ""), 0)
14
+ * c/s ap traffic, exporter = Derive-Secret(master, "c ap traffic" / "s ap traffic" / "exp master", CH..server Finished)
15
+ *
16
+ * Every function takes the hash length (32 or 48) rather than a suite, because
17
+ * that is all that changes between them; `tlsSuiteHashLength` turns a suite
18
+ * into one. The traffic key and IV are here too, because T2's record layer
19
+ * needs them and RFC 8448 prints them beside the secrets.
20
+ *
21
+ * **In place.** Each step also has an `*Into` form that computes in an
22
+ * `HkdfScratch` the caller owns and writes into the caller's array, and
23
+ * `TlsTranscript` resets and reads its hash in hashers it allocated once, so
24
+ * a handshake that keeps its state in a connection slot can run the whole
25
+ * schedule inside `using a = arena()` blocks and leave the arena where it was
26
+ * (TLS-3 in `docs/security/tls.md`). The scratch is wiped by every step.
27
+ *
28
+ * **Secrets are not wiped.** Every function here answers or holds a secret as
29
+ * plain bytes, and each stays in arena memory until that memory is reused.
30
+ * `secureZero`, the store no optimiser removes, is on `main`, and `std/` may
31
+ * call it once a release ships it (CLAUDE.md §Security, TLS-1 in
32
+ * `docs/security/tls.md`).
33
+ *
34
+ * Written from RFC 8446, not ported from another implementation.
35
+ */
36
+ import {
37
+ HkdfScratch,
38
+ hkdfExpandLabelInto,
39
+ hkdfExpandLabelSha256,
40
+ hkdfExpandLabelSha384,
41
+ hkdfExtractInto,
42
+ hkdfExtractSha256,
43
+ hkdfExtractSha384,
44
+ } from "nish/crypto/hkdf"
45
+ import { hmacCopySha256, hmacCopySha384, hmacSha256, hmacSha384 } from "nish/crypto/hmac"
46
+ import { tlsHexInto } from "nish/net/tls/codec"
47
+ import { SHA256_SIZE, Sha256, sha256 } from "nish/crypto/sha256"
48
+ import { SHA384_SIZE, Sha384, sha384 } from "nish/crypto/sha512"
49
+
50
+ /** `TLS_AES_128_GCM_SHA256` (RFC 8446 §B.4). */
51
+ export const TLS_AES_128_GCM_SHA256: i32 = 0x1301
52
+ /** `TLS_AES_256_GCM_SHA384` (RFC 8446 §B.4). */
53
+ export const TLS_AES_256_GCM_SHA384: i32 = 0x1302
54
+ /** `TLS_CHACHA20_POLY1305_SHA256` (RFC 8446 §B.4). */
55
+ export const TLS_CHACHA20_POLY1305_SHA256: i32 = 0x1303
56
+
57
+ /** The length of every TLS 1.3 AEAD nonce, and so of every traffic IV (RFC 8446 §5.3). */
58
+ export const TLS_IV_SIZE: i32 = 12
59
+
60
+ /** A typed zero for the offsets below: a bare literal is an `f64` under `--number-mode f64`. */
61
+ const TLS_SCHEDULE_FROM: i32 = 0
62
+
63
+ /**
64
+ * The hash length of `suite`: 32 for the two SHA-256 suites, 48 for
65
+ * `TLS_AES_256_GCM_SHA384`, and 0 for any suite this module does not
66
+ * negotiate, which is how a caller tells the two apart.
67
+ */
68
+ export const tlsSuiteHashLength = (suite: i32): i32 => {
69
+ switch (suite) {
70
+ case TLS_AES_128_GCM_SHA256:
71
+ return SHA256_SIZE
72
+ case TLS_CHACHA20_POLY1305_SHA256:
73
+ return SHA256_SIZE
74
+ case TLS_AES_256_GCM_SHA384:
75
+ return SHA384_SIZE
76
+ default:
77
+ return 0
78
+ }
79
+ }
80
+
81
+ /** The AEAD key length of `suite`: 16 for AES-128-GCM, 32 for the other two, 0 for an unknown suite. */
82
+ export const tlsSuiteKeyLength = (suite: i32): i32 => {
83
+ switch (suite) {
84
+ case TLS_AES_128_GCM_SHA256:
85
+ return 16
86
+ case TLS_CHACHA20_POLY1305_SHA256:
87
+ return 32
88
+ case TLS_AES_256_GCM_SHA384:
89
+ return 32
90
+ default:
91
+ return 0
92
+ }
93
+ }
94
+
95
+ /**
96
+ * HKDF-Expand-Label (RFC 8446 §7.1) over the hash `hashLength` names: `length`
97
+ * bytes from `secret`, the label (without its `"tls13 "` prefix, which is
98
+ * added) and `context`.
99
+ */
100
+ export const tlsExpandLabel = (
101
+ hashLength: i32,
102
+ secret: u8[],
103
+ label: string,
104
+ context: u8[],
105
+ length: i32
106
+ ): u8[] =>
107
+ hashLength === SHA384_SIZE
108
+ ? hkdfExpandLabelSha384(secret, label, context, length)
109
+ : hkdfExpandLabelSha256(secret, label, context, length)
110
+
111
+ /** HKDF-Extract (RFC 5869 §2.2) over the hash `hashLength` names; an empty salt is HashLen zeros. */
112
+ export const tlsExtract = (hashLength: i32, salt: u8[], ikm: u8[]): u8[] =>
113
+ hashLength === SHA384_SIZE ? hkdfExtractSha384(salt, ikm) : hkdfExtractSha256(salt, ikm)
114
+
115
+ /** The hash of the empty string, the transcript `Derive-Secret(., "derived", "")` hashes. */
116
+ export const tlsEmptyHash = (hashLength: i32): u8[] => {
117
+ const none: u8[] = []
118
+ return hashLength === SHA384_SIZE ? sha384(none) : sha256(none)
119
+ }
120
+
121
+ /** Derive-Secret (RFC 8446 §7.1): Expand-Label of `secret` with `label` and a transcript hash, HashLen bytes. */
122
+ export const tlsDeriveSecret = (hashLength: i32, secret: u8[], label: string, transcriptHash: u8[]): u8[] =>
123
+ tlsExpandLabel(hashLength, secret, label, transcriptHash, hashLength)
124
+
125
+ /** The early secret with no PSK: HKDF-Extract of HashLen zeros under a zero salt (RFC 8446 §7.1). */
126
+ export const tlsEarlySecret = (hashLength: i32): u8[] => {
127
+ const none: u8[] = []
128
+ return tlsExtract(hashLength, none, new Array<u8>(hashLength))
129
+ }
130
+
131
+ /** The handshake secret: HKDF-Extract of the ECDHE secret under `Derive-Secret(early, "derived", "")`. */
132
+ export const tlsHandshakeSecret = (hashLength: i32, earlySecret: u8[], ecdhe: u8[]): u8[] =>
133
+ tlsExtract(hashLength, tlsDeriveSecret(hashLength, earlySecret, "derived", tlsEmptyHash(hashLength)), ecdhe)
134
+
135
+ /** The master secret: HKDF-Extract of HashLen zeros under `Derive-Secret(handshake, "derived", "")`. */
136
+ export const tlsMasterSecret = (hashLength: i32, handshakeSecret: u8[]): u8[] =>
137
+ tlsExtract(
138
+ hashLength,
139
+ tlsDeriveSecret(hashLength, handshakeSecret, "derived", tlsEmptyHash(hashLength)),
140
+ new Array<u8>(hashLength)
141
+ )
142
+
143
+ /**
144
+ * A Finished message's `verify_data` (RFC 8446 §4.4.4): the HMAC of the
145
+ * transcript hash under `finished_key = Expand-Label(baseKey, "finished", "",
146
+ * HashLen)`, where `baseKey` is the sender's handshake traffic secret.
147
+ */
148
+ export const tlsFinishedVerifyData = (hashLength: i32, baseKey: u8[], transcriptHash: u8[]): u8[] => {
149
+ const none: u8[] = []
150
+ const finishedKey: u8[] = tlsExpandLabel(hashLength, baseKey, "finished", none, hashLength)
151
+ return hashLength === SHA384_SIZE
152
+ ? hmacSha384(finishedKey, transcriptHash)
153
+ : hmacSha256(finishedKey, transcriptHash)
154
+ }
155
+
156
+ /** The AEAD key a traffic secret gives `suite`'s record protection (RFC 8446 §7.3); empty for a suite this module does not negotiate. */
157
+ export const tlsTrafficKey = (suite: i32, secret: u8[]): u8[] => {
158
+ const none: u8[] = []
159
+ const hashLength: i32 = tlsSuiteHashLength(suite)
160
+ if (hashLength === 0) {
161
+ return none
162
+ }
163
+ return tlsExpandLabel(hashLength, secret, "key", none, tlsSuiteKeyLength(suite))
164
+ }
165
+
166
+ /** The 12-byte IV a traffic secret gives `suite`'s record protection (RFC 8446 §7.3); empty for a suite this module does not negotiate. */
167
+ export const tlsTrafficIv = (suite: i32, secret: u8[]): u8[] => {
168
+ const none: u8[] = []
169
+ const hashLength: i32 = tlsSuiteHashLength(suite)
170
+ if (hashLength === 0) {
171
+ return none
172
+ }
173
+ return tlsExpandLabel(hashLength, secret, "iv", none, TLS_IV_SIZE)
174
+ }
175
+
176
+ /**
177
+ * The running transcript hash of RFC 8446 §4.4.1: every handshake message,
178
+ * header included, in the order sent, over the negotiated suite's hash.
179
+ *
180
+ * `hash` reads the hash so far from a copy, so the transcript keeps going: the
181
+ * schedule takes it after ServerHello, after Certificate, after
182
+ * CertificateVerify and after the server's Finished. `restartWithMessageHash`
183
+ * is the HelloRetryRequest rule: the first ClientHello is replaced by the
184
+ * synthetic `message_hash` message holding its hash.
185
+ *
186
+ * Both hashers are kept so that the field types do not depend on the suite;
187
+ * only the one `hashLength` names is fed. So are a fresh pair, which `reset`
188
+ * starts the transcript again from, and a twin pair `hashInto` reads the hash
189
+ * through: all six are made once, so a transcript reused for the next
190
+ * connection with `reset` allocates nothing that outlives a call.
191
+ */
192
+ export class TlsTranscript {
193
+ /** 32 for SHA-256, 48 for SHA-384. */
194
+ hashLength: i32
195
+ sha256: Sha256
196
+ sha384: Sha384
197
+ /** Never fed: the initial hash values `reset` copies from. */
198
+ fresh256: Sha256
199
+ fresh384: Sha384
200
+ /** Where `hashInto` finishes a copy of the running hash, so that the transcript goes on. */
201
+ twin256: Sha256
202
+ twin384: Sha384
203
+
204
+ constructor(hashLength: i32) {
205
+ this.hashLength = hashLength
206
+ this.sha256 = new Sha256()
207
+ this.sha384 = new Sha384()
208
+ this.fresh256 = new Sha256()
209
+ this.fresh384 = new Sha384()
210
+ this.twin256 = new Sha256()
211
+ this.twin384 = new Sha384()
212
+ }
213
+
214
+ /** Starts an empty transcript over the hash `hashLength` names, in the hashers it already has. */
215
+ reset(hashLength: i32): void {
216
+ this.hashLength = hashLength
217
+ hmacCopySha256(this.fresh256, this.sha256)
218
+ hmacCopySha384(this.fresh384, this.sha384)
219
+ }
220
+
221
+ /** Absorbs `data[off .. off + len)`, a whole handshake message or part of one. */
222
+ update(data: u8[], off: i32, len: i32): void {
223
+ if (this.hashLength === SHA384_SIZE) {
224
+ this.sha384.update(data, off, len)
225
+ } else {
226
+ this.sha256.update(data, off, len)
227
+ }
228
+ }
229
+
230
+ /**
231
+ * Writes the transcript hash of everything absorbed so far, `hashLength`
232
+ * bytes, at `out[at]`; the transcript goes on. What the digest allocates
233
+ * dies with the call. A window outside `out` writes what fits.
234
+ */
235
+ hashInto(out: u8[], at: i32): void {
236
+ let digest: u8[] = []
237
+ if (this.hashLength === SHA384_SIZE) {
238
+ hmacCopySha384(this.sha384, this.twin384)
239
+ digest = this.twin384.digest()
240
+ } else {
241
+ hmacCopySha256(this.sha256, this.twin256)
242
+ digest = this.twin256.digest()
243
+ }
244
+ for (let k: i32 = 0; k < toI32(digest.length) && at + k >= 0 && at + k < toI32(out.length); k++) {
245
+ out[at + k] = digest[k]
246
+ }
247
+ }
248
+
249
+ /** The transcript hash of everything absorbed so far, in a fresh array; the transcript goes on. */
250
+ hash(): u8[] {
251
+ const out: u8[] = new Array<u8>(this.hashLength)
252
+ this.hashInto(out, TLS_SCHEDULE_FROM)
253
+ return out
254
+ }
255
+
256
+ /**
257
+ * Replaces the transcript so far, which must be exactly the first
258
+ * ClientHello, by `message_hash` (type 254, a 24-bit length of HashLen,
259
+ * then Hash(ClientHello1)), as RFC 8446 §4.4.1 has a server do before it
260
+ * absorbs its HelloRetryRequest.
261
+ */
262
+ restartWithMessageHash(): void {
263
+ const first: u8[] = new Array<u8>(SHA384_SIZE)
264
+ this.hashInto(first, TLS_SCHEDULE_FROM)
265
+ const header: u8[] = [toU8(254), toU8(0), toU8(0), toU8(this.hashLength)]
266
+ const headerLength: i32 = 4
267
+ this.reset(this.hashLength)
268
+ this.update(header, TLS_SCHEDULE_FROM, headerLength)
269
+ this.update(first, TLS_SCHEDULE_FROM, this.hashLength)
270
+ }
271
+ }
272
+
273
+ // ---- The schedule in place -------------------------------------------------------
274
+
275
+ /** SHA-256 of the empty string, Derive-Secret's context for "derived" (RFC 8446 §7.1). */
276
+ const TLS_EMPTY_HASH_SHA256: string = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
277
+ /** SHA-384 of the empty string. */
278
+ const TLS_EMPTY_HASH_SHA384: string =
279
+ "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"
280
+
281
+ /** Writes the hash of the empty string under the hash `hashLength` names, from the constants above, at `out[0]`. */
282
+ const tlsEmptyHashInto = (hashLength: i32, out: u8[]): void => {
283
+ tlsHexInto(
284
+ hashLength === SHA384_SIZE ? TLS_EMPTY_HASH_SHA384 : TLS_EMPTY_HASH_SHA256,
285
+ out,
286
+ TLS_SCHEDULE_FROM
287
+ )
288
+ }
289
+
290
+ /**
291
+ * `tlsDeriveSecret` in place: Derive-Secret (RFC 8446 §7.1) of `secret` with
292
+ * `label` and the transcript hash `transcriptHash[hashOff .. hashOff +
293
+ * hashLength)`, its HashLen bytes written at `out[0]`.
294
+ */
295
+ export const tlsDeriveSecretInto = (
296
+ kdf: HkdfScratch,
297
+ hashLength: i32,
298
+ secret: u8[],
299
+ label: string,
300
+ transcriptHash: u8[],
301
+ hashOff: i32,
302
+ out: u8[]
303
+ ): void => {
304
+ hkdfExpandLabelInto(
305
+ kdf,
306
+ hashLength,
307
+ secret,
308
+ label,
309
+ transcriptHash,
310
+ hashOff,
311
+ hashLength,
312
+ out,
313
+ TLS_SCHEDULE_FROM,
314
+ hashLength
315
+ )
316
+ }
317
+
318
+ /**
319
+ * `tlsMasterSecret` in place: HKDF-Extract of HashLen zeros under
320
+ * `Derive-Secret(handshake, "derived", "")`, written at `out[0]`. The salt is
321
+ * wiped before it returns.
322
+ */
323
+ export const tlsMasterSecretInto = (
324
+ kdf: HkdfScratch,
325
+ hashLength: i32,
326
+ handshakeSecret: u8[],
327
+ out: u8[]
328
+ ): void => {
329
+ const empty: u8[] = new Array<u8>(hashLength)
330
+ tlsEmptyHashInto(hashLength, empty)
331
+ const salt: u8[] = new Array<u8>(hashLength)
332
+ tlsDeriveSecretInto(kdf, hashLength, handshakeSecret, "derived", empty, TLS_SCHEDULE_FROM, salt)
333
+ hkdfExtractInto(kdf, hashLength, salt, new Array<u8>(hashLength), out, TLS_SCHEDULE_FROM)
334
+ secureZero(salt)
335
+ }
336
+
337
+ /**
338
+ * `tlsFinishedVerifyData` in place: the HMAC of `transcriptHash[hashOff ..
339
+ * hashOff + hashLength)` under `finished_key = Expand-Label(baseKey,
340
+ * "finished", "", HashLen)` (RFC 8446 §4.4.4), written at `out[at]`. The
341
+ * finished key is wiped before it returns, and so is the scratch.
342
+ */
343
+ export const tlsFinishedVerifyDataInto = (
344
+ kdf: HkdfScratch,
345
+ hashLength: i32,
346
+ baseKey: u8[],
347
+ transcriptHash: u8[],
348
+ hashOff: i32,
349
+ out: u8[],
350
+ at: i32
351
+ ): void => {
352
+ const none: u8[] = []
353
+ const finishedKey: u8[] = new Array<u8>(hashLength)
354
+ hkdfExpandLabelInto(
355
+ kdf,
356
+ hashLength,
357
+ baseKey,
358
+ "finished",
359
+ none,
360
+ TLS_SCHEDULE_FROM,
361
+ TLS_SCHEDULE_FROM,
362
+ finishedKey,
363
+ TLS_SCHEDULE_FROM,
364
+ hashLength
365
+ )
366
+ if (hashLength === SHA384_SIZE) {
367
+ kdf.sha384.begin(finishedKey, TLS_SCHEDULE_FROM, hashLength)
368
+ kdf.sha384.update(transcriptHash, hashOff, hashLength)
369
+ kdf.sha384.finishInto(out, at)
370
+ } else {
371
+ kdf.sha256.begin(finishedKey, TLS_SCHEDULE_FROM, hashLength)
372
+ kdf.sha256.update(transcriptHash, hashOff, hashLength)
373
+ kdf.sha256.finishInto(out, at)
374
+ }
375
+ secureZero(finishedKey)
376
+ kdf.wipe()
377
+ }
378
+
379
+ /**
380
+ * `tlsTrafficKey` and `tlsTrafficIv` in place: the AEAD key a traffic secret
381
+ * gives `suite` (RFC 8446 §7.3) written into `key`, which must be the suite's
382
+ * key length, and its 12-byte IV into `iv`. `false`, writing nothing, for a
383
+ * suite this module does not negotiate, a secret that is not its hash's
384
+ * length, or a key or IV array of the wrong length.
385
+ */
386
+ export const tlsTrafficKeysInto = (
387
+ kdf: HkdfScratch,
388
+ suite: i32,
389
+ secret: u8[],
390
+ key: u8[],
391
+ iv: u8[]
392
+ ): boolean => {
393
+ const none: u8[] = []
394
+ const hashLength: i32 = tlsSuiteHashLength(suite)
395
+ const keyLength: i32 = tlsSuiteKeyLength(suite)
396
+ if (
397
+ hashLength === 0 ||
398
+ toI32(secret.length) !== hashLength ||
399
+ toI32(key.length) !== keyLength ||
400
+ toI32(iv.length) !== TLS_IV_SIZE
401
+ ) {
402
+ return false
403
+ }
404
+ hkdfExpandLabelInto(
405
+ kdf,
406
+ hashLength,
407
+ secret,
408
+ "key",
409
+ none,
410
+ TLS_SCHEDULE_FROM,
411
+ TLS_SCHEDULE_FROM,
412
+ key,
413
+ TLS_SCHEDULE_FROM,
414
+ keyLength
415
+ )
416
+ hkdfExpandLabelInto(
417
+ kdf,
418
+ hashLength,
419
+ secret,
420
+ "iv",
421
+ none,
422
+ TLS_SCHEDULE_FROM,
423
+ TLS_SCHEDULE_FROM,
424
+ iv,
425
+ TLS_SCHEDULE_FROM,
426
+ TLS_IV_SIZE
427
+ )
428
+ return true
429
+ }