@amritk/nish-x86_64-linux 0.24.0 → 0.26.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/bin/nish +0 -0
- package/docs/AI.md +45 -4
- package/package.json +1 -1
- package/runtime/browser.mjs +4 -3
- package/runtime/core/host.d.ts +12 -0
- package/runtime/core/host.mjs +74 -2
- package/runtime/nish.d.ts +148 -0
- package/runtime/nish.h +59 -0
- package/runtime/nish.mjs +25 -0
- package/runtime/node.mjs +136 -6
- package/runtime/runtime-net.c +44 -3
- package/runtime/runtime-os.c +351 -18
- package/scripts/build.sh +13 -3
- package/std/README.md +27 -10
- package/std/cli-args.ts +1216 -0
- package/std/cli-flags.ts +585 -0
- package/std/cli.ts +308 -19
- package/std/compress/checksum.ts +132 -20
- package/std/compress/deflate.ts +638 -248
- package/std/compress/gzip.ts +20 -6
- package/std/crypto/LICENSE-fiat-crypto-p384 +21 -0
- package/std/crypto/p256.ts +63 -1
- package/std/crypto/p384.ts +6044 -0
- package/std/crypto/pki-roots.ts +322 -0
- package/std/crypto/pki.ts +1207 -0
- package/std/crypto/rsa.ts +663 -0
- package/std/crypto/x509.ts +1054 -58
- package/std/net/dns-config.ts +734 -0
- package/std/net/dns-message.ts +517 -0
- package/std/net/dns-resolver.ts +1015 -0
- package/std/net/dns.ts +478 -0
- package/std/net/http1-client.ts +1227 -0
- package/std/net/http1-server.ts +7 -2
- package/std/net/http1.ts +9 -9
- package/std/net/postgres.ts +259 -26
- package/std/net/tls/client.ts +1094 -0
- package/std/net/tls/codec.ts +585 -3
- package/std/net/tls/record-client.ts +1192 -0
- package/std/net/tls/verify.ts +221 -0
- package/std/net/tls-tcp.ts +642 -11
- package/std/net/tls.ts +2 -2
- package/std/net/url.ts +559 -4
- package/std/yaml-write.ts +415 -0
|
@@ -0,0 +1,663 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `nish/crypto/rsa` — RSA signature verification: RSASSA-PKCS1-v1_5 and
|
|
3
|
+
* RSASSA-PSS over SHA-256, SHA-384 and SHA-512, under a public key read from
|
|
4
|
+
* its DER. Verification only; this module neither signs nor holds a private key.
|
|
5
|
+
*
|
|
6
|
+
* import { RSA_HASH_SHA256, RsaPublicKey, rsaParsePublicKey, rsaVerifyPkcs1v15, rsaVerifyPss } from "nish/crypto/rsa";
|
|
7
|
+
*
|
|
8
|
+
* const key: RsaPublicKey | null = rsaParsePublicKey(der); // PKCS#1 RSAPublicKey
|
|
9
|
+
* const ok: boolean = key !== null && rsaVerifyPkcs1v15(key, RSA_HASH_SHA256, message, sig);
|
|
10
|
+
* const pss: boolean = key !== null && rsaVerifyPss(key, RSA_HASH_SHA256, 32, message, sig);
|
|
11
|
+
*
|
|
12
|
+
* **The key** is the DER of PKCS#1's `RSAPublicKey ::= SEQUENCE { modulus
|
|
13
|
+
* INTEGER, publicExponent INTEGER }` (RFC 8017 §A.1.1), nothing before it and
|
|
14
|
+
* nothing after it. It is read strictly: definite lengths in their shortest
|
|
15
|
+
* form, each INTEGER positive and in its shortest form, a modulus of
|
|
16
|
+
* `RSA_MIN_BITS` to `RSA_MAX_BITS` bits that is odd, and an exponent that is
|
|
17
|
+
* odd, at least 3 and below 2^32 (so below the modulus). Anything else answers
|
|
18
|
+
* `null`. The 2^32 bound is not RFC 8017's; it caps what one verification
|
|
19
|
+
* costs, because the work grows with the exponent's length, and every
|
|
20
|
+
* certificate in use carries 65537 (RSA-3, docs/security/crypto-rsa.md).
|
|
21
|
+
*
|
|
22
|
+
* **Verification** answers `false`, never a panic, for an unknown hash id, a
|
|
23
|
+
* signature that is not exactly as long as the modulus or is not below it, a
|
|
24
|
+
* negative salt length, and any encoding that is not exactly the one RFC 8017
|
|
25
|
+
* defines. PKCS#1 v1.5 builds the whole encoded message it expects, `00 01 FF
|
|
26
|
+
* … FF 00 DigestInfo`, and compares it with what the signature opens to, so no
|
|
27
|
+
* part of the opened block is parsed (Bleichenbacher's 2006 forgery against a
|
|
28
|
+
* parser that skipped trailing bytes). The DigestInfo carries the NULL
|
|
29
|
+
* parameters RFC 8017 §9.2 note 1 prints; the form without them, which the
|
|
30
|
+
* RFC lets a verifier accept, is refused. PSS is RFC 8017 §8.1.2 and §9.1.2
|
|
31
|
+
* step by step, with MGF1 over the same hash as the message, the leftmost
|
|
32
|
+
* bits of the masked block checked to be zero and the 0x01 separator checked.
|
|
33
|
+
*
|
|
34
|
+
* **Variable time, on purpose.** A public key, a signature and a message are
|
|
35
|
+
* all public, so nothing here has a secret to leak: the exponentiation
|
|
36
|
+
* branches on the exponent's bits, the reductions branch on comparisons and
|
|
37
|
+
* the encodings are compared with an early exit. That is why this module does
|
|
38
|
+
* not use `nish:secret` or `nish/crypto/ct`.
|
|
39
|
+
*
|
|
40
|
+
* **The arithmetic** is written for this module from the textbook. Numbers
|
|
41
|
+
* are little-endian `u32` limbs, products are taken in `u64`, and modular
|
|
42
|
+
* multiplication is Montgomery's (P. L. Montgomery, "Modular multiplication
|
|
43
|
+
* without trial division", Math. Comp. 44, 1985) in the coarsely integrated
|
|
44
|
+
* operand scanning form of Ç. K. Koç, T. Acar and B. S. Kaliski, "Analyzing
|
|
45
|
+
* and comparing Montgomery multiplication algorithms" (IEEE Micro, 1996), the
|
|
46
|
+
* same algorithm as A. Menezes, P. van Oorschot and S. Vanstone, *Handbook of
|
|
47
|
+
* Applied Cryptography* (1996), Algorithm 14.36, with one conditional
|
|
48
|
+
* subtraction at the end. The exponent is applied left to right by square
|
|
49
|
+
* and multiply (HAC Algorithm 14.79's binary special case). The closest
|
|
50
|
+
* upstream is BearSSL's `i31` code (`br_i31_montymul`, `br_i31_modpow`), and
|
|
51
|
+
* nothing here follows it: BearSSL keeps 31-bit words and a constant-time
|
|
52
|
+
* structure, this keeps 32-bit words and branches freely.
|
|
53
|
+
*
|
|
54
|
+
* Private names carry the `rsa` prefix because a `std/` module's private
|
|
55
|
+
* functions share the importing program's flat symbol namespace
|
|
56
|
+
* (`docs/wp26-stdlib.md` §3e).
|
|
57
|
+
*/
|
|
58
|
+
import { sha256 } from "nish/crypto/sha256"
|
|
59
|
+
import { sha384, sha512 } from "nish/crypto/sha512"
|
|
60
|
+
|
|
61
|
+
/** SHA-256, the hash id `rsaVerifyPkcs1v15` and `rsaVerifyPss` take. The same number as `nish/crypto/x509`'s `X509_HASH_SHA256`. */
|
|
62
|
+
export const RSA_HASH_SHA256: i32 = 1
|
|
63
|
+
|
|
64
|
+
/** SHA-384. */
|
|
65
|
+
export const RSA_HASH_SHA384: i32 = 2
|
|
66
|
+
|
|
67
|
+
/** SHA-512. */
|
|
68
|
+
export const RSA_HASH_SHA512: i32 = 3
|
|
69
|
+
|
|
70
|
+
/** The smallest modulus `rsaParsePublicKey` accepts, in bits. A policy that wants 2048 checks `bits` itself. */
|
|
71
|
+
export const RSA_MIN_BITS: i32 = 1024
|
|
72
|
+
|
|
73
|
+
/** The largest modulus `rsaParsePublicKey` accepts, in bits. */
|
|
74
|
+
export const RSA_MAX_BITS: i32 = 8192
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* A public key as `rsaParsePublicKey` read it. One built by hand is not
|
|
78
|
+
* checked: the verifiers answer it without a panic, and their answer means
|
|
79
|
+
* something only for a key the parser would accept. They read `n` and `e`,
|
|
80
|
+
* never `bits`.
|
|
81
|
+
*/
|
|
82
|
+
export class RsaPublicKey {
|
|
83
|
+
/** The modulus, big-endian with no leading zero byte. */
|
|
84
|
+
n: u8[]
|
|
85
|
+
/** The public exponent, big-endian with no leading zero byte. */
|
|
86
|
+
e: u8[]
|
|
87
|
+
/** The modulus's length in bits: 2048 for a 2048-bit key. */
|
|
88
|
+
bits: i32
|
|
89
|
+
|
|
90
|
+
constructor(n: u8[], e: u8[], bits: i32) {
|
|
91
|
+
this.n = n
|
|
92
|
+
this.e = e
|
|
93
|
+
this.bits = bits
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
// The key's DER (X.690 §8.1, §8.3, §10.1)
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Where the contents of the element at `der[at]` start, when it has the
|
|
103
|
+
* identifier `tag` and a definite length in its shortest form that fits
|
|
104
|
+
* before `end`; -1 otherwise. The length is `rsaDerLength`'s answer for the
|
|
105
|
+
* same arguments. Lengths of more than two octets are refused: the largest
|
|
106
|
+
* key's DER is about a kilobyte.
|
|
107
|
+
*/
|
|
108
|
+
const rsaDerContents = (der: u8[], at: i32, end: i32, tag: i32): i32 => {
|
|
109
|
+
if (at < 0 || at + 2 > end || toI32(der[at]) !== tag) {
|
|
110
|
+
return -1
|
|
111
|
+
}
|
|
112
|
+
const first: i32 = toI32(der[at + 1])
|
|
113
|
+
let start: i32 = at + 2
|
|
114
|
+
let length: i32 = first
|
|
115
|
+
if (first === 0x81) {
|
|
116
|
+
if (at + 3 > end) {
|
|
117
|
+
return -1
|
|
118
|
+
}
|
|
119
|
+
length = toI32(der[at + 2])
|
|
120
|
+
if (length < 0x80) {
|
|
121
|
+
return -1
|
|
122
|
+
}
|
|
123
|
+
start = at + 3
|
|
124
|
+
} else if (first === 0x82) {
|
|
125
|
+
if (at + 4 > end) {
|
|
126
|
+
return -1
|
|
127
|
+
}
|
|
128
|
+
length = (toI32(der[at + 2]) << 8) | toI32(der[at + 3])
|
|
129
|
+
if (length < 0x100) {
|
|
130
|
+
return -1
|
|
131
|
+
}
|
|
132
|
+
start = at + 4
|
|
133
|
+
} else if (first >= 0x80) {
|
|
134
|
+
return -1
|
|
135
|
+
}
|
|
136
|
+
if (length > end - start) {
|
|
137
|
+
return -1
|
|
138
|
+
}
|
|
139
|
+
return start
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** The contents length of the element `rsaDerContents` found at `der[at]`. */
|
|
143
|
+
const rsaDerLength = (der: u8[], at: i32): i32 => {
|
|
144
|
+
const first: i32 = toI32(der[at + 1])
|
|
145
|
+
if (first === 0x81) {
|
|
146
|
+
return toI32(der[at + 2])
|
|
147
|
+
}
|
|
148
|
+
if (first === 0x82) {
|
|
149
|
+
return (toI32(der[at + 2]) << 8) | toI32(der[at + 3])
|
|
150
|
+
}
|
|
151
|
+
return first
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* The magnitude of the positive INTEGER whose contents are `der[start ..
|
|
156
|
+
* start + length)`, big-endian with no leading zero byte; `null` for an empty
|
|
157
|
+
* one, a negative one, and one not in its shortest form (a leading 0x00 that
|
|
158
|
+
* a clear top bit after it did not need).
|
|
159
|
+
*/
|
|
160
|
+
const rsaDerUnsigned = (der: u8[], start: i32, length: i32): u8[] | null => {
|
|
161
|
+
const end: i32 = start + length
|
|
162
|
+
if (start < 0 || length < 1 || end > toI32(der.length) || toI32(der[start]) >= 0x80) {
|
|
163
|
+
return null
|
|
164
|
+
}
|
|
165
|
+
let from: i32 = start
|
|
166
|
+
if (toI32(der[start]) === 0) {
|
|
167
|
+
if (length === 1 || toI32(der[start + 1]) < 0x80) {
|
|
168
|
+
return null
|
|
169
|
+
}
|
|
170
|
+
from = start + 1
|
|
171
|
+
}
|
|
172
|
+
const out: u8[] = new Array<u8>(end - from)
|
|
173
|
+
for (let i: i32 = from; i < end; i++) {
|
|
174
|
+
out[i - from] = der[i]
|
|
175
|
+
}
|
|
176
|
+
return out
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** The number of significant bits in the big-endian `v`, which has no leading zero byte. */
|
|
180
|
+
const rsaBitLength = (v: u8[]): i32 => {
|
|
181
|
+
const length: i32 = toI32(v.length)
|
|
182
|
+
if (length === 0) {
|
|
183
|
+
return 0
|
|
184
|
+
}
|
|
185
|
+
let top: i32 = toI32(v[0])
|
|
186
|
+
let bits: i32 = (length - 1) << 3
|
|
187
|
+
while (top > 0) {
|
|
188
|
+
bits += 1
|
|
189
|
+
top = top >> 1
|
|
190
|
+
}
|
|
191
|
+
return bits
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** Whether the big-endian `a` is below `b`, both without a leading zero byte. */
|
|
195
|
+
const rsaBytesBelow = (a: u8[], b: u8[]): boolean => {
|
|
196
|
+
const aLength: i32 = toI32(a.length)
|
|
197
|
+
const bLength: i32 = toI32(b.length)
|
|
198
|
+
if (aLength !== bLength) {
|
|
199
|
+
return aLength < bLength
|
|
200
|
+
}
|
|
201
|
+
for (let i: i32 = 0; i < aLength && i < bLength; i++) {
|
|
202
|
+
if (a[i] !== b[i]) {
|
|
203
|
+
return a[i] < b[i]
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return false
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Reads the DER of a PKCS#1 `RSAPublicKey` (RFC 8017 §A.1.1), the whole of
|
|
211
|
+
* `der`. Answers `null` for anything but one SEQUENCE of two positive,
|
|
212
|
+
* minimally encoded INTEGERs with definite, minimal lengths and nothing
|
|
213
|
+
* after it; for a modulus that is even or not `RSA_MIN_BITS` to
|
|
214
|
+
* `RSA_MAX_BITS` bits long; and for an exponent that is even, below 3, or
|
|
215
|
+
* not below 2^32 (which also keeps it below the modulus).
|
|
216
|
+
*/
|
|
217
|
+
export const rsaParsePublicKey = (der: u8[]): RsaPublicKey | null => {
|
|
218
|
+
const total: i32 = toI32(der.length)
|
|
219
|
+
const body: i32 = rsaDerContents(der, 0, total, 0x30)
|
|
220
|
+
if (body < 0 || body + rsaDerLength(der, 0) !== total) {
|
|
221
|
+
return null
|
|
222
|
+
}
|
|
223
|
+
const nStart: i32 = rsaDerContents(der, body, total, 0x02)
|
|
224
|
+
if (nStart < 0) {
|
|
225
|
+
return null
|
|
226
|
+
}
|
|
227
|
+
const nEnd: i32 = nStart + rsaDerLength(der, body)
|
|
228
|
+
const eStart: i32 = rsaDerContents(der, nEnd, total, 0x02)
|
|
229
|
+
if (eStart < 0) {
|
|
230
|
+
return null
|
|
231
|
+
}
|
|
232
|
+
const eLength: i32 = rsaDerLength(der, nEnd)
|
|
233
|
+
if (eStart + eLength !== total) {
|
|
234
|
+
return null
|
|
235
|
+
}
|
|
236
|
+
const n: u8[] | null = rsaDerUnsigned(der, nStart, nEnd - nStart)
|
|
237
|
+
const e: u8[] | null = rsaDerUnsigned(der, eStart, eLength)
|
|
238
|
+
if (n === null || e === null) {
|
|
239
|
+
return null
|
|
240
|
+
}
|
|
241
|
+
const bits: i32 = rsaBitLength(n)
|
|
242
|
+
if (bits < RSA_MIN_BITS || bits > RSA_MAX_BITS || (toI32(n[toI32(n.length) - 1]) & 1) === 0) {
|
|
243
|
+
return null
|
|
244
|
+
}
|
|
245
|
+
const eLast: i32 = toI32(e[toI32(e.length) - 1])
|
|
246
|
+
if (toI32(e.length) > 4 || (eLast & 1) === 0 || (toI32(e.length) === 1 && eLast < 3)) {
|
|
247
|
+
return null
|
|
248
|
+
}
|
|
249
|
+
return new RsaPublicKey(n, e, bits)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// ---------------------------------------------------------------------------
|
|
253
|
+
// Montgomery arithmetic on little-endian u32 limbs
|
|
254
|
+
// ---------------------------------------------------------------------------
|
|
255
|
+
|
|
256
|
+
/** The big-endian `bytes` as `limbs` little-endian `u32` limbs, limb 0 the least significant; `bytes` fits. */
|
|
257
|
+
const rsaLimbsFromBytes = (bytes: u8[], limbs: i32): u32[] => {
|
|
258
|
+
const out: u32[] = new Array<u32>(limbs)
|
|
259
|
+
const size: i32 = toI32(out.length)
|
|
260
|
+
const length: i32 = toI32(bytes.length)
|
|
261
|
+
for (let i: i32 = 0; i < length; i++) {
|
|
262
|
+
const shift: i32 = length - 1 - i
|
|
263
|
+
const limb: i32 = shift >> 2
|
|
264
|
+
if (limb >= 0 && limb < size) {
|
|
265
|
+
out[limb] = out[limb] | (toU32(bytes[i]) << toU32((shift & 3) << 3))
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return out
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/** The limbs `a` as `size` big-endian bytes; the value fits. */
|
|
272
|
+
const rsaBytesFromLimbs = (a: u32[], size: i32): u8[] => {
|
|
273
|
+
const out: u8[] = new Array<u8>(size)
|
|
274
|
+
const limbs: i32 = toI32(a.length)
|
|
275
|
+
for (let i: i32 = 0; i < toI32(out.length); i++) {
|
|
276
|
+
const shift: i32 = size - 1 - i
|
|
277
|
+
const limb: i32 = shift >> 2
|
|
278
|
+
if (limb >= 0 && limb < limbs) {
|
|
279
|
+
out[i] = toU8(a[limb] >> toU32((shift & 3) << 3))
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return out
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* -n^-1 mod 2^32 for the odd limb `n0`, by Newton's iteration: an odd `x`
|
|
287
|
+
* with `x * n0 = 1` mod 2^b gives `x (2 - x n0)` with it mod 2^2b, and
|
|
288
|
+
* `x = n0` already holds mod 8, so four steps reach 2^48.
|
|
289
|
+
*/
|
|
290
|
+
const rsaMontInverse = (n0: u32): u32 => {
|
|
291
|
+
let x: u32 = n0
|
|
292
|
+
for (let i: i32 = 0; i < 4; i++) {
|
|
293
|
+
const nx: u32 = toU32(toU64(n0) * toU64(x))
|
|
294
|
+
x = toU32(toU64(x) * toU64(toU32(2 - toU64(nx))))
|
|
295
|
+
}
|
|
296
|
+
return toU32(0 - toU64(x))
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/** Whether the `count`-limb value `a` is at least `n`, compared from the top limb. */
|
|
300
|
+
const rsaAtLeast = (a: u32[], n: u32[], count: i32): boolean => {
|
|
301
|
+
if (count > toI32(a.length) || count > toI32(n.length)) {
|
|
302
|
+
return true
|
|
303
|
+
}
|
|
304
|
+
for (let i: i32 = count - 1; i >= 0; i--) {
|
|
305
|
+
if (a[i] !== n[i]) {
|
|
306
|
+
return a[i] > n[i]
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return true
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/** `a = a - n` over `count` limbs, dropping the borrow out of the top. */
|
|
313
|
+
const rsaSubInPlace = (a: u32[], n: u32[], count: i32): void => {
|
|
314
|
+
if (count > toI32(a.length) || count > toI32(n.length)) {
|
|
315
|
+
return
|
|
316
|
+
}
|
|
317
|
+
let borrow: u64 = 0
|
|
318
|
+
for (let i: i32 = 0; i < count; i++) {
|
|
319
|
+
const d: u64 = toU64(a[i]) - toU64(n[i]) - borrow
|
|
320
|
+
a[i] = toU32(d)
|
|
321
|
+
borrow = (d >> 32) & 1
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* `out = a b R^-1 mod n`, R = 2^(32 count), for `a` and `b` below `n`: Koç,
|
|
327
|
+
* Acar and Kaliski's CIOS. `t` is scratch of `count + 2` limbs. Each row adds
|
|
328
|
+
* `a b[i]` into `t`, then the multiple `m n` of the modulus that clears the
|
|
329
|
+
* low limb, and shifts down a limb; `t` stays below 2n, and one subtraction
|
|
330
|
+
* of `n` brings it below `n`. Every sum is at most (2^32 - 1) + (2^32 - 1)^2
|
|
331
|
+
* + (2^32 - 1) = 2^64 - 1, so a `u64` holds it.
|
|
332
|
+
*/
|
|
333
|
+
const rsaMontMul = (out: u32[], a: u32[], b: u32[], n: u32[], n0inv: u32, t: u32[], count: i32): void => {
|
|
334
|
+
if (
|
|
335
|
+
count < 1 ||
|
|
336
|
+
count > toI32(out.length) ||
|
|
337
|
+
count > toI32(a.length) ||
|
|
338
|
+
count > toI32(b.length) ||
|
|
339
|
+
count > toI32(n.length) ||
|
|
340
|
+
count + 2 > toI32(t.length)
|
|
341
|
+
) {
|
|
342
|
+
return
|
|
343
|
+
}
|
|
344
|
+
for (let i: i32 = 0; i < toI32(t.length); i++) {
|
|
345
|
+
t[i] = 0
|
|
346
|
+
}
|
|
347
|
+
for (let i: i32 = 0; i < count; i++) {
|
|
348
|
+
const bi: u64 = toU64(b[i])
|
|
349
|
+
let carry: u64 = 0
|
|
350
|
+
for (let j: i32 = 0; j < count; j++) {
|
|
351
|
+
const s: u64 = toU64(t[j]) + toU64(a[j]) * bi + carry
|
|
352
|
+
t[j] = toU32(s)
|
|
353
|
+
carry = s >> 32
|
|
354
|
+
}
|
|
355
|
+
const top: u64 = toU64(t[count]) + carry
|
|
356
|
+
t[count] = toU32(top)
|
|
357
|
+
t[count + 1] = toU32(top >> 32)
|
|
358
|
+
const m: u64 = toU64(toU32(toU64(t[0]) * toU64(n0inv)))
|
|
359
|
+
let c: u64 = (toU64(t[0]) + m * toU64(n[0])) >> 32
|
|
360
|
+
for (let j: i32 = 1; j < count; j++) {
|
|
361
|
+
const s: u64 = toU64(t[j]) + m * toU64(n[j]) + c
|
|
362
|
+
t[j - 1] = toU32(s)
|
|
363
|
+
c = s >> 32
|
|
364
|
+
}
|
|
365
|
+
const last: u64 = toU64(t[count]) + c
|
|
366
|
+
t[count - 1] = toU32(last)
|
|
367
|
+
t[count] = t[count + 1] + toU32(last >> 32)
|
|
368
|
+
}
|
|
369
|
+
if (t[count] !== 0 || rsaAtLeast(t, n, count)) {
|
|
370
|
+
rsaSubInPlace(t, n, count)
|
|
371
|
+
}
|
|
372
|
+
for (let i: i32 = 0; i < count; i++) {
|
|
373
|
+
out[i] = t[i]
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/** `r = 2 r mod n` over `count` limbs, for `r` below `n`; `r[count]` takes the bit the doubling carries out, so the comparison with `n` sees it. */
|
|
378
|
+
const rsaDoubleMod = (r: u32[], n: u32[], count: i32): void => {
|
|
379
|
+
if (count < 1 || count > toI32(n.length) || count + 1 > toI32(r.length)) {
|
|
380
|
+
return
|
|
381
|
+
}
|
|
382
|
+
let carry: u32 = 0
|
|
383
|
+
for (let i: i32 = 0; i < count; i++) {
|
|
384
|
+
const v: u32 = r[i]
|
|
385
|
+
r[i] = (v << 1) | carry
|
|
386
|
+
carry = v >> 31
|
|
387
|
+
}
|
|
388
|
+
r[count] = carry
|
|
389
|
+
if (carry !== 0 || rsaAtLeast(r, n, count)) {
|
|
390
|
+
rsaSubInPlace(r, n, count)
|
|
391
|
+
r[count] = 0
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* R^2 mod n, R = 2^(32 count), for the `count`-limb odd `n`. Writing 32 count
|
|
397
|
+
* as `s 2^j` with `s` odd, doubling 1 modulo `n` 32 count + s times gives
|
|
398
|
+
* R 2^s, and each Montgomery squaring of R 2^x gives R 2^2x, so `j` of them
|
|
399
|
+
* reach R 2^(32 count) = R^2: about a quarter of the work of doubling all the
|
|
400
|
+
* way.
|
|
401
|
+
*/
|
|
402
|
+
const rsaMontR2 = (n: u32[], n0inv: u32, t: u32[], count: i32): u32[] => {
|
|
403
|
+
let s: i32 = count << 5
|
|
404
|
+
let squarings: i32 = 0
|
|
405
|
+
while (s > 0 && (s & 1) === 0) {
|
|
406
|
+
s = s >> 1
|
|
407
|
+
squarings += 1
|
|
408
|
+
}
|
|
409
|
+
const r: u32[] = new Array<u32>(count + 1)
|
|
410
|
+
r[0] = 1
|
|
411
|
+
for (let k: i32 = 0; k < (count << 5) + s; k++) {
|
|
412
|
+
rsaDoubleMod(r, n, count)
|
|
413
|
+
}
|
|
414
|
+
for (let k: i32 = 0; k < squarings; k++) {
|
|
415
|
+
rsaMontMul(r, r, r, n, n0inv, t, count)
|
|
416
|
+
}
|
|
417
|
+
return r
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* `s^e mod n` as `size` big-endian bytes, for an odd `n` and an `s` below it.
|
|
422
|
+
* R^2 mod n comes from `rsaMontR2`; `s` is moved into
|
|
423
|
+
* the Montgomery domain by one multiplication by it, raised by square and
|
|
424
|
+
* multiply from the exponent's top bit, and moved out by a multiplication by 1.
|
|
425
|
+
*/
|
|
426
|
+
const rsaModPow = (s: u8[], e: u8[], n: u8[], size: i32): u8[] => {
|
|
427
|
+
const count: i32 = (toI32(n.length) + 3) >> 2
|
|
428
|
+
const nl: u32[] = rsaLimbsFromBytes(n, count)
|
|
429
|
+
const n0inv: u32 = rsaMontInverse(nl[0])
|
|
430
|
+
const t: u32[] = new Array<u32>(count + 2)
|
|
431
|
+
const r2: u32[] = rsaMontR2(nl, n0inv, t, count)
|
|
432
|
+
const base: u32[] = new Array<u32>(count)
|
|
433
|
+
rsaMontMul(base, rsaLimbsFromBytes(s, count), r2, nl, n0inv, t, count)
|
|
434
|
+
const acc: u32[] = new Array<u32>(count)
|
|
435
|
+
for (let i: i32 = 0; i < toI32(acc.length) && i < toI32(base.length); i++) {
|
|
436
|
+
acc[i] = base[i]
|
|
437
|
+
}
|
|
438
|
+
const bits: i32 = rsaBitLength(e)
|
|
439
|
+
const eLength: i32 = toI32(e.length)
|
|
440
|
+
for (let k: i32 = bits - 2; k >= 0; k--) {
|
|
441
|
+
rsaMontMul(acc, acc, acc, nl, n0inv, t, count)
|
|
442
|
+
const at: i32 = eLength - 1 - (k >> 3)
|
|
443
|
+
if (at >= 0 && at < eLength && ((toI32(e[at]) >> (k & 7)) & 1) === 1) {
|
|
444
|
+
rsaMontMul(acc, acc, base, nl, n0inv, t, count)
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
const one: u32[] = new Array<u32>(count)
|
|
448
|
+
one[0] = 1
|
|
449
|
+
rsaMontMul(acc, acc, one, nl, n0inv, t, count)
|
|
450
|
+
return rsaBytesFromLimbs(acc, size)
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* RSAVP1 (RFC 8017 §5.2.2) after §8.1.2 and §8.2.2's step 1: the signature as
|
|
455
|
+
* `size` big-endian bytes raised to `e` mod `n`, or `null` when the signature
|
|
456
|
+
* is not exactly as long as the modulus or its integer is not below `n`.
|
|
457
|
+
* `size` is the encoded message's length, the modulus's or one byte less; a
|
|
458
|
+
* value too large for it answers `null`.
|
|
459
|
+
*/
|
|
460
|
+
const rsaOpen = (key: RsaPublicKey, sig: u8[], size: i32): u8[] | null => {
|
|
461
|
+
const k: i32 = toI32(sig.length)
|
|
462
|
+
if (k !== toI32(key.n.length) || size < 0 || size > k) {
|
|
463
|
+
return null
|
|
464
|
+
}
|
|
465
|
+
let lead: i32 = 0
|
|
466
|
+
while (lead < k && toI32(sig[lead]) === 0) {
|
|
467
|
+
lead += 1
|
|
468
|
+
}
|
|
469
|
+
const trimmed: u8[] = new Array<u8>(k - lead)
|
|
470
|
+
for (let i: i32 = lead; i < k; i++) {
|
|
471
|
+
trimmed[i - lead] = sig[i]
|
|
472
|
+
}
|
|
473
|
+
if (!rsaBytesBelow(trimmed, key.n)) {
|
|
474
|
+
return null
|
|
475
|
+
}
|
|
476
|
+
const m: u8[] = rsaModPow(trimmed, key.e, key.n, k)
|
|
477
|
+
const mLength: i32 = toI32(m.length)
|
|
478
|
+
for (let i: i32 = 0; i < mLength - size && i < mLength; i++) {
|
|
479
|
+
if (toI32(m[i]) !== 0) {
|
|
480
|
+
return null
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
const out: u8[] = new Array<u8>(size)
|
|
484
|
+
for (let i: i32 = 0; i < toI32(out.length); i++) {
|
|
485
|
+
out[i] = m[mLength - size + i]
|
|
486
|
+
}
|
|
487
|
+
return out
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// ---------------------------------------------------------------------------
|
|
491
|
+
// The encodings (RFC 8017 §9.1, §9.2, §B.2.1)
|
|
492
|
+
// ---------------------------------------------------------------------------
|
|
493
|
+
|
|
494
|
+
/** The digest length of the hash id `hash`, or 0 for an id this module does not know. */
|
|
495
|
+
const rsaHashSize = (hash: i32): i32 => {
|
|
496
|
+
if (hash === RSA_HASH_SHA256) {
|
|
497
|
+
return 32
|
|
498
|
+
}
|
|
499
|
+
if (hash === RSA_HASH_SHA384) {
|
|
500
|
+
return 48
|
|
501
|
+
}
|
|
502
|
+
if (hash === RSA_HASH_SHA512) {
|
|
503
|
+
return 64
|
|
504
|
+
}
|
|
505
|
+
return 0
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/** The digest of `data` under the hash id `hash`, which `rsaHashSize` knows. */
|
|
509
|
+
const rsaDigest = (hash: i32, data: u8[]): u8[] => {
|
|
510
|
+
if (hash === RSA_HASH_SHA384) {
|
|
511
|
+
return sha384(data)
|
|
512
|
+
}
|
|
513
|
+
if (hash === RSA_HASH_SHA512) {
|
|
514
|
+
return sha512(data)
|
|
515
|
+
}
|
|
516
|
+
return sha256(data)
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* The DER of the DigestInfo's algorithm and the OCTET STRING header before
|
|
521
|
+
* the digest, RFC 8017 §9.2 note 1: the id-sha256, id-sha384 or id-sha512 OID
|
|
522
|
+
* with NULL parameters. The OIDs differ in their last octet alone.
|
|
523
|
+
*/
|
|
524
|
+
const rsaDigestInfoPrefix = (hash: i32, hashSize: i32): u8[] => {
|
|
525
|
+
const out: u8[] = [
|
|
526
|
+
0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00,
|
|
527
|
+
0x04, 0x20,
|
|
528
|
+
]
|
|
529
|
+
out[1] = toU8(hashSize + 17)
|
|
530
|
+
out[14] = toU8(hash)
|
|
531
|
+
out[18] = toU8(hashSize)
|
|
532
|
+
return out
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/** Whether `a` and `b` hold the same bytes. Both are public, so it stops at the first difference. */
|
|
536
|
+
const rsaSameBytes = (a: u8[], b: u8[]): boolean => {
|
|
537
|
+
const length: i32 = toI32(a.length)
|
|
538
|
+
if (toI32(b.length) !== length) {
|
|
539
|
+
return false
|
|
540
|
+
}
|
|
541
|
+
for (let i: i32 = 0; i < length && i < toI32(b.length); i++) {
|
|
542
|
+
if (a[i] !== b[i]) {
|
|
543
|
+
return false
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
return true
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* Verifies an RSASSA-PKCS1-v1_5 signature (RFC 8017 §8.2.2) of `msg` under
|
|
551
|
+
* `key`, with the hash id `hash`. The encoded message the signature should
|
|
552
|
+
* open to, `00 01 FF … FF 00 DigestInfo`, is built whole (EMSA-PKCS1-v1_5,
|
|
553
|
+
* §9.2) and compared with what it does open to. `false` for an unknown hash
|
|
554
|
+
* id, a modulus too short for the encoding, a signature that is not exactly
|
|
555
|
+
* as long as the modulus or not below it, and any other bytes.
|
|
556
|
+
*/
|
|
557
|
+
export const rsaVerifyPkcs1v15 = (key: RsaPublicKey, hash: i32, msg: u8[], sig: u8[]): boolean => {
|
|
558
|
+
const hashSize: i32 = rsaHashSize(hash)
|
|
559
|
+
const k: i32 = toI32(key.n.length)
|
|
560
|
+
const prefix: u8[] = rsaDigestInfoPrefix(hash, hashSize)
|
|
561
|
+
const tLength: i32 = toI32(prefix.length) + hashSize
|
|
562
|
+
if (hashSize === 0 || k < tLength + 11) {
|
|
563
|
+
return false
|
|
564
|
+
}
|
|
565
|
+
const em: u8[] | null = rsaOpen(key, sig, k)
|
|
566
|
+
if (em === null) {
|
|
567
|
+
return false
|
|
568
|
+
}
|
|
569
|
+
const expected: u8[] = [0x00, 0x01]
|
|
570
|
+
for (let i: i32 = 2; i < k - tLength - 1; i++) {
|
|
571
|
+
expected.push(0xff)
|
|
572
|
+
}
|
|
573
|
+
expected.push(0x00)
|
|
574
|
+
for (const byte of prefix) {
|
|
575
|
+
expected.push(byte)
|
|
576
|
+
}
|
|
577
|
+
for (const byte of rsaDigest(hash, msg)) {
|
|
578
|
+
expected.push(byte)
|
|
579
|
+
}
|
|
580
|
+
return rsaSameBytes(em, expected)
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* MGF1 (RFC 8017 §B.2.1) with the hash id `hash` over `seed`, `length` bytes:
|
|
585
|
+
* the digests of `seed || C` for the four-byte counters C = 0, 1, …, joined.
|
|
586
|
+
*/
|
|
587
|
+
const rsaMgf1 = (hash: i32, seed: u8[], length: i32): u8[] => {
|
|
588
|
+
const out: u8[] = []
|
|
589
|
+
for (let counter: i32 = 0; toI32(out.length) < length; counter++) {
|
|
590
|
+
const input: u8[] = []
|
|
591
|
+
for (const byte of seed) {
|
|
592
|
+
input.push(byte)
|
|
593
|
+
}
|
|
594
|
+
input.push(toU8(counter >> 24))
|
|
595
|
+
input.push(toU8(counter >> 16))
|
|
596
|
+
input.push(toU8(counter >> 8))
|
|
597
|
+
input.push(toU8(counter))
|
|
598
|
+
for (const byte of rsaDigest(hash, input)) {
|
|
599
|
+
if (toI32(out.length) < length) {
|
|
600
|
+
out.push(byte)
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
return out
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* Verifies an RSASSA-PSS signature (RFC 8017 §8.1.2) of `msg` under `key`,
|
|
609
|
+
* with the hash id `hash` for the message and for MGF1, and a salt of exactly
|
|
610
|
+
* `saltLen` bytes. Every check of EMSA-PSS-VERIFY (§9.1.2) is made: the
|
|
611
|
+
* length, the trailing 0xbc, the leftmost `8 emLen - emBits` bits of the
|
|
612
|
+
* masked block and of the unmasked one, the zero octets and the 0x01 before
|
|
613
|
+
* the salt, and the hash. `false` for any of them, an unknown hash id, a
|
|
614
|
+
* negative `saltLen`, and a signature that is not exactly as long as the
|
|
615
|
+
* modulus or not below it.
|
|
616
|
+
*/
|
|
617
|
+
export const rsaVerifyPss = (key: RsaPublicKey, hash: i32, saltLen: i32, msg: u8[], sig: u8[]): boolean => {
|
|
618
|
+
const hashSize: i32 = rsaHashSize(hash)
|
|
619
|
+
if (hashSize === 0 || saltLen < 0) {
|
|
620
|
+
return false
|
|
621
|
+
}
|
|
622
|
+
const emBits: i32 = rsaBitLength(key.n) - 1
|
|
623
|
+
const emLen: i32 = (emBits + 7) >> 3
|
|
624
|
+
if (saltLen > emLen || emLen < hashSize + saltLen + 2) {
|
|
625
|
+
return false
|
|
626
|
+
}
|
|
627
|
+
const em: u8[] | null = rsaOpen(key, sig, emLen)
|
|
628
|
+
if (em === null || toI32(em[emLen - 1]) !== 0xbc) {
|
|
629
|
+
return false
|
|
630
|
+
}
|
|
631
|
+
const dbLength: i32 = emLen - hashSize - 1
|
|
632
|
+
const full: i32 = 0xff
|
|
633
|
+
const topMask: i32 = full >> ((emLen << 3) - emBits)
|
|
634
|
+
if ((toI32(em[0]) & ~topMask) !== 0) {
|
|
635
|
+
return false
|
|
636
|
+
}
|
|
637
|
+
const h: u8[] = []
|
|
638
|
+
for (let i: i32 = dbLength; i < emLen - 1; i++) {
|
|
639
|
+
h.push(em[i])
|
|
640
|
+
}
|
|
641
|
+
const db: u8[] = rsaMgf1(hash, h, dbLength)
|
|
642
|
+
for (let i: i32 = 0; i < dbLength && i < toI32(db.length); i++) {
|
|
643
|
+
db[i] = db[i] ^ em[i]
|
|
644
|
+
}
|
|
645
|
+
db[0] = toU8(toI32(db[0]) & topMask)
|
|
646
|
+
const zeros: i32 = emLen - hashSize - saltLen - 2
|
|
647
|
+
for (let i: i32 = 0; i < zeros && i < toI32(db.length); i++) {
|
|
648
|
+
if (toI32(db[i]) !== 0) {
|
|
649
|
+
return false
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
if (toI32(db[zeros]) !== 0x01) {
|
|
653
|
+
return false
|
|
654
|
+
}
|
|
655
|
+
const prime: u8[] = [0, 0, 0, 0, 0, 0, 0, 0]
|
|
656
|
+
for (const byte of rsaDigest(hash, msg)) {
|
|
657
|
+
prime.push(byte)
|
|
658
|
+
}
|
|
659
|
+
for (let i: i32 = dbLength - saltLen; i >= 0 && i < dbLength && i < toI32(db.length); i++) {
|
|
660
|
+
prime.push(db[i])
|
|
661
|
+
}
|
|
662
|
+
return rsaSameBytes(rsaDigest(hash, prime), h)
|
|
663
|
+
}
|