sm-crypto-wasm 0.7.0 → 0.7.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 (126) hide show
  1. package/README.md +41 -876
  2. package/dist/asn1/decode.d.ts +103 -12
  3. package/dist/asn1/decode.js +129 -10
  4. package/dist/asn1/encode.d.ts +120 -19
  5. package/dist/asn1/encode.js +158 -19
  6. package/dist/asn1/index.d.ts +6 -0
  7. package/dist/asn1/index.js +6 -0
  8. package/dist/asn1/oid.d.ts +18 -0
  9. package/dist/asn1/oid.js +30 -1
  10. package/dist/asn1/time.d.ts +32 -0
  11. package/dist/asn1/time.js +55 -1
  12. package/dist/asn1/types.d.ts +100 -16
  13. package/dist/asn1/types.js +47 -6
  14. package/dist/cms/errors.d.ts +12 -2
  15. package/dist/cms/errors.js +7 -1
  16. package/dist/cms/index.d.ts +5 -0
  17. package/dist/cms/index.js +5 -0
  18. package/dist/cms/oids.d.ts +37 -7
  19. package/dist/cms/oids.js +37 -7
  20. package/dist/cms/parse.d.ts +155 -13
  21. package/dist/cms/parse.js +98 -4
  22. package/dist/cms/sign.d.ts +80 -10
  23. package/dist/cms/sign.js +54 -2
  24. package/dist/cms/verify.d.ts +84 -9
  25. package/dist/cms/verify.js +54 -5
  26. package/dist/common/hybrid.d.ts +25 -0
  27. package/dist/common/hybrid.js +25 -0
  28. package/dist/common/sealed.d.ts +119 -15
  29. package/dist/common/sealed.js +67 -9
  30. package/dist/esbuild-plugin.d.ts +74 -5
  31. package/dist/esbuild-plugin.js +69 -4
  32. package/dist/index.d.ts +19 -0
  33. package/dist/index.js +22 -0
  34. package/dist/pem/asn1.d.ts +13 -0
  35. package/dist/pem/asn1.js +13 -0
  36. package/dist/pem/index.d.ts +2 -0
  37. package/dist/pem/index.js +2 -0
  38. package/dist/pem/pkcs8.d.ts +64 -8
  39. package/dist/pem/pkcs8.js +66 -6
  40. package/dist/pem/sm2.d.ts +76 -4
  41. package/dist/pem/sm2.js +169 -12
  42. package/dist/pem/sm9.d.ts +42 -2
  43. package/dist/pem/sm9.js +42 -2
  44. package/dist/runtime/base64.core.d.ts +25 -1
  45. package/dist/runtime/base64.core.js +31 -1
  46. package/dist/runtime/convert.d.ts +70 -7
  47. package/dist/runtime/convert.js +129 -9
  48. package/dist/runtime/errors.d.ts +64 -8
  49. package/dist/runtime/errors.js +64 -8
  50. package/dist/runtime/index.d.ts +5 -0
  51. package/dist/runtime/index.js +5 -0
  52. package/dist/runtime/loadWasm.browser.d.ts +33 -0
  53. package/dist/runtime/loadWasm.browser.js +46 -0
  54. package/dist/runtime/loadWasm.core.d.ts +59 -3
  55. package/dist/runtime/loadWasm.core.js +53 -3
  56. package/dist/runtime/loadWasm.d.ts +44 -0
  57. package/dist/runtime/loadWasm.js +79 -4
  58. package/dist/runtime/random.browser.d.ts +24 -0
  59. package/dist/runtime/random.browser.js +31 -1
  60. package/dist/runtime/random.core.d.ts +21 -0
  61. package/dist/runtime/random.core.js +27 -0
  62. package/dist/runtime/random.d.ts +28 -0
  63. package/dist/runtime/random.js +40 -1
  64. package/dist/sm2/exchange.d.ts +132 -16
  65. package/dist/sm2/exchange.js +120 -9
  66. package/dist/sm2/hybrid.d.ts +65 -3
  67. package/dist/sm2/hybrid.js +53 -1
  68. package/dist/sm2/index.d.ts +260 -21
  69. package/dist/sm2/index.js +346 -23
  70. package/dist/sm2/kem.d.ts +62 -5
  71. package/dist/sm2/kem.js +37 -2
  72. package/dist/sm2/keyInput.d.ts +36 -3
  73. package/dist/sm2/keyInput.js +36 -3
  74. package/dist/sm3/index.d.ts +30 -0
  75. package/dist/sm3/index.js +55 -1
  76. package/dist/sm4/index.d.ts +125 -17
  77. package/dist/sm4/index.js +201 -14
  78. package/dist/sm9/core.d.ts +58 -8
  79. package/dist/sm9/core.js +36 -5
  80. package/dist/sm9/hybrid.d.ts +66 -3
  81. package/dist/sm9/hybrid.js +46 -1
  82. package/dist/sm9/index.d.ts +265 -19
  83. package/dist/sm9/index.js +175 -5
  84. package/dist/sm9/input.d.ts +37 -2
  85. package/dist/sm9/input.js +50 -1
  86. package/dist/sm9/kem.d.ts +57 -4
  87. package/dist/sm9/kem.js +47 -1
  88. package/dist/webcrypto/algorithms.d.ts +58 -12
  89. package/dist/webcrypto/algorithms.js +58 -10
  90. package/dist/webcrypto/cryptoKey.d.ts +81 -15
  91. package/dist/webcrypto/cryptoKey.js +69 -11
  92. package/dist/webcrypto/errors.d.ts +29 -5
  93. package/dist/webcrypto/errors.js +29 -5
  94. package/dist/webcrypto/index.d.ts +10 -0
  95. package/dist/webcrypto/index.js +10 -0
  96. package/dist/webcrypto/subtle.d.ts +53 -3
  97. package/dist/webcrypto/subtle.js +69 -1
  98. package/dist/x509/encode.d.ts +86 -16
  99. package/dist/x509/encode.js +89 -16
  100. package/dist/x509/errors.d.ts +16 -1
  101. package/dist/x509/errors.js +16 -1
  102. package/dist/x509/extensions.d.ts +46 -7
  103. package/dist/x509/extensions.js +67 -9
  104. package/dist/x509/index.d.ts +7 -0
  105. package/dist/x509/index.js +19 -0
  106. package/dist/x509/ip.d.ts +9 -0
  107. package/dist/x509/ip.js +21 -0
  108. package/dist/x509/issue.d.ts +45 -2
  109. package/dist/x509/issue.js +107 -0
  110. package/dist/x509/oids.d.ts +41 -7
  111. package/dist/x509/oids.js +58 -7
  112. package/dist/x509/parse.d.ts +21 -0
  113. package/dist/x509/parse.js +115 -1
  114. package/dist/x509/sha1.d.ts +12 -1
  115. package/dist/x509/sha1.js +18 -1
  116. package/dist/x509/sha256.d.ts +12 -1
  117. package/dist/x509/sha256.js +31 -1
  118. package/dist/x509/sig.d.ts +15 -0
  119. package/dist/x509/sig.js +28 -1
  120. package/dist/x509/types.d.ts +312 -57
  121. package/dist/x509/types.js +6 -0
  122. package/dist/x509/verify.d.ts +51 -4
  123. package/dist/x509/verify.js +42 -3
  124. package/dist/zuc/index.d.ts +128 -10
  125. package/dist/zuc/index.js +136 -7
  126. package/package.json +53 -36
