@amritk/nish-x86_64-linux 0.20.0 → 0.22.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.
Files changed (74) hide show
  1. package/INSTALL.md +52 -10
  2. package/bin/nish +0 -0
  3. package/docs/AI.md +2777 -0
  4. package/package.json +2 -1
  5. package/runtime/browser.d.ts +6 -0
  6. package/runtime/browser.mjs +77 -0
  7. package/runtime/core/arrays.d.ts +36 -0
  8. package/runtime/core/arrays.mjs +153 -0
  9. package/runtime/core/checks.mjs +20 -0
  10. package/runtime/core/host.d.ts +80 -0
  11. package/runtime/core/host.mjs +325 -0
  12. package/runtime/core/numbers.d.ts +66 -0
  13. package/runtime/core/numbers.mjs +343 -0
  14. package/runtime/core/result.d.ts +45 -0
  15. package/runtime/core/result.mjs +140 -0
  16. package/runtime/core/strings.d.ts +14 -0
  17. package/runtime/core/strings.mjs +169 -0
  18. package/runtime/core.d.ts +9 -0
  19. package/runtime/core.mjs +55 -0
  20. package/runtime/host.d.ts +6 -0
  21. package/runtime/nish.d.ts +46 -2
  22. package/runtime/nish.h +75 -2
  23. package/runtime/nish.mjs +23 -3
  24. package/runtime/node.mjs +386 -0
  25. package/runtime/runtime-bytes.c +401 -0
  26. package/runtime/runtime-cross.c +1 -1
  27. package/runtime/runtime-host.c +1 -1
  28. package/runtime/runtime-net.c +12 -1
  29. package/runtime/runtime-os.c +1 -1
  30. package/runtime/runtime-parallel.c +1 -1
  31. package/runtime/runtime-simd.c +231 -7
  32. package/runtime/runtime-term.c +504 -0
  33. package/runtime/runtime-wasm.c +0 -11
  34. package/runtime/runtime.c +190 -6
  35. package/runtime/shim.mjs +6 -985
  36. package/runtime/sqlite/LICENSE.md +85 -0
  37. package/runtime/sqlite/README.md +45 -0
  38. package/runtime/sqlite/nish-sqlite.c +359 -0
  39. package/runtime/sqlite/sqlite3.c +271131 -0
  40. package/runtime/sqlite/sqlite3.h +14447 -0
  41. package/scripts/build.sh +311 -59
  42. package/std/LICENSE-fast-float +23 -0
  43. package/std/LICENSE-fdlibm +8 -0
  44. package/std/README.md +32 -12
  45. package/std/base64.ts +116 -0
  46. package/std/bytes.ts +256 -0
  47. package/std/cli.ts +344 -0
  48. package/std/collections.ts +6 -5
  49. package/std/crypto/LICENSE-crypt_blowfish +26 -0
  50. package/std/crypto/base64url.ts +125 -0
  51. package/std/crypto/bcrypt.ts +1557 -0
  52. package/std/crypto/hmac.ts +138 -2
  53. package/std/crypto/x509.ts +11 -122
  54. package/std/json-tokenizer.ts +2998 -57
  55. package/std/json-value.ts +22 -3
  56. package/std/json.ts +87 -8
  57. package/std/math.ts +608 -0
  58. package/std/net/http1-server.ts +282 -40
  59. package/std/net/http1.ts +40 -21
  60. package/std/net/http3-server.ts +50 -12
  61. package/std/net/postgres.ts +2294 -0
  62. package/std/net/prefork.ts +23 -3
  63. package/std/net/quic-listener.ts +20 -4
  64. package/std/random.ts +66 -4
  65. package/std/regex.ts +4274 -0
  66. package/std/sqlite.ts +391 -0
  67. package/std/term-io.ts +978 -0
  68. package/std/term-pixels.ts +874 -0
  69. package/std/term-probe.ts +459 -0
  70. package/std/term-rate.ts +993 -0
  71. package/std/term.ts +2453 -0
  72. package/std/text.ts +90 -7
  73. package/std/yaml-lines.ts +141 -0
  74. package/std/yaml.ts +4675 -0
@@ -46,12 +46,17 @@
46
46
  * stores nothing of its own and an arena scope around it releases all it
47
47
  * allocated (see "Caller-owned scratch" below).
48
48
  *
