@h-ai/cli 0.1.0-alpha.65 → 0.1.0-alpha.67
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/README.en.md +66 -251
- package/README.ja.md +67 -252
- package/README.md +66 -251
- package/dist/{chunk-47V5OT22.js → chunk-7DSURTJ4.js} +32 -115
- package/dist/chunk-7DSURTJ4.js.map +1 -0
- package/dist/{chunk-IPG3QNYK.js → chunk-AOQ4N657.js} +212 -8
- package/dist/chunk-AOQ4N657.js.map +1 -0
- package/dist/cli-config-templates-6AHNUGBN.js +5 -0
- package/dist/{cli-config-templates-SJ2MBIR7.js.map → cli-config-templates-6AHNUGBN.js.map} +1 -1
- package/dist/{cli-skill-templates-A5VIR5J6.js → cli-skill-templates-FC3QRKDO.js} +3 -3
- package/dist/{cli-skill-templates-A5VIR5J6.js.map → cli-skill-templates-FC3QRKDO.js.map} +1 -1
- package/dist/index.js +644 -391
- package/dist/index.js.map +1 -1
- package/dist/{src-6PPBKQ6Q.js → src-2V6VP4I5.js} +972 -520
- package/dist/src-2V6VP4I5.js.map +1 -0
- package/package.json +8 -8
- package/templates/README.md +48 -145
- package/templates/apps/admin/src/routes/admin/+layout.svelte.hbs +1 -1
- package/templates/apps/api/.dockerignore.hbs +18 -12
- package/templates/apps/api/.gitignore.hbs +9 -1
- package/templates/apps/api/apps/{{projectName}}-contract/README.md.hbs +23 -2
- package/templates/apps/api/apps/{{projectName}}-service/README.md.hbs +28 -7
- package/templates/apps/api/apps/{{projectName}}-service/package.json.hbs +1 -3
- package/templates/apps/api/hai.build.json.hbs +1 -0
- package/templates/apps/api/images/app.Dockerfile.hbs +35 -0
- package/templates/apps/api/package.json.hbs +10 -8
- package/templates/apps/fullstack/.dockerignore.hbs +18 -14
- package/templates/apps/fullstack/.gitignore.hbs +9 -1
- package/templates/apps/fullstack/apps/{{projectName}}-app/README.md.hbs +23 -8
- package/templates/apps/fullstack/apps/{{projectName}}-app/index.html.hbs +1 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/package.json.hbs +0 -2
- package/templates/apps/fullstack/apps/{{projectName}}-app/public/runtime-config.js.hbs +4 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/vite.config.ts.hbs +3 -3
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/README.md.hbs +25 -10
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/package.json.hbs +2 -3
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/src/lib.rs.hbs +73 -2
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/tauri.conf.json.hbs +2 -2
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/vite.config.ts.hbs +2 -2
- package/templates/apps/fullstack/apps/{{projectName}}-miniapp/README.md.hbs +16 -6
- package/templates/apps/fullstack/apps/{{projectName}}-web/README.md.hbs +24 -10
- package/templates/apps/fullstack/apps/{{projectName}}-web/package.json.hbs +0 -2
- package/templates/apps/fullstack/apps/{{projectName}}-web/vite.config.ts.hbs +3 -3
- package/templates/apps/fullstack/e2e/fullstack.spec.ts.hbs +12 -1
- package/templates/apps/fullstack/hai.build.json.hbs +7 -0
- package/templates/apps/fullstack/images/app.Dockerfile.hbs +36 -0
- package/templates/apps/fullstack/images/web.Dockerfile.hbs +34 -0
- package/templates/apps/fullstack/package.json.hbs +7 -12
- package/templates/apps/fullstack/packages/{{projectName}}-contract/README.md.hbs +23 -2
- package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +28 -7
- package/templates/apps/fullstack/packages/{{projectName}}-serv/package.json.hbs +0 -1
- package/templates/apps/fullstack/packages/{{projectName}}-shared/.gitignore.hbs +7 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/README.md.hbs +33 -12
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AppShell.svelte.hbs +2 -2
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/settings.svelte.hbs +3 -3
- package/templates/apps/fullstack/packages/{{projectName}}-shared/tests/api-client.test.ts.hbs +2 -2
- package/templates/apps/h5/src/routes/+layout.svelte.hbs +2 -2
- package/templates/apps/mobile-app/index.html.hbs +1 -0
- package/templates/apps/mobile-app/public/runtime-config.js +1 -0
- package/templates/apps/mobile-app/src/App.svelte.hbs +2 -2
- package/templates/apps/mobile-app/src/lib/api.ts.hbs +2 -1
- package/templates/apps/mobile-app/src/lib/app-config.ts.hbs +3 -2
- package/templates/apps/mobile-app/src/lib/pages/home.svelte.hbs +2 -2
- package/templates/apps/website/src/routes/+layout.svelte.hbs +3 -3
- package/templates/apps/website/src/routes/services/+page.svelte.hbs +1 -1
- package/templates/base/.dockerignore.hbs +18 -13
- package/templates/base/.gitignore.hbs +9 -1
- package/templates/base/e2e/app.spec.ts.hbs +10 -0
- package/templates/base/hai.build.json.hbs +1 -0
- package/templates/base/images/app.Dockerfile.hbs +64 -0
- package/templates/base/{docker → images/web}/nginx.conf.hbs +6 -0
- package/templates/base/package.json.hbs +20 -19
- package/templates/base/svelte.config.js.hbs +2 -0
- package/templates/base/vite.config.ts.hbs +9 -3
- package/templates/shared/.gitattributes +11 -0
- package/templates/shared/container-runtime-config.sh +30 -0
- package/templates/shared/run-e2e.mjs +65 -0
- package/templates/shared/vite-runtime-config.ts +54 -0
- package/templates/skills/AGENTS.md +3 -3
- package/templates/skills/bridges/admin/AGENTS.md +1 -1
- package/templates/skills/bridges/api/AGENTS.md +1 -1
- package/templates/skills/bridges/fullstack/AGENTS.md.hbs +1 -1
- package/templates/skills/bridges/h5/AGENTS.md +1 -1
- package/templates/skills/bridges/mobile-app/AGENTS.md +1 -1
- package/templates/skills/bridges/website/AGENTS.md +1 -1
- package/templates/skills/hai-api-client/SKILL.md +14 -161
- package/templates/skills/hai-api-client/reference.md +166 -0
- package/templates/skills/hai-api-contract/SKILL.md +15 -273
- package/templates/skills/hai-api-contract/reference.md +278 -0
- package/templates/skills/hai-app-create/SKILL.md +2 -2
- package/templates/skills/hai-app-create/development.md +6 -4
- package/templates/skills/hai-app-create/reference.md +5 -4
- package/templates/skills/hai-app-review/SKILL.md +1 -1
- package/templates/skills/hai-app-tests/SKILL.md +4 -3
- package/templates/skills/hai-app-tests/reference.md +2 -2
- package/templates/skills/hai-app-tests/validation.md +31 -0
- package/templates/skills/hai-audit/SKILL.md +17 -142
- package/templates/skills/hai-audit/reference.md +145 -0
- package/templates/skills/hai-build/SKILL.md +24 -3
- package/templates/skills/hai-build/reference.md +10 -9
- package/templates/skills/hai-cache/SKILL.md +15 -182
- package/templates/skills/hai-cache/reference.md +187 -0
- package/templates/skills/hai-capacitor/SKILL.md +4 -3
- package/templates/skills/hai-capacitor/reference.md +6 -4
- package/templates/skills/hai-ci/SKILL.md +2 -0
- package/templates/skills/hai-core/SKILL.md +3 -3
- package/templates/skills/hai-crypto/SKILL.md +16 -252
- package/templates/skills/hai-crypto/reference.md +256 -0
- package/templates/skills/hai-datapipe/SKILL.md +15 -196
- package/templates/skills/hai-datapipe/reference.md +202 -0
- package/templates/skills/hai-deploy/SKILL.md +28 -271
- package/templates/skills/hai-deploy/middleware.md +6 -18
- package/templates/skills/hai-framework-sync/SKILL.md +2 -2
- package/templates/skills/hai-framework-sync/sync.md +1 -1
- package/templates/skills/hai-iam/SKILL.md +1 -3
- package/templates/skills/hai-kit/SKILL.md +12 -167
- package/templates/skills/hai-kit/reference.md +172 -0
- package/templates/skills/hai-payment/SKILL.md +19 -251
- package/templates/skills/hai-payment/reference.md +256 -0
- package/templates/skills/hai-pr-review/SKILL.md +4 -4
- package/templates/skills/hai-reach/SKILL.md +2 -2
- package/templates/skills/hai-reldb/SKILL.md +1 -1
- package/templates/skills/hai-scheduler/SKILL.md +15 -195
- package/templates/skills/hai-scheduler/reference.md +202 -0
- package/templates/skills/hai-serv/SKILL.md +2 -2
- package/templates/skills/hai-spec-implement/SKILL.md +1 -1
- package/templates/skills/hai-spec-implement/workflow.md +3 -3
- package/templates/skills/hai-storage/SKILL.md +17 -238
- package/templates/skills/hai-storage/reference.md +243 -0
- package/templates/skills/hai-ui/SKILL.md +1 -1
- package/templates/skills/hai-ui/reference.md +11 -5
- package/templates/skills/hai-vecdb/SKILL.md +2 -2
- package/dist/chunk-47V5OT22.js.map +0 -1
- package/dist/chunk-IPG3QNYK.js.map +0 -1
- package/dist/cli-config-templates-SJ2MBIR7.js +0 -5
- package/dist/src-6PPBKQ6Q.js.map +0 -1
- package/templates/apps/api/Dockerfile.hbs +0 -48
- package/templates/apps/fullstack/Dockerfile.hbs +0 -69
- package/templates/base/Dockerfile.hbs +0 -79
- /package/templates/apps/fullstack/{docker → images/web}/19-runtime-config.envsh.hbs +0 -0
- /package/templates/apps/fullstack/{docker → images/web}/nginx.conf.hbs +0 -0
- /package/templates/apps/fullstack/{docker → images/web}/runtime-config.js.template.hbs +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: hai-crypto
|
|
3
|
-
description: "
|
|
3
|
+
description: "实现 SM2/SM3/SM4 加解密、验签、密码哈希,或通过 serv/kit/api-client 接入传输加密。"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# hai-crypto
|
|
@@ -11,261 +11,25 @@ description: "使用 @h-ai/crypto 进行 SM2/SM3/SM4、密码哈希与传输加
|
|
|
11
11
|
| --- | --- |
|
|
12
12
|
| 能力 | 使用 @h-ai/crypto 进行 SM2/SM3/SM4、密码哈希与传输加密 |
|
|
13
13
|
| 适用场景 | 应用加密、验签、密码保存或传输保护 |
|
|
14
|
-
| 输入 |
|
|
14
|
+
| 输入 | 无参 init、字节/文本、密钥和 transport 装配选项 |
|
|
15
15
|
| 输出 | 加解密/验签的 HaiResult;transport 工厂按公开类型使用 |
|
|
16
16
|
| 限制 | 先 init;password 仅服务端,浏览器仅支持部分能力。传输通过 serv/kit/api-client 顶层装配,不导入内部工厂。 |
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
## 使用路径
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
1. `crypto.init()` 无配置参数,检查结果;确认目标端是否支持所需能力,password 仅 Node。
|
|
21
|
+
2. 选用公开 asymmetric/hash/symmetric/password 操作,检查 HaiResult;SM3 HMAC 不等同于 SHA-256 HMAC。
|
|
22
|
+
3. 传输加密经 serv/kit/api-client 顶层配置接入,统一协商与刷新路径;不导入内部工厂。
|
|
23
|
+
4. 验证加解密往返、错误密钥/签名和关闭,密钥与明文不写日志或浏览器公开配置。
|
|
21
24
|
|
|
22
|
-
|
|
25
|
+
## 按需参考
|
|
23
26
|
|
|
24
|
-
|
|
25
|
-
|------|---------|--------|------|
|
|
26
|
-
| `crypto.asymmetric` 非对称加密 | ✅ | ✅ | SM2 加解密、签名验签 |
|
|
27
|
-
| `crypto.hash` 哈希 | ✅ | ✅ | SM3 哈希、HMAC |
|
|
28
|
-
| `crypto.symmetric` 对称加密 | ✅ | ✅ | SM4 ECB/CBC |
|
|
29
|
-
| `crypto.password` 密码哈希 | ✅ | ❌ | 依赖 Node.js crypto(服务端专用) |
|
|
30
|
-
| `crypto.transport` 传输加密 | ✅ | ✅ | 服务端管理器 + 客户端 encryptedFetch |
|
|
27
|
+
按本次操作读取对应小节;以已安装版本的公开类型核验签名,示例中的业务变量由应用提供。
|
|
31
28
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
- 密码存储与验证(加盐迭代哈希)
|
|
40
|
-
- 传输加密:为 serv / kit / api-client 提供统一协议、密钥协商和请求响应加解密
|
|
41
|
-
|
|
42
|
-
## 使用步骤
|
|
43
|
-
|
|
44
|
-
### 1. 初始化与关闭
|
|
45
|
-
|
|
46
|
-
```typescript
|
|
47
|
-
import { crypto } from '@h-ai/crypto'
|
|
48
|
-
|
|
49
|
-
await crypto.init()
|
|
50
|
-
|
|
51
|
-
// 使用后关闭
|
|
52
|
-
await crypto.close()
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
## 核心 API
|
|
56
|
-
|
|
57
|
-
### 非对称加密 — `crypto.asymmetric`
|
|
58
|
-
|
|
59
|
-
| 方法 | 签名 | 说明 |
|
|
60
|
-
| ------------------- | ----------------------------------------------------------- | ------------ |
|
|
61
|
-
| `generateKeyPair` | `() => HaiResult<KeyPair>` | 生成密钥对 |
|
|
62
|
-
| `encrypt` | `(data, publicKey, options?) => HaiResult<string>` | 公钥加密 |
|
|
63
|
-
| `decrypt` | `(ciphertext, privateKey, options?) => HaiResult<string>` | 私钥解密 |
|
|
64
|
-
| `sign` | `(data, privateKey, options?) => HaiResult<string>` | 私钥签名 |
|
|
65
|
-
| `verify` | `(data, signature, publicKey, options?) => HaiResult<boolean>` | 公钥验签 |
|
|
66
|
-
| `isValidPublicKey` | `(key: string) => boolean` | 校验公钥格式 |
|
|
67
|
-
| `isValidPrivateKey` | `(key: string) => boolean` | 校验私钥格式 |
|
|
68
|
-
|
|
69
|
-
```typescript
|
|
70
|
-
const keyPair = crypto.asymmetric.generateKeyPair()
|
|
71
|
-
if (keyPair.success) {
|
|
72
|
-
const { publicKey, privateKey } = keyPair.data
|
|
73
|
-
|
|
74
|
-
const encrypted = crypto.asymmetric.encrypt('敏感数据', publicKey)
|
|
75
|
-
if (encrypted.success) {
|
|
76
|
-
const decrypted = crypto.asymmetric.decrypt(encrypted.data, privateKey)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const signature = crypto.asymmetric.sign('待签名数据', privateKey)
|
|
80
|
-
if (signature.success) {
|
|
81
|
-
const valid = crypto.asymmetric.verify('待签名数据', signature.data, publicKey)
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
**AsymmetricEncryptOptions**:`{ cipherMode?: 0 | 1, outputFormat?: 'hex' | 'base64' }`
|
|
87
|
-
**SignOptions**:`{ hash?: boolean, userId?: string }`
|
|
88
|
-
|
|
89
|
-
### 哈希 — `crypto.hash`
|
|
90
|
-
|
|
91
|
-
| 方法 | 签名 | 说明 |
|
|
92
|
-
| -------- | ---------------------------------------------------------- | -------- |
|
|
93
|
-
| `hash` | `(data: string \| Uint8Array, options?) => HaiResult<string>` | 哈希 |
|
|
94
|
-
| `hmac` | `(data, key) => HaiResult<string>` | HMAC |
|
|
95
|
-
| `verify` | `(data, expectedHash) => HaiResult<boolean>` | 验证哈希 |
|
|
96
|
-
|
|
97
|
-
```typescript
|
|
98
|
-
const hash = crypto.hash.hash('hello')
|
|
99
|
-
const hmac = crypto.hash.hmac('hello', 'secret-key')
|
|
100
|
-
const valid = crypto.hash.verify('hello', hash.data!)
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
**HashOptions**:`{ inputEncoding?: 'utf8' | 'hex' }`
|
|
104
|
-
|
|
105
|
-
### 对称加密 — `crypto.symmetric`
|
|
106
|
-
|
|
107
|
-
| 方法 | 签名 | 说明 |
|
|
108
|
-
| --------------- | ----------------------------------------------- | --------------------------- |
|
|
109
|
-
| `generateKey` | `() => string` | 生成 128-bit 密钥(32 hex) |
|
|
110
|
-
| `generateIV` | `() => string` | 生成随机 IV(32 hex) |
|
|
111
|
-
| `encrypt` | `(data, key, options?) => HaiResult<SymmetricEncryptedPayload>` | 加密(返回结构化密文) |
|
|
112
|
-
| `decrypt` | `(payload, key) => HaiResult<string>` | 解密结构化密文 |
|
|
113
|
-
| `encryptWithIV` | `(data, key) => HaiResult<EncryptWithIVResult>` | CBC 模式加密(自动生成 IV) |
|
|
114
|
-
| `decryptWithIV` | `(ciphertext, key, iv) => HaiResult<string>` | CBC 模式解密 |
|
|
115
|
-
| `deriveKey` | `(password, salt) => string` | 从密码和盐值派生密钥 |
|
|
116
|
-
| `isValidKey` | `(key: string) => boolean` | 校验密钥格式 |
|
|
117
|
-
| `isValidIV` | `(iv: string) => boolean` | 校验 IV 格式 |
|
|
118
|
-
|
|
119
|
-
```typescript
|
|
120
|
-
const key = crypto.symmetric.generateKey()
|
|
121
|
-
|
|
122
|
-
// 默认安全用法:CBC + 自动 IV,返回 { mode, ciphertext, iv, encoding }
|
|
123
|
-
const encrypted = crypto.symmetric.encrypt('明文数据', key)
|
|
124
|
-
if (encrypted.success) {
|
|
125
|
-
const decrypted = crypto.symmetric.decrypt(encrypted.data, key)
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// 需要单独存储 IV 时使用结构化结果
|
|
129
|
-
const withIV = crypto.symmetric.encryptWithIV('明文数据', key)
|
|
130
|
-
if (withIV.success) {
|
|
131
|
-
const decrypted = crypto.symmetric.decryptWithIV(withIV.data.ciphertext, key, withIV.data.iv)
|
|
132
|
-
}
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
**SymmetricEncryptOptions**:`{ mode?: 'ecb' | 'cbc', iv?: string, outputFormat?: 'hex' | 'base64' }`
|
|
136
|
-
**SymmetricEncryptedPayload**:`{ mode: 'ecb' | 'cbc', ciphertext: string, iv?: string, encoding: 'hex' | 'base64' }`
|
|
137
|
-
|
|
138
|
-
> `encrypt()` 默认使用 CBC 并自动生成 IV。ECB 会泄漏明文结构,只有底层协议明确要求时才显式 `{ mode: 'ecb' }`。
|
|
139
|
-
|
|
140
|
-
### 密码哈希 — `crypto.password`
|
|
141
|
-
|
|
142
|
-
| 方法 | 签名 | 说明 |
|
|
143
|
-
| -------- | --------------------------------------- | -------- |
|
|
144
|
-
| `hash` | `(password, config?) => HaiResult<string>` | 密码哈希 |
|
|
145
|
-
| `verify` | `(password, hash) => HaiResult<boolean>` | 验证密码 |
|
|
146
|
-
|
|
147
|
-
```typescript
|
|
148
|
-
const hashed = crypto.password.hash('MyPassword123')
|
|
149
|
-
if (hashed.success) {
|
|
150
|
-
const valid = crypto.password.verify('MyPassword123', hashed.data)
|
|
151
|
-
}
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
哈希格式:`$hai$<iterations>$<salt>$<hash>`
|
|
155
|
-
**PasswordConfig**:`{ saltLength?: number, iterations?: number }`
|
|
156
|
-
|
|
157
|
-
### 传输加密 — `crypto.transport`
|
|
158
|
-
|
|
159
|
-
传输加密主工厂必须从 `crypto.transport` 访问;共享 `keyStore` provider 请从 `@h-ai/crypto` 根入口导入,不从子目录内部路径导入。
|
|
160
|
-
|
|
161
|
-
| 方法 | 签名 | 说明 |
|
|
162
|
-
| --- | --- | --- |
|
|
163
|
-
| `createServer` | `(options?) => HaiResult<TransportEncryptionManager>` | 创建服务端传输加密管理器 |
|
|
164
|
-
| `createClient` | `({ keyExchangeUrl, fetch? }) => TransportClient` | 创建客户端 encryptedFetch 会话 |
|
|
165
|
-
| `protocol` | `TRANSPORT_PROTOCOL` | 协议常量:`X-Client-Id`、`X-Encrypted`、默认协商路径 |
|
|
166
|
-
|
|
167
|
-
共享 `keyStore` provider(从 `@h-ai/crypto` 根入口导入):
|
|
168
|
-
|
|
169
|
-
| 工厂 | 签名 | 说明 |
|
|
170
|
-
| --- | --- | --- |
|
|
171
|
-
| `createInMemoryKeyStore` | `(maxClients?) => TransportKeyStore` | 默认 FIFO 内存实现 |
|
|
172
|
-
| `createRedisTransportKeyStore` | `({ cache, ttlSeconds? }) => TransportKeyStore` | 基于 `@h-ai/cache` 的共享实现,通常配 Redis |
|
|
173
|
-
| `createReldbTransportKeyStore` | `({ reldb, ttlSeconds? }) => TransportKeyStore` | 基于 `@h-ai/reldb` 的共享实现,自动建表 |
|
|
174
|
-
|
|
175
|
-
```typescript
|
|
176
|
-
const server = crypto.transport.createServer({ maxClients: 10000 })
|
|
177
|
-
if (!server.success)
|
|
178
|
-
return server
|
|
179
|
-
|
|
180
|
-
const client = crypto.transport.createClient({
|
|
181
|
-
keyExchangeUrl: 'https://api.example.com/api/v1/_hai/key-exchange',
|
|
182
|
-
})
|
|
183
|
-
|
|
184
|
-
const resp = await client.encryptedFetch('https://api.example.com/api/v1/echo', {
|
|
185
|
-
method: 'POST',
|
|
186
|
-
body: JSON.stringify({ hello: 'world' }),
|
|
187
|
-
})
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
```typescript
|
|
191
|
-
import { createRedisTransportKeyStore, crypto } from '@h-ai/crypto'
|
|
192
|
-
import { cache } from '@h-ai/cache'
|
|
193
|
-
|
|
194
|
-
await cache.init({ type: 'redis', host: '127.0.0.1', port: 6379 })
|
|
195
|
-
|
|
196
|
-
const sharedServer = crypto.transport.createServer({
|
|
197
|
-
keyStore: createRedisTransportKeyStore({ cache, ttlSeconds: 3600 }),
|
|
198
|
-
})
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
使用流程:
|
|
202
|
-
1. 先 `await crypto.init()`。
|
|
203
|
-
2. 服务端 `createServer()` 后暴露一个 POST 密钥协商端点:接收 `clientPublicKey`,返回 `serverPublicKey + clientId`。
|
|
204
|
-
3. 客户端 `createClient({ keyExchangeUrl })` 后,首次 `init()` / `encryptedFetch()` 会自动做密钥协商。
|
|
205
|
-
4. 协商完成后,请求附带 `X-Client-Id`;若请求有 body,则自动包装成 `{ encryptedKey, ciphertext, iv }`。
|
|
206
|
-
5. 服务端先 `decryptRequest()`,业务处理后再 `encryptResponse(clientId, data)`。
|
|
207
|
-
6. 客户端收到 `X-Encrypted: true` 的响应后自动解密;`destroy()` 可清空当前会话。
|
|
208
|
-
|
|
209
|
-
`encryptedFetch()` 与原生 fetch 一样会 reject:网络错误、密钥协商失败、请求加密失败或响应解密失败都应在调用方按 fetch 错误处理策略捕获。
|
|
210
|
-
|
|
211
|
-
常规应用优先使用上层封装:
|
|
212
|
-
- serv:`serv.createApp({ transport: { crypto } })`
|
|
213
|
-
- kit:`kit.createHandle({ crypto: { crypto, transport: true } })` + `kit.client.create({ transport: { crypto } })`
|
|
214
|
-
- api-client:`apiClient.init({ transport: { crypto } })`
|
|
215
|
-
|
|
216
|
-
## 错误码 — `HaiCryptoError`
|
|
217
|
-
|
|
218
|
-
| 错误码 | code | 说明 |
|
|
219
|
-
|--------|------|------|
|
|
220
|
-
| `HaiCryptoError.INVALID_INPUT` | `hai:crypto:002` | 无效输入 |
|
|
221
|
-
| `HaiCryptoError.INVALID_KEY` | `hai:crypto:003` | 无效密钥 |
|
|
222
|
-
| `HaiCryptoError.NOT_INITIALIZED` | `hai:crypto:010` | 未初始化 |
|
|
223
|
-
| `HaiCryptoError.INIT_FAILED` | `hai:crypto:011` | 初始化失败 |
|
|
224
|
-
| `HaiCryptoError.KEY_GENERATION_FAILED` | `hai:crypto:020` | 密钥生成失败 |
|
|
225
|
-
| `HaiCryptoError.ENCRYPTION_FAILED` | `hai:crypto:021` | 加密失败 |
|
|
226
|
-
| `HaiCryptoError.DECRYPTION_FAILED` | `hai:crypto:022` | 解密失败 |
|
|
227
|
-
| `HaiCryptoError.SIGN_FAILED` | `hai:crypto:023` | 签名失败 |
|
|
228
|
-
| `HaiCryptoError.VERIFY_FAILED` | `hai:crypto:024` | 验签失败 |
|
|
229
|
-
| `HaiCryptoError.HASH_FAILED` | `hai:crypto:040` | 哈希计算失败 |
|
|
230
|
-
| `HaiCryptoError.HMAC_FAILED` | `hai:crypto:041` | HMAC 计算失败 |
|
|
231
|
-
| `HaiCryptoError.INVALID_IV` | `hai:crypto:060` | 无效 IV |
|
|
232
|
-
|
|
233
|
-
## 常见模式
|
|
234
|
-
|
|
235
|
-
### 数据加密存储
|
|
236
|
-
|
|
237
|
-
```typescript
|
|
238
|
-
const key = process.env.HAI_CRYPTO_DATA_KEY!
|
|
239
|
-
const encrypted = crypto.symmetric.encrypt(sensitiveData, key)
|
|
240
|
-
// 存入数据库
|
|
241
|
-
|
|
242
|
-
// 读取时解密
|
|
243
|
-
const decrypted = crypto.symmetric.decrypt(storedPayload, key)
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
> 默认密文是结构化对象,必须完整存储 `mode` / `ciphertext` / `iv` / `encoding` 字段;如果数据库字段已拆分 IV 与密文,请改用 `encryptWithIV()` / `decryptWithIV()`。
|
|
247
|
-
|
|
248
|
-
### 密码存储与验证
|
|
249
|
-
|
|
250
|
-
```typescript
|
|
251
|
-
// 注册时哈希存储
|
|
252
|
-
const hashResult = crypto.password.hash(userPassword)
|
|
253
|
-
if (hashResult.success) {
|
|
254
|
-
// 存储 hashResult.data 到数据库
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// 登录时验证
|
|
258
|
-
const verifyResult = crypto.password.verify(inputPassword, storedHash)
|
|
259
|
-
if (verifyResult.success && verifyResult.data) {
|
|
260
|
-
// 密码匹配
|
|
261
|
-
}
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
## 相关 Skills
|
|
265
|
-
|
|
266
|
-
- `hai-core`:配置与 HaiResult 模型
|
|
267
|
-
- `hai-iam`:密码哈希(内部自动调用 crypto.password)
|
|
268
|
-
- `hai-kit`:SvelteKit 集成(传输加密)
|
|
269
|
-
- `hai-serv` / `hai-api-client`:跨域 HTTP API 的透明传输加密
|
|
270
|
-
|
|
271
|
-
管理端在线加密演示直接调用 Crypto SM3/SM4 API,SM4 使用随机临时密钥和 IV,并在显示成功前解密校验;密钥不保存。输入改变即清空旧结果,禁止用随机摘要或 Base64 伪装算法结果。
|
|
29
|
+
- [运行环境](reference.md#运行环境)
|
|
30
|
+
- [适用场景](reference.md#适用场景)
|
|
31
|
+
- [使用步骤](reference.md#使用步骤)
|
|
32
|
+
- [核心 API](reference.md#核心-api)
|
|
33
|
+
- [错误码 — `HaiCryptoError`](reference.md#错误码--haicryptoerror)
|
|
34
|
+
- [常见模式](reference.md#常见模式)
|
|
35
|
+
- [相关 Skills](reference.md#相关-skills)
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# hai-crypto 参考
|
|
2
|
+
|
|
3
|
+
> `@h-ai/crypto` 提供非对称加密、哈希、对称加密与密码哈希能力,支持 Node.js 与浏览器双端。
|
|
4
|
+
|
|
5
|
+
## 运行环境
|
|
6
|
+
|
|
7
|
+
**Node.js + 浏览器双端可用。** 浏览器端通过 `crypto.init()` 初始化(无需配置参数)。
|
|
8
|
+
|
|
9
|
+
| 能力 | Node.js | 浏览器 | 说明 |
|
|
10
|
+
|------|---------|--------|------|
|
|
11
|
+
| `crypto.asymmetric` 非对称加密 | ✅ | ✅ | SM2 加解密、签名验签 |
|
|
12
|
+
| `crypto.hash` 哈希 | ✅ | ✅ | SM3 哈希、HMAC |
|
|
13
|
+
| `crypto.symmetric` 对称加密 | ✅ | ✅ | SM4 ECB/CBC |
|
|
14
|
+
| `crypto.password` 密码哈希 | ✅ | ❌ | 依赖 Node.js crypto(服务端专用) |
|
|
15
|
+
| `crypto.transport` 传输加密 | ✅ | ✅ | 服务端管理器 + 客户端 encryptedFetch |
|
|
16
|
+
|
|
17
|
+
浏览器端主要用于 kit 传输加密场景(`kit.client.create({ transport: { crypto } })`),一般不需要直接调用 crypto API。
|
|
18
|
+
|
|
19
|
+
## 适用场景
|
|
20
|
+
|
|
21
|
+
- 非对称加密/解密、签名/验签、密钥生成
|
|
22
|
+
- 哈希计算与 HMAC
|
|
23
|
+
- 对称加密/解密(ECB/CBC 模式)
|
|
24
|
+
- 密码存储与验证(加盐迭代哈希)
|
|
25
|
+
- 传输加密:为 serv / kit / api-client 提供统一协议、密钥协商和请求响应加解密
|
|
26
|
+
|
|
27
|
+
## 使用步骤
|
|
28
|
+
|
|
29
|
+
### 1. 初始化与关闭
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import { crypto } from '@h-ai/crypto'
|
|
33
|
+
|
|
34
|
+
await crypto.init()
|
|
35
|
+
|
|
36
|
+
// 使用后关闭
|
|
37
|
+
await crypto.close()
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## 核心 API
|
|
41
|
+
|
|
42
|
+
### 非对称加密 — `crypto.asymmetric`
|
|
43
|
+
|
|
44
|
+
| 方法 | 签名 | 说明 |
|
|
45
|
+
| ------------------- | ----------------------------------------------------------- | ------------ |
|
|
46
|
+
| `generateKeyPair` | `() => HaiResult<KeyPair>` | 生成密钥对 |
|
|
47
|
+
| `encrypt` | `(data, publicKey, options?) => HaiResult<string>` | 公钥加密 |
|
|
48
|
+
| `decrypt` | `(ciphertext, privateKey, options?) => HaiResult<string>` | 私钥解密 |
|
|
49
|
+
| `sign` | `(data, privateKey, options?) => HaiResult<string>` | 私钥签名 |
|
|
50
|
+
| `verify` | `(data, signature, publicKey, options?) => HaiResult<boolean>` | 公钥验签 |
|
|
51
|
+
| `isValidPublicKey` | `(key: string) => boolean` | 校验公钥格式 |
|
|
52
|
+
| `isValidPrivateKey` | `(key: string) => boolean` | 校验私钥格式 |
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
const keyPair = crypto.asymmetric.generateKeyPair()
|
|
56
|
+
if (keyPair.success) {
|
|
57
|
+
const { publicKey, privateKey } = keyPair.data
|
|
58
|
+
|
|
59
|
+
const encrypted = crypto.asymmetric.encrypt('敏感数据', publicKey)
|
|
60
|
+
if (encrypted.success) {
|
|
61
|
+
const decrypted = crypto.asymmetric.decrypt(encrypted.data, privateKey)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const signature = crypto.asymmetric.sign('待签名数据', privateKey)
|
|
65
|
+
if (signature.success) {
|
|
66
|
+
const valid = crypto.asymmetric.verify('待签名数据', signature.data, publicKey)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**AsymmetricEncryptOptions**:`{ cipherMode?: 0 | 1, outputFormat?: 'hex' | 'base64' }`
|
|
72
|
+
**SignOptions**:`{ hash?: boolean, userId?: string }`
|
|
73
|
+
|
|
74
|
+
### 哈希 — `crypto.hash`
|
|
75
|
+
|
|
76
|
+
| 方法 | 签名 | 说明 |
|
|
77
|
+
| -------- | ---------------------------------------------------------- | -------- |
|
|
78
|
+
| `hash` | `(data: string \| Uint8Array, options?) => HaiResult<string>` | 哈希 |
|
|
79
|
+
| `hmac` | `(data, key) => HaiResult<string>` | HMAC |
|
|
80
|
+
| `verify` | `(data, expectedHash) => HaiResult<boolean>` | 验证哈希 |
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
const hash = crypto.hash.hash('hello')
|
|
84
|
+
const hmac = crypto.hash.hmac('hello', 'secret-key')
|
|
85
|
+
const valid = crypto.hash.verify('hello', hash.data!)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**HashOptions**:`{ inputEncoding?: 'utf8' | 'hex' }`
|
|
89
|
+
|
|
90
|
+
### 对称加密 — `crypto.symmetric`
|
|
91
|
+
|
|
92
|
+
| 方法 | 签名 | 说明 |
|
|
93
|
+
| --------------- | ----------------------------------------------- | --------------------------- |
|
|
94
|
+
| `generateKey` | `() => string` | 生成 128-bit 密钥(32 hex) |
|
|
95
|
+
| `generateIV` | `() => string` | 生成随机 IV(32 hex) |
|
|
96
|
+
| `encrypt` | `(data, key, options?) => HaiResult<SymmetricEncryptedPayload>` | 加密(返回结构化密文) |
|
|
97
|
+
| `decrypt` | `(payload, key) => HaiResult<string>` | 解密结构化密文 |
|
|
98
|
+
| `encryptWithIV` | `(data, key) => HaiResult<EncryptWithIVResult>` | CBC 模式加密(自动生成 IV) |
|
|
99
|
+
| `decryptWithIV` | `(ciphertext, key, iv) => HaiResult<string>` | CBC 模式解密 |
|
|
100
|
+
| `deriveKey` | `(password, salt) => string` | 从密码和盐值派生密钥 |
|
|
101
|
+
| `isValidKey` | `(key: string) => boolean` | 校验密钥格式 |
|
|
102
|
+
| `isValidIV` | `(iv: string) => boolean` | 校验 IV 格式 |
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
const key = crypto.symmetric.generateKey()
|
|
106
|
+
|
|
107
|
+
// 默认安全用法:CBC + 自动 IV,返回 { mode, ciphertext, iv, encoding }
|
|
108
|
+
const encrypted = crypto.symmetric.encrypt('明文数据', key)
|
|
109
|
+
if (encrypted.success) {
|
|
110
|
+
const decrypted = crypto.symmetric.decrypt(encrypted.data, key)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// 需要单独存储 IV 时使用结构化结果
|
|
114
|
+
const withIV = crypto.symmetric.encryptWithIV('明文数据', key)
|
|
115
|
+
if (withIV.success) {
|
|
116
|
+
const decrypted = crypto.symmetric.decryptWithIV(withIV.data.ciphertext, key, withIV.data.iv)
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**SymmetricEncryptOptions**:`{ mode?: 'ecb' | 'cbc', iv?: string, outputFormat?: 'hex' | 'base64' }`
|
|
121
|
+
**SymmetricEncryptedPayload**:`{ mode: 'ecb' | 'cbc', ciphertext: string, iv?: string, encoding: 'hex' | 'base64' }`
|
|
122
|
+
|
|
123
|
+
> `encrypt()` 默认使用 CBC 并自动生成 IV。ECB 会泄漏明文结构,只有底层协议明确要求时才显式 `{ mode: 'ecb' }`。
|
|
124
|
+
|
|
125
|
+
### 密码哈希 — `crypto.password`
|
|
126
|
+
|
|
127
|
+
| 方法 | 签名 | 说明 |
|
|
128
|
+
| -------- | --------------------------------------- | -------- |
|
|
129
|
+
| `hash` | `(password, config?) => HaiResult<string>` | 密码哈希 |
|
|
130
|
+
| `verify` | `(password, hash) => HaiResult<boolean>` | 验证密码 |
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
const hashed = crypto.password.hash('MyPassword123')
|
|
134
|
+
if (hashed.success) {
|
|
135
|
+
const valid = crypto.password.verify('MyPassword123', hashed.data)
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
哈希格式:`$hai$<iterations>$<salt>$<hash>`
|
|
140
|
+
**PasswordConfig**:`{ saltLength?: number, iterations?: number }`
|
|
141
|
+
|
|
142
|
+
### 传输加密 — `crypto.transport`
|
|
143
|
+
|
|
144
|
+
传输加密主工厂必须从 `crypto.transport` 访问;共享 `keyStore` provider 请从 `@h-ai/crypto` 根入口导入,不从子目录内部路径导入。
|
|
145
|
+
|
|
146
|
+
| 方法 | 签名 | 说明 |
|
|
147
|
+
| --- | --- | --- |
|
|
148
|
+
| `createServer` | `(options?) => HaiResult<TransportEncryptionManager>` | 创建服务端传输加密管理器 |
|
|
149
|
+
| `createClient` | `({ keyExchangeUrl, fetch? }) => TransportClient` | 创建客户端 encryptedFetch 会话 |
|
|
150
|
+
| `protocol` | `TRANSPORT_PROTOCOL` | 协议常量:`X-Client-Id`、`X-Encrypted`、默认协商路径 |
|
|
151
|
+
|
|
152
|
+
共享 `keyStore` provider(从 `@h-ai/crypto` 根入口导入):
|
|
153
|
+
|
|
154
|
+
| 工厂 | 签名 | 说明 |
|
|
155
|
+
| --- | --- | --- |
|
|
156
|
+
| `createInMemoryKeyStore` | `(maxClients?) => TransportKeyStore` | 默认 FIFO 内存实现 |
|
|
157
|
+
| `createRedisTransportKeyStore` | `({ cache, ttlSeconds? }) => TransportKeyStore` | 基于 `@h-ai/cache` 的共享实现,通常配 Redis |
|
|
158
|
+
| `createReldbTransportKeyStore` | `({ reldb, ttlSeconds? }) => TransportKeyStore` | 基于 `@h-ai/reldb` 的共享实现,自动建表 |
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
const server = crypto.transport.createServer({ maxClients: 10000 })
|
|
162
|
+
if (!server.success)
|
|
163
|
+
return server
|
|
164
|
+
|
|
165
|
+
const client = crypto.transport.createClient({
|
|
166
|
+
keyExchangeUrl: 'https://api.example.com/api/v1/_hai/key-exchange',
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
const resp = await client.encryptedFetch('https://api.example.com/api/v1/echo', {
|
|
170
|
+
method: 'POST',
|
|
171
|
+
body: JSON.stringify({ hello: 'world' }),
|
|
172
|
+
})
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
import { createRedisTransportKeyStore, crypto } from '@h-ai/crypto'
|
|
177
|
+
import { cache } from '@h-ai/cache'
|
|
178
|
+
|
|
179
|
+
await cache.init({ type: 'redis', host: '127.0.0.1', port: 6379 })
|
|
180
|
+
|
|
181
|
+
const sharedServer = crypto.transport.createServer({
|
|
182
|
+
keyStore: createRedisTransportKeyStore({ cache, ttlSeconds: 3600 }),
|
|
183
|
+
})
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
使用流程:
|
|
187
|
+
1. 先 `await crypto.init()`。
|
|
188
|
+
2. 服务端 `createServer()` 后暴露一个 POST 密钥协商端点:接收 `clientPublicKey`,返回 `serverPublicKey + clientId`。
|
|
189
|
+
3. 客户端 `createClient({ keyExchangeUrl })` 后,首次 `init()` / `encryptedFetch()` 会自动做密钥协商。
|
|
190
|
+
4. 协商完成后,请求附带 `X-Client-Id`;若请求有 body,则自动包装成 `{ encryptedKey, ciphertext, iv }`。
|
|
191
|
+
5. 服务端先 `decryptRequest()`,业务处理后再 `encryptResponse(clientId, data)`。
|
|
192
|
+
6. 客户端收到 `X-Encrypted: true` 的响应后自动解密;`destroy()` 可清空当前会话。
|
|
193
|
+
|
|
194
|
+
`encryptedFetch()` 与原生 fetch 一样会 reject:网络错误、密钥协商失败、请求加密失败或响应解密失败都应在调用方按 fetch 错误处理策略捕获。
|
|
195
|
+
|
|
196
|
+
常规应用优先使用上层封装:
|
|
197
|
+
- serv:`serv.createApp({ transport: { crypto } })`
|
|
198
|
+
- kit:`kit.createHandle({ crypto: { crypto, transport: true } })` + `kit.client.create({ transport: { crypto } })`
|
|
199
|
+
- api-client:`apiClient.init({ transport: { crypto } })`
|
|
200
|
+
|
|
201
|
+
## 错误码 — `HaiCryptoError`
|
|
202
|
+
|
|
203
|
+
| 错误码 | code | 说明 |
|
|
204
|
+
|--------|------|------|
|
|
205
|
+
| `HaiCryptoError.INVALID_INPUT` | `hai:crypto:002` | 无效输入 |
|
|
206
|
+
| `HaiCryptoError.INVALID_KEY` | `hai:crypto:003` | 无效密钥 |
|
|
207
|
+
| `HaiCryptoError.NOT_INITIALIZED` | `hai:crypto:010` | 未初始化 |
|
|
208
|
+
| `HaiCryptoError.INIT_FAILED` | `hai:crypto:011` | 初始化失败 |
|
|
209
|
+
| `HaiCryptoError.KEY_GENERATION_FAILED` | `hai:crypto:020` | 密钥生成失败 |
|
|
210
|
+
| `HaiCryptoError.ENCRYPTION_FAILED` | `hai:crypto:021` | 加密失败 |
|
|
211
|
+
| `HaiCryptoError.DECRYPTION_FAILED` | `hai:crypto:022` | 解密失败 |
|
|
212
|
+
| `HaiCryptoError.SIGN_FAILED` | `hai:crypto:023` | 签名失败 |
|
|
213
|
+
| `HaiCryptoError.VERIFY_FAILED` | `hai:crypto:024` | 验签失败 |
|
|
214
|
+
| `HaiCryptoError.HASH_FAILED` | `hai:crypto:040` | 哈希计算失败 |
|
|
215
|
+
| `HaiCryptoError.HMAC_FAILED` | `hai:crypto:041` | HMAC 计算失败 |
|
|
216
|
+
| `HaiCryptoError.INVALID_IV` | `hai:crypto:060` | 无效 IV |
|
|
217
|
+
|
|
218
|
+
## 常见模式
|
|
219
|
+
|
|
220
|
+
### 数据加密存储
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
const key = process.env.HAI_CRYPTO_DATA_KEY!
|
|
224
|
+
const encrypted = crypto.symmetric.encrypt(sensitiveData, key)
|
|
225
|
+
// 存入数据库
|
|
226
|
+
|
|
227
|
+
// 读取时解密
|
|
228
|
+
const decrypted = crypto.symmetric.decrypt(storedPayload, key)
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
> 默认密文是结构化对象,必须完整存储 `mode` / `ciphertext` / `iv` / `encoding` 字段;如果数据库字段已拆分 IV 与密文,请改用 `encryptWithIV()` / `decryptWithIV()`。
|
|
232
|
+
|
|
233
|
+
### 密码存储与验证
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
// 注册时哈希存储
|
|
237
|
+
const hashResult = crypto.password.hash(userPassword)
|
|
238
|
+
if (hashResult.success) {
|
|
239
|
+
// 存储 hashResult.data 到数据库
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// 登录时验证
|
|
243
|
+
const verifyResult = crypto.password.verify(inputPassword, storedHash)
|
|
244
|
+
if (verifyResult.success && verifyResult.data) {
|
|
245
|
+
// 密码匹配
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## 相关 Skills
|
|
250
|
+
|
|
251
|
+
- `hai-core`:配置与 HaiResult 模型
|
|
252
|
+
- `hai-iam`:密码哈希(内部自动调用 crypto.password)
|
|
253
|
+
- `hai-kit`:SvelteKit 集成(传输加密)
|
|
254
|
+
- `hai-serv` / `hai-api-client`:跨域 HTTP API 的透明传输加密
|
|
255
|
+
|
|
256
|
+
管理端在线加密演示直接调用 Crypto SM3/SM4 API,SM4 使用随机临时密钥和 IV,并在显示成功前解密校验;密钥不保存。输入改变即清空旧结果,禁止用随机摘要或 Base64 伪装算法结果。
|