@@ -23,7 +23,9 @@
23
23
  * platform: 'browser',
24
24
  * format: 'esm',
25
25
  * outdir: 'dist/assets', // 产物 JS 落这里
26
+ * // output JS goes here
26
27
  * plugins: [smCryptoWasm()], // → wasm 复制到 dist/<algo>/<algo>.wasm
28
+ * // copies wasm to dist/<algo>/<algo>.wasm
27
29
  * });
28
30
  * ```
29
31
  *
@@ -31,19 +33,69 @@
31
33
  * 产物目录的上级。
32
34
  *
33
35
  * 只需用到部分算法时传 `algorithms` 少复制几个。
36
+ *
37
+ * esbuild plugin: place the `.wasm` assets **where the runtime can resolve them** in a
38
+ * browser bundle.
39
+ *
40
+ * ## Why it is needed
41
+ *
42
+ * The browser loader fetches wasm with `fetch(new URL('../<algo>/<algo>.wasm',
43
+ * import.meta.url))` (a form both Vite and Webpack 5 understand: they archive the asset
44
+ * and rewrite the URL). **esbuild does not** — neither `--outfile` nor `--outdir` moves
45
+ * the file that `new URL` points at (measured on 0.28.2). Result: the build succeeds and
46
+ * `fetch` 404s at runtime.
47
+ *
48
+ * After the build finishes this plugin copies `dist/<algo>/<algo>.wasm` to that relative
49
+ * location: the runtime URL is `../<algo>/<algo>.wasm` relative to **the emitted JS
50
+ * file**, so the target base directory is **the parent of the directory holding the
51
+ * emitted JS** (derived from esbuild's `outdir` / `outfile`).
52
+ *
53
+ * ## Usage
54
+ *
55
+ * ```ts
56
+ * import { smCryptoWasm } from 'sm-crypto-wasm/esbuild-plugin';
57
+ *
58
+ * await esbuild.build({
59
+ * entryPoints: ['src/main.ts'],
60
+ * bundle: true,
61
+ * platform: 'browser',
62
+ * format: 'esm',
63
+ * outdir: 'dist/assets', // the emitted JS lands here
64
+ * plugins: [smCryptoWasm()], // → wasm is copied to dist/<algo>/<algo>.wasm
65
+ * });
66
+ * ```
67
+ *
68
+ * Pointing `outdir` at a subdirectory (e.g. `dist/assets`) is recommended so the wasm
69
+ * lands in `dist/<algo>/` instead of the parent of the output directory.
70
+ *
71
+ * Pass `algorithms` when only some algorithms are used, to copy fewer files.
34
72
  */
35
73
  import { copyFileSync, existsSync, mkdirSync } from 'node:fs';
36
74
  import { dirname, join, resolve } from 'node:path';
37
75
  import { fileURLToPath } from 'node:url';
38
- /** 支持的算法名(与加载器白名单一致)。 */
76
+ /** 支持的算法名(与加载器白名单一致)。
77
+ *
78
+ * Supported algorithm names (in sync with the loader allow-list).
79
+ */
39
80
  const WASM_ALGOS = ['sm2', 'sm3', 'sm4', 'sm9', 'zuc'];
40
- /** 本包 `dist/` 的位置(编译后插件自身就在 `dist/` 下)。 */
81
+ /** 本包 `dist/` 的位置(编译后插件自身就在 `dist/` 下)。
82
+ *
83
+ * Location of this package's `dist/` (once compiled, the plugin itself lives under
84
+ * `dist/`).
85
+ */
41
86
  const THIS_DIST_DIR = dirname(fileURLToPath(import.meta.url));
42
87
  /**
43
88
  * 推导 wasm 的目标基目录。
44
89
  *
45
90
  * 运行时相对**产物 JS 文件**解析 `../<algo>/<algo>.wasm`,所以目标是产物 JS 目录的上级。
46
91
  * esbuild 通常把入口产物放在 `outdir` 根(单入口时 `outbase` 就是入口所在目录)。
92
+ *
93
+ * Derive the base directory for the wasm output.
94
+ *
95
+ * At runtime `../<algo>/<algo>.wasm` is resolved relative to **the emitted JS file**, so
96
+ * the target is the parent of the emitted JS directory. esbuild usually puts the entry
97
+ * output at the root of `outdir` (with a single entry, `outbase` is the entry's own
98
+ * directory).
47
99
  */
48
100
  function resolveTargetBase(opts) {
49
101
  if (opts.outdir)
@@ -57,6 +109,11 @@ function resolveTargetBase(opts) {
57
109
  *
58
110
  * @param options 见 {@link SmCryptoWasmPluginOptions}。
59
111
  * @returns 可直接放进 `plugins` 数组的插件对象。
112
+ *
113
+ * Create the esbuild plugin: copy the wasm assets after a successful build.
114
+ *
115
+ * @param options See {@link SmCryptoWasmPluginOptions}.
116
+ * @returns A plugin object that can be placed directly in the `plugins` array.
60
117
  */
61
118
  export function smCryptoWasm(options = {}) {
62
119
  const algos = options.algorithms ?? WASM_ALGOS;
@@ -66,15 +123,23 @@ export function smCryptoWasm(options = {}) {
66
123
  setup(build) {
67
124
  build.onEnd((result) => {
68
125
  // 构建失败时不产出资源,避免留下半套产物。
126
+ //
127
+ // Emit no assets when the build failed, so no half-written output is left behind.
69
128
  if (result.errors.length > 0)
70
129
  return;
71
130
  const targetBase = options.outDir ?? resolveTargetBase(build.initialOptions);
131
+ // `write: false` 等场景:没有落盘位置
132
+ //
133
+ // Cases such as `write: false`: there is no location to write to.
72
134
  if (targetBase === undefined)
73
- return; // `write: false` 等场景:没有落盘位置
135
+ return;
74
136
  for (const algo of algos) {
75
137
  const from = join(sourceDir, algo, `${algo}.wasm`);
138
+ // 只装了部分算法时静默跳过。
139
+ //
140
+ // Silently skip algorithms that were not installed.
76
141
  if (!existsSync(from))
77
- continue; // 只装了部分算法时静默跳过
142
+ continue;
78
143
  const to = join(targetBase, algo, `${algo}.wasm`);
79
144
  mkdirSync(dirname(to), { recursive: true });
80
145
  copyFileSync(from, to);
package/dist/index.d.ts CHANGED
@@ -6,6 +6,7 @@
6
6
  * import { sm3, sm4, zuc, sm2 } from 'sm-crypto-wasm';
7
7
  *
8
8
  * await sm3.ensureLoaded(); // 首次用某算法前预热其 wasm
9
+ * // preload that algorithm's wasm before first use
9
10
  * sm3.hash('hello');
10
11
  * ```