49
- * Written from RFC 2104, not ported from another implementation.
49
+ * `pbkdf2HmacSha256` is PBKDF2 with HMAC-SHA-256 (RFC 8018 §5.2), the key
50
+ * derivation SCRAM-SHA-256 runs over a password: the password goes in as a
51
+ * `Secret<u8[]>` and the derived key comes out as one, and every U_j and T_i
52
+ * is wiped before it answers (see "PBKDF2" below).
53
+ *
54
+ * Written from RFC 2104 and RFC 8018, not ported from another implementation.
50
55
  */
51
56
  import { SHA256_BLOCK, SHA256_SIZE, Sha256 } from "nish/crypto/sha256"
52
57
  import { SHA384_SIZE, SHA512_BLOCK, SHA512_SIZE, Sha384, Sha512 } from "nish/crypto/sha512"
53
58
  import { timingSafeEqual } from "nish/crypto/ct"
54
- import { Secret, exposeWith, wipe } from "nish:secret"
59
+ import { Secret, exposeWith, secret, wipe } from "nish:secret"
55
60
 
56
61
  /** RFC 2104 §2's `ipad`, the byte XORed into the key for the inner hash. */
57
62
  const HMAC_IPAD: i32 = 0x36
@@ -661,3 +666,134 @@ export class HmacSha384Scratch {
661
666
  hmacWipeSha384(this.outer)
662
667
  }
663
668
  }
