@gjsify/crypto 0.3.16 → 0.3.18

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/lib/esm/asn1.js CHANGED
@@ -1,630 +1,2 @@
1
- import { Buffer } from "node:buffer";
2
-
3
- //#region src/asn1.ts
4
- /**
5
- * Strip PEM armor (header/footer lines), base64-decode the body to DER bytes.
6
- */
7
- function pemToDer(pem) {
8
- const lines = pem.trim().split(/\r?\n/);
9
- const headerIdx = lines.findIndex((l) => l.startsWith("-----BEGIN "));
10
- if (headerIdx === -1) {
11
- throw new Error("Invalid PEM: no BEGIN line found");
12
- }
13
- const headerLine = lines[headerIdx];
14
- const headerMatch = headerLine.match(/^-----BEGIN (.+)-----$/);
15
- if (!headerMatch) {
16
- throw new Error("Invalid PEM header format");
17
- }
18
- const type = headerMatch[1];
19
- const footerIdx = lines.findIndex((l, i) => i > headerIdx && l.startsWith("-----END "));
20
- if (footerIdx === -1) {
21
- throw new Error("Invalid PEM: no END line found");
22
- }
23
- const base64Body = lines.slice(headerIdx + 1, footerIdx).join("");
24
- const der = Buffer.from(base64Body, "base64");
25
- return {
26
- type,
27
- der: new Uint8Array(der.buffer, der.byteOffset, der.byteLength)
28
- };
29
- }
30
- /** ASN.1 tag constants */
31
- const ASN1_INTEGER = 2;
32
- const ASN1_BIT_STRING = 3;
33
- const ASN1_OCTET_STRING = 4;
34
- const ASN1_NULL = 5;
35
- const ASN1_OID = 6;
36
- const ASN1_SEQUENCE = 48;
37
- /**
38
- * Parse one TLV (tag-length-value) from the DER buffer starting at `offset`.
39
- * Returns the parsed value and the new offset past it.
40
- */
41
- function parseTlv(buf, offset) {
42
- if (offset >= buf.length) {
43
- throw new Error("ASN.1 parse error: unexpected end of data");
44
- }
45
- const tag = buf[offset++];
46
- let length;
47
- const firstLenByte = buf[offset++];
48
- if (firstLenByte < 128) {
49
- length = firstLenByte;
50
- } else {
51
- const numLenBytes = firstLenByte & 127;
52
- if (numLenBytes === 0) {
53
- throw new Error("ASN.1 parse error: indefinite length not supported");
54
- }
55
- length = 0;
56
- for (let i = 0; i < numLenBytes; i++) {
57
- length = length << 8 | buf[offset++];
58
- }
59
- }
60
- const data = buf.slice(offset, offset + length);
61
- const next = offset + length;
62
- const result = {
63
- tag,
64
- data
65
- };
66
- if (tag === ASN1_SEQUENCE) {
67
- result.children = parseSequenceChildren(data);
68
- }
69
- return {
70
- value: result,
71
- next
72
- };
73
- }
74
- /**
75
- * Parse all TLV children within a SEQUENCE's data bytes.
76
- */
77
- function parseSequenceChildren(data) {
78
- const children = [];
79
- let pos = 0;
80
- while (pos < data.length) {
81
- const { value, next } = parseTlv(data, pos);
82
- children.push(value);
83
- pos = next;
84
- }
85
- return children;
86
- }
87
- /**
88
- * Parse the entire DER buffer as a single top-level TLV.
89
- */
90
- function parseDer(buf) {
91
- const { value } = parseTlv(buf, 0);
92
- return value;
93
- }
94
- /**
95
- * Convert an ASN.1 INTEGER's raw data bytes to a non-negative BigInt.
96
- * ASN.1 INTEGERs are big-endian two's-complement. For RSA keys all values
97
- * are positive, so we just strip any leading 0x00 padding byte.
98
- */
99
- function integerToBigInt(data) {
100
- let start = 0;
101
- while (start < data.length - 1 && data[start] === 0) {
102
- start++;
103
- }
104
- let result = 0n;
105
- for (let i = start; i < data.length; i++) {
106
- result = result << 8n | BigInt(data[i]);
107
- }
108
- return result;
109
- }
110
- /** RSA encryption OID: 1.2.840.113549.1.1.1 */
111
- const RSA_OID = new Uint8Array([
112
- 42,
113
- 134,
114
- 72,
115
- 134,
116
- 247,
117
- 13,
118
- 1,
119
- 1,
120
- 1
121
- ]);
122
- function oidsEqual(a, b) {
123
- if (a.length !== b.length) return false;
124
- for (let i = 0; i < a.length; i++) {
125
- if (a[i] !== b[i]) return false;
126
- }
127
- return true;
128
- }
129
- /**
130
- * Parse PKCS#1 RSAPublicKey:
131
- * SEQUENCE { INTEGER n, INTEGER e }
132
- */
133
- function parseRsaPublicKeyPkcs1(seq) {
134
- const children = seq.children;
135
- if (!children || children.length < 2) {
136
- throw new Error("Invalid PKCS#1 RSAPublicKey structure");
137
- }
138
- return {
139
- n: integerToBigInt(children[0].data),
140
- e: integerToBigInt(children[1].data)
141
- };
142
- }
143
- /**
144
- * Parse PKCS#1 RSAPrivateKey:
145
- * SEQUENCE {
146
- * INTEGER version,
147
- * INTEGER n,
148
- * INTEGER e,
149
- * INTEGER d,
150
- * INTEGER p,
151
- * INTEGER q,
152
- * INTEGER dp,
153
- * INTEGER dq,
154
- * INTEGER qi
155
- * }
156
- */
157
- function parseRsaPrivateKeyPkcs1(seq) {
158
- const children = seq.children;
159
- if (!children || children.length < 6) {
160
- throw new Error("Invalid PKCS#1 RSAPrivateKey structure");
161
- }
162
- return {
163
- n: integerToBigInt(children[1].data),
164
- e: integerToBigInt(children[2].data),
165
- d: integerToBigInt(children[3].data),
166
- p: integerToBigInt(children[4].data),
167
- q: integerToBigInt(children[5].data)
168
- };
169
- }
170
- /**
171
- * Parse PKCS#8 SubjectPublicKeyInfo:
172
- * SEQUENCE {
173
- * SEQUENCE { OID algorithm, NULL } -- AlgorithmIdentifier
174
- * BIT STRING -- wraps PKCS#1 RSAPublicKey
175
- * }
176
- */
177
- function parseSubjectPublicKeyInfo(seq) {
178
- const children = seq.children;
179
- if (!children || children.length < 2) {
180
- throw new Error("Invalid SubjectPublicKeyInfo structure");
181
- }
182
- const algIdSeq = children[0];
183
- if (!algIdSeq.children || algIdSeq.children.length < 1) {
184
- throw new Error("Invalid AlgorithmIdentifier");
185
- }
186
- const oid = algIdSeq.children[0];
187
- if (oid.tag !== ASN1_OID || !oidsEqual(oid.data, RSA_OID)) {
188
- throw new Error("Unsupported algorithm: only RSA is supported");
189
- }
190
- const bitString = children[1];
191
- if (bitString.tag !== ASN1_BIT_STRING) {
192
- throw new Error("Expected BIT STRING for public key data");
193
- }
194
- const innerDer = bitString.data.slice(1);
195
- const innerSeq = parseDer(innerDer);
196
- return parseRsaPublicKeyPkcs1(innerSeq);
197
- }
198
- /**
199
- * Parse PKCS#8 PrivateKeyInfo:
200
- * SEQUENCE {
201
- * INTEGER version,
202
- * SEQUENCE { OID algorithm, NULL } -- AlgorithmIdentifier
203
- * OCTET STRING -- wraps PKCS#1 RSAPrivateKey
204
- * }
205
- */
206
- function parsePrivateKeyInfo(seq) {
207
- const children = seq.children;
208
- if (!children || children.length < 3) {
209
- throw new Error("Invalid PrivateKeyInfo structure");
210
- }
211
- const algIdSeq = children[1];
212
- if (!algIdSeq.children || algIdSeq.children.length < 1) {
213
- throw new Error("Invalid AlgorithmIdentifier");
214
- }
215
- const oid = algIdSeq.children[0];
216
- if (oid.tag !== ASN1_OID || !oidsEqual(oid.data, RSA_OID)) {
217
- throw new Error("Unsupported algorithm: only RSA is supported");
218
- }
219
- const octetString = children[2];
220
- if (octetString.tag !== ASN1_OCTET_STRING) {
221
- throw new Error("Expected OCTET STRING for private key data");
222
- }
223
- const innerSeq = parseDer(octetString.data);
224
- return parseRsaPrivateKeyPkcs1(innerSeq);
225
- }
226
- /**
227
- * Encode a length value in DER format.
228
- */
229
- function encodeLength(length) {
230
- if (length < 128) {
231
- return new Uint8Array([length]);
232
- }
233
- const bytes = [];
234
- let val = length;
235
- while (val > 0) {
236
- bytes.unshift(val & 255);
237
- val >>= 8;
238
- }
239
- return new Uint8Array([128 | bytes.length, ...bytes]);
240
- }
241
- /**
242
- * Encode a TLV (tag-length-value).
243
- */
244
- function encodeTlv(tag, data) {
245
- const len = encodeLength(data.length);
246
- const result = new Uint8Array(1 + len.length + data.length);
247
- result[0] = tag;
248
- result.set(len, 1);
249
- result.set(data, 1 + len.length);
250
- return result;
251
- }
252
- /**
253
- * Encode a BigInt as an ASN.1 INTEGER.
254
- */
255
- function bigintToAsn1Integer(value) {
256
- if (value === 0n) {
257
- return encodeTlv(ASN1_INTEGER, new Uint8Array([0]));
258
- }
259
- const hex = value.toString(16);
260
- const paddedHex = hex.length % 2 ? "0" + hex : hex;
261
- const bytes = [];
262
- for (let i = 0; i < paddedHex.length; i += 2) {
263
- bytes.push(parseInt(paddedHex.substring(i, i + 2), 16));
264
- }
265
- if (bytes[0] & 128) {
266
- bytes.unshift(0);
267
- }
268
- return encodeTlv(ASN1_INTEGER, new Uint8Array(bytes));
269
- }
270
- /**
271
- * Encode an ASN.1 SEQUENCE from its children.
272
- */
273
- function encodeSequence(children) {
274
- let totalLen = 0;
275
- for (const child of children) totalLen += child.length;
276
- const data = new Uint8Array(totalLen);
277
- let offset = 0;
278
- for (const child of children) {
279
- data.set(child, offset);
280
- offset += child.length;
281
- }
282
- return encodeTlv(ASN1_SEQUENCE, data);
283
- }
284
- /**
285
- * Encode an ASN.1 BIT STRING (with 0 unused bits).
286
- */
287
- function encodeBitString(data) {
288
- const inner = new Uint8Array(1 + data.length);
289
- inner[0] = 0;
290
- inner.set(data, 1);
291
- return encodeTlv(ASN1_BIT_STRING, inner);
292
- }
293
- /**
294
- * Encode an ASN.1 OCTET STRING.
295
- */
296
- function encodeOctetString(data) {
297
- return encodeTlv(ASN1_OCTET_STRING, data);
298
- }
299
- /**
300
- * Encode an ASN.1 OID.
301
- */
302
- function encodeOid(oidBytes) {
303
- return encodeTlv(ASN1_OID, oidBytes);
304
- }
305
- /**
306
- * Encode ASN.1 NULL.
307
- */
308
- function encodeNull() {
309
- return new Uint8Array([ASN1_NULL, 0]);
310
- }
311
- /**
312
- * Encode RSA public key components as PKCS#1 RSAPublicKey DER.
313
- */
314
- function encodeRsaPublicKeyPkcs1(components) {
315
- return encodeSequence([bigintToAsn1Integer(components.n), bigintToAsn1Integer(components.e)]);
316
- }
317
- /**
318
- * Encode RSA public key as PKCS#8 SubjectPublicKeyInfo DER.
319
- */
320
- function encodeSubjectPublicKeyInfo(components) {
321
- const algorithmId = encodeSequence([encodeOid(RSA_OID), encodeNull()]);
322
- const rsaPublicKey = encodeRsaPublicKeyPkcs1(components);
323
- const bitString = encodeBitString(rsaPublicKey);
324
- return encodeSequence([algorithmId, bitString]);
325
- }
326
- /**
327
- * Encode RSA private key components as PKCS#1 RSAPrivateKey DER.
328
- */
329
- function encodeRsaPrivateKeyPkcs1(components) {
330
- const dp = components.d % (components.p - 1n);
331
- const dq = components.d % (components.q - 1n);
332
- const qi = modInverse(components.q, components.p);
333
- return encodeSequence([
334
- bigintToAsn1Integer(0n),
335
- bigintToAsn1Integer(components.n),
336
- bigintToAsn1Integer(components.e),
337
- bigintToAsn1Integer(components.d),
338
- bigintToAsn1Integer(components.p),
339
- bigintToAsn1Integer(components.q),
340
- bigintToAsn1Integer(dp),
341
- bigintToAsn1Integer(dq),
342
- bigintToAsn1Integer(qi)
343
- ]);
344
- }
345
- /**
346
- * Encode RSA private key as PKCS#8 PrivateKeyInfo DER.
347
- */
348
- function encodePrivateKeyInfo(components) {
349
- const algorithmId = encodeSequence([encodeOid(RSA_OID), encodeNull()]);
350
- const rsaPrivateKey = encodeRsaPrivateKeyPkcs1(components);
351
- const octetString = encodeOctetString(rsaPrivateKey);
352
- return encodeSequence([
353
- bigintToAsn1Integer(0n),
354
- algorithmId,
355
- octetString
356
- ]);
357
- }
358
- /**
359
- * Convert DER bytes to PEM string.
360
- */
361
- function derToPem(der, type) {
362
- const base64 = Buffer.from(der).toString("base64");
363
- const lines = [`-----BEGIN ${type}-----`];
364
- for (let i = 0; i < base64.length; i += 64) {
365
- lines.push(base64.substring(i, i + 64));
366
- }
367
- lines.push(`-----END ${type}-----`);
368
- return lines.join("\n");
369
- }
370
- /**
371
- * Modular inverse: a^(-1) mod m using extended Euclidean algorithm.
372
- */
373
- function modInverse(a, m) {
374
- let [old_r, r] = [a % m, m];
375
- let [old_s, s] = [1n, 0n];
376
- while (r !== 0n) {
377
- const q = old_r / r;
378
- [old_r, r] = [r, old_r - q * r];
379
- [old_s, s] = [s, old_s - q * s];
380
- }
381
- return (old_s % m + m) % m;
382
- }
383
- /**
384
- * Parse an X.509 certificate from PEM or DER.
385
- */
386
- function parseX509(pem) {
387
- const { der } = pemToDer(pem);
388
- return parseX509Der(der);
389
- }
390
- /**
391
- * Parse an X.509 certificate from DER bytes.
392
- */
393
- function parseX509Der(der) {
394
- const root = parseDer(der);
395
- if (root.tag !== ASN1_SEQUENCE || !root.children || root.children.length < 3) {
396
- throw new Error("Invalid X.509 certificate structure");
397
- }
398
- const tbsCertificate = root.children[0];
399
- const signatureAlgorithm = root.children[1];
400
- const signatureBitString = root.children[2];
401
- if (!tbsCertificate.children || tbsCertificate.children.length < 6) {
402
- throw new Error("Invalid TBSCertificate structure");
403
- }
404
- let idx = 0;
405
- if (tbsCertificate.children[0].tag === 160) {
406
- idx++;
407
- }
408
- const serialNumber = integerToBigInt(tbsCertificate.children[idx].data);
409
- idx++;
410
- idx++;
411
- const issuer = parseDN(tbsCertificate.children[idx]);
412
- idx++;
413
- const validity = tbsCertificate.children[idx];
414
- const validFrom = parseAsn1Time(validity.children[0]);
415
- const validTo = parseAsn1Time(validity.children[1]);
416
- idx++;
417
- const subject = parseDN(tbsCertificate.children[idx]);
418
- idx++;
419
- let publicKey = null;
420
- let publicKeyAlgorithm = "unknown";
421
- if (idx < tbsCertificate.children.length) {
422
- const spki = tbsCertificate.children[idx];
423
- try {
424
- if (spki.children && spki.children.length >= 2) {
425
- const algId = spki.children[0];
426
- if (algId.children && algId.children.length >= 1) {
427
- const oid = algId.children[0];
428
- if (oid.tag === ASN1_OID && oidsEqual(oid.data, RSA_OID)) {
429
- publicKeyAlgorithm = "rsa";
430
- publicKey = parseSubjectPublicKeyInfo(spki);
431
- }
432
- }
433
- }
434
- } catch {}
435
- idx++;
436
- }
437
- let subjectAltName;
438
- let extensions;
439
- for (let i = idx; i < tbsCertificate.children.length; i++) {
440
- const child = tbsCertificate.children[i];
441
- if (child.tag === 163 && child.data.length > 0) {
442
- const extSeq = parseDer(child.data);
443
- if (extSeq.children) {
444
- extensions = extSeq.children;
445
- const SAN_OID = new Uint8Array([
446
- 85,
447
- 29,
448
- 17
449
- ]);
450
- for (const ext of extSeq.children) {
451
- if (ext.children && ext.children.length >= 2) {
452
- const extOid = ext.children[0];
453
- if (extOid.tag === ASN1_OID && oidsEqual(extOid.data, SAN_OID)) {
454
- const extValue = ext.children[ext.children.length - 1];
455
- subjectAltName = parseSAN(extValue.data);
456
- }
457
- }
458
- }
459
- }
460
- }
461
- }
462
- let sigAlg = "unknown";
463
- if (signatureAlgorithm.children && signatureAlgorithm.children.length >= 1) {
464
- sigAlg = oidToName(signatureAlgorithm.children[0].data);
465
- }
466
- const signature = signatureBitString.tag === ASN1_BIT_STRING ? signatureBitString.data.slice(1) : signatureBitString.data;
467
- return {
468
- raw: der,
469
- tbsCertificate: tbsCertificate.data,
470
- serialNumber,
471
- issuer,
472
- subject,
473
- validFrom,
474
- validTo,
475
- publicKey,
476
- publicKeyAlgorithm,
477
- signatureAlgorithm: sigAlg,
478
- signature,
479
- subjectAltName,
480
- extensions
481
- };
482
- }
483
- const OID_NAMES = {
484
- "2.5.4.3": "CN",
485
- "2.5.4.6": "C",
486
- "2.5.4.7": "L",
487
- "2.5.4.8": "ST",
488
- "2.5.4.10": "O",
489
- "2.5.4.11": "OU",
490
- "1.2.840.113549.1.9.1": "emailAddress"
491
- };
492
- const SIG_ALG_NAMES = {
493
- "1.2.840.113549.1.1.1": "rsaEncryption",
494
- "1.2.840.113549.1.1.5": "sha1WithRSAEncryption",
495
- "1.2.840.113549.1.1.11": "sha256WithRSAEncryption",
496
- "1.2.840.113549.1.1.12": "sha384WithRSAEncryption",
497
- "1.2.840.113549.1.1.13": "sha512WithRSAEncryption"
498
- };
499
- function decodeOidString(data) {
500
- if (data.length === 0) return "";
501
- const components = [];
502
- components.push(Math.floor(data[0] / 40));
503
- components.push(data[0] % 40);
504
- let value = 0;
505
- for (let i = 1; i < data.length; i++) {
506
- value = value << 7 | data[i] & 127;
507
- if (!(data[i] & 128)) {
508
- components.push(value);
509
- value = 0;
510
- }
511
- }
512
- return components.join(".");
513
- }
514
- function oidToName(data) {
515
- const oidStr = decodeOidString(data);
516
- return SIG_ALG_NAMES[oidStr] || oidStr;
517
- }
518
- function parseDN(seq) {
519
- if (!seq.children) return "";
520
- const parts = [];
521
- for (const rdn of seq.children) {
522
- const rdnChildren = rdn.tag === 49 ? parseSequenceChildren(rdn.data) : rdn.children || [];
523
- for (const atv of rdnChildren) {
524
- if (atv.children && atv.children.length >= 2) {
525
- const oidData = atv.children[0].data;
526
- const oidStr = decodeOidString(oidData);
527
- const name = OID_NAMES[oidStr] || oidStr;
528
- const valueBytes = atv.children[1].data;
529
- const value = new TextDecoder().decode(valueBytes);
530
- parts.push(`${name}=${value}`);
531
- }
532
- }
533
- }
534
- return parts.join(", ");
535
- }
536
- function parseAsn1Time(tlv) {
537
- const str = new TextDecoder().decode(tlv.data);
538
- if (tlv.tag === 23) {
539
- let year = parseInt(str.substring(0, 2), 10);
540
- year = year >= 50 ? 1900 + year : 2e3 + year;
541
- const month = parseInt(str.substring(2, 4), 10) - 1;
542
- const day = parseInt(str.substring(4, 6), 10);
543
- const hour = parseInt(str.substring(6, 8), 10);
544
- const minute = parseInt(str.substring(8, 10), 10);
545
- const second = parseInt(str.substring(10, 12), 10);
546
- return new Date(Date.UTC(year, month, day, hour, minute, second));
547
- }
548
- if (tlv.tag === 24) {
549
- const year = parseInt(str.substring(0, 4), 10);
550
- const month = parseInt(str.substring(4, 6), 10) - 1;
551
- const day = parseInt(str.substring(6, 8), 10);
552
- const hour = parseInt(str.substring(8, 10), 10);
553
- const minute = parseInt(str.substring(10, 12), 10);
554
- const second = parseInt(str.substring(12, 14), 10);
555
- return new Date(Date.UTC(year, month, day, hour, minute, second));
556
- }
557
- throw new Error(`Unsupported time tag: 0x${tlv.tag.toString(16)}`);
558
- }
559
- function parseSAN(data) {
560
- const names = [];
561
- try {
562
- const seq = parseDer(data);
563
- if (seq.tag === ASN1_SEQUENCE && seq.children) {
564
- for (const child of seq.children) {
565
- if (child.tag === 130) {
566
- names.push("DNS:" + new TextDecoder().decode(child.data));
567
- } else if (child.tag === 135) {
568
- if (child.data.length === 4) {
569
- names.push("IP Address:" + child.data.join("."));
570
- } else if (child.data.length === 16) {
571
- const parts = [];
572
- for (let i = 0; i < 16; i += 2) {
573
- parts.push((child.data[i] << 8 | child.data[i + 1]).toString(16));
574
- }
575
- names.push("IP Address:" + parts.join(":"));
576
- }
577
- }
578
- }
579
- }
580
- } catch {}
581
- return names;
582
- }
583
- /**
584
- * Parse a PEM-encoded RSA key. Supports:
585
- * - RSA PUBLIC KEY (PKCS#1)
586
- * - PUBLIC KEY (PKCS#8 SubjectPublicKeyInfo)
587
- * - RSA PRIVATE KEY (PKCS#1)
588
- * - PRIVATE KEY (PKCS#8 PrivateKeyInfo)
589
- */
590
- function parsePemKey(pem) {
591
- const { type, der } = pemToDer(pem);
592
- const root = parseDer(der);
593
- if (root.tag !== ASN1_SEQUENCE) {
594
- throw new Error("Invalid key format: expected top-level SEQUENCE");
595
- }
596
- switch (type) {
597
- case "RSA PUBLIC KEY": return {
598
- type: "rsa-public",
599
- components: parseRsaPublicKeyPkcs1(root)
600
- };
601
- case "PUBLIC KEY": return {
602
- type: "rsa-public",
603
- components: parseSubjectPublicKeyInfo(root)
604
- };
605
- case "RSA PRIVATE KEY": return {
606
- type: "rsa-private",
607
- components: parseRsaPrivateKeyPkcs1(root)
608
- };
609
- case "PRIVATE KEY": return {
610
- type: "rsa-private",
611
- components: parsePrivateKeyInfo(root)
612
- };
613
- default: throw new Error(`Unsupported PEM type: ${type}`);
614
- }
615
- }
616
- /**
617
- * Get the key size in bytes (byte length of modulus n).
618
- */
619
- function rsaKeySize(n) {
620
- let bits = 0;
621
- let val = n;
622
- while (val > 0n) {
623
- bits++;
624
- val >>= 1n;
625
- }
626
- return Math.ceil(bits / 8);
627
- }
628
-
629
- //#endregion
630
- export { bigintToAsn1Integer, derToPem, encodePrivateKeyInfo, encodeRsaPrivateKeyPkcs1, encodeRsaPublicKeyPkcs1, encodeSequence, encodeSubjectPublicKeyInfo, parsePemKey, parseX509, parseX509Der, rsaKeySize };
1
+ import{Buffer as e}from"node:buffer";function t(t){let n=t.trim().split(/\r?\n/),r=n.findIndex(e=>e.startsWith(`-----BEGIN `));if(r===-1)throw Error(`Invalid PEM: no BEGIN line found`);let i=n[r].match(/^-----BEGIN (.+)-----$/);if(!i)throw Error(`Invalid PEM header format`);let a=i[1],o=n.findIndex((e,t)=>t>r&&e.startsWith(`-----END `));if(o===-1)throw Error(`Invalid PEM: no END line found`);let s=n.slice(r+1,o).join(``),c=e.from(s,`base64`);return{type:a,der:new Uint8Array(c.buffer,c.byteOffset,c.byteLength)}}function n(e,t){if(t>=e.length)throw Error(`ASN.1 parse error: unexpected end of data`);let n=e[t++],i,a=e[t++];if(a<128)i=a;else{let n=a&127;if(n===0)throw Error(`ASN.1 parse error: indefinite length not supported`);i=0;for(let r=0;r<n;r++)i=i<<8|e[t++]}let o=e.slice(t,t+i),s=t+i,c={tag:n,data:o};return n===48&&(c.children=r(o)),{value:c,next:s}}function r(e){let t=[],r=0;for(;r<e.length;){let{value:i,next:a}=n(e,r);t.push(i),r=a}return t}function i(e){let{value:t}=n(e,0);return t}function a(e){let t=0;for(;t<e.length-1&&e[t]===0;)t++;let n=0n;for(let r=t;r<e.length;r++)n=n<<8n|BigInt(e[r]);return n}const o=new Uint8Array([42,134,72,134,247,13,1,1,1]);function s(e,t){if(e.length!==t.length)return!1;for(let n=0;n<e.length;n++)if(e[n]!==t[n])return!1;return!0}function c(e){let t=e.children;if(!t||t.length<2)throw Error(`Invalid PKCS#1 RSAPublicKey structure`);return{n:a(t[0].data),e:a(t[1].data)}}function l(e){let t=e.children;if(!t||t.length<6)throw Error(`Invalid PKCS#1 RSAPrivateKey structure`);return{n:a(t[1].data),e:a(t[2].data),d:a(t[3].data),p:a(t[4].data),q:a(t[5].data)}}function u(e){let t=e.children;if(!t||t.length<2)throw Error(`Invalid SubjectPublicKeyInfo structure`);let n=t[0];if(!n.children||n.children.length<1)throw Error(`Invalid AlgorithmIdentifier`);let r=n.children[0];if(r.tag!==6||!s(r.data,o))throw Error(`Unsupported algorithm: only RSA is supported`);let a=t[1];if(a.tag!==3)throw Error(`Expected BIT STRING for public key data`);return c(i(a.data.slice(1)))}function d(e){let t=e.children;if(!t||t.length<3)throw Error(`Invalid PrivateKeyInfo structure`);let n=t[1];if(!n.children||n.children.length<1)throw Error(`Invalid AlgorithmIdentifier`);let r=n.children[0];if(r.tag!==6||!s(r.data,o))throw Error(`Unsupported algorithm: only RSA is supported`);let a=t[2];if(a.tag!==4)throw Error(`Expected OCTET STRING for private key data`);return l(i(a.data))}function f(e){if(e<128)return new Uint8Array([e]);let t=[],n=e;for(;n>0;)t.unshift(n&255),n>>=8;return new Uint8Array([128|t.length,...t])}function p(e,t){let n=f(t.length),r=new Uint8Array(1+n.length+t.length);return r[0]=e,r.set(n,1),r.set(t,1+n.length),r}function m(e){if(e===0n)return p(2,new Uint8Array([0]));let t=e.toString(16),n=t.length%2?`0`+t:t,r=[];for(let e=0;e<n.length;e+=2)r.push(parseInt(n.substring(e,e+2),16));return r[0]&128&&r.unshift(0),p(2,new Uint8Array(r))}function h(e){let t=0;for(let n of e)t+=n.length;let n=new Uint8Array(t),r=0;for(let t of e)n.set(t,r),r+=t.length;return p(48,n)}function g(e){let t=new Uint8Array(1+e.length);return t[0]=0,t.set(e,1),p(3,t)}function _(e){return p(4,e)}function v(e){return p(6,e)}function y(){return new Uint8Array([5,0])}function b(e){return h([m(e.n),m(e.e)])}function x(e){return h([h([v(o),y()]),g(b(e))])}function S(e){let t=e.d%(e.p-1n),n=e.d%(e.q-1n),r=T(e.q,e.p);return h([m(0n),m(e.n),m(e.e),m(e.d),m(e.p),m(e.q),m(t),m(n),m(r)])}function C(e){let t=h([v(o),y()]),n=_(S(e));return h([m(0n),t,n])}function w(t,n){let r=e.from(t).toString(`base64`),i=[`-----BEGIN ${n}-----`];for(let e=0;e<r.length;e+=64)i.push(r.substring(e,e+64));return i.push(`-----END ${n}-----`),i.join(`
2
+ `)}function T(e,t){let[n,r]=[e%t,t],[i,a]=[1n,0n];for(;r!==0n;){let e=n/r;[n,r]=[r,n-e*r],[i,a]=[a,i-e*a]}return(i%t+t)%t}function E(e){let{der:n}=t(e);return D(n)}function D(e){let t=i(e);if(t.tag!==48||!t.children||t.children.length<3)throw Error(`Invalid X.509 certificate structure`);let n=t.children[0],r=t.children[1],c=t.children[2];if(!n.children||n.children.length<6)throw Error(`Invalid TBSCertificate structure`);let l=0;n.children[0].tag===160&&l++;let d=a(n.children[l].data);l++,l++;let f=M(n.children[l]);l++;let p=n.children[l],m=N(p.children[0]),h=N(p.children[1]);l++;let g=M(n.children[l]);l++;let _=null,v=`unknown`;if(l<n.children.length){let e=n.children[l];try{if(e.children&&e.children.length>=2){let t=e.children[0];if(t.children&&t.children.length>=1){let n=t.children[0];n.tag===6&&s(n.data,o)&&(v=`rsa`,_=u(e))}}}catch{}l++}let y,b;for(let e=l;e<n.children.length;e++){let t=n.children[e];if(t.tag===163&&t.data.length>0){let e=i(t.data);if(e.children){b=e.children;let t=new Uint8Array([85,29,17]);for(let n of e.children)if(n.children&&n.children.length>=2){let e=n.children[0];if(e.tag===6&&s(e.data,t)){let e=n.children[n.children.length-1];y=P(e.data)}}}}}let x=`unknown`;r.children&&r.children.length>=1&&(x=j(r.children[0].data));let S=c.tag===3?c.data.slice(1):c.data;return{raw:e,tbsCertificate:n.data,serialNumber:d,issuer:f,subject:g,validFrom:m,validTo:h,publicKey:_,publicKeyAlgorithm:v,signatureAlgorithm:x,signature:S,subjectAltName:y,extensions:b}}const O={"2.5.4.3":`CN`,"2.5.4.6":`C`,"2.5.4.7":`L`,"2.5.4.8":`ST`,"2.5.4.10":`O`,"2.5.4.11":`OU`,"1.2.840.113549.1.9.1":`emailAddress`},k={"1.2.840.113549.1.1.1":`rsaEncryption`,"1.2.840.113549.1.1.5":`sha1WithRSAEncryption`,"1.2.840.113549.1.1.11":`sha256WithRSAEncryption`,"1.2.840.113549.1.1.12":`sha384WithRSAEncryption`,"1.2.840.113549.1.1.13":`sha512WithRSAEncryption`};function A(e){if(e.length===0)return``;let t=[];t.push(Math.floor(e[0]/40)),t.push(e[0]%40);let n=0;for(let r=1;r<e.length;r++)n=n<<7|e[r]&127,e[r]&128||(t.push(n),n=0);return t.join(`.`)}function j(e){let t=A(e);return k[t]||t}function M(e){if(!e.children)return``;let t=[];for(let n of e.children){let e=n.tag===49?r(n.data):n.children||[];for(let n of e)if(n.children&&n.children.length>=2){let e=n.children[0].data,r=A(e),i=O[r]||r,a=n.children[1].data,o=new TextDecoder().decode(a);t.push(`${i}=${o}`)}}return t.join(`, `)}function N(e){let t=new TextDecoder().decode(e.data);if(e.tag===23){let e=parseInt(t.substring(0,2),10);e=e>=50?1900+e:2e3+e;let n=parseInt(t.substring(2,4),10)-1,r=parseInt(t.substring(4,6),10),i=parseInt(t.substring(6,8),10),a=parseInt(t.substring(8,10),10),o=parseInt(t.substring(10,12),10);return new Date(Date.UTC(e,n,r,i,a,o))}if(e.tag===24){let e=parseInt(t.substring(0,4),10),n=parseInt(t.substring(4,6),10)-1,r=parseInt(t.substring(6,8),10),i=parseInt(t.substring(8,10),10),a=parseInt(t.substring(10,12),10),o=parseInt(t.substring(12,14),10);return new Date(Date.UTC(e,n,r,i,a,o))}throw Error(`Unsupported time tag: 0x${e.tag.toString(16)}`)}function P(e){let t=[];try{let n=i(e);if(n.tag===48&&n.children){for(let e of n.children)if(e.tag===130)t.push(`DNS:`+new TextDecoder().decode(e.data));else if(e.tag===135){if(e.data.length===4)t.push(`IP Address:`+e.data.join(`.`));else if(e.data.length===16){let n=[];for(let t=0;t<16;t+=2)n.push((e.data[t]<<8|e.data[t+1]).toString(16));t.push(`IP Address:`+n.join(`:`))}}}}catch{}return t}function F(e){let{type:n,der:r}=t(e),a=i(r);if(a.tag!==48)throw Error(`Invalid key format: expected top-level SEQUENCE`);switch(n){case`RSA PUBLIC KEY`:return{type:`rsa-public`,components:c(a)};case`PUBLIC KEY`:return{type:`rsa-public`,components:u(a)};case`RSA PRIVATE KEY`:return{type:`rsa-private`,components:l(a)};case`PRIVATE KEY`:return{type:`rsa-private`,components:d(a)};default:throw Error(`Unsupported PEM type: ${n}`)}}function I(e){let t=0,n=e;for(;n>0n;)t++,n>>=1n;return Math.ceil(t/8)}export{m as bigintToAsn1Integer,w as derToPem,C as encodePrivateKeyInfo,S as encodeRsaPrivateKeyPkcs1,b as encodeRsaPublicKeyPkcs1,h as encodeSequence,x as encodeSubjectPublicKeyInfo,F as parsePemKey,E as parseX509,D as parseX509Der,I as rsaKeySize};
@@ -1,43 +1 @@
1
- //#region src/bigint-math.ts
2
- /**
3
- * Modular exponentiation using square-and-multiply (BigInt).
4
- * Returns (base ** exp) % mod.
5
- */
6
- function modPow(base, exp, mod) {
7
- if (mod === 1n) return 0n;
8
- base = (base % mod + mod) % mod;
9
- let result = 1n;
10
- while (exp > 0n) {
11
- if (exp & 1n) {
12
- result = result * base % mod;
13
- }
14
- exp >>= 1n;
15
- base = base * base % mod;
16
- }
17
- return result;
18
- }
19
- /**
20
- * Convert a BigInt to a big-endian Uint8Array of exactly `length` bytes.
21
- */
22
- function bigIntToBytes(value, length) {
23
- const result = new Uint8Array(length);
24
- let v = value;
25
- for (let i = length - 1; i >= 0; i--) {
26
- result[i] = Number(v & 255n);
27
- v >>= 8n;
28
- }
29
- return result;
30
- }
31
- /**
32
- * Convert a Uint8Array (big-endian) to a non-negative BigInt.
33
- */
34
- function bytesToBigInt(bytes) {
35
- let result = 0n;
36
- for (let i = 0; i < bytes.length; i++) {
37
- result = result << 8n | BigInt(bytes[i]);
38
- }
39
- return result;
40
- }
41
-
42
- //#endregion
43
- export { bigIntToBytes, bytesToBigInt, modPow };
1
+ function e(e,t,n){if(n===1n)return 0n;e=(e%n+n)%n;let r=1n;for(;t>0n;)t&1n&&(r=r*e%n),t>>=1n,e=e*e%n;return r}function t(e,t){let n=new Uint8Array(t),r=e;for(let e=t-1;e>=0;e--)n[e]=Number(r&255n),r>>=8n;return n}function n(e){let t=0n;for(let n=0;n<e.length;n++)t=t<<8n|BigInt(e[n]);return t}export{t as bigIntToBytes,n as bytesToBigInt,e as modPow};