11
12
  *
@@ -15,6 +16,24 @@
15
16
  * `import { encryptECB } from 'sm-crypto-wasm/sm4'`。
16
17
  *
17
18
  * spec/plan 对应:plan Task 12;spec §5 产物结构、§6 API。
19
+ *
20
+ * sm-crypto-wasm aggregate entry point (facade).
21
+ *
22
+ * Usage:
23
+ * ```ts
24
+ * import { sm3, sm4, zuc, sm2 } from 'sm-crypto-wasm';
25
+ *
26
+ * await sm3.ensureLoaded(); // warm an algorithm's wasm before first use
27
+ * sm3.hash('hello');
28
+ * ```
29
+ *
30
+ * Design: every algorithm is its own namespace exposing `ensureLoaded()` plus its
31
+ * business functions. The wasm is split per algorithm and only the algorithm that
32
+ * is actually called gets loaded (see the memoization in
33
+ * `src/runtime/loadWasm.ts`). Sub-path imports are supported for further
34
+ * tree-shaking: `import { encryptECB } from 'sm-crypto-wasm/sm4'`.
35
+ *
36
+ * spec/plan: plan Task 12; spec §5 artifact layout, §6 API.
18
37
  */
19
38
  export * as cms from './cms/index.js';
20
39
  export { bytesToHex, fromBytes, hexToBytes, toBytes } from './runtime/convert.js';
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@
6
6
  * import { sm3, sm4, zuc, sm2 } from 'sm-crypto-wasm';
7
7
  *
8
8
  * await sm3.ensureLoaded(); // 首次用某算法前预热其 wasm
9
+ * // preload that algorithm's wasm before first use
9
10
  * sm3.hash('hello');