669
+
670
+ // ---- PBKDF2 ----------------------------------------------------------------
671
+ //
672
+ // PBKDF2 with HMAC-SHA-256 as its PRF (RFC 8018 §5.2), the key derivation
673
+ // SCRAM-SHA-256 (RFC 7677, RFC 5802 §3 "Hi") runs over a password. The
674
+ // password keys an inner and an outer hasher once; every U_j after that is
675
+ // two compressions in a working hasher copied from them, so a count of 4096
676
+ // costs 4096 HMACs and never keys one again.
677
+
678
+ /** What `pbkdf2HmacSha256` passes through `exposeWith`, which carries one argument. */
679
+ interface Pbkdf2Request {
680
+ /** The salt, public: SCRAM's server sends it. */
681
+ salt: u8[]
682
+ /** The iteration count `c`, at least 1. */
683
+ iterations: i32
684
+ /** The derived key's length `dkLen` in bytes, at least 1. */
685
+ length: i32
686
+ }
687
+
688
+ /** The length of INT(i), the big-endian block index after the salt; typed, as `HMAC_FROM` is. */
689
+ const PBKDF2_INDEX: i32 = 4
690
+
691
+ /**
692
+ * Ends the HMAC `work` holds, keyed as `keyedOuter` is on the outer side, and
693
+ * writes its 32-byte tag into `out`. Both digests `work` answers are wiped
694
+ * here, so they die with this call and its arena scope.
695
+ */
696
+ const pbkdf2Finish = (keyedOuter: Sha256, work: Sha256, out: u8[]): void => {
697
+ const innerDigest: u8[] = work.digest()
698
+ hmacCopySha256(keyedOuter, work)
699
+ work.update(innerDigest, HMAC_FROM, SHA256_SIZE)
700
+ wipe(innerDigest)
701
+ const tag: u8[] = work.digest()
702
+ for (let i: i32 = 0; i < SHA256_SIZE && i < toI32(tag.length) && i < toI32(out.length); i += 1) {
703
+ out[i] = tag[i]
704
+ }
705
+ wipe(tag)
706
+ }
707
+
708
+ /** `pbkdf2HmacSha256` on the exposed password. */
709
+ const pbkdf2HmacSha256Exposed = (password: u8[], request: Pbkdf2Request): u8[] | null => {
710
+ const salt: u8[] = request.salt
711
+ const iterations: i32 = request.iterations
712
+ const length: i32 = request.length
713
+ // Before any `toI32`, which would saturate under `--number-mode f64`.
714
+ if (password.length > 2147483647 || salt.length > 2147483647) {
715
+ return null
716
+ }
717
+ if (iterations < 1 || length < 1) {
718
+ return null
719
+ }
720
+ const keyedInner = new Sha256()
721
+ const keyedOuter = new Sha256()
722
+ hmacKeySha256(keyedInner, keyedOuter, password)
723
+ const work = new Sha256()
724
+ const u: u8[] = new Array<u8>(SHA256_SIZE)
725
+ const t: u8[] = new Array<u8>(SHA256_SIZE)
726
+ const index: u8[] = new Array<u8>(PBKDF2_INDEX)
727
+ const dk: u8[] = new Array<u8>(length)
728
+ // dkLen is an i32, so it never reaches RFC 8018's (2^32 - 1) * hLen bound,
729
+ // and the block index below never passes 2^26.
730
+ let block: i32 = 1
731
+ let done: i32 = 0
732
+ while (done < length) {
733
+ // U_1 = PRF(P, S || INT(i)), INT(i) four bytes, most significant first.
734
+ index[0] = toU8((block >> 24) & 0xff)
735
+ index[1] = toU8((block >> 16) & 0xff)
736
+ index[2] = toU8((block >> 8) & 0xff)
737
+ index[3] = toU8(block & 0xff)
738
+ hmacCopySha256(keyedInner, work)
739
+ work.update(salt, HMAC_FROM, toI32(salt.length))
740
+ work.update(index, HMAC_FROM, PBKDF2_INDEX)
741
+ pbkdf2Finish(keyedOuter, work, u)
742
+ for (let j: i32 = 0; j < SHA256_SIZE && j < toI32(t.length) && j < toI32(u.length); j += 1) {
743
+ t[j] = u[j]
744
+ }
745
+ // U_c = PRF(P, U_{c-1}); T_i = U_1 XOR ... XOR U_c.
746
+ for (let c: i32 = 1; c < iterations; c += 1) {
747
+ hmacCopySha256(keyedInner, work)
748
+ work.update(u, HMAC_FROM, SHA256_SIZE)
749
+ pbkdf2Finish(keyedOuter, work, u)
750
+ for (let j: i32 = 0; j < SHA256_SIZE && j < toI32(t.length) && j < toI32(u.length); j += 1) {
751
+ t[j] = t[j] ^ u[j]
752
+ }
753
+ }
754
+ const take: i32 = length - done < SHA256_SIZE ? length - done : SHA256_SIZE
755
+ for (let j: i32 = 0; j < take && j < toI32(t.length) && done + j < toI32(dk.length); j += 1) {
756
+ dk[done + j] = t[j]
757
+ }
758
+ done += take
759
+ block += 1
760
+ }
761
+ wipe(u)
762
+ wipe(t)
763
+ hmacWipeSha256(work)
764
+ hmacWipeSha256(keyedInner)
765
+ hmacWipeSha256(keyedOuter)
766
+ return dk
767
+ }
768
+
769
+ /**
770
+ * PBKDF2-HMAC-SHA256(P, S, c, dkLen) as RFC 8018 §5.2 defines it: the
771
+ * `dkLen`-byte key derived from the password `password` and the salt `salt`
772
+ * over `iterations` rounds, as a `Secret`.
773
+ *
774
+ * const salted: Secret<u8[]> | null = pbkdf2HmacSha256(password, salt, 4096, 32);
775
+ *
776
+ * Bad input answers `null` and never panics: an iteration count or a length
777
+ * below 1, or a password or salt longer than 2^31 - 1 bytes. The password is
778
+ * read only inside `exposeWith`, and every U_j, every T_i, both keyed hashers
779
+ * and the working one are wiped before the key is answered; the digests on
780
+ * the way are wiped in the call that made them. The time taken depends on
781
+ * `iterations`, `dkLen` and the password's length past a block, all of which
782
+ * RFC 8018 treats as public, and on nothing of the password's bytes. The time
783
+ * is linear in `iterations` and nothing here bounds it, so a caller that takes
784
+ * the count from an untrusted peer (a SCRAM server's `i=`) must cap it first:
785
+ * 2^31 - 1 rounds is about 2^32 compressions.
786
+ */
787
+ export const pbkdf2HmacSha256 = (
788
+ password: Secret<u8[]>,
789
+ salt: u8[],
790
+ iterations: i32,
791
+ length: i32
792
+ ): Secret<u8[]> | null => {
793
+ const request: Pbkdf2Request = { salt: salt, iterations: iterations, length: length }
794
+ const dk: u8[] | null = exposeWith(password, request, pbkdf2HmacSha256Exposed)
795
+ if (dk === null) {
796
+ return null
797
+ }
798
+ return secret(dk)
799
+ }
@@ -72,10 +72,10 @@
72
72
  *
73
73
  * **Constant time.** A private key is the one secret that passes through here:
74
74
  * it is base64-decoded from PEM, lifted out of its DER, and handed to
75
- * `nish/crypto/p256`. Base64 maps a character to its sextet and back by
76
- * arithmetic on range masks, as `nish/crypto/base64url` does, and folds a bad
77
- * character into one word read after the whole text, so neither a branch nor a
78
- * table index depends on the key's bytes. PEM's framing is found by comparing
75
+ * `nish/crypto/p256`. Base64 is `nish/crypto/base64url`'s `base64StdPadDecode`,
76
+ * which maps a character to its sextet by arithmetic on range masks and folds a
77
+ * bad character into one word read after the whole text, so neither a branch
78
+ * nor a table index depends on the key's bytes. PEM's framing is found by comparing
79
79
  * the start of each line with the fixed `-----BEGIN ` and `-----END `, which no
80
80
  * base64 character matches, so those comparisons end on a line's first byte
81
81
  * whatever the key is. The DER reader branches on tags and
@@ -96,6 +96,7 @@
96
96
  * (`docs/wp26-stdlib.md` §3e).
97
97
  */
98
98
  import { Secret, secret, wipe } from "nish:secret"
99
+ import { base64StdPadDecode, base64StdPadEncode } from "nish/crypto/base64url"
99
100
  import { p256PublicKey, p256SignSha256, p256VerifySha256 } from "nish/crypto/p256"
100
101
  import { sha256 } from "nish/crypto/sha256"
101
102
 
@@ -704,124 +705,9 @@ const x509Bytes = (text: string): u8[] => {
704
705
  }
705
706
 
706
707
  // ---------------------------------------------------------------------------
707
- // PEM (RFC 7468) and standard base64 (RFC 4648 §4)
708
+ // PEM (RFC 7468), over `nish/crypto/base64url`'s padded base64
708
709
  // ---------------------------------------------------------------------------
709
710
 
710
- /**
711
- * All ones when `lo <= c <= hi`, else zero, without a branch; `c` is a byte or
712
- * a sextet. The subtractions are `u32`'s, which wrap by definition, rather
713
- * than checked `i32` ones, whose check would be a branch on a byte of what may
714
- * be a private key's PEM; the sign bit `>> 31` reads is the same.
715
- * `x509Base64CharOf` and `x509Base64SextetOf` sum in `u32` for the same reason.
716
- */
717
- const x509RangeMask = (c: i32, lo: i32, hi: i32): i32 =>
718
- toI32((toU32(lo) - 1 - toU32(c)) & (toU32(c) - toU32(hi) - 1)) >> 31
719
-
720
- /**
721
- * The base64 character for the sextet `v`: `'A' + v`, stepped by the gap to
722
- * each later range it has reached — 26 lands on `a`, 52 on `0`, 62 on `+` and
723
- * 63 on `/`.
724
- */
725
- const x509Base64CharOf = (v: i32): i32 =>
726
- toI32(
727
- 65 +
728
- toU32(v) +
729
- toU32(x509RangeMask(v, 26, 63) & 6) -
730
- toU32(x509RangeMask(v, 52, 63) & 75) -
731
- toU32(x509RangeMask(v, 62, 63) & 15) +
732
- toU32(x509RangeMask(v, 63, 63) & 3)
733
- )
734
-
735
- /** The sextet the byte `c` stands for in base64, or `-1` when it is not in the alphabet. */
736
- const x509Base64SextetOf = (c: i32): i32 => {
737
- const upper: i32 = x509RangeMask(c, 65, 90)
738
- const lower: i32 = x509RangeMask(c, 97, 122)
739
- const digit: i32 = x509RangeMask(c, 48, 57)
740
- const plus: i32 = x509RangeMask(c, 43, 43)
741
- const slash: i32 = x509RangeMask(c, 47, 47)
742
- const value: i32 =
743
- (upper & toI32(toU32(c) - 65)) |
744
- (lower & toI32(toU32(c) - 71)) |
745
- (digit & toI32(toU32(c) + 4)) |
746
- (plus & 62) |
747
- (slash & 63)
748
- return value | ~(upper | lower | digit | plus | slash)
749
- }
750
-
751
- /** `data` in padded base64, as one line. */
752
- const x509Base64Encode = (data: u8[]): string => {
753
- const parts: string[] = []
754
- let acc: i32 = 0
755
- let bits: i32 = 0
756
- for (let k: i32 = 0; k < toI32(data.length); k++) {
757
- acc = ((acc << 8) | toI32(data[k])) & 0xfff
758
- bits = bits + 8
759
- while (bits >= 6) {
760
- bits = bits - 6
761
- parts.push(String.fromCharCode(x509Base64CharOf((acc >> bits) & 63)))
762
- }
763
- }
764
- if (bits > 0) {
765
- parts.push(String.fromCharCode(x509Base64CharOf((acc << (6 - bits)) & 63)))
766
- }
767
- // One `=` for a final group of two bytes, two for one byte.
768
- const tail: i32 = toI32(data.length) % 3
769
- if (tail > 0) {
770
- parts.push(tail === 1 ? "==" : "=")
771
- }
772
- return parts.join("")
773
- }
774
-
775
- /**
776
- * The bytes of padded base64 `text`, or `null` unless it is the one canonical
777
- * spelling of them: a whole number of four-character groups, `=` only as the
778
- * last one or two characters, every other character in the alphabet, and the
779
- * bits the padding leaves over all zero (RFC 4648 §3.5). Where the padding is
780
- * depends on the length alone; the characters themselves are read by masks and
781
- * judged once, after the last.
782
- */
783
- const x509Base64Decode = (text: string): u8[] | null => {
784
- const n: i32 = toI32(text.length)
785
- if (n === 0 || (n & 3) !== 0) {
786
- return null
787
- }
788
- let pad: i32 = 0
789
- if (toI32(text.charCodeAt(n - 1)) === 61) {
790
- pad = toI32(text.charCodeAt(n - 2)) === 61 ? 2 : 1
791
- }
792
- const chars: i32 = n - pad
793
- const out: u8[] = new Array<u8>((n >> 2) * 3 - pad)
794
- const outLen: i32 = toI32(out.length)
795
- let bad: i32 = 0
796
- let acc: i32 = 0
797
- let bits: i32 = 0
798
- let j: i32 = 0
799
- for (let k: i32 = 0; k < toI32(text.length); k++) {
800
- // The padding is past `chars`, and is not data; which positions those are
801
- // is a fact about the length.
802
- if (k < chars) {
803
- const v: i32 = x509Base64SextetOf(toI32(text.charCodeAt(k)))
804
- bad = bad | (v >> 31)
805
- acc = ((acc << 6) | (v & 63)) & 0xfff
806
- bits = bits + 6
807
- if (bits >= 8) {
808
- bits = bits - 8
809
- // Always true — `out` was sized from the same length — and written so
810
- // the store keeps no bounds check.
811
- if (j >= 0 && j < outLen) {
812
- out[j] = toU8((acc >> bits) & 0xff)
813
- }
814
- j = j + 1
815
- }
816
- }
817
- }
818
- bad = bad | (acc & ((1 << bits) - 1))
819
- if (bad !== 0) {
820
- return null
821
- }
822
- return out
823
- }
824
-
825
711
  /** Whether `text` starts with `prefix`. */
826
712
  const x509StartsWith = (text: string, prefix: string): boolean => {
827
713
  const n: i32 = toI32(prefix.length)
@@ -841,7 +727,7 @@ const x509EndsWith = (text: string, suffix: string): boolean => {
841
727
  * ending in a line feed.
842
728
  */
843
729
  export const derToPem = (der: u8[], label: string): string => {
844
- const body: string = x509Base64Encode(der)
730
+ const body: string = base64StdPadEncode(der)
845
731
  const n: i32 = toI32(body.length)
846
732
  const lines: string[] = [`-----BEGIN ${label}-----`]
847
733
  for (let at: i32 = 0; at < n; at = at + 64) {
@@ -894,7 +780,10 @@ export const pemToDer = (pem: string, label: string): u8[][] | null => {
894
780
  }
895
781
  // Every block is decoded, whatever its label: a malformed block beside the
896
782
  // one asked for is refused, not skipped (docs/security/crypto-x509.md, X509-1).
897
- const der: u8[] | null = x509Base64Decode(body.join(""))
783
+ // An empty body is refused: a block with no DER is malformed, though
784
+ // the empty text is base64 for no bytes.
785
+ const text: string = body.join("")
786
+ const der: u8[] | null = text.length === 0 ? null : base64StdPadDecode(text)
898
787
  if (der === null) {
899
788
  return null
900
789
  }