10
11
  * ```
11
12
  *
@@ -15,10 +16,31 @@
15
16
  * `import { encryptECB } from 'sm-crypto-wasm/sm4'`。
16
17
  *
17
18
  * spec/plan 对应:plan Task 12;spec §5 产物结构、§6 API。
19
+ *
20
+ * sm-crypto-wasm aggregate entry point (facade).
21
+ *
22
+ * Usage:
23
+ * ```ts
24
+ * import { sm3, sm4, zuc, sm2 } from 'sm-crypto-wasm';
25
+ *
26
+ * await sm3.ensureLoaded(); // warm an algorithm's wasm before first use
27
+ * sm3.hash('hello');
28
+ * ```
29
+ *
30
+ * Design: every algorithm is its own namespace exposing `ensureLoaded()` plus its
31
+ * business functions. The wasm is split per algorithm and only the algorithm that
32
+ * is actually called gets loaded (see the memoization in
33
+ * `src/runtime/loadWasm.ts`). Sub-path imports are supported for further
34
+ * tree-shaking: `import { encryptECB } from 'sm-crypto-wasm/sm4'`.
35
+ *
36
+ * spec/plan: plan Task 12; spec §5 artifact layout, §6 API.
18
37
  */
19
38
  export * as cms from './cms/index.js';
20
39
  export { bytesToHex, fromBytes, hexToBytes, toBytes } from './runtime/convert.js';
21
40
  // 运行时工具(错误类型、编解码)也导出,便于调用方捕获本库错误。
41
+ //
42
+ // Runtime helpers (error types, codecs) are re-exported so callers can catch
43
+ // this library's errors.
22
44
  export { CiphertextError, DecryptionError, InvalidCiphertextError, InvalidKeyError, InvalidPublicKeyError, isSmCryptoError, SmCryptoError, } from './runtime/errors.js';
23
45
  export { loadWasm, loadWasmSync } from './runtime/loadWasm.js';
24
46
  export * as sm2 from './sm2/index.js';
@@ -10,6 +10,19 @@
10
10
  * - `encodeOid` / `decodeOid` / `asn1IntValue` → OID 与 INTEGER 解码
11
11
  *
12
12
  * spec/plan 对应:X.509/CMS plan 阶段 0「迁移」。
13
+ *
14
+ * Legacy ASN.1 entry point (compatibility layer).
15
+ *
16
+ * The implementation moved to `src/asn1/` (the shared DER/BER layer). This file only
17
+ * keeps the historical export names so that `src/pem/*` and the existing tests did not
18
+ * have to change:
19
+ *
20
+ * - `parseDer` → `src/asn1/decode.ts`
21
+ * - `encodeDer` → `encode` in `src/asn1/encode.ts`
22
+ * - `asn1Int` / `asn1Octets` / `asn1Oid` / `asn1Null` / `asn1Seq` → the matching builders
23
+ * - `encodeOid` / `decodeOid` / `asn1IntValue` → OID and INTEGER decoding
24
+ *
25
+ * spec/plan: X.509/CMS plan phase 0, "migration".
13
26
  */
14
27
  export { decodeOid, encode as encodeDer, encodeOid, integer as asn1Int, nullValue as asn1Null, octetString as asn1Octets, oid as asn1Oid, parseDer, readInteger as asn1IntValue, seq as asn1Seq, } from '../asn1/index.js';
15
28
  export { Asn1Error, type Asn1Node } from '../asn1/types.js';
package/dist/pem/asn1.js CHANGED
@@ -10,6 +10,19 @@
10
10
  * - `encodeOid` / `decodeOid` / `asn1IntValue` → OID 与 INTEGER 解码
11
11
  *
12
12
  * spec/plan 对应:X.509/CMS plan 阶段 0「迁移」。
13
+ *
14
+ * Legacy ASN.1 entry point (compatibility layer).
15
+ *
16
+ * The implementation moved to `src/asn1/` (the shared DER/BER layer). This file only
17
+ * keeps the historical export names so that `src/pem/*` and the existing tests did not
18
+ * have to change:
19
+ *
20
+ * - `parseDer` → `src/asn1/decode.ts`
21
+ * - `encodeDer` → `encode` in `src/asn1/encode.ts`
22
+ * - `asn1Int` / `asn1Octets` / `asn1Oid` / `asn1Null` / `asn1Seq` → the matching builders
23
+ * - `encodeOid` / `decodeOid` / `asn1IntValue` → OID and INTEGER decoding
24
+ *
25
+ * spec/plan: X.509/CMS plan phase 0, "migration".
13
26
  */
14
27
  export { decodeOid, encode as encodeDer, encodeOid, integer as asn1Int, nullValue as asn1Null, octetString as asn1Octets, oid as asn1Oid, parseDer, readInteger as asn1IntValue, seq as asn1Seq, } from '../asn1/index.js';
15
28
  export { Asn1Error } from '../asn1/types.js';
@@ -1,5 +1,7 @@
1
1
  /**
2
2
  * PEM 子模块 barrel。
3
+ *
4
+ * PEM submodule barrel.
3
5
  */
4
6
  export * from './asn1.js';
5
7
  export * from './pkcs8.js';
package/dist/pem/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  /**
2
2
  * PEM 子模块 barrel。
3
+ *
4
+ * PEM submodule barrel.
3
5
  */
4
6
  export * from './asn1.js';
5
7
  export * from './pkcs8.js';
@@ -9,27 +9,83 @@
9
9
  * - AlgorithmIdentifier ::= SEQUENCE { algorithm OID, parameters ANY DEFINED BY algorithm OPTIONAL }
10
10
  *
11
11
  * 本仓库只支持"parameters = NULL"这一类算法(SM2 / SM9 都符合)。
12
+ *
13
+ * PKCS#8 PrivateKeyInfo and SPKI SubjectPublicKeyInfo parsing/encoding.
14
+ *
15
+ * spec/plan: plan Task 4; spec §12.1 Q3.
16
+ *
17
+ * Types involved:
18
+ * - PrivateKeyInfo ::= SEQUENCE { version INTEGER, algorithm AlgorithmIdentifier,
19
+ * privateKey OCTET STRING [, attributes ...] }
20
+ * - SubjectPublicKeyInfo ::= SEQUENCE { algorithm AlgorithmIdentifier,
21
+ * subjectPublicKey BIT STRING }
22
+ * - AlgorithmIdentifier ::= SEQUENCE { algorithm OID, parameters ANY DEFINED BY
23
+ * algorithm OPTIONAL }
24
+ *
25
+ * This repository only supports algorithms of the "parameters = NULL" kind (both SM2
26
+ * and SM9 qualify).
12
27
  */
13
28
  /**
14
29
  * PrivateKeyInfo 的最小化解析结果。
30
+ *
31
+ * The minimally parsed result of a PrivateKeyInfo.
15
32
  */
16
33
  export interface ParsedPrivateKey {
17
- /** 算法 OID,如 `"1.2.156.10197.1.100"`(SM9)。 */
34
+ /**
35
+ * 算法 OID,如 `"1.2.156.10197.1.100"`(SM9)。
36
+ *
37
+ * Algorithm OID, e.g. `"1.2.156.10197.1.100"` (SM9).
38
+ */
18
39
  readonly algorithmOid: string;
19
- /** 原始私钥字节(EC privateKey OCTET STRING 内容,含可选 public-key 拼接)。 */
40
+ /**
41
+ * 原始私钥字节(EC privateKey OCTET STRING 内容,含可选 public-key 拼接)。
42
+ *
43
+ * Raw private key bytes (the contents of the EC privateKey OCTET STRING, including an
44
+ * optional concatenated public key).
45
+ */
20
46
  readonly privateKey: Uint8Array;
21
47
  }
22
- /** 编码 PrivateKeyInfo PEM。 */
48
+ /**
49
+ * 编码 PrivateKeyInfo PEM。
50
+ *
51
+ * Encodes a PrivateKeyInfo PEM.
52
+ */
23
53
  export declare function encodePkcs8PrivateKey(algorithmOid: string, privateKey: Uint8Array): string;
24
- /** 解析 PRIVATE KEY PEM。 */
54
+ /**
55
+ * 解析 PRIVATE KEY PEM。
56
+ *
57
+ * Parses a PRIVATE KEY PEM.
58
+ */
25
59
  export declare function parsePkcs8PrivateKey(pem: string): ParsedPrivateKey;
26
- /** SPKI 解析结果。 */
60
+ /**
61
+ * SPKI 解析结果。
62
+ *
63
+ * The parsed result of an SPKI.
64
+ */
27
65
  export interface ParsedPublicKey {
66
+ /**
67
+ * 算法 OID,如 `"1.2.156.10197.1.100"`(SM9)。
68
+ *
69
+ * Algorithm OID, e.g. `"1.2.156.10197.1.100"` (SM9).
70
+ */
28
71
  readonly algorithmOid: string;
29
- /** 公钥 BIT STRING 内容。对 EC 类算法:未使用字节 0x00 + X || Y(66 字节)。 */
72
+ /**
73
+ * 公钥 BIT STRING 内容。对 EC 类算法:未使用字节 0x00 + X || Y(66 字节)。
74
+ *
75
+ * Contents of the public key BIT STRING. For EC-like algorithms: the unused-bits byte
76
+ * 0x00 followed by X || Y (66 bytes).
77
+ */
30
78
  readonly publicKey: Uint8Array;
31
79
  }
32
- /** 编码 SPKI PEM(算法 OID + 公钥 BIT STRING)。 */
80
+ /**
81
+ * 编码 SPKI PEM(算法 OID + 公钥 BIT STRING)。
82
+ *
83
+ * Encodes an SPKI PEM (algorithm OID + public key BIT STRING).
84
+ */
33
85
  export declare function encodeSpkiPublicKey(algorithmOid: string, publicKey: Uint8Array): string;
34
- /** 解析 PUBLIC KEY PEM。 */
86
+ /**
87
+ * 解析 PUBLIC KEY PEM。
88
+ *
89
+ * Parses a PUBLIC KEY PEM.
90
+ */
35
91
  export declare function parseSpkiPublicKey(pem: string): ParsedPublicKey;
package/dist/pem/pkcs8.js CHANGED
@@ -9,11 +9,30 @@
9
9
  * - AlgorithmIdentifier ::= SEQUENCE { algorithm OID, parameters ANY DEFINED BY algorithm OPTIONAL }
10
10
  *
11
11
  * 本仓库只支持"parameters = NULL"这一类算法(SM2 / SM9 都符合)。
12
+ *
13
+ * PKCS#8 PrivateKeyInfo and SPKI SubjectPublicKeyInfo parsing/encoding.
14
+ *
15
+ * spec/plan: plan Task 4; spec §12.1 Q3.
16
+ *
17
+ * Types involved:
18
+ * - PrivateKeyInfo ::= SEQUENCE { version INTEGER, algorithm AlgorithmIdentifier,
19
+ * privateKey OCTET STRING [, attributes ...] }
20
+ * - SubjectPublicKeyInfo ::= SEQUENCE { algorithm AlgorithmIdentifier,
21
+ * subjectPublicKey BIT STRING }
22
+ * - AlgorithmIdentifier ::= SEQUENCE { algorithm OID, parameters ANY DEFINED BY
23
+ * algorithm OPTIONAL }
24
+ *
25
+ * This repository only supports algorithms of the "parameters = NULL" kind (both SM2
26
+ * and SM9 qualify).
12
27
  */
13
28
  import { base64ToBytes, bytesToBase64 } from '../runtime/convert.js';
14
29
  import { InvalidKeyError } from '../runtime/errors.js';
15
30
  import { asn1Int, asn1Null, asn1Octets, asn1Oid, asn1Seq, parseDer } from './asn1.js';
16
- /** 编码 PrivateKeyInfo PEM。 */
31
+ /**
32
+ * 编码 PrivateKeyInfo PEM。
33
+ *
34
+ * Encodes a PrivateKeyInfo PEM.
35
+ */
17
36
  export function encodePkcs8PrivateKey(algorithmOid, privateKey) {
18
37
  const seq = asn1Seq([
19
38
  asn1Int(0),
@@ -22,12 +41,19 @@ export function encodePkcs8PrivateKey(algorithmOid, privateKey) {
22
41
  ]);
23
42
  return derToPem(seq.raw, 'PRIVATE KEY');
24
43
  }
25
- /** 解析 PRIVATE KEY PEM。 */
44
+ /**
45
+ * 解析 PRIVATE KEY PEM。
46
+ *
47
+ * Parses a PRIVATE KEY PEM.
48
+ */
26
49
  export function parsePkcs8PrivateKey(pem) {
27
50
  const seq = parseDer(pemToDer(pem));
28
51
  if (seq.tag !== 0x10) {
29
- // SEQUENCE = 0x10 in low-tag form (constructed context-specific) but
30
- // UNIVERSAL SEQUENCE is 0x30. asn1.ts 把 tag 数字按 UNIVERSAL 存。
52
+ // `src/asn1` 存的是 UNIVERSAL tag 编号(SEQUENCE = 16 = 0x10),不是首字节
53
+ // 0x30,因此这里按编号比较。
54
+ //
55
+ // `src/asn1` stores the UNIVERSAL tag number (SEQUENCE = 16 = 0x10) rather than
56
+ // the leading byte 0x30, so the comparison uses the number.
31
57
  throw new InvalidKeyError('parsePkcs8PrivateKey: top-level is not SEQUENCE');
32
58
  }
33
59
  if (!seq.children || seq.children.length < 3) {
@@ -55,9 +81,15 @@ export function parsePkcs8PrivateKey(pem) {
55
81
  privateKey: privateKeyOctets.value,
56
82
  };
57
83
  }
58
- /** 编码 SPKI PEM(算法 OID + 公钥 BIT STRING)。 */
84
+ /**
85
+ * 编码 SPKI PEM(算法 OID + 公钥 BIT STRING)。
86
+ *
87
+ * Encodes an SPKI PEM (algorithm OID + public key BIT STRING).
88
+ */
59
89
  export function encodeSpkiPublicKey(algorithmOid, publicKey) {
60
90
  // BIT STRING:未使用位 = 0,前缀一字节 0x00。
91
+ //
92
+ // BIT STRING: zero unused bits, prefixed with a single 0x00 byte.
61
93
  const bitStringValue = new Uint8Array(publicKey.length + 1);
62
94
  bitStringValue.set(publicKey, 1);
63
95
  const seq = asn1Seq([
@@ -66,7 +98,11 @@ export function encodeSpkiPublicKey(algorithmOid, publicKey) {
66
98
  ]);
67
99
  return derToPem(seq.raw, 'PUBLIC KEY');
68
100
  }
69
- /** 解析 PUBLIC KEY PEM。 */
101
+ /**
102
+ * 解析 PUBLIC KEY PEM。
103
+ *
104
+ * Parses a PUBLIC KEY PEM.
105
+ */
70
106
  export function parseSpkiPublicKey(pem) {
71
107
  const seq = parseDer(pemToDer(pem));
72
108
  if (seq.tag !== 0x10) {
@@ -88,6 +124,8 @@ export function parseSpkiPublicKey(pem) {
88
124
  throw new InvalidKeyError('parseSpkiPublicKey: missing BIT STRING');
89
125
  }
90
126
  // 去掉 BIT STRING 第一个字节的"未使用位"计数(我们固定为 0)。
127
+ //
128
+ // Strip the leading unused-bit count of the BIT STRING (always 0 in our encoding).
91
129
  const inner = bitString.value.subarray(1);
92
130
  return {
93
131
  algorithmOid: decodeOidFromNode(oidNode),
@@ -95,6 +133,11 @@ export function parseSpkiPublicKey(pem) {
95
133
  };
96
134
  }
97
135
  // ----------------- 内部 -----------------
136
+ //
137
+ // ----------------- Internals -----------------
138
+ // 从 ASN.1 节点解码 OID。
139
+ //
140
+ // Decodes an OID from an ASN.1 node.
98
141
  function decodeOidFromNode(node) {
99
142
  if (node.tag !== 0x06)
100
143
  throw new InvalidKeyError('decodeOidFromNode: not OID');
@@ -115,6 +158,9 @@ function decodeOidFromNode(node) {
115
158
  throw new InvalidKeyError('decodeOid: truncated');
116
159
  return parts.join('.');
117
160
  }
161
+ // PEM → DER。
162
+ //
163
+ // PEM to DER.
118
164
  function pemToDer(pem) {
119
165
  const lines = pem.split(/\r?\n/);
120
166
  const body = [];
@@ -138,6 +184,9 @@ function pemToDer(pem) {
138
184
  const b64 = body.join('');
139
185
  return base64ToBytes(b64);
140
186
  }
187
+ // DER → PEM。
188
+ //
189
+ // DER to PEM.
141
190
  function derToPem(der, kind) {
142
191
  const b64 = bytesToBase64(der);
143
192
  const lines = [];
@@ -146,6 +195,9 @@ function derToPem(der, kind) {
146
195
  }
147
196
  return `-----BEGIN ${kind}-----\n${lines.join('\n')}\n-----END ${kind}-----\n`;
148
197
  }
198
+ // 构造 BIT STRING 节点。
199
+ //
200
+ // Builds a BIT STRING node.
149
201
  function bitStringNode(value) {
150
202
  const lengthBytes = encodeLen(value.length);
151
203
  const raw = new Uint8Array(1 + lengthBytes.length + value.length);
@@ -165,6 +217,9 @@ function bitStringNode(value) {
165
217
  raw,
166
218
  };
167
219
  }
220
+ // 编码 DER 长度。
221
+ //
222
+ // Encodes a DER length.
168
223
  function encodeLen(n) {
169
224
  if (n < 0x80)
170
225
  return new Uint8Array([n]);
@@ -179,3 +234,8 @@ function encodeLen(n) {
179
234
  // base64 编解码统一走 `../runtime/convert.js` 的跨运行时实现(Node 走 Buffer
180
235
  // 快路径、浏览器回落 btoa/atob);本文件原先自带一份,其 Node 分支直接引用了
181
236
  // `Buffer`,在浏览器里会 ReferenceError。
237
+ //
238
+ // base64 encoding/decoding goes through the cross-runtime implementation in
239
+ // `../runtime/convert.js` (a Buffer fast path on Node, a btoa/atob fallback in the
240
+ // browser). This file used to carry its own copy whose Node branch referenced `Buffer`
241
+ // directly, which raised a ReferenceError in the browser.
package/dist/pem/sm2.d.ts CHANGED
@@ -24,10 +24,44 @@
24
24
  *
25
25
  * 编码函数接受/产出与解析一致的格式(私钥 PKCS#8、公钥 SPKI),供
26
26
  * 密钥生成与测试使用。
27
+ *
28
+ * SM2 key PEM encoding/decoding (PKCS#8 / SEC1 / SPKI).
29
+ *
30
+ * Unlike the generic parsing in `./pkcs8`, this layer knows the SM2 encodings:
31
+ * - Private keys:
32
+ * - PKCS#8 `PrivateKeyInfo` (`-----BEGIN PRIVATE KEY-----`); its `privateKey` OCTET
33
+ * STRING holds an RFC 5915 `ECPrivateKey`:
34
+ * ```
35
+ * ECPrivateKey ::= SEQUENCE {
36
+ * version INTEGER (1),
37
+ * privateKey OCTET STRING, -- 32-byte d
38
+ * parameters [0] EXPLICIT OBJECT IDENTIFIER OPTIONAL, -- sm2p256v1
39
+ * publicKey [1] EXPLICIT BIT STRING OPTIONAL
40
+ * }
41
+ * ```
42
+ * - SEC1 `ECPrivateKey` (`-----BEGIN EC PRIVATE KEY-----`) is exactly that structure.
43
+ * - Public keys: SPKI `SubjectPublicKeyInfo` (`-----BEGIN PUBLIC KEY-----`) with
44
+ * `algorithm = { id-ecPublicKey, sm2p256v1 }` and a 65-byte uncompressed point
45
+ * `04 || X || Y` as `subjectPublicKey`.
46
+ *
47
+ * Algorithm identifiers / curve OIDs:
48
+ * - id-ecPublicKey = 1.2.840.10045.2.1
49
+ * - sm2p256v1 = 1.2.156.10197.1.301
50
+ *
51
+ * The encoders produce the same formats the parsers accept (PKCS#8 for private keys,
52
+ * SPKI for public keys) for key generation and tests.
53
+ */
54
+ /**
55
+ * `id-ecPublicKey` OID。
56
+ *
57
+ * The `id-ecPublicKey` OID.
27
58
  */
28
- /** `id-ecPublicKey` OID。 */
29
59
  export declare const OID_ID_EC_PUBLIC_KEY = "1.2.840.10045.2.1";
30
- /** `sm2p256v1`(推荐曲线)OID。 */
60
+ /**
61
+ * `sm2p256v1`(推荐曲线)OID。
62
+ *
63
+ * The `sm2p256v1` (recommended curve) OID.
64
+ */
31
65
  export declare const OID_SM2_CURVE = "1.2.156.10197.1.301";
32
66
  /**
33
67
  * 解析 SM2 私钥 PEM,返回 32 字节私钥 d。
@@ -35,24 +69,44 @@ export declare const OID_SM2_CURVE = "1.2.156.10197.1.301";
35
69
  * 支持 PKCS#8(`BEGIN PRIVATE KEY`)与 SEC1(`BEGIN EC PRIVATE KEY`)。
36
70
  *
37
71
  * @throws InvalidKeyError PEM/DER 结构非法、或曲线不是 SM2。
72
+ *
73
+ * Parses an SM2 private key PEM and returns the 32-byte private key d.
74
+ *
75
+ * Supports PKCS#8 (`BEGIN PRIVATE KEY`) and SEC1 (`BEGIN EC PRIVATE KEY`).
76
+ *
77
+ * @throws InvalidKeyError When the PEM/DER structure is invalid or the curve is not SM2.
38
78
  */
39
79
  export declare function parseSm2PrivateKeyPem(pem: string): Uint8Array;
40
80
  /**
41
81
  * 解析 SM2 私钥 DER(PKCS#8 或 SEC1),返回 32 字节私钥 d。
42
82
  *
43
83
  * WebCrypto 的 `importKey('pkcs8', ...)` 使用这个入口。
84
+ *
85
+ * Parses an SM2 private key DER (PKCS#8 or SEC1) and returns the 32-byte private key d.
86
+ *
87
+ * WebCrypto's `importKey('pkcs8', ...)` uses this entry point.
44
88
  */
45
89
  export declare function parseSm2PrivateKeyDer(der: Uint8Array): Uint8Array;
46
90
  /**
47
91
  * 解析 SM2 公钥 PEM,返回 65 字节未压缩点 `04 || X || Y`。
48
92
  *
49
93
  * @throws InvalidKeyError PEM/DER 结构非法、曲线不是 SM2、或点不是未压缩形式。
94
+ *
95
+ * Parses an SM2 public key PEM and returns the 65-byte uncompressed point
96
+ * `04 || X || Y`.
97
+ *
98
+ * @throws InvalidKeyError When the PEM/DER structure is invalid, the curve is not SM2,
99
+ * or the point is not in uncompressed form.
50
100
  */
51
101
  export declare function parseSm2PublicKeyPem(pem: string): Uint8Array;
52
102
  /**
53
103
  * 解析 SM2 公钥 DER(SPKI),返回 65 字节未压缩点。
54
104
  *
55
105
  * WebCrypto 的 `importKey('spki', ...)` 使用这个入口。
106
+ *
107
+ * Parses an SM2 public key DER (SPKI) and returns the 65-byte uncompressed point.
108
+ *
109
+ * WebCrypto's `importKey('spki', ...)` uses this entry point.
56
110
  */
57
111
  export declare function parseSm2PublicKeyDer(der: Uint8Array): Uint8Array;
58
112
  /**
@@ -60,15 +114,33 @@ export declare function parseSm2PublicKeyDer(der: Uint8Array): Uint8Array;
60
114
  *
61
115
  * @param d 32 字节私钥(hex / Uint8Array)。
62
116
  * @param pub 可选公钥(64 或 65 字节);给出则内嵌到 ECPrivateKey 的 `[1]`。
117
+ *
118
+ * Encodes an SM2 private key as PKCS#8 PEM (`BEGIN PRIVATE KEY`).
119
+ *
120
+ * @param d 32-byte private key (hex / Uint8Array).
121
+ * @param pub Optional public key (64 or 65 bytes); when given it is embedded into the
122
+ * `[1]` field of the ECPrivateKey.
63
123
  */
64
124
  export declare function encodeSm2PrivateKeyPem(d: string | Uint8Array, pub?: string | Uint8Array): string;
65
- /** 编码 SM2 私钥为 PKCS#8 DER。 */
125
+ /**
126
+ * 编码 SM2 私钥为 PKCS#8 DER。
127
+ *
128
+ * Encodes an SM2 private key as PKCS#8 DER.
129
+ */
66
130
  export declare function encodeSm2PrivateKeyDer(d: string | Uint8Array, pub?: string | Uint8Array): Uint8Array;
67
131
  /**
68
132
  * 编码 SM2 公钥为 SPKI PEM(`BEGIN PUBLIC KEY`)。
69
133
  *
70
134
  * @param pub 64(X || Y)或 65(04 || X || Y)字节公钥。
135
+ *
136
+ * Encodes an SM2 public key as SPKI PEM (`BEGIN PUBLIC KEY`).
137
+ *
138
+ * @param pub 64-byte (X || Y) or 65-byte (04 || X || Y) public key.
71
139
  */
72
140
  export declare function encodeSm2PublicKeyPem(pub: string | Uint8Array): string;
73
- /** 编码 SM2 公钥为 SPKI DER。 */
141
+ /**
142
+ * 编码 SM2 公钥为 SPKI DER。
143
+ *
144
+ * Encodes an SM2 public key as SPKI DER.
145
+ */
74
146
  export declare function encodeSm2PublicKeyDer(pub: string | Uint8Array): Uint8Array;