@h-ai/crypto 0.1.0-alpha.13 → 0.1.0-alpha.16
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.md +44 -0
- package/dist/index.d.ts +217 -1
- package/dist/index.js +288 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
- 哈希(哈希、HMAC、验证)
|
|
9
9
|
- 对称加密(ECB/CBC 模式)
|
|
10
10
|
- 密码哈希(加盐迭代哈希)
|
|
11
|
+
- 传输加密(`crypto.transport`:服务端管理器 + 客户端 `encryptedFetch`)
|
|
11
12
|
- 前后端通用(Node.js / 浏览器)
|
|
12
13
|
|
|
13
14
|
## 安全声明
|
|
@@ -140,6 +141,49 @@ if (hashed.success) {
|
|
|
140
141
|
}
|
|
141
142
|
```
|
|
142
143
|
|
|
144
|
+
### 传输加密(crypto.transport)
|
|
145
|
+
|
|
146
|
+
传输加密统一通过 `crypto.transport` 命名空间提供,供 `@h-ai/serv`、`@h-ai/kit` 与 `@h-ai/api-client` 复用同一套协议常量和载荷格式。
|
|
147
|
+
|
|
148
|
+
常规应用优先让上层封装代接:
|
|
149
|
+
|
|
150
|
+
- 服务端:`serv.createApp({ transport: { crypto } })` 或 `kit.createHandle({ crypto: { crypto, transport: true } })`
|
|
151
|
+
- 客户端:`apiClient.init({ transport: { crypto } })` 或 `kit.client.create({ transport: { crypto } })`
|
|
152
|
+
|
|
153
|
+
只有在自定义运行时、测试或你确实要自己接 HTTP 协商端点时,才建议直接调用 `crypto.transport.createServer()` / `createClient()`。
|
|
154
|
+
|
|
155
|
+
#### 使用流程
|
|
156
|
+
|
|
157
|
+
1. 先 `await crypto.init()`,确保 `crypto.asymmetric` 与 `crypto.symmetric` 已初始化。
|
|
158
|
+
2. 服务端调用 `crypto.transport.createServer()` 创建 `manager`;它持有服务端密钥对,并负责保存客户端公钥。
|
|
159
|
+
3. 服务端提供一个 POST 密钥协商端点:接收 `{ clientPublicKey }`,调用 `manager.registerClientKey()` 注册客户端,再返回 `{ serverPublicKey: manager.getServerPublicKey(), clientId }`。
|
|
160
|
+
4. 客户端调用 `crypto.transport.createClient({ keyExchangeUrl })` 创建会话;首次 `client.init()` 或 `client.encryptedFetch()` 会自动完成这次协商。
|
|
161
|
+
5. 协商完成后,客户端请求会附带 `X-Client-Id`;若请求有 body,则 body 会被包装成 `{ encryptedKey, ciphertext, iv }`,并带上 `X-Encrypted: true`。无 body 的请求只附带 `X-Client-Id`,不会额外生成密文 body。
|
|
162
|
+
6. 服务端根据 `clientId` 找到客户端公钥,先 `manager.decryptRequest()` 解密请求体,再执行业务逻辑。
|
|
163
|
+
7. 服务端返回 JSON 响应前,用 `manager.encryptResponse(clientId, data)` 重新加密,并设置 `X-Encrypted: true`;客户端收到后会自动解密。
|
|
164
|
+
8. 客户端调用 `client.destroy()` 可清空当前会话;服务端调用 `manager.close()`,或在模块级调用 `await crypto.close()`,用于释放资源。
|
|
165
|
+
|
|
166
|
+
> 默认 `keyStore` 是进程内内存实现。多节点部署时,需要会话粘性(sticky session),或改用共享的 `TransportKeyStore` 实现来保存客户端公钥。
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
// 服务端:通常由 serv.createApp({ transport: { crypto } }) 或 kit.createHandle({ crypto }) 内部调用
|
|
170
|
+
const server = crypto.transport.createServer({ maxClients: 10000 })
|
|
171
|
+
if (!server.success)
|
|
172
|
+
throw new Error(server.error.message)
|
|
173
|
+
|
|
174
|
+
// 客户端:通常由 apiClient.init({ transport: { crypto } }) 或 kit.client.create({ transport }) 内部调用
|
|
175
|
+
const client = crypto.transport.createClient({
|
|
176
|
+
keyExchangeUrl: 'https://api.example.com/api/v1/_hai/key-exchange',
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
const response = await client.encryptedFetch('https://api.example.com/api/v1/echo', {
|
|
180
|
+
method: 'POST',
|
|
181
|
+
body: JSON.stringify({ hello: 'world' }),
|
|
182
|
+
})
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
协议常量通过 `crypto.transport.protocol`(或 `TRANSPORT_PROTOCOL`)访问:`X-Client-Id`、`X-Encrypted`、默认 `/_hai/key-exchange`。
|
|
186
|
+
|
|
143
187
|
### 关闭模块
|
|
144
188
|
|
|
145
189
|
```ts
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,152 @@
|
|
|
1
1
|
import * as _h_ai_core from '@h-ai/core';
|
|
2
2
|
import { HaiResult } from '@h-ai/core';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* @h-ai/crypto — 传输加密类型与协议常量
|
|
6
|
+
*
|
|
7
|
+
* 提供 SM2 + SM4(或等效非对称 + 对称)混合传输加密所需的接口与协议常量,
|
|
8
|
+
* 由 kit / serv / api-client 共享,确保两端协议完全一致。
|
|
9
|
+
*
|
|
10
|
+
* @module crypto-transport-types
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 传输加密协议常量。
|
|
15
|
+
*
|
|
16
|
+
* 所有使用端必须复用这组常量,避免「header 名拼写漂移导致两端协议错配」。
|
|
17
|
+
*/
|
|
18
|
+
declare const TRANSPORT_PROTOCOL: {
|
|
19
|
+
/** 客户端 ID 请求头名。 */
|
|
20
|
+
readonly CLIENT_ID_HEADER: "X-Client-Id";
|
|
21
|
+
/** 标识响应体已加密的响应头名。 */
|
|
22
|
+
readonly ENCRYPTED_HEADER: "X-Encrypted";
|
|
23
|
+
/** `X-Encrypted` 响应头的开启值。 */
|
|
24
|
+
readonly ENCRYPTED_HEADER_VALUE: "true";
|
|
25
|
+
/** 密钥协商端点的默认子路径(相对于挂载前缀)。 */
|
|
26
|
+
readonly DEFAULT_KEY_EXCHANGE_PATH: "/_hai/key-exchange";
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* 密钥协商请求体(客户端 → 服务端)。
|
|
30
|
+
*/
|
|
31
|
+
interface KeyExchangeRequest {
|
|
32
|
+
readonly clientPublicKey: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 密钥协商响应体(服务端 → 客户端)。
|
|
36
|
+
*/
|
|
37
|
+
interface KeyExchangeResponse {
|
|
38
|
+
readonly serverPublicKey: string;
|
|
39
|
+
readonly clientId: string;
|
|
40
|
+
}
|
|
41
|
+
/** 非对称密钥对。 */
|
|
42
|
+
interface TransportKeyPair {
|
|
43
|
+
publicKey: string;
|
|
44
|
+
privateKey: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 端到端传输的加密载荷格式。
|
|
48
|
+
*
|
|
49
|
+
* `encryptedKey` 用对端非对称公钥加密的对称会话密钥;`ciphertext` + `iv`
|
|
50
|
+
* 为该会话密钥加密的明文。两端必须使用同一份字段命名。
|
|
51
|
+
*/
|
|
52
|
+
interface EncryptedPayload {
|
|
53
|
+
readonly encryptedKey: string;
|
|
54
|
+
readonly ciphertext: string;
|
|
55
|
+
readonly iv: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* 传输加密所需的非对称 + 对称能力子集。
|
|
59
|
+
*
|
|
60
|
+
* 不直接依赖 `@h-ai/crypto` 的具体实现,便于测试时注入 mock;
|
|
61
|
+
* 实际使用时 `crypto` 模块的实例本身即可结构兼容。
|
|
62
|
+
*/
|
|
63
|
+
interface TransportCryptoServiceLike {
|
|
64
|
+
asymmetric: {
|
|
65
|
+
generateKeyPair: () => HaiResult<TransportKeyPair>;
|
|
66
|
+
encrypt: (data: string, publicKey: string) => HaiResult<string>;
|
|
67
|
+
decrypt: (ciphertext: string, privateKey: string) => HaiResult<string>;
|
|
68
|
+
};
|
|
69
|
+
symmetric: {
|
|
70
|
+
generateKey: () => string;
|
|
71
|
+
encryptWithIV: (data: string, key: string) => HaiResult<{
|
|
72
|
+
ciphertext: string;
|
|
73
|
+
iv: string;
|
|
74
|
+
}>;
|
|
75
|
+
decryptWithIV: (ciphertext: string, key: string, iv: string) => HaiResult<string>;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 客户端公钥存储抽象。
|
|
80
|
+
*
|
|
81
|
+
* 默认实现为进程内 Map({@link createInMemoryKeyStore}),多节点部署时建议
|
|
82
|
+
* 接入 Redis / 数据库实现以保证跨节点一致性。
|
|
83
|
+
*
|
|
84
|
+
* 设计原则:方法均为异步签名,避免后续替换为分布式实现时大改接口;
|
|
85
|
+
* 内存实现以 `Promise.resolve` 包裹即可。
|
|
86
|
+
*/
|
|
87
|
+
interface TransportKeyStore {
|
|
88
|
+
/** 注册新客户端,返回服务端生成的 `clientId`。 */
|
|
89
|
+
register: (publicKey: string) => Promise<string>;
|
|
90
|
+
/** 查询已注册客户端公钥。 */
|
|
91
|
+
get: (clientId: string) => Promise<string | undefined>;
|
|
92
|
+
/** 主动删除(可选,便于客户端登出时清理)。 */
|
|
93
|
+
delete?: (clientId: string) => Promise<void>;
|
|
94
|
+
/** 释放底层资源(关闭连接、清理定时器等)。 */
|
|
95
|
+
close?: () => Promise<void>;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* 服务端传输加密管理器。
|
|
99
|
+
*
|
|
100
|
+
* 由 {@link createTransportEncryption} 创建;负责服务端密钥对持有、客户端密钥
|
|
101
|
+
* 注册与请求/响应的加解密。
|
|
102
|
+
*
|
|
103
|
+
* @remarks
|
|
104
|
+
* 典型调用顺序:
|
|
105
|
+
*
|
|
106
|
+
* 1. `registerClientKey(clientPublicKey)`:在密钥协商端点中保存客户端公钥,并生成 `clientId`。
|
|
107
|
+
* 2. `getServerPublicKey()`:把服务端公钥返回给客户端,供后续请求加密会话密钥。
|
|
108
|
+
* 3. `decryptRequest(payload)`:普通业务请求进入业务逻辑前,先把密文请求体解成明文。
|
|
109
|
+
* 4. `encryptResponse(clientId, data)`:业务处理完成后,按当前客户端公钥重新加密响应体。
|
|
110
|
+
* 5. `close()`:服务关闭时释放底层 keyStore 资源。
|
|
111
|
+
*/
|
|
112
|
+
interface TransportEncryptionManager {
|
|
113
|
+
getServerPublicKey: () => string;
|
|
114
|
+
registerClientKey: (clientPublicKey: string) => Promise<string>;
|
|
115
|
+
getClientPublicKey: (clientId: string) => Promise<string | undefined>;
|
|
116
|
+
encryptResponse: (clientId: string, data: string) => Promise<HaiResult<EncryptedPayload>>;
|
|
117
|
+
decryptRequest: (payload: EncryptedPayload) => HaiResult<string>;
|
|
118
|
+
/** 关闭:释放 keyStore 资源。 */
|
|
119
|
+
close: () => Promise<void>;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* 客户端传输加密会话。
|
|
123
|
+
*
|
|
124
|
+
* 由 {@link createTransportClient} 创建;包装宿主 `fetch`,
|
|
125
|
+
* 自动完成首次密钥协商并对后续请求自动加解密。
|
|
126
|
+
*
|
|
127
|
+
* @remarks
|
|
128
|
+
* 典型调用顺序:
|
|
129
|
+
*
|
|
130
|
+
* 1. `init()`(可选):预先完成一次密钥协商。
|
|
131
|
+
* 2. `encryptedFetch()`:业务请求统一走这里;若当前会话尚未 ready,会先自动执行 `init()`。
|
|
132
|
+
* 3. `ready()`:查看当前会话是否已经拿到 `clientId` 与服务端公钥。
|
|
133
|
+
* 4. `destroy()`:登出、切租户或切环境时清空会话;下一次请求会重新协商。
|
|
134
|
+
*/
|
|
135
|
+
interface TransportClient {
|
|
136
|
+
/**
|
|
137
|
+
* 完成密钥协商;多次调用幂等(同一会话只协商一次)。
|
|
138
|
+
*
|
|
139
|
+
* 通常无需手动调用:`encryptedFetch` 在首次请求前会自动 `init()`。
|
|
140
|
+
*/
|
|
141
|
+
init: () => Promise<HaiResult<void>>;
|
|
142
|
+
/** 包装后的 fetch;签名与全局 `fetch` 一致,请求/响应自动加解密。 */
|
|
143
|
+
encryptedFetch: typeof fetch;
|
|
144
|
+
/** 是否已完成密钥协商。 */
|
|
145
|
+
ready: () => boolean;
|
|
146
|
+
/** 销毁会话(清空客户端密钥)。 */
|
|
147
|
+
destroy: () => void;
|
|
148
|
+
}
|
|
149
|
+
|
|
4
150
|
declare const HaiCryptoError: {
|
|
5
151
|
readonly INVALID_INPUT: _h_ai_core.HaiErrorDef;
|
|
6
152
|
readonly INVALID_KEY: _h_ai_core.HaiErrorDef;
|
|
@@ -266,6 +412,74 @@ interface PasswordOperations {
|
|
|
266
412
|
*/
|
|
267
413
|
verify: (password: string, hash: string) => HaiResult<boolean>;
|
|
268
414
|
}
|
|
415
|
+
/**
|
|
416
|
+
* 传输加密操作接口(端到端混合加密)。
|
|
417
|
+
*
|
|
418
|
+
* 通过 `crypto.transport` 访问,需先调用 `crypto.init()`。
|
|
419
|
+
*
|
|
420
|
+
* @remarks
|
|
421
|
+
* 使用流程(直接使用底层 transport 工厂时):
|
|
422
|
+
*
|
|
423
|
+
* 1. 先 `await crypto.init()`,确保 `crypto.asymmetric` / `crypto.symmetric` 已就绪。
|
|
424
|
+
* 2. 服务端调用 `crypto.transport.createServer()` 创建 `TransportEncryptionManager`;该管理器负责持有服务端密钥对,并管理客户端公钥。
|
|
425
|
+
* 3. 服务端暴露一个 POST 密钥协商端点:接收 `{ clientPublicKey }`,调用 `manager.registerClientKey()` 注册客户端公钥,再返回 `{ serverPublicKey: manager.getServerPublicKey(), clientId }`。
|
|
426
|
+
* 4. 客户端调用 `crypto.transport.createClient({ keyExchangeUrl })` 创建会话;首次 `client.init()` 或 `client.encryptedFetch()` 会自动完成密钥协商。
|
|
427
|
+
* 5. 协商完成后,客户端每次请求都会附带 `X-Client-Id`;若请求有 body,则 body 会被包装成 `{ encryptedKey, ciphertext, iv }`,并设置 `X-Encrypted: true`。
|
|
428
|
+
* 6. 服务端在业务逻辑前调用 `manager.decryptRequest()` 解密请求体,在返回前调用 `manager.encryptResponse(clientId, data)` 为当前客户端重新加密响应。
|
|
429
|
+
* 7. 客户端收到 `X-Encrypted: true` 的响应后会自动解密;调用 `client.destroy()` 可清空当前会话,下次请求会重新协商。
|
|
430
|
+
*
|
|
431
|
+
* 常规应用优先使用上层封装,而不是手写 HTTP 协商细节:
|
|
432
|
+
* - `serv.createApp({ transport: { crypto } })`
|
|
433
|
+
* - `kit.createHandle({ crypto: { crypto, transport: true } })`
|
|
434
|
+
* - `apiClient.init({ transport: { crypto } })`
|
|
435
|
+
*
|
|
436
|
+
* @example 服务端
|
|
437
|
+
* ```ts
|
|
438
|
+
* const result = crypto.transport.createServer()
|
|
439
|
+
* if (!result.success) throw result.error
|
|
440
|
+
* const manager = result.data
|
|
441
|
+
* ```
|
|
442
|
+
*
|
|
443
|
+
* @example 客户端
|
|
444
|
+
* ```ts
|
|
445
|
+
* const client = crypto.transport.createClient({
|
|
446
|
+
* keyExchangeUrl: 'https://api.example.com/api/v1/_hai/key-exchange',
|
|
447
|
+
* })
|
|
448
|
+
* const resp = await client.encryptedFetch('https://api.example.com/api/v1/echo', {
|
|
449
|
+
* method: 'POST', body: JSON.stringify({ hello: 'world' }),
|
|
450
|
+
* })
|
|
451
|
+
* ```
|
|
452
|
+
*/
|
|
453
|
+
interface TransportOperations {
|
|
454
|
+
/**
|
|
455
|
+
* 创建服务端传输加密管理器。
|
|
456
|
+
*
|
|
457
|
+
* options.maxClients:默认内存 keyStore 的最大客户端数(默认 10000)。
|
|
458
|
+
* 成功返回 manager;密钥生成失败返回 `HaiCommonError.INTERNAL_ERROR`。
|
|
459
|
+
*
|
|
460
|
+
* @remarks
|
|
461
|
+
* 通常在服务启动阶段创建一次,并交给 HTTP 中间件 / 路由处理器复用。
|
|
462
|
+
*/
|
|
463
|
+
createServer: (options?: {
|
|
464
|
+
maxClients?: number;
|
|
465
|
+
}) => HaiResult<TransportEncryptionManager>;
|
|
466
|
+
/**
|
|
467
|
+
* 创建客户端传输加密会话。
|
|
468
|
+
*
|
|
469
|
+
* options.keyExchangeUrl:密钥协商端点完整 URL。
|
|
470
|
+
* options.fetch:实际发送 HTTP 请求的 fetch(默认 `globalThis.fetch`)。
|
|
471
|
+
*
|
|
472
|
+
* @remarks
|
|
473
|
+
* 返回的是“单会话”客户端:同一个实例会复用已协商得到的 `clientId` 与服务端公钥;
|
|
474
|
+
* 调用 `destroy()` 后会回到未协商状态。
|
|
475
|
+
*/
|
|
476
|
+
createClient: (options: {
|
|
477
|
+
keyExchangeUrl: string;
|
|
478
|
+
fetch?: typeof fetch;
|
|
479
|
+
}) => TransportClient;
|
|
480
|
+
/** 协议常量(headers、密钥协商默认路径)。 */
|
|
481
|
+
readonly protocol: typeof TRANSPORT_PROTOCOL;
|
|
482
|
+
}
|
|
269
483
|
/**
|
|
270
484
|
* 加密模块函数接口
|
|
271
485
|
*
|
|
@@ -306,6 +520,8 @@ interface CryptoFunctions {
|
|
|
306
520
|
readonly symmetric: SymmetricOperations;
|
|
307
521
|
/** 密码哈希操作(未初始化时所有方法返回 NOT_INITIALIZED) */
|
|
308
522
|
readonly password: PasswordOperations;
|
|
523
|
+
/** 传输加密操作(端到端混合加密;createServer 在未初始化时返回 NOT_INITIALIZED) */
|
|
524
|
+
readonly transport: TransportOperations;
|
|
309
525
|
}
|
|
310
526
|
|
|
311
527
|
/**
|
|
@@ -333,4 +549,4 @@ interface CryptoFunctions {
|
|
|
333
549
|
*/
|
|
334
550
|
declare const crypto: CryptoFunctions;
|
|
335
551
|
|
|
336
|
-
export { type AsymmetricEncryptOptions, type AsymmetricOperations, type CipherMode, type CryptoFunctions, type EncryptWithIVResult, HaiCryptoError, type HashOperations, type HashOptions, type KeyPair, type PasswordConfig, type PasswordOperations, type SignOptions, type SymmetricMode, type SymmetricOperations, type SymmetricOptions, crypto };
|
|
552
|
+
export { type AsymmetricEncryptOptions, type AsymmetricOperations, type CipherMode, type CryptoFunctions, type EncryptWithIVResult, type EncryptedPayload, HaiCryptoError, type HashOperations, type HashOptions, type KeyExchangeRequest, type KeyExchangeResponse, type KeyPair, type PasswordConfig, type PasswordOperations, type SignOptions, type SymmetricMode, type SymmetricOperations, type SymmetricOptions, TRANSPORT_PROTOCOL, type TransportClient, type TransportCryptoServiceLike, type TransportEncryptionManager, type TransportKeyPair, type TransportKeyStore, type TransportOperations, crypto };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { core, ok, err } from '@h-ai/core';
|
|
1
|
+
import { core, ok, err, HaiCommonError } from '@h-ai/core';
|
|
2
2
|
import smCrypto from 'sm-crypto';
|
|
3
3
|
|
|
4
4
|
// src/crypto-main.ts
|
|
@@ -738,6 +738,277 @@ function generateRandomHex(byteLength) {
|
|
|
738
738
|
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
739
739
|
}
|
|
740
740
|
|
|
741
|
+
// src/transport/crypto-transport-types.ts
|
|
742
|
+
var TRANSPORT_PROTOCOL = {
|
|
743
|
+
/** 客户端 ID 请求头名。 */
|
|
744
|
+
CLIENT_ID_HEADER: "X-Client-Id",
|
|
745
|
+
/** 标识响应体已加密的响应头名。 */
|
|
746
|
+
ENCRYPTED_HEADER: "X-Encrypted",
|
|
747
|
+
/** `X-Encrypted` 响应头的开启值。 */
|
|
748
|
+
ENCRYPTED_HEADER_VALUE: "true",
|
|
749
|
+
/** 密钥协商端点的默认子路径(相对于挂载前缀)。 */
|
|
750
|
+
DEFAULT_KEY_EXCHANGE_PATH: "/_hai/key-exchange"
|
|
751
|
+
};
|
|
752
|
+
|
|
753
|
+
// src/transport/crypto-transport-client.ts
|
|
754
|
+
function createTransportClient(options) {
|
|
755
|
+
const baseFetch = options.fetch ?? fetch;
|
|
756
|
+
let keyPair = null;
|
|
757
|
+
let serverPublicKey = null;
|
|
758
|
+
let clientId = null;
|
|
759
|
+
let initPromise = null;
|
|
760
|
+
async function doInit() {
|
|
761
|
+
const kpResult = options.crypto.asymmetric.generateKeyPair();
|
|
762
|
+
if (!kpResult.success)
|
|
763
|
+
return err(HaiCommonError.INTERNAL_ERROR, "Failed to generate client key pair", kpResult.error);
|
|
764
|
+
const localKeyPair = kpResult.data;
|
|
765
|
+
let response;
|
|
766
|
+
try {
|
|
767
|
+
response = await baseFetch(options.keyExchangeUrl, {
|
|
768
|
+
method: "POST",
|
|
769
|
+
headers: { "Content-Type": "application/json" },
|
|
770
|
+
body: JSON.stringify({ clientPublicKey: localKeyPair.publicKey })
|
|
771
|
+
});
|
|
772
|
+
} catch (cause) {
|
|
773
|
+
return err(HaiCommonError.INTERNAL_ERROR, "Key exchange request failed", cause);
|
|
774
|
+
}
|
|
775
|
+
if (!response.ok)
|
|
776
|
+
return err(HaiCommonError.INTERNAL_ERROR, `Key exchange returned HTTP ${response.status}`);
|
|
777
|
+
let body;
|
|
778
|
+
try {
|
|
779
|
+
body = await response.json();
|
|
780
|
+
} catch (cause) {
|
|
781
|
+
return err(HaiCommonError.INTERNAL_ERROR, "Key exchange response is not valid JSON", cause);
|
|
782
|
+
}
|
|
783
|
+
if (!body.serverPublicKey || !body.clientId)
|
|
784
|
+
return err(HaiCommonError.INTERNAL_ERROR, "Key exchange response missing fields");
|
|
785
|
+
keyPair = localKeyPair;
|
|
786
|
+
serverPublicKey = body.serverPublicKey;
|
|
787
|
+
clientId = body.clientId;
|
|
788
|
+
return ok(void 0);
|
|
789
|
+
}
|
|
790
|
+
async function ensureReady() {
|
|
791
|
+
if (clientId && serverPublicKey)
|
|
792
|
+
return ok(void 0);
|
|
793
|
+
if (!initPromise) {
|
|
794
|
+
initPromise = doInit().then((result) => {
|
|
795
|
+
if (!result.success)
|
|
796
|
+
initPromise = null;
|
|
797
|
+
return result;
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
return initPromise;
|
|
801
|
+
}
|
|
802
|
+
function encryptBody(plaintext) {
|
|
803
|
+
if (!serverPublicKey)
|
|
804
|
+
return err(HaiCommonError.INTERNAL_ERROR, "Transport client not initialized");
|
|
805
|
+
const symKey = options.crypto.symmetric.generateKey();
|
|
806
|
+
const encResult = options.crypto.symmetric.encryptWithIV(plaintext, symKey);
|
|
807
|
+
if (!encResult.success)
|
|
808
|
+
return err(HaiCommonError.INTERNAL_ERROR, "Failed to encrypt request body", encResult.error);
|
|
809
|
+
const keyEncResult = options.crypto.asymmetric.encrypt(symKey, serverPublicKey);
|
|
810
|
+
if (!keyEncResult.success)
|
|
811
|
+
return err(HaiCommonError.INTERNAL_ERROR, "Failed to encrypt session key", keyEncResult.error);
|
|
812
|
+
return ok({
|
|
813
|
+
encryptedKey: keyEncResult.data,
|
|
814
|
+
ciphertext: encResult.data.ciphertext,
|
|
815
|
+
iv: encResult.data.iv
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
function decryptPayload(payload) {
|
|
819
|
+
if (!keyPair)
|
|
820
|
+
return err(HaiCommonError.INTERNAL_ERROR, "Transport client not initialized");
|
|
821
|
+
const keyDec = options.crypto.asymmetric.decrypt(payload.encryptedKey, keyPair.privateKey);
|
|
822
|
+
if (!keyDec.success)
|
|
823
|
+
return err(HaiCommonError.INTERNAL_ERROR, "Failed to decrypt session key", keyDec.error);
|
|
824
|
+
const dec = options.crypto.symmetric.decryptWithIV(payload.ciphertext, keyDec.data, payload.iv);
|
|
825
|
+
if (!dec.success)
|
|
826
|
+
return err(HaiCommonError.INTERNAL_ERROR, "Failed to decrypt response body", dec.error);
|
|
827
|
+
return ok(dec.data);
|
|
828
|
+
}
|
|
829
|
+
const encryptedFetch = async (input, init) => {
|
|
830
|
+
const requestInput = isRequestLike(input) ? input : void 0;
|
|
831
|
+
const targetUrl = typeof input === "string" ? input : input instanceof URL ? input.toString() : requestInput?.url ?? String(input);
|
|
832
|
+
if (targetUrl === options.keyExchangeUrl)
|
|
833
|
+
return baseFetch(input, init);
|
|
834
|
+
const ready = await ensureReady();
|
|
835
|
+
if (!ready.success)
|
|
836
|
+
throw new Error(ready.error.message);
|
|
837
|
+
const headers = new Headers(init?.headers ?? requestInput?.headers);
|
|
838
|
+
headers.set(TRANSPORT_PROTOCOL.CLIENT_ID_HEADER, clientId);
|
|
839
|
+
let rawBody = init?.body;
|
|
840
|
+
if (rawBody == null && requestInput) {
|
|
841
|
+
const method = (init?.method ?? requestInput.method).toUpperCase();
|
|
842
|
+
if (method !== "GET" && method !== "HEAD") {
|
|
843
|
+
const text = await requestInput.clone().text();
|
|
844
|
+
if (text)
|
|
845
|
+
rawBody = text;
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
let nextBody = rawBody;
|
|
849
|
+
if (rawBody != null) {
|
|
850
|
+
const plaintext = await bodyToText(rawBody);
|
|
851
|
+
const encResult = encryptBody(plaintext);
|
|
852
|
+
if (!encResult.success)
|
|
853
|
+
throw new Error(encResult.error.message);
|
|
854
|
+
nextBody = JSON.stringify(encResult.data);
|
|
855
|
+
headers.set("Content-Type", "application/json");
|
|
856
|
+
headers.set(TRANSPORT_PROTOCOL.ENCRYPTED_HEADER, TRANSPORT_PROTOCOL.ENCRYPTED_HEADER_VALUE);
|
|
857
|
+
}
|
|
858
|
+
const finalInput = requestInput ? requestInput.url : input;
|
|
859
|
+
const finalInit = {
|
|
860
|
+
...init,
|
|
861
|
+
method: init?.method ?? requestInput?.method,
|
|
862
|
+
headers,
|
|
863
|
+
body: nextBody,
|
|
864
|
+
cache: init?.cache ?? requestInput?.cache,
|
|
865
|
+
credentials: init?.credentials ?? requestInput?.credentials,
|
|
866
|
+
integrity: init?.integrity ?? requestInput?.integrity,
|
|
867
|
+
keepalive: init?.keepalive ?? requestInput?.keepalive,
|
|
868
|
+
mode: init?.mode ?? requestInput?.mode,
|
|
869
|
+
redirect: init?.redirect ?? requestInput?.redirect,
|
|
870
|
+
referrer: init?.referrer ?? requestInput?.referrer,
|
|
871
|
+
referrerPolicy: init?.referrerPolicy ?? requestInput?.referrerPolicy,
|
|
872
|
+
signal: init?.signal ?? requestInput?.signal
|
|
873
|
+
};
|
|
874
|
+
const response = await baseFetch(finalInput, finalInit);
|
|
875
|
+
if (response.headers.get(TRANSPORT_PROTOCOL.ENCRYPTED_HEADER) !== TRANSPORT_PROTOCOL.ENCRYPTED_HEADER_VALUE)
|
|
876
|
+
return response;
|
|
877
|
+
const cloned = response.clone();
|
|
878
|
+
let payload;
|
|
879
|
+
try {
|
|
880
|
+
payload = await cloned.json();
|
|
881
|
+
} catch {
|
|
882
|
+
return response;
|
|
883
|
+
}
|
|
884
|
+
if (!isEncryptedPayload(payload))
|
|
885
|
+
return response;
|
|
886
|
+
const decResult = decryptPayload(payload);
|
|
887
|
+
if (!decResult.success)
|
|
888
|
+
throw new Error(decResult.error.message);
|
|
889
|
+
const respHeaders = new Headers(response.headers);
|
|
890
|
+
respHeaders.delete(TRANSPORT_PROTOCOL.ENCRYPTED_HEADER);
|
|
891
|
+
respHeaders.delete("Content-Length");
|
|
892
|
+
return new Response(decResult.data, {
|
|
893
|
+
status: response.status,
|
|
894
|
+
statusText: response.statusText,
|
|
895
|
+
headers: respHeaders
|
|
896
|
+
});
|
|
897
|
+
};
|
|
898
|
+
return {
|
|
899
|
+
init: ensureReady,
|
|
900
|
+
encryptedFetch,
|
|
901
|
+
ready: () => clientId !== null && serverPublicKey !== null,
|
|
902
|
+
destroy() {
|
|
903
|
+
keyPair = null;
|
|
904
|
+
serverPublicKey = null;
|
|
905
|
+
clientId = null;
|
|
906
|
+
initPromise = null;
|
|
907
|
+
}
|
|
908
|
+
};
|
|
909
|
+
}
|
|
910
|
+
async function bodyToText(body) {
|
|
911
|
+
if (typeof body === "string")
|
|
912
|
+
return body;
|
|
913
|
+
if (body instanceof URLSearchParams)
|
|
914
|
+
return body.toString();
|
|
915
|
+
if (body instanceof Blob)
|
|
916
|
+
return body.text();
|
|
917
|
+
if (body instanceof ArrayBuffer)
|
|
918
|
+
return new TextDecoder().decode(body);
|
|
919
|
+
if (ArrayBuffer.isView(body))
|
|
920
|
+
return new TextDecoder().decode(body.buffer);
|
|
921
|
+
return new Response(body).text();
|
|
922
|
+
}
|
|
923
|
+
function isRequestLike(input) {
|
|
924
|
+
if (typeof input !== "object" || input === null)
|
|
925
|
+
return false;
|
|
926
|
+
const candidate = input;
|
|
927
|
+
const headers = candidate.headers;
|
|
928
|
+
return typeof candidate.url === "string" && typeof headers?.get === "function" && typeof candidate.method === "string" && typeof candidate.clone === "function";
|
|
929
|
+
}
|
|
930
|
+
function isEncryptedPayload(payload) {
|
|
931
|
+
if (!payload || typeof payload !== "object")
|
|
932
|
+
return false;
|
|
933
|
+
const p = payload;
|
|
934
|
+
return typeof p.encryptedKey === "string" && typeof p.ciphertext === "string" && typeof p.iv === "string";
|
|
935
|
+
}
|
|
936
|
+
function createInMemoryKeyStore(maxClients = 1e4) {
|
|
937
|
+
const clientKeys = /* @__PURE__ */ new Map();
|
|
938
|
+
let counter = 0;
|
|
939
|
+
return {
|
|
940
|
+
async register(publicKey) {
|
|
941
|
+
counter++;
|
|
942
|
+
const clientId = `c_${counter}_${Date.now()}`;
|
|
943
|
+
if (clientKeys.size >= maxClients) {
|
|
944
|
+
const oldest = clientKeys.keys().next().value;
|
|
945
|
+
if (oldest !== void 0)
|
|
946
|
+
clientKeys.delete(oldest);
|
|
947
|
+
}
|
|
948
|
+
clientKeys.set(clientId, publicKey);
|
|
949
|
+
return clientId;
|
|
950
|
+
},
|
|
951
|
+
async get(clientId) {
|
|
952
|
+
return clientKeys.get(clientId);
|
|
953
|
+
},
|
|
954
|
+
async delete(clientId) {
|
|
955
|
+
clientKeys.delete(clientId);
|
|
956
|
+
},
|
|
957
|
+
async close() {
|
|
958
|
+
clientKeys.clear();
|
|
959
|
+
}
|
|
960
|
+
};
|
|
961
|
+
}
|
|
962
|
+
function createTransportEncryption(cryptoService, options = {}) {
|
|
963
|
+
const keyPairResult = cryptoService.asymmetric.generateKeyPair();
|
|
964
|
+
if (!keyPairResult.success)
|
|
965
|
+
return err(HaiCommonError.INTERNAL_ERROR, "Failed to generate transport key pair", keyPairResult.error);
|
|
966
|
+
const serverKeyPair = keyPairResult.data;
|
|
967
|
+
const keyStore = options.keyStore ?? createInMemoryKeyStore(options.maxClients);
|
|
968
|
+
const manager = {
|
|
969
|
+
getServerPublicKey() {
|
|
970
|
+
return serverKeyPair.publicKey;
|
|
971
|
+
},
|
|
972
|
+
async registerClientKey(clientPublicKey) {
|
|
973
|
+
return keyStore.register(clientPublicKey);
|
|
974
|
+
},
|
|
975
|
+
async getClientPublicKey(clientId) {
|
|
976
|
+
return keyStore.get(clientId);
|
|
977
|
+
},
|
|
978
|
+
async encryptResponse(clientId, data) {
|
|
979
|
+
const clientPublicKey = await keyStore.get(clientId);
|
|
980
|
+
if (!clientPublicKey)
|
|
981
|
+
return err(HaiCommonError.NOT_FOUND, `Unknown transport client: ${clientId}`);
|
|
982
|
+
const symmetricKey = cryptoService.symmetric.generateKey();
|
|
983
|
+
const encResult = cryptoService.symmetric.encryptWithIV(data, symmetricKey);
|
|
984
|
+
if (!encResult.success)
|
|
985
|
+
return err(HaiCommonError.INTERNAL_ERROR, "Failed to encrypt response payload", encResult.error);
|
|
986
|
+
const keyEncResult = cryptoService.asymmetric.encrypt(symmetricKey, clientPublicKey);
|
|
987
|
+
if (!keyEncResult.success)
|
|
988
|
+
return err(HaiCommonError.INTERNAL_ERROR, "Failed to encrypt session key", keyEncResult.error);
|
|
989
|
+
const payload = {
|
|
990
|
+
encryptedKey: keyEncResult.data,
|
|
991
|
+
ciphertext: encResult.data.ciphertext,
|
|
992
|
+
iv: encResult.data.iv
|
|
993
|
+
};
|
|
994
|
+
return ok(payload);
|
|
995
|
+
},
|
|
996
|
+
decryptRequest(payload) {
|
|
997
|
+
const keyDecResult = cryptoService.asymmetric.decrypt(payload.encryptedKey, serverKeyPair.privateKey);
|
|
998
|
+
if (!keyDecResult.success)
|
|
999
|
+
return err(HaiCommonError.INTERNAL_ERROR, "Failed to decrypt session key", keyDecResult.error);
|
|
1000
|
+
const decResult = cryptoService.symmetric.decryptWithIV(payload.ciphertext, keyDecResult.data, payload.iv);
|
|
1001
|
+
if (!decResult.success)
|
|
1002
|
+
return err(HaiCommonError.INTERNAL_ERROR, "Failed to decrypt request payload", decResult.error);
|
|
1003
|
+
return ok(decResult.data);
|
|
1004
|
+
},
|
|
1005
|
+
async close() {
|
|
1006
|
+
await keyStore.close?.();
|
|
1007
|
+
}
|
|
1008
|
+
};
|
|
1009
|
+
return ok(manager);
|
|
1010
|
+
}
|
|
1011
|
+
|
|
741
1012
|
// src/crypto-main.ts
|
|
742
1013
|
var logger = core.logger.child({ module: "crypto", scope: "main" });
|
|
743
1014
|
var initialized = false;
|
|
@@ -754,6 +1025,14 @@ var notInitializedAsymmetric = notInitialized.proxy("sync");
|
|
|
754
1025
|
var notInitializedHash = notInitialized.proxy("sync");
|
|
755
1026
|
var notInitializedSymmetric = notInitialized.proxy("sync");
|
|
756
1027
|
var notInitializedPassword = notInitialized.proxy("sync");
|
|
1028
|
+
function getCrypto() {
|
|
1029
|
+
return crypto2;
|
|
1030
|
+
}
|
|
1031
|
+
var transportOperations = {
|
|
1032
|
+
createServer: (options) => createTransportEncryption(getCrypto(), options),
|
|
1033
|
+
createClient: (options) => createTransportClient({ crypto: getCrypto(), ...options }),
|
|
1034
|
+
protocol: TRANSPORT_PROTOCOL
|
|
1035
|
+
};
|
|
757
1036
|
var crypto2 = {
|
|
758
1037
|
/**
|
|
759
1038
|
* 初始化加密模块
|
|
@@ -819,6 +1098,13 @@ var crypto2 = {
|
|
|
819
1098
|
get password() {
|
|
820
1099
|
return currentPassword ?? notInitializedPassword;
|
|
821
1100
|
},
|
|
1101
|
+
/**
|
|
1102
|
+
* 传输加密操作(端到端混合加密)
|
|
1103
|
+
*
|
|
1104
|
+
* createServer 内部直接复用 asymmetric/symmetric,因此未初始化时
|
|
1105
|
+
* 自动通过 asymmetric proxy 返回 NOT_INITIALIZED 错误。
|
|
1106
|
+
*/
|
|
1107
|
+
transport: transportOperations,
|
|
822
1108
|
/** 是否已初始化 */
|
|
823
1109
|
get isInitialized() {
|
|
824
1110
|
return initialized;
|
|
@@ -843,6 +1129,6 @@ var crypto2 = {
|
|
|
843
1129
|
}
|
|
844
1130
|
};
|
|
845
1131
|
|
|
846
|
-
export { HaiCryptoError, crypto2 as crypto };
|
|
1132
|
+
export { HaiCryptoError, TRANSPORT_PROTOCOL, crypto2 as crypto };
|
|
847
1133
|
//# sourceMappingURL=index.js.map
|
|
848
1134
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../messages/en-US.json","../messages/zh-CN.json","../src/crypto-i18n.ts","../src/crypto-types.ts","../src/crypto-password.ts","../src/crypto-utils.ts","../src/crypto-sm2.ts","../src/crypto-sm3.ts","../src/crypto-sm4.ts","../src/crypto-main.ts"],"names":["core","ok","err","smCrypto","sm3","crypto"],"mappings":"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","file":"index.js","sourcesContent":["{\n \"$schema\": \"https://inlang.com/schema/inlang-message-format\",\n \"crypto_notInitialized\": \"Crypto module not initialized, call crypto.init() first\",\n \"crypto_initFailed\": \"Crypto module initialization failed: {error}\",\n \"crypto_sm2PublicKeyInvalid\": \"Invalid SM2 public key format\",\n \"crypto_sm2PrivateKeyInvalid\": \"Invalid SM2 private key format\",\n \"crypto_sm2EncryptEmpty\": \"SM2 encryption returned empty result\",\n \"crypto_sm2DecryptFailed\": \"SM2 decryption failed or returned invalid result\",\n \"crypto_sm2SignEmpty\": \"SM2 signature returned empty result\",\n \"crypto_sm2KeyPairGenerateFailed\": \"SM2 key pair generation failed: {error}\",\n \"crypto_sm2EncryptFailed\": \"SM2 encryption failed: {error}\",\n \"crypto_sm2DecryptFailedWithError\": \"SM2 decryption failed: {error}\",\n \"crypto_sm2SignFailed\": \"SM2 signing failed: {error}\",\n \"crypto_sm2VerifyFailed\": \"SM2 verification failed: {error}\",\n \"crypto_sm3HashEmpty\": \"SM3 hash returned empty result\",\n \"crypto_sm3HashFailed\": \"SM3 hash calculation failed: {error}\",\n \"crypto_sm3HmacFailed\": \"HMAC-SM3 calculation failed: {error}\",\n \"crypto_sm3VerifyFailed\": \"SM3 hash verification failed: {error}\",\n \"crypto_sm4KeyInvalid\": \"SM4 key must be 16 bytes (32 hex characters)\",\n \"crypto_sm4CbcNeedIv\": \"CBC mode requires IV\",\n \"crypto_sm4IvInvalid\": \"SM4 IV must be 16 bytes (32 hex characters)\",\n \"crypto_sm4EncryptEmpty\": \"SM4 encryption returned empty result\",\n \"crypto_sm4DecryptFailed\": \"SM4 decryption failed\",\n \"crypto_sm4EncryptFailed\": \"SM4 encryption failed: {error}\",\n \"crypto_sm4DecryptFailedWithError\": \"SM4 decryption failed: {error}\",\n \"crypto_passwordEmpty\": \"Password cannot be empty\",\n \"crypto_passwordHashEmpty\": \"Password and hash cannot be empty\",\n \"crypto_passwordHashFailed\": \"Password hashing failed\",\n \"crypto_hashFormatInvalid\": \"Invalid hash format\",\n \"crypto_passwordVerifyFailed\": \"Password verification failed\"\n}\n","{\n \"$schema\": \"https://inlang.com/schema/inlang-message-format\",\n \"crypto_notInitialized\": \"加密模块尚未初始化,请先调用 crypto.init()\",\n \"crypto_initFailed\": \"加密模块初始化失败:{error}\",\n \"crypto_sm2PublicKeyInvalid\": \"无效的 SM2 公钥格式\",\n \"crypto_sm2PrivateKeyInvalid\": \"无效的 SM2 私钥格式\",\n \"crypto_sm2EncryptEmpty\": \"SM2 加密返回空结果\",\n \"crypto_sm2DecryptFailed\": \"SM2 解密失败或返回无效结果\",\n \"crypto_sm2SignEmpty\": \"SM2 签名返回空结果\",\n \"crypto_sm2KeyPairGenerateFailed\": \"SM2 密钥对生成失败: {error}\",\n \"crypto_sm2EncryptFailed\": \"SM2 加密失败: {error}\",\n \"crypto_sm2DecryptFailedWithError\": \"SM2 解密失败: {error}\",\n \"crypto_sm2SignFailed\": \"SM2 签名失败: {error}\",\n \"crypto_sm2VerifyFailed\": \"SM2 验签失败: {error}\",\n \"crypto_sm3HashEmpty\": \"SM3 哈希返回空结果\",\n \"crypto_sm3HashFailed\": \"SM3 哈希计算失败: {error}\",\n \"crypto_sm3HmacFailed\": \"HMAC-SM3 计算失败: {error}\",\n \"crypto_sm3VerifyFailed\": \"SM3 哈希验证失败: {error}\",\n \"crypto_sm4KeyInvalid\": \"SM4 密钥必须为 16 字节(32 个十六进制字符)\",\n \"crypto_sm4CbcNeedIv\": \"CBC 模式必须提供 IV\",\n \"crypto_sm4IvInvalid\": \"SM4 IV 必须为 16 字节(32 个十六进制字符)\",\n \"crypto_sm4EncryptEmpty\": \"SM4 加密返回空结果\",\n \"crypto_sm4DecryptFailed\": \"SM4 解密失败\",\n \"crypto_sm4EncryptFailed\": \"SM4 加密失败: {error}\",\n \"crypto_sm4DecryptFailedWithError\": \"SM4 解密失败: {error}\",\n \"crypto_passwordEmpty\": \"密码不能为空\",\n \"crypto_passwordHashEmpty\": \"密码和哈希值不能为空\",\n \"crypto_passwordHashFailed\": \"密码哈希失败\",\n \"crypto_hashFormatInvalid\": \"无效的哈希格式\",\n \"crypto_passwordVerifyFailed\": \"密码验证失败\"\n}\n","/**\n * @h-ai/crypto — i18n\n *\n * 本文件提供加密模块的 i18n 文案访问入口。\n * @module crypto-i18n\n */\n\nimport { core } from '@h-ai/core'\nimport messagesEnUS from '../messages/en-US.json'\nimport messagesZhCN from '../messages/zh-CN.json'\n\n/** 加密模块 i18n 消息键类型(自动从 zh-CN 消息文件推断) */\ntype CryptoMessageKey = keyof typeof messagesZhCN\n\n/**\n * 加密模块 i18n 消息获取器\n *\n * 根据当前全局 locale 返回对应语言的消息文本,支持参数插值。\n *\n * @example\n * ```ts\n * cryptoM('crypto_sm2PublicKeyInvalid')\n * cryptoM('crypto_initFailed', { params: { error: 'bad config' } })\n * ```\n */\nexport const cryptoM = core.i18n.createMessageGetter<CryptoMessageKey>({\n 'zh-CN': messagesZhCN,\n 'en-US': messagesEnUS,\n})\n","/**\n * @h-ai/crypto — 公共类型\n *\n * 定义加密模块的对外接口类型。\n * @module crypto-types\n */\n\nimport type { ErrorInfo, HaiResult } from '@h-ai/core'\nimport { core } from '@h-ai/core'\n\nconst CryptoErrorInfo = {\n INVALID_INPUT: '002:400',\n INVALID_KEY: '003:400',\n NOT_INITIALIZED: '010:500',\n INIT_FAILED: '011:500',\n KEY_GENERATION_FAILED: '020:500',\n ENCRYPTION_FAILED: '021:500',\n DECRYPTION_FAILED: '022:500',\n SIGN_FAILED: '023:500',\n VERIFY_FAILED: '024:500',\n HASH_FAILED: '040:500',\n HMAC_FAILED: '041:500',\n INVALID_IV: '060:400',\n} as const satisfies ErrorInfo\n\nexport const HaiCryptoError = core.error.buildHaiErrorsDef('crypto', CryptoErrorInfo)\n\n// ─── 非对称加密类型 ───\n\n/** 密文模式:0=C1C2C3(旧版),1=C1C3C2(国标) */\nexport type CipherMode = 0 | 1\n\n/** 非对称密钥对 */\nexport interface KeyPair {\n /** 公钥(十六进制字符串,包含 04 前缀为非压缩格式) */\n publicKey: string\n /** 私钥(十六进制字符串,64 字符) */\n privateKey: string\n}\n\n/** 非对称加密选项 */\nexport interface AsymmetricEncryptOptions {\n /** 密文模式:0=C1C2C3(旧版),1=C1C3C2(国标,默认) */\n cipherMode?: CipherMode\n /** 输出格式 */\n outputFormat?: 'hex' | 'base64'\n}\n\n/** 签名选项 */\nexport interface SignOptions {\n /** 是否对数据进行哈希(默认 true) */\n hash?: boolean\n /** 用户 ID(默认 \"1234567812345678\") */\n userId?: string\n}\n\n// ─── 哈希类型 ───\n\n/** 哈希选项 */\nexport interface HashOptions {\n /** 输入编码 */\n inputEncoding?: 'utf8' | 'hex'\n}\n\n// ─── 对称加密类型 ───\n\n/** 对称加密模式 */\nexport type SymmetricMode = 'ecb' | 'cbc'\n\n/** 对称加密选项 */\nexport interface SymmetricOptions {\n /** 加密模式 */\n mode?: SymmetricMode\n /** IV 向量(CBC 模式必需,32 个十六进制字符) */\n iv?: string\n /** 输入编码 */\n inputEncoding?: 'utf8' | 'hex'\n /** 输出格式 */\n outputFormat?: 'hex' | 'base64'\n}\n\n/** 带 IV 加密结果 */\nexport interface EncryptWithIVResult {\n /** 密文 */\n ciphertext: string\n /** IV 向量 */\n iv: string\n}\n\n// ─── 密码类型 ───\n\n/** 密码哈希配置 */\nexport interface PasswordConfig {\n /** 盐值长度(默认 16) */\n saltLength?: number\n /** 迭代次数(默认 10000) */\n iterations?: number\n}\n\n// ─── 操作接口 ───\n\n/**\n * 非对称加密操作接口\n *\n * 通过 `crypto.asymmetric` 访问,需先调用 `crypto.init()`。\n */\nexport interface AsymmetricOperations {\n /**\n * 生成密钥对\n *\n * @returns 成功时包含公私钥对;失败时返回 KEY_GENERATION_FAILED\n */\n generateKeyPair: () => HaiResult<KeyPair>\n /**\n * 非对称加密\n *\n * @param data - 待加密明文\n * @param publicKey - 公钥(十六进制,支持带/不带 04 前缀)\n * @param options - 加密选项(密文模式、输出格式)\n * @returns 成功时返回密文字符串;失败时返回 INVALID_KEY 或 ENCRYPTION_FAILED\n */\n encrypt: (data: string, publicKey: string, options?: AsymmetricEncryptOptions) => HaiResult<string>\n /**\n * 非对称解密\n *\n * 自动检测 base64 格式输入并转换为 hex。\n *\n * @param ciphertext - 密文(hex 或 base64)\n * @param privateKey - 私钥(64 字符十六进制)\n * @param options - 解密选项(密文模式需与加密时一致)\n * @returns 成功时返回明文;失败时返回 INVALID_KEY 或 DECRYPTION_FAILED\n */\n decrypt: (ciphertext: string, privateKey: string, options?: AsymmetricEncryptOptions) => HaiResult<string>\n /**\n * 签名\n *\n * @param data - 待签名数据\n * @param privateKey - 私钥(64 字符十六进制)\n * @param options - 签名选项(hash 开关、userId)\n * @returns 成功时返回签名字符串;失败时返回 INVALID_KEY 或 SIGN_FAILED\n */\n sign: (data: string, privateKey: string, options?: SignOptions) => HaiResult<string>\n /**\n * 验签\n *\n * @param data - 原始数据\n * @param signature - 签名(需与签名时使用相同的 hash/userId 选项)\n * @param publicKey - 公钥(支持带/不带 04 前缀)\n * @param options - 验签选项\n * @returns 成功时返回 boolean;失败时返回 INVALID_KEY 或 VERIFY_FAILED\n */\n verify: (data: string, signature: string, publicKey: string, options?: SignOptions) => HaiResult<boolean>\n /**\n * 校验公钥格式是否合法\n *\n * 合法格式:128 字符十六进制(无前缀)或 130 字符(含 04 前缀)。\n */\n isValidPublicKey: (key: string) => boolean\n /**\n * 校验私钥格式是否合法\n *\n * 合法格式:64 字符十六进制。\n */\n isValidPrivateKey: (key: string) => boolean\n}\n\n/**\n * 哈希操作接口\n *\n * 通过 `crypto.hash` 访问,需先调用 `crypto.init()`。\n */\nexport interface HashOperations {\n /**\n * 计算哈希\n *\n * @param data - 待哈希数据(字符串或 Uint8Array)\n * @param options - 输入编码选项\n * @returns 成功时返回 64 字符十六进制哈希值;失败时返回 HASH_FAILED\n */\n hash: (data: string | Uint8Array, options?: HashOptions) => HaiResult<string>\n /**\n * 计算 HMAC\n *\n * 使用 HMAC 算法(RFC 2104)计算消息认证码。\n * 当密钥长度超过块大小(64 字节)时,会先对密钥进行哈希。\n *\n * @param data - 待计算数据\n * @param key - HMAC 密钥\n * @returns 成功时返回 64 字符十六进制 HMAC 值;失败时返回 HMAC_FAILED\n */\n hmac: (data: string, key: string) => HaiResult<string>\n /**\n * 验证数据的哈希是否匹配\n *\n * 比较时忽略大小写。\n *\n * @param data - 原始数据\n * @param expectedHash - 期望的哈希值\n * @returns 成功时返回 boolean;失败时返回 HASH_FAILED\n */\n verify: (data: string, expectedHash: string) => HaiResult<boolean>\n}\n\n/**\n * 对称加密操作接口\n *\n * 通过 `crypto.symmetric` 访问,需先调用 `crypto.init()`。\n * 支持 ECB/CBC 两种模式,CBC 模式需要提供 IV。\n */\nexport interface SymmetricOperations {\n /** 生成随机密钥(16 字节 = 32 个十六进制字符) */\n generateKey: () => string\n /** 生成随机 IV(16 字节 = 32 个十六进制字符) */\n generateIV: () => string\n /**\n * 对称加密\n *\n * @param data - 待加密明文\n * @param key - 密钥(32 字符十六进制)\n * @param options - 加密模式/IV/输出格式\n * @returns 成功时返回密文;失败时返回 INVALID_KEY/INVALID_IV/ENCRYPTION_FAILED\n */\n encrypt: (data: string, key: string, options?: SymmetricOptions) => HaiResult<string>\n /**\n * 对称解密\n *\n * 自动检测 base64 格式输入并转换为 hex。\n *\n * @param ciphertext - 密文(hex 或 base64)\n * @param key - 密钥(32 字符十六进制)\n * @param options - 解密模式/IV(需与加密时一致)\n * @returns 成功时返回明文;失败时返回 INVALID_KEY/INVALID_IV/DECRYPTION_FAILED\n */\n decrypt: (ciphertext: string, key: string, options?: SymmetricOptions) => HaiResult<string>\n /**\n * 带 IV 加密(CBC 模式,自动生成随机 IV)\n *\n * @param data - 待加密明文\n * @param key - 密钥(32 字符十六进制)\n * @returns 成功时返回 { ciphertext, iv };失败时同 encrypt\n */\n encryptWithIV: (data: string, key: string) => HaiResult<EncryptWithIVResult>\n /**\n * 带 IV 解密(CBC 模式)\n *\n * @param ciphertext - 密文\n * @param key - 密钥\n * @param iv - 加密时使用的 IV\n * @returns 成功时返回明文;失败时同 decrypt\n */\n decryptWithIV: (ciphertext: string, key: string, iv: string) => HaiResult<string>\n /**\n * 从密码和盐值派生密钥\n *\n * 内部仅执行单次哈希(password + salt) 取前 32 字符作为密钥。\n *\n * ⚠️ 安全警告:**此实现不是标准 KDF**,不具备密码爆破抗性。\n * - 禁止用于密码存储(请用 `crypto.password.hash`)。\n * - 禁止用于高价值密钥派生(请在应用层采用 PBKDF2 / scrypt / Argon2)。\n *\n * @deprecated 未来版本可能移除。详见模块 README 安全声明。\n * @param password - 密码\n * @param salt - 盐值\n * @returns 32 字符十六进制密钥\n */\n deriveKey: (password: string, salt: string) => string\n /** 校验密钥格式是否合法(32 字符十六进制) */\n isValidKey: (key: string) => boolean\n /** 校验 IV 格式是否合法(32 字符十六进制) */\n isValidIV: (iv: string) => boolean\n}\n\n/**\n * 密码哈希操作接口\n *\n * 通过 `crypto.password` 访问,需先调用 `crypto.init()`。\n * 使用迭代加盐的方式生成密码哈希。\n */\nexport interface PasswordOperations {\n /**\n * 对密码进行哈希\n *\n * 输出格式: `$hai$<iterations>$<salt>$<hash>`\n *\n * @param password - 明文密码(不能为空)\n * @param config - 可选配置(盐值长度、迭代次数)\n * @returns 成功时返回格式化的哈希字符串;失败时返回 INVALID_INPUT 或 HASH_FAILED\n */\n hash: (password: string, config?: PasswordConfig) => HaiResult<string>\n /**\n * 验证密码是否匹配\n *\n * 自动从哈希字符串中解析迭代次数和盐值进行重新计算。\n *\n * @param password - 待验证的明文密码\n * @param hash - 存储的哈希值(格式: `$hai$<iterations>$<salt>$<hash>`)\n * @returns 成功时返回 boolean;失败时返回 INVALID_INPUT 或 VERIFY_FAILED\n */\n verify: (password: string, hash: string) => HaiResult<boolean>\n}\n\n// ─── 函数接口 ───\n\n/**\n * 加密模块函数接口\n *\n * `crypto` 服务对象的类型定义。使用前必须调用 `init()` 初始化。\n *\n * @example\n * ```ts\n * import { crypto } from '@h-ai/crypto'\n *\n * await crypto.init()\n * const hash = crypto.hash.hash('hello')\n * await crypto.close()\n * ```\n */\nexport interface CryptoFunctions {\n /**\n * 初始化加密模块\n *\n * 创建非对称/哈希/对称/密码哈希操作实例。\n * 重复调用会先关闭再重新初始化。\n *\n * @returns 成功时返回 ok(undefined);失败时返回 INIT_FAILED\n */\n init: () => Promise<HaiResult<void>>\n /**\n * 关闭加密模块,释放内部状态\n *\n * 关闭后再访问 asymmetric/hash/symmetric/password 会返回 NOT_INITIALIZED 错误。\n */\n close: () => Promise<void>\n /** 是否已初始化 */\n readonly isInitialized: boolean\n /** 非对称加密操作(未初始化时所有方法返回 NOT_INITIALIZED) */\n readonly asymmetric: AsymmetricOperations\n /** 哈希操作(未初始化时所有方法返回 NOT_INITIALIZED) */\n readonly hash: HashOperations\n /** 对称加密操作(未初始化时所有方法返回 NOT_INITIALIZED) */\n readonly symmetric: SymmetricOperations\n /** 密码哈希操作(未初始化时所有方法返回 NOT_INITIALIZED) */\n readonly password: PasswordOperations\n}\n","/**\n * @h-ai/crypto — 密码操作\n *\n * 提供迭代加盐(SM3)密码哈希与校验功能。\n * @module crypto-password\n */\n\nimport type { HaiResult } from '@h-ai/core'\n\nimport type { HashOperations, PasswordConfig, PasswordOperations } from './crypto-types.js'\nimport { core, err, ok } from '@h-ai/core'\n\nimport { cryptoM } from './crypto-i18n.js'\nimport { HaiCryptoError } from './crypto-types.js'\n\n// ─── 常量 ───\n\n/** 迭代次数最小值(防止退化为 0 迭代导致明文等价泄漏) */\nconst MIN_ITERATIONS = 1\n/** 迭代次数最大值(防止伪造哈希触发 CPU 饱和) */\nconst MAX_ITERATIONS = 1_000_000\n/** 盐值长度范围,限制异常输入 */\nconst MIN_SALT_LENGTH = 8\nconst MAX_SALT_LENGTH = 128\n\n// ─── 依赖接口 ───\n\n/** createPasswordFunctions 所需的外部依赖 */\ninterface PasswordDeps {\n /** 哈希操作实例,用于迭代哈希计算 */\n hash: HashOperations\n}\n\n// ─── 工具函数 ───\n\n/**\n * 生成加密安全的随机盐值\n *\n * 使用 Web Crypto API(crypto.getRandomValues)从大小写字母和数字中随机选取字符。\n *\n * @param length - 盐值长度(字符数)\n * @returns 随机盐值字符串\n */\nfunction generateSalt(length: number): string {\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'\n const randomBytes = new Uint8Array(length)\n globalThis.crypto.getRandomValues(randomBytes)\n let salt = ''\n for (let i = 0; i < length; i++) {\n salt += chars.charAt(randomBytes[i] % chars.length)\n }\n return salt\n}\n\n/**\n * 对数据进行多次迭代哈希(密钥拉伸)\n *\n * 首次输入为 salt + data,后续每次用前一轮的哈希结果作为输入。\n * 任一轮哈希计算失败则立即返回错误。\n *\n * @param hash - 哈希操作实例\n * @param data - 原始数据(通常为密码)\n * @param salt - 盐值\n * @param iterations - 迭代次数\n * @returns 成功时返回最终哈希值(64 字符十六进制)\n */\nfunction iterateHash(\n hash: HashOperations,\n data: string,\n salt: string,\n iterations: number,\n): HaiResult<string> {\n let current = salt + data\n for (let i = 0; i < iterations; i++) {\n const result = hash.hash(current)\n if (!result.success) {\n return result\n }\n current = result.data\n }\n return ok(current)\n}\n\n// ─── 密码操作工厂 ───\n\n/**\n * 创建密码哈希操作实例\n *\n * 内部使用迭代加盐的方式生成密码哈希,格式为 `$hai$<iterations>$<salt>$<hash>`。\n *\n * @param deps - 依赖(需要注入哈希操作实例)\n * @returns PasswordOperations 接口实现\n */\nexport function createPasswordFunctions(deps: PasswordDeps): PasswordOperations {\n const { hash: hashOps } = deps\n\n return {\n /**\n * 对密码进行迭代加盐哈希\n *\n * 输出格式: `$hai$<iterations>$<salt>$<hash>`\n *\n * @param password - 明文密码(不能为空)\n * @param config - 可选配置(盐值长度、迭代次数)\n * @returns 成功时返回格式化的哈希字符串;失败时返回 INVALID_INPUT 或 HASH_FAILED\n */\n hash(password: string, config: PasswordConfig = {}): HaiResult<string> {\n const { saltLength = 16, iterations = 10000 } = config\n\n try {\n if (!password) {\n return err(\n HaiCryptoError.INVALID_INPUT,\n cryptoM('crypto_passwordEmpty'),\n )\n }\n\n if (!Number.isInteger(iterations) || iterations < MIN_ITERATIONS || iterations > MAX_ITERATIONS) {\n return err(\n HaiCryptoError.INVALID_INPUT,\n cryptoM('crypto_hashFormatInvalid'),\n )\n }\n if (!Number.isInteger(saltLength) || saltLength < MIN_SALT_LENGTH || saltLength > MAX_SALT_LENGTH) {\n return err(\n HaiCryptoError.INVALID_INPUT,\n cryptoM('crypto_hashFormatInvalid'),\n )\n }\n\n const salt = generateSalt(saltLength)\n const hashResult = iterateHash(hashOps, password, salt, iterations)\n if (!hashResult.success) {\n return hashResult\n }\n\n const formatted = `$hai$${iterations}$${salt}$${hashResult.data}`\n return ok(formatted)\n }\n catch (error) {\n return err(\n HaiCryptoError.HASH_FAILED,\n cryptoM('crypto_passwordHashFailed'),\n error,\n )\n }\n },\n\n /**\n * 验证密码是否匹配已存储的哈希\n *\n * 从哈希字符串中解析迭代次数和盐值,重新计算后比较。\n * 格式要求: `$hai$<iterations>$<salt>$<hash>`\n *\n * @param password - 待验证的明文密码\n * @param hash - 存储的哈希值\n * @returns 成功时返回 boolean;失败时返回 INVALID_INPUT 或 VERIFY_FAILED\n */\n verify(password: string, hash: string): HaiResult<boolean> {\n try {\n if (!password || !hash) {\n return err(\n HaiCryptoError.INVALID_INPUT,\n cryptoM('crypto_passwordHashEmpty'),\n )\n }\n\n const parts = hash.split('$')\n if (parts.length !== 5 || parts[1] !== 'hai') {\n return err(\n HaiCryptoError.INVALID_INPUT,\n cryptoM('crypto_hashFormatInvalid'),\n )\n }\n\n const storedIterations = Number.parseInt(parts[2], 10)\n const salt = parts[3]\n const storedHash = parts[4]\n\n if (\n Number.isNaN(storedIterations)\n || storedIterations < MIN_ITERATIONS\n || storedIterations > MAX_ITERATIONS\n || !salt\n || !storedHash\n ) {\n return err(\n HaiCryptoError.INVALID_INPUT,\n cryptoM('crypto_hashFormatInvalid'),\n )\n }\n\n const hashResult = iterateHash(hashOps, password, salt, storedIterations)\n if (!hashResult.success) {\n return hashResult\n }\n\n return ok(core.string.constantTimeEqual(hashResult.data, storedHash))\n }\n catch (error) {\n return err(\n HaiCryptoError.VERIFY_FAILED,\n cryptoM('crypto_passwordVerifyFailed'),\n error,\n )\n }\n },\n }\n}\n","/**\n * @h-ai/crypto — 内部工具函数\n *\n * 提供 SM2/SM4 共用的编码转换辅助函数。 仅供模块内部使用,不对外导出。\n * @module crypto-utils\n */\n\n/**\n * 判断字符串是否为 Base64 格式\n *\n * 使用简单启发式:包含 +、/ 或以 = 结尾视为 base64。\n *\n * @param str - 待检测字符串\n */\nexport function isBase64(str: string): boolean {\n return str.includes('+') || str.includes('/') || str.endsWith('=')\n}\n\n/**\n * Hex 字符串转 Base64 编码\n *\n * 使用 Web 标准 API btoa,前后端通用(Node 16+ / 所有现代浏览器)。\n *\n * @param hex - 十六进制字符串(长度必须为偶数)\n * @returns Base64 编码字符串\n */\nexport function hexToBase64(hex: string): string {\n const bytes = new Uint8Array(hex.length / 2)\n for (let i = 0; i < hex.length; i += 2) {\n bytes[i / 2] = Number.parseInt(hex.slice(i, i + 2), 16)\n }\n return btoa(String.fromCharCode(...bytes))\n}\n\n/**\n * Base64 编码转 Hex 字符串\n *\n * 使用 Web 标准 API atob,前后端通用(Node 16+ / 所有现代浏览器)。\n *\n * @param base64 - Base64 编码字符串\n * @returns 小写十六进制字符串\n */\nexport function base64ToHex(base64: string): string {\n const binary = atob(base64)\n const bytes = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i)\n }\n return Array.from(bytes)\n .map(b => b.toString(16).padStart(2, '0'))\n .join('')\n}\n","/**\n * @h-ai/crypto — SM2 非对称加密\n *\n * 提供 SM2 密钥对生成、加解密、签名与验签操作。\n * @module crypto-sm2\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { AsymmetricEncryptOptions, AsymmetricOperations, KeyPair, SignOptions } from './crypto-types.js'\n\nimport { err, ok } from '@h-ai/core'\n// @ts-expect-error sm-crypto 无类型定义\nimport smCrypto from 'sm-crypto'\n\nimport { cryptoM } from './crypto-i18n.js'\nimport {\n\n HaiCryptoError,\n\n} from './crypto-types.js'\nimport { base64ToHex, hexToBase64, isBase64 } from './crypto-utils.js'\n\nconst { sm2 } = smCrypto\nconst SM2_PUBLIC_KEY_REGEX = /^[0-9a-f]{128}$/i\nconst SM2_PRIVATE_KEY_REGEX = /^[0-9a-f]{64}$/i\n\n// ─── SM2 算法实现 ───\n\n/**\n * 创建 SM2 算法操作实例\n *\n * 基于 sm-crypto 库实现 SM2 非对称加密、签名与验签。\n * 公钥支持带/不带 04 前缀两种格式(内部统一补齐)。\n * 密文支持 hex/base64 两种格式(解密时自动检测)。\n *\n * @returns AsymmetricOperations 接口实现\n */\nexport function createSM2(): AsymmetricOperations {\n return {\n /**\n * 生成 SM2 密钥对\n *\n * @returns 成功时返回包含公钥(130 字符含 04 前缀)和私钥(64 字符)的密钥对\n */\n generateKeyPair(): HaiResult<KeyPair> {\n try {\n const keyPair = sm2.generateKeyPairHex()\n return ok({\n publicKey: keyPair.publicKey,\n privateKey: keyPair.privateKey,\n })\n }\n catch (error) {\n return err(\n HaiCryptoError.KEY_GENERATION_FAILED,\n cryptoM('crypto_sm2KeyPairGenerateFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n },\n\n /**\n * SM2 非对称加密\n *\n * 公钥自动补齐 04 前缀;支持 hex/base64 输出。\n *\n * @param data - 待加密明文\n * @param publicKey - 公钥(支持带/不带 04 前缀)\n * @param options - 加密选项(密文模式、输出格式)\n * @returns 成功时返回密文;失败时返回 INVALID_KEY 或 ENCRYPTION_FAILED\n */\n encrypt(\n data: string,\n publicKey: string,\n options: AsymmetricEncryptOptions = {},\n ): HaiResult<string> {\n const { cipherMode = 1, outputFormat = 'hex' } = options\n\n if (!this.isValidPublicKey(publicKey)) {\n return err(\n HaiCryptoError.INVALID_KEY,\n cryptoM('crypto_sm2PublicKeyInvalid'),\n )\n }\n\n try {\n // 确保公钥带 04 前缀\n const key = publicKey.startsWith('04') ? publicKey : `04${publicKey}`\n const encrypted = sm2.doEncrypt(data, key, cipherMode)\n\n if (!encrypted) {\n return err(\n HaiCryptoError.ENCRYPTION_FAILED,\n cryptoM('crypto_sm2EncryptEmpty'),\n )\n }\n\n if (outputFormat === 'base64') {\n return ok(hexToBase64(encrypted))\n }\n\n return ok(encrypted)\n }\n catch (error) {\n return err(\n HaiCryptoError.ENCRYPTION_FAILED,\n cryptoM('crypto_sm2EncryptFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n },\n\n /**\n * SM2 非对称解密\n *\n * 自动检测 base64 格式输入并转换为 hex 后解密。\n *\n * @param ciphertext - 密文(hex 或 base64)\n * @param privateKey - 私钥(64 字符十六进制)\n * @param options - 解密选项(密文模式需与加密时一致)\n * @returns 成功时返回明文;失败时返回 INVALID_KEY 或 DECRYPTION_FAILED\n */\n decrypt(\n ciphertext: string,\n privateKey: string,\n options: AsymmetricEncryptOptions = {},\n ): HaiResult<string> {\n const { cipherMode = 1 } = options\n\n if (!this.isValidPrivateKey(privateKey)) {\n return err(\n HaiCryptoError.INVALID_KEY,\n cryptoM('crypto_sm2PrivateKeyInvalid'),\n )\n }\n\n try {\n // 自动检测并转换 base64 格式\n let input = ciphertext\n if (isBase64(ciphertext)) {\n input = base64ToHex(ciphertext)\n }\n\n const decrypted = sm2.doDecrypt(input, privateKey, cipherMode)\n\n if (decrypted === false || decrypted === null || decrypted === undefined) {\n return err(\n HaiCryptoError.DECRYPTION_FAILED,\n cryptoM('crypto_sm2DecryptFailed'),\n )\n }\n\n return ok(decrypted)\n }\n catch (error) {\n return err(\n HaiCryptoError.DECRYPTION_FAILED,\n cryptoM('crypto_sm2DecryptFailedWithError', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n },\n\n /**\n * SM2 数字签名\n *\n * 默认对数据先做哈希(hash=true),使用 userId 作为签名附加参数。\n *\n * @param data - 待签名数据\n * @param privateKey - 私钥(64 字符十六进制)\n * @param options - 签名选项(hash 开关、userId)\n * @returns 成功时返回签名字符串;失败时返回 INVALID_KEY 或 SIGN_FAILED\n */\n sign(\n data: string,\n privateKey: string,\n options: SignOptions = {},\n ): HaiResult<string> {\n const { hash = true, userId = '1234567812345678' } = options\n\n if (!this.isValidPrivateKey(privateKey)) {\n return err(\n HaiCryptoError.INVALID_KEY,\n cryptoM('crypto_sm2PrivateKeyInvalid'),\n )\n }\n\n try {\n const signature = sm2.doSignature(data, privateKey, { hash, userId })\n\n if (!signature) {\n return err(\n HaiCryptoError.SIGN_FAILED,\n cryptoM('crypto_sm2SignEmpty'),\n )\n }\n\n return ok(signature)\n }\n catch (error) {\n return err(\n HaiCryptoError.SIGN_FAILED,\n cryptoM('crypto_sm2SignFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n },\n\n /**\n * SM2 签名验证\n *\n * 公钥自动补齐 04 前缀;hash/userId 需与签名时一致。\n *\n * @param data - 原始数据\n * @param signature - 签名值\n * @param publicKey - 公钥(支持带/不带 04 前缀)\n * @param options - 验签选项(hash 开关、userId)\n * @returns 成功时返回 boolean;失败时返回 INVALID_KEY 或 VERIFY_FAILED\n */\n verify(\n data: string,\n signature: string,\n publicKey: string,\n options: SignOptions = {},\n ): HaiResult<boolean> {\n const { hash = true, userId = '1234567812345678' } = options\n\n if (!this.isValidPublicKey(publicKey)) {\n return err(\n HaiCryptoError.INVALID_KEY,\n cryptoM('crypto_sm2PublicKeyInvalid'),\n )\n }\n\n try {\n // 确保公钥带 04 前缀\n const key = publicKey.startsWith('04') ? publicKey : `04${publicKey}`\n const isValid = sm2.doVerifySignature(data, signature, key, { hash, userId })\n return ok(!!isValid)\n }\n catch (error) {\n return err(\n HaiCryptoError.VERIFY_FAILED,\n cryptoM('crypto_sm2VerifyFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n },\n\n /**\n * 校验公钥格式是否合法\n *\n * 合法格式:128 字符十六进制(无前缀)或 130 字符(含 04 前缀)。\n *\n * @param key - 待校验公钥\n * @returns 格式合法返回 true\n */\n isValidPublicKey(key: string): boolean {\n if (!key || typeof key !== 'string')\n return false\n // 公钥长度:无前缀 128 字符,带 04 前缀 130 字符\n const cleanKey = key.startsWith('04') ? key.slice(2) : key\n return SM2_PUBLIC_KEY_REGEX.test(cleanKey)\n },\n\n /**\n * 校验私钥格式是否合法\n *\n * 合法格式:64 字符十六进制。\n *\n * @param key - 待校验私钥\n * @returns 格式合法返回 true\n */\n isValidPrivateKey(key: string): boolean {\n if (!key || typeof key !== 'string')\n return false\n // 私钥长度:64 字符\n return SM2_PRIVATE_KEY_REGEX.test(key)\n },\n }\n}\n","/**\n * @h-ai/crypto — SM3 哈希\n *\n * 提供 SM3 消息摘要与 HMAC 操作。\n * @module crypto-sm3\n */\n\nimport type { HaiResult } from '@h-ai/core'\n\nimport type { HashOperations, HashOptions } from './crypto-types.js'\nimport { core, err, ok } from '@h-ai/core'\n// @ts-expect-error sm-crypto 无类型定义\nimport smCrypto from 'sm-crypto'\n\nimport { cryptoM } from './crypto-i18n.js'\nimport {\n HaiCryptoError,\n\n} from './crypto-types.js'\n\nconst { sm3 } = smCrypto\n\n// ─── SM3 算法实现 ───\n\n/**\n * 创建 SM3 算法操作实例\n *\n * 基于 sm-crypto 库实现 SM3 哈希、HMAC 与哈希验证。\n * 支持字符串(UTF-8/Hex)和 Uint8Array 输入。\n * HMAC 实现遵循 RFC 2104 标准。\n *\n * @returns HashOperations 接口实现\n */\nexport function createSM3(): HashOperations {\n return {\n /**\n * 计算 SM3 哈希\n *\n * 支持字符串(UTF-8/Hex)和 Uint8Array 输入。\n *\n * @param data - 待哈希数据\n * @param options - 输入编码与输出格式\n * @returns 成功时返回 64 字符十六进制哈希值;失败时返回 HASH_FAILED\n */\n hash(\n data: string | Uint8Array,\n options: HashOptions = {},\n ): HaiResult<string> {\n const { inputEncoding = 'utf8' } = options\n\n try {\n let input: string | number[]\n\n if (data instanceof Uint8Array) {\n // Uint8Array 转为数字数组(sm-crypto 支持的格式)\n input = Array.from(data)\n }\n else if (inputEncoding === 'hex') {\n // 十六进制字符串转为数字数组\n input = hexToBytes(data)\n }\n else {\n // UTF-8 字符串直接传入\n input = data\n }\n\n const result = sm3(input)\n\n if (!result) {\n return err(\n HaiCryptoError.HASH_FAILED,\n cryptoM('crypto_sm3HashEmpty'),\n )\n }\n\n return ok(result)\n }\n catch (error) {\n return err(\n HaiCryptoError.HASH_FAILED,\n cryptoM('crypto_sm3HashFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n },\n\n /**\n * 计算 HMAC-SM3 消息认证码\n *\n * 实现遵循 RFC 2104;密钥超过块大小(64 字节)时先对密钥做哈希。\n *\n * @param data - 待计算数据\n * @param key - HMAC 密钥\n * @returns 成功时返回 64 字符十六进制 HMAC 值;失败时返回 HMAC_FAILED\n */\n hmac(data: string, key: string): HaiResult<string> {\n try {\n const blockSize = 64\n const opad = 0x5C\n const ipad = 0x36\n\n // 处理密钥\n let keyBytes: number[]\n if (key.length > blockSize) {\n const hashedKey = sm3(key)\n keyBytes = hexToBytes(hashedKey)\n }\n else {\n keyBytes = stringToBytes(key)\n }\n\n // 填充密钥到块大小\n while (keyBytes.length < blockSize) {\n keyBytes.push(0)\n }\n\n // 计算 iKeyPad 和 oKeyPad\n const iKeyPad = keyBytes.map(b => b ^ ipad)\n const oKeyPad = keyBytes.map(b => b ^ opad)\n\n // 计算内层哈希:H(iKeyPad || data)\n const innerInput = iKeyPad.concat(stringToBytes(data))\n const innerHash = sm3(innerInput)\n\n // 计算外层哈希:H(oKeyPad || innerHash)\n const outerInput = oKeyPad.concat(hexToBytes(innerHash))\n const result = sm3(outerInput)\n\n return ok(result)\n }\n catch (error) {\n return err(\n HaiCryptoError.HMAC_FAILED,\n cryptoM('crypto_sm3HmacFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n },\n\n /**\n * 验证数据的哈希是否匹配\n *\n * 对数据做 SM3 哈希后与期望值比较(忽略大小写)。\n *\n * @param data - 原始数据\n * @param expectedHash - 期望的哈希值\n * @returns 成功时返回 boolean;失败时返回 HASH_FAILED\n */\n verify(data: string, expectedHash: string): HaiResult<boolean> {\n try {\n const hashResult = sm3(data)\n return ok(core.string.constantTimeEqual(hashResult.toLowerCase(), expectedHash.toLowerCase()))\n }\n catch (error) {\n return err(\n HaiCryptoError.HASH_FAILED,\n cryptoM('crypto_sm3VerifyFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n },\n }\n}\n\n// ─── 辅助函数 ───\n\n/**\n * 十六进制字符串转字节数组\n *\n * @param hex - 十六进制字符串(长度必须为偶数)\n * @returns 字节数组\n */\nfunction hexToBytes(hex: string): number[] {\n const bytes: number[] = []\n for (let i = 0; i < hex.length; i += 2) {\n bytes.push(Number.parseInt(hex.slice(i, i + 2), 16))\n }\n return bytes\n}\n\n/**\n * UTF-8 字符串转字节数组\n *\n * 使用 TextEncoder 进行编码转换。\n *\n * @param str - UTF-8 字符串\n * @returns 字节数组\n */\nfunction stringToBytes(str: string): number[] {\n const encoder = new TextEncoder()\n return Array.from(encoder.encode(str))\n}\n","/**\n * @h-ai/crypto — SM4 对称加密\n *\n * 提供 SM4 对称加解密操作(CBC/ECB 模式)。\n * @module crypto-sm4\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { EncryptWithIVResult, SymmetricOperations, SymmetricOptions } from './crypto-types.js'\n\nimport { err, ok } from '@h-ai/core'\n// @ts-expect-error sm-crypto 无类型定义\nimport smCrypto from 'sm-crypto'\n\nimport { cryptoM } from './crypto-i18n.js'\nimport {\n\n HaiCryptoError,\n\n} from './crypto-types.js'\nimport { base64ToHex, hexToBase64, isBase64 } from './crypto-utils.js'\n\nconst { sm3, sm4 } = smCrypto\nconst SM4_HEX_32_REGEX = /^[0-9a-f]{32}$/i\n\n// ─── SM4 算法实现 ───\n\n/**\n * 创建 SM4 算法操作实例\n *\n * 基于 sm-crypto 库实现 SM4 对称加密/解密。\n * 支持 ECB(默认)和 CBC 两种模式,使用 PKCS#7 填充。\n * 密文支持 hex/base64 两种格式(解密时自动检测)。\n *\n * @returns SymmetricOperations 接口实现\n */\nexport function createSM4(): SymmetricOperations {\n return {\n /** 生成随机密钥(16 字节 = 32 个十六进制字符) */\n generateKey(): string {\n return generateRandomHex(16)\n },\n\n /** 生成随机 IV(16 字节 = 32 个十六进制字符) */\n generateIV(): string {\n return generateRandomHex(16)\n },\n\n /**\n * SM4 对称加密\n *\n * 支持 ECB(默认)和 CBC 两种模式,使用 PKCS#7 填充。\n * CBC 模式需提供合法 IV。\n *\n * ⚠️ 安全警告:**ECB 默认模式不安全**—相同明文块产生相同密文块,泄漏结构信息。\n * 生产场景请优先使用 `encryptWithIV()`(自动随机 IV 的 CBC)或显式传入\n * `{ mode: 'cbc', iv }`。ECB 模式仅保留兼容性,未来版本可能移除默认值。\n *\n * @param data - 待加密明文\n * @param key - 密钥(32 字符十六进制)\n * @param options - 加密模式/IV/输出格式\n * @returns 成功时返回密文;失败时返回 INVALID_KEY/INVALID_IV/ENCRYPTION_FAILED\n */\n encrypt(\n data: string,\n key: string,\n options: SymmetricOptions = {},\n ): HaiResult<string> {\n const {\n mode = 'ecb',\n iv,\n outputFormat = 'hex',\n } = options\n\n if (!this.isValidKey(key)) {\n return err(\n HaiCryptoError.INVALID_KEY,\n cryptoM('crypto_sm4KeyInvalid'),\n )\n }\n\n if (mode === 'cbc' && !iv) {\n return err(\n HaiCryptoError.INVALID_IV,\n cryptoM('crypto_sm4CbcNeedIv'),\n )\n }\n\n if (mode === 'cbc' && iv && !this.isValidIV(iv)) {\n return err(\n HaiCryptoError.INVALID_IV,\n cryptoM('crypto_sm4IvInvalid'),\n )\n }\n\n try {\n const sm4Options: Record<string, unknown> = {\n mode,\n padding: 'pkcs#7',\n }\n\n if (mode === 'cbc' && iv) {\n sm4Options.iv = iv\n }\n\n const encrypted = sm4.encrypt(data, key, sm4Options)\n\n if (!encrypted) {\n return err(\n HaiCryptoError.ENCRYPTION_FAILED,\n cryptoM('crypto_sm4EncryptEmpty'),\n )\n }\n\n if (outputFormat === 'base64') {\n return ok(hexToBase64(encrypted))\n }\n\n return ok(encrypted)\n }\n catch (error) {\n return err(\n HaiCryptoError.ENCRYPTION_FAILED,\n cryptoM('crypto_sm4EncryptFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n },\n\n /**\n * SM4 对称解密\n *\n * 自动检测 base64 格式输入并转换为 hex。\n * 解密模式和 IV 需与加密时一致。\n *\n * @param ciphertext - 密文(hex 或 base64)\n * @param key - 密钥(32 字符十六进制)\n * @param options - 解密模式/IV\n * @returns 成功时返回明文;失败时返回 INVALID_KEY/INVALID_IV/DECRYPTION_FAILED\n */\n decrypt(\n ciphertext: string,\n key: string,\n options: SymmetricOptions = {},\n ): HaiResult<string> {\n const { mode = 'ecb', iv } = options\n\n if (!this.isValidKey(key)) {\n return err(\n HaiCryptoError.INVALID_KEY,\n cryptoM('crypto_sm4KeyInvalid'),\n )\n }\n\n if (mode === 'cbc' && !iv) {\n return err(\n HaiCryptoError.INVALID_IV,\n cryptoM('crypto_sm4CbcNeedIv'),\n )\n }\n\n try {\n // 自动检测并转换 base64 格式\n let input = ciphertext\n if (isBase64(ciphertext)) {\n input = base64ToHex(ciphertext)\n }\n\n const sm4Options: Record<string, unknown> = {\n mode,\n padding: 'pkcs#7',\n }\n\n if (mode === 'cbc' && iv) {\n sm4Options.iv = iv\n }\n\n const decrypted = sm4.decrypt(input, key, sm4Options)\n\n if (decrypted === false || decrypted === null || decrypted === undefined) {\n return err(\n HaiCryptoError.DECRYPTION_FAILED,\n cryptoM('crypto_sm4DecryptFailed'),\n )\n }\n\n return ok(decrypted)\n }\n catch (error) {\n return err(\n HaiCryptoError.DECRYPTION_FAILED,\n cryptoM('crypto_sm4DecryptFailedWithError', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n },\n\n /**\n * 带 IV 加密(CBC 模式,自动生成随机 IV)\n *\n * @param data - 待加密明文\n * @param key - 密钥(32 字符十六进制)\n * @returns 成功时返回 { ciphertext, iv };失败时同 encrypt\n */\n encryptWithIV(\n data: string,\n key: string,\n ): HaiResult<EncryptWithIVResult> {\n const iv = this.generateIV()\n const result = this.encrypt(data, key, { mode: 'cbc', iv })\n\n if (!result.success) {\n return result\n }\n\n return ok({ ciphertext: result.data, iv })\n },\n\n /**\n * 带 IV 解密(CBC 模式)\n *\n * @param ciphertext - 密文\n * @param key - 密钥\n * @param iv - 加密时使用的 IV\n * @returns 成功时返回明文;失败时同 decrypt\n */\n decryptWithIV(\n ciphertext: string,\n key: string,\n iv: string,\n ): HaiResult<string> {\n return this.decrypt(ciphertext, key, { mode: 'cbc', iv })\n },\n\n /**\n * 从密码和盐值派生密钥\n *\n * 内部仅执行单次 SM3 哈希(password + salt),取前 32 字符作为密钥。\n *\n * ⚠️ 安全警告:**此实现不是标准 KDF**,不具备密码爆破抗性(无迭代、无内存硬化)。\n * - **禁止用于密码存储**:密码散列请用 `crypto.password.hash()`。\n * - **禁止用于高价值密钥派生**:如需从密码派生加密密钥,请在应用层自行实现 PBKDF2 / scrypt / Argon2。\n * - 仅适用于测试、迭代兼容或不敏感的场景。\n *\n * @deprecated 未来版本可能移除。密码散列请用 `crypto.password.hash`;密钥派生请使用标准 KDF。\n * @param password - 密码\n * @param salt - 盐值\n * @returns 32 字符十六进制密钥\n */\n deriveKey(password: string, salt: string): string {\n const combined = password + salt\n const hash = sm3(combined)\n // 取前 32 个十六进制字符(16 字节)\n return hash.slice(0, 32)\n },\n\n /** 校验密钥格式是否合法(32 字符十六进制) */\n isValidKey(key: string): boolean {\n return SM4_HEX_32_REGEX.test(key)\n },\n\n /** 校验 IV 格式是否合法(32 字符十六进制) */\n isValidIV(iv: string): boolean {\n return SM4_HEX_32_REGEX.test(iv)\n },\n }\n}\n\n// ─── 辅助函数 ───\n\n/**\n * 生成加密安全的随机十六进制字符串\n *\n * 使用 Web Crypto API(crypto.getRandomValues),前后端通用。\n *\n * @param byteLength - 字节数(输出字符数为 byteLength × 2)\n * @returns 小写十六进制字符串\n */\nfunction generateRandomHex(byteLength: number): string {\n const bytes = new Uint8Array(byteLength)\n // Web Crypto API,前后端通用\n crypto.getRandomValues(bytes)\n return Array.from(bytes)\n .map(b => b.toString(16).padStart(2, '0'))\n .join('')\n}\n","/**\n * @h-ai/crypto — 加密服务主入口\n *\n * 提供统一的 `crypto` 对象,聚合所有结构化加密操作。\n * @module crypto-main\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { AsymmetricOperations, CryptoFunctions, HashOperations, PasswordOperations, SymmetricOperations } from './crypto-types.js'\n\nimport { core, err, ok } from '@h-ai/core'\n\nimport { cryptoM } from './crypto-i18n.js'\nimport { createPasswordFunctions } from './crypto-password.js'\nimport { createSM2 } from './crypto-sm2.js'\nimport { createSM3 } from './crypto-sm3.js'\nimport { createSM4 } from './crypto-sm4.js'\nimport {\n\n HaiCryptoError,\n\n} from './crypto-types.js'\n\nconst logger = core.logger.child({ module: 'crypto', scope: 'main' })\n\n// ─── 内部状态 ───\n\n/** 是否已初始化 */\nlet initialized = false\n/** 并发初始化防护标志 */\nlet initInProgress = false\n/** 当前非对称加密操作实例 */\nlet currentAsymmetric: AsymmetricOperations | null = null\n/** 当前哈希操作实例 */\nlet currentHash: HashOperations | null = null\n/** 当前对称加密操作实例 */\nlet currentSymmetric: SymmetricOperations | null = null\n/** 当前密码哈希操作实例 */\nlet currentPassword: PasswordOperations | null = null\n\n// ─── 未初始化占位 ───\n\nconst notInitialized = core.module.createNotInitializedKit(\n HaiCryptoError.NOT_INITIALIZED,\n () => cryptoM('crypto_notInitialized'),\n)\n\nconst notInitializedAsymmetric = notInitialized.proxy<AsymmetricOperations>('sync')\nconst notInitializedHash = notInitialized.proxy<HashOperations>('sync')\nconst notInitializedSymmetric = notInitialized.proxy<SymmetricOperations>('sync')\nconst notInitializedPassword = notInitialized.proxy<PasswordOperations>('sync')\n\n// ─── 服务对象 ───\n\n/**\n * 加密模块服务对象(统一入口)\n *\n * 使用前必须调用 `crypto.init()` 进行初始化。\n * 未初始化时访问 asymmetric/hash/symmetric/password 的任何方法均返回 NOT_INITIALIZED 错误。\n *\n * @example\n * ```ts\n * import { crypto } from '@h-ai/crypto'\n *\n * await crypto.init()\n * const hash = crypto.hash.hash('hello')\n * const keyPair = crypto.asymmetric.generateKeyPair()\n * await crypto.close()\n * ```\n */\nexport const crypto: CryptoFunctions = {\n /**\n * 初始化加密模块\n *\n * 创建非对称/哈希/对称/密码哈希操作实例。\n * 重复调用会先关闭再重新初始化。\n *\n * @returns 成功时返回 ok(undefined);失败时返回 INIT_FAILED\n */\n async init(): Promise<HaiResult<void>> {\n // 并发初始化防护:避免多次 init 同时执行导致资源泄漏\n if (initInProgress) {\n logger.warn('Crypto init already in progress, skipping concurrent call')\n return err(\n HaiCryptoError.INIT_FAILED,\n cryptoM('crypto_initFailed', { params: { error: 'Concurrent initialization detected' } }),\n )\n }\n initInProgress = true\n\n try {\n if (initialized) {\n logger.warn('Crypto module is already initialized, reinitializing')\n await crypto.close()\n }\n\n logger.info('Initializing crypto module')\n\n currentAsymmetric = createSM2()\n currentHash = createSM3()\n currentSymmetric = createSM4()\n currentPassword = createPasswordFunctions({ hash: currentHash })\n initialized = true\n logger.info('Crypto module initialized')\n return ok(undefined)\n }\n catch (error) {\n // 清理部分赋值的状态\n currentAsymmetric = null\n currentHash = null\n currentSymmetric = null\n currentPassword = null\n initialized = false\n logger.error('Crypto module initialization failed', { error })\n return err(\n HaiCryptoError.INIT_FAILED,\n cryptoM('crypto_initFailed', {\n params: { error: error instanceof Error ? error.message : String(error) },\n }),\n error,\n )\n }\n finally {\n initInProgress = false\n }\n },\n\n /** 非对称加密操作(未初始化时所有方法返回 NOT_INITIALIZED) */\n get asymmetric(): AsymmetricOperations { return currentAsymmetric ?? notInitializedAsymmetric },\n /** 哈希操作(未初始化时所有方法返回 NOT_INITIALIZED) */\n get hash(): HashOperations { return currentHash ?? notInitializedHash },\n /** 对称加密操作(未初始化时所有方法返回 NOT_INITIALIZED) */\n get symmetric(): SymmetricOperations { return currentSymmetric ?? notInitializedSymmetric },\n /** 密码哈希操作(未初始化时所有方法返回 NOT_INITIALIZED) */\n get password(): PasswordOperations { return currentPassword ?? notInitializedPassword },\n /** 是否已初始化 */\n get isInitialized() { return initialized },\n\n /**\n * 关闭加密模块,释放内部状态\n *\n * 关闭后访问 asymmetric/hash/symmetric/password 会返回 NOT_INITIALIZED 错误。\n */\n async close() {\n if (!initialized) {\n logger.info('Crypto module already closed, skipping')\n return\n }\n\n logger.info('Closing crypto module')\n\n currentAsymmetric = null\n currentHash = null\n currentSymmetric = null\n currentPassword = null\n initialized = false\n\n logger.info('Crypto module closed')\n },\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../messages/en-US.json","../messages/zh-CN.json","../src/crypto-i18n.ts","../src/crypto-types.ts","../src/crypto-password.ts","../src/crypto-utils.ts","../src/crypto-sm2.ts","../src/crypto-sm3.ts","../src/crypto-sm4.ts","../src/transport/crypto-transport-types.ts","../src/transport/crypto-transport-client.ts","../src/transport/crypto-transport-server.ts","../src/crypto-main.ts"],"names":["core","ok","err","smCrypto","sm3","HaiCommonError","crypto"],"mappings":"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","file":"index.js","sourcesContent":["{\n \"$schema\": \"https://inlang.com/schema/inlang-message-format\",\n \"crypto_notInitialized\": \"Crypto module not initialized, call crypto.init() first\",\n \"crypto_initFailed\": \"Crypto module initialization failed: {error}\",\n \"crypto_sm2PublicKeyInvalid\": \"Invalid SM2 public key format\",\n \"crypto_sm2PrivateKeyInvalid\": \"Invalid SM2 private key format\",\n \"crypto_sm2EncryptEmpty\": \"SM2 encryption returned empty result\",\n \"crypto_sm2DecryptFailed\": \"SM2 decryption failed or returned invalid result\",\n \"crypto_sm2SignEmpty\": \"SM2 signature returned empty result\",\n \"crypto_sm2KeyPairGenerateFailed\": \"SM2 key pair generation failed: {error}\",\n \"crypto_sm2EncryptFailed\": \"SM2 encryption failed: {error}\",\n \"crypto_sm2DecryptFailedWithError\": \"SM2 decryption failed: {error}\",\n \"crypto_sm2SignFailed\": \"SM2 signing failed: {error}\",\n \"crypto_sm2VerifyFailed\": \"SM2 verification failed: {error}\",\n \"crypto_sm3HashEmpty\": \"SM3 hash returned empty result\",\n \"crypto_sm3HashFailed\": \"SM3 hash calculation failed: {error}\",\n \"crypto_sm3HmacFailed\": \"HMAC-SM3 calculation failed: {error}\",\n \"crypto_sm3VerifyFailed\": \"SM3 hash verification failed: {error}\",\n \"crypto_sm4KeyInvalid\": \"SM4 key must be 16 bytes (32 hex characters)\",\n \"crypto_sm4CbcNeedIv\": \"CBC mode requires IV\",\n \"crypto_sm4IvInvalid\": \"SM4 IV must be 16 bytes (32 hex characters)\",\n \"crypto_sm4EncryptEmpty\": \"SM4 encryption returned empty result\",\n \"crypto_sm4DecryptFailed\": \"SM4 decryption failed\",\n \"crypto_sm4EncryptFailed\": \"SM4 encryption failed: {error}\",\n \"crypto_sm4DecryptFailedWithError\": \"SM4 decryption failed: {error}\",\n \"crypto_passwordEmpty\": \"Password cannot be empty\",\n \"crypto_passwordHashEmpty\": \"Password and hash cannot be empty\",\n \"crypto_passwordHashFailed\": \"Password hashing failed\",\n \"crypto_hashFormatInvalid\": \"Invalid hash format\",\n \"crypto_passwordVerifyFailed\": \"Password verification failed\"\n}\n","{\n \"$schema\": \"https://inlang.com/schema/inlang-message-format\",\n \"crypto_notInitialized\": \"加密模块尚未初始化,请先调用 crypto.init()\",\n \"crypto_initFailed\": \"加密模块初始化失败:{error}\",\n \"crypto_sm2PublicKeyInvalid\": \"无效的 SM2 公钥格式\",\n \"crypto_sm2PrivateKeyInvalid\": \"无效的 SM2 私钥格式\",\n \"crypto_sm2EncryptEmpty\": \"SM2 加密返回空结果\",\n \"crypto_sm2DecryptFailed\": \"SM2 解密失败或返回无效结果\",\n \"crypto_sm2SignEmpty\": \"SM2 签名返回空结果\",\n \"crypto_sm2KeyPairGenerateFailed\": \"SM2 密钥对生成失败: {error}\",\n \"crypto_sm2EncryptFailed\": \"SM2 加密失败: {error}\",\n \"crypto_sm2DecryptFailedWithError\": \"SM2 解密失败: {error}\",\n \"crypto_sm2SignFailed\": \"SM2 签名失败: {error}\",\n \"crypto_sm2VerifyFailed\": \"SM2 验签失败: {error}\",\n \"crypto_sm3HashEmpty\": \"SM3 哈希返回空结果\",\n \"crypto_sm3HashFailed\": \"SM3 哈希计算失败: {error}\",\n \"crypto_sm3HmacFailed\": \"HMAC-SM3 计算失败: {error}\",\n \"crypto_sm3VerifyFailed\": \"SM3 哈希验证失败: {error}\",\n \"crypto_sm4KeyInvalid\": \"SM4 密钥必须为 16 字节(32 个十六进制字符)\",\n \"crypto_sm4CbcNeedIv\": \"CBC 模式必须提供 IV\",\n \"crypto_sm4IvInvalid\": \"SM4 IV 必须为 16 字节(32 个十六进制字符)\",\n \"crypto_sm4EncryptEmpty\": \"SM4 加密返回空结果\",\n \"crypto_sm4DecryptFailed\": \"SM4 解密失败\",\n \"crypto_sm4EncryptFailed\": \"SM4 加密失败: {error}\",\n \"crypto_sm4DecryptFailedWithError\": \"SM4 解密失败: {error}\",\n \"crypto_passwordEmpty\": \"密码不能为空\",\n \"crypto_passwordHashEmpty\": \"密码和哈希值不能为空\",\n \"crypto_passwordHashFailed\": \"密码哈希失败\",\n \"crypto_hashFormatInvalid\": \"无效的哈希格式\",\n \"crypto_passwordVerifyFailed\": \"密码验证失败\"\n}\n","/**\n * @h-ai/crypto — i18n\n *\n * 本文件提供加密模块的 i18n 文案访问入口。\n * @module crypto-i18n\n */\n\nimport { core } from '@h-ai/core'\nimport messagesEnUS from '../messages/en-US.json'\nimport messagesZhCN from '../messages/zh-CN.json'\n\n/** 加密模块 i18n 消息键类型(自动从 zh-CN 消息文件推断) */\ntype CryptoMessageKey = keyof typeof messagesZhCN\n\n/**\n * 加密模块 i18n 消息获取器\n *\n * 根据当前全局 locale 返回对应语言的消息文本,支持参数插值。\n *\n * @example\n * ```ts\n * cryptoM('crypto_sm2PublicKeyInvalid')\n * cryptoM('crypto_initFailed', { params: { error: 'bad config' } })\n * ```\n */\nexport const cryptoM = core.i18n.createMessageGetter<CryptoMessageKey>({\n 'zh-CN': messagesZhCN,\n 'en-US': messagesEnUS,\n})\n","/**\n * @h-ai/crypto — 公共类型\n *\n * 定义加密模块的对外接口类型。\n * @module crypto-types\n */\n\nimport type { ErrorInfo, HaiResult } from '@h-ai/core'\nimport type {\n TRANSPORT_PROTOCOL as TRANSPORT_PROTOCOL_T,\n TransportClient,\n TransportEncryptionManager,\n} from './transport/crypto-transport-types.js'\nimport { core } from '@h-ai/core'\n\nconst CryptoErrorInfo = {\n INVALID_INPUT: '002:400',\n INVALID_KEY: '003:400',\n NOT_INITIALIZED: '010:500',\n INIT_FAILED: '011:500',\n KEY_GENERATION_FAILED: '020:500',\n ENCRYPTION_FAILED: '021:500',\n DECRYPTION_FAILED: '022:500',\n SIGN_FAILED: '023:500',\n VERIFY_FAILED: '024:500',\n HASH_FAILED: '040:500',\n HMAC_FAILED: '041:500',\n INVALID_IV: '060:400',\n} as const satisfies ErrorInfo\n\nexport const HaiCryptoError = core.error.buildHaiErrorsDef('crypto', CryptoErrorInfo)\n\n// ─── 非对称加密类型 ───\n\n/** 密文模式:0=C1C2C3(旧版),1=C1C3C2(国标) */\nexport type CipherMode = 0 | 1\n\n/** 非对称密钥对 */\nexport interface KeyPair {\n /** 公钥(十六进制字符串,包含 04 前缀为非压缩格式) */\n publicKey: string\n /** 私钥(十六进制字符串,64 字符) */\n privateKey: string\n}\n\n/** 非对称加密选项 */\nexport interface AsymmetricEncryptOptions {\n /** 密文模式:0=C1C2C3(旧版),1=C1C3C2(国标,默认) */\n cipherMode?: CipherMode\n /** 输出格式 */\n outputFormat?: 'hex' | 'base64'\n}\n\n/** 签名选项 */\nexport interface SignOptions {\n /** 是否对数据进行哈希(默认 true) */\n hash?: boolean\n /** 用户 ID(默认 \"1234567812345678\") */\n userId?: string\n}\n\n// ─── 哈希类型 ───\n\n/** 哈希选项 */\nexport interface HashOptions {\n /** 输入编码 */\n inputEncoding?: 'utf8' | 'hex'\n}\n\n// ─── 对称加密类型 ───\n\n/** 对称加密模式 */\nexport type SymmetricMode = 'ecb' | 'cbc'\n\n/** 对称加密选项 */\nexport interface SymmetricOptions {\n /** 加密模式 */\n mode?: SymmetricMode\n /** IV 向量(CBC 模式必需,32 个十六进制字符) */\n iv?: string\n /** 输入编码 */\n inputEncoding?: 'utf8' | 'hex'\n /** 输出格式 */\n outputFormat?: 'hex' | 'base64'\n}\n\n/** 带 IV 加密结果 */\nexport interface EncryptWithIVResult {\n /** 密文 */\n ciphertext: string\n /** IV 向量 */\n iv: string\n}\n\n// ─── 密码类型 ───\n\n/** 密码哈希配置 */\nexport interface PasswordConfig {\n /** 盐值长度(默认 16) */\n saltLength?: number\n /** 迭代次数(默认 10000) */\n iterations?: number\n}\n\n// ─── 操作接口 ───\n\n/**\n * 非对称加密操作接口\n *\n * 通过 `crypto.asymmetric` 访问,需先调用 `crypto.init()`。\n */\nexport interface AsymmetricOperations {\n /**\n * 生成密钥对\n *\n * @returns 成功时包含公私钥对;失败时返回 KEY_GENERATION_FAILED\n */\n generateKeyPair: () => HaiResult<KeyPair>\n /**\n * 非对称加密\n *\n * @param data - 待加密明文\n * @param publicKey - 公钥(十六进制,支持带/不带 04 前缀)\n * @param options - 加密选项(密文模式、输出格式)\n * @returns 成功时返回密文字符串;失败时返回 INVALID_KEY 或 ENCRYPTION_FAILED\n */\n encrypt: (data: string, publicKey: string, options?: AsymmetricEncryptOptions) => HaiResult<string>\n /**\n * 非对称解密\n *\n * 自动检测 base64 格式输入并转换为 hex。\n *\n * @param ciphertext - 密文(hex 或 base64)\n * @param privateKey - 私钥(64 字符十六进制)\n * @param options - 解密选项(密文模式需与加密时一致)\n * @returns 成功时返回明文;失败时返回 INVALID_KEY 或 DECRYPTION_FAILED\n */\n decrypt: (ciphertext: string, privateKey: string, options?: AsymmetricEncryptOptions) => HaiResult<string>\n /**\n * 签名\n *\n * @param data - 待签名数据\n * @param privateKey - 私钥(64 字符十六进制)\n * @param options - 签名选项(hash 开关、userId)\n * @returns 成功时返回签名字符串;失败时返回 INVALID_KEY 或 SIGN_FAILED\n */\n sign: (data: string, privateKey: string, options?: SignOptions) => HaiResult<string>\n /**\n * 验签\n *\n * @param data - 原始数据\n * @param signature - 签名(需与签名时使用相同的 hash/userId 选项)\n * @param publicKey - 公钥(支持带/不带 04 前缀)\n * @param options - 验签选项\n * @returns 成功时返回 boolean;失败时返回 INVALID_KEY 或 VERIFY_FAILED\n */\n verify: (data: string, signature: string, publicKey: string, options?: SignOptions) => HaiResult<boolean>\n /**\n * 校验公钥格式是否合法\n *\n * 合法格式:128 字符十六进制(无前缀)或 130 字符(含 04 前缀)。\n */\n isValidPublicKey: (key: string) => boolean\n /**\n * 校验私钥格式是否合法\n *\n * 合法格式:64 字符十六进制。\n */\n isValidPrivateKey: (key: string) => boolean\n}\n\n/**\n * 哈希操作接口\n *\n * 通过 `crypto.hash` 访问,需先调用 `crypto.init()`。\n */\nexport interface HashOperations {\n /**\n * 计算哈希\n *\n * @param data - 待哈希数据(字符串或 Uint8Array)\n * @param options - 输入编码选项\n * @returns 成功时返回 64 字符十六进制哈希值;失败时返回 HASH_FAILED\n */\n hash: (data: string | Uint8Array, options?: HashOptions) => HaiResult<string>\n /**\n * 计算 HMAC\n *\n * 使用 HMAC 算法(RFC 2104)计算消息认证码。\n * 当密钥长度超过块大小(64 字节)时,会先对密钥进行哈希。\n *\n * @param data - 待计算数据\n * @param key - HMAC 密钥\n * @returns 成功时返回 64 字符十六进制 HMAC 值;失败时返回 HMAC_FAILED\n */\n hmac: (data: string, key: string) => HaiResult<string>\n /**\n * 验证数据的哈希是否匹配\n *\n * 比较时忽略大小写。\n *\n * @param data - 原始数据\n * @param expectedHash - 期望的哈希值\n * @returns 成功时返回 boolean;失败时返回 HASH_FAILED\n */\n verify: (data: string, expectedHash: string) => HaiResult<boolean>\n}\n\n/**\n * 对称加密操作接口\n *\n * 通过 `crypto.symmetric` 访问,需先调用 `crypto.init()`。\n * 支持 ECB/CBC 两种模式,CBC 模式需要提供 IV。\n */\nexport interface SymmetricOperations {\n /** 生成随机密钥(16 字节 = 32 个十六进制字符) */\n generateKey: () => string\n /** 生成随机 IV(16 字节 = 32 个十六进制字符) */\n generateIV: () => string\n /**\n * 对称加密\n *\n * @param data - 待加密明文\n * @param key - 密钥(32 字符十六进制)\n * @param options - 加密模式/IV/输出格式\n * @returns 成功时返回密文;失败时返回 INVALID_KEY/INVALID_IV/ENCRYPTION_FAILED\n */\n encrypt: (data: string, key: string, options?: SymmetricOptions) => HaiResult<string>\n /**\n * 对称解密\n *\n * 自动检测 base64 格式输入并转换为 hex。\n *\n * @param ciphertext - 密文(hex 或 base64)\n * @param key - 密钥(32 字符十六进制)\n * @param options - 解密模式/IV(需与加密时一致)\n * @returns 成功时返回明文;失败时返回 INVALID_KEY/INVALID_IV/DECRYPTION_FAILED\n */\n decrypt: (ciphertext: string, key: string, options?: SymmetricOptions) => HaiResult<string>\n /**\n * 带 IV 加密(CBC 模式,自动生成随机 IV)\n *\n * @param data - 待加密明文\n * @param key - 密钥(32 字符十六进制)\n * @returns 成功时返回 { ciphertext, iv };失败时同 encrypt\n */\n encryptWithIV: (data: string, key: string) => HaiResult<EncryptWithIVResult>\n /**\n * 带 IV 解密(CBC 模式)\n *\n * @param ciphertext - 密文\n * @param key - 密钥\n * @param iv - 加密时使用的 IV\n * @returns 成功时返回明文;失败时同 decrypt\n */\n decryptWithIV: (ciphertext: string, key: string, iv: string) => HaiResult<string>\n /**\n * 从密码和盐值派生密钥\n *\n * 内部仅执行单次哈希(password + salt) 取前 32 字符作为密钥。\n *\n * ⚠️ 安全警告:**此实现不是标准 KDF**,不具备密码爆破抗性。\n * - 禁止用于密码存储(请用 `crypto.password.hash`)。\n * - 禁止用于高价值密钥派生(请在应用层采用 PBKDF2 / scrypt / Argon2)。\n *\n * @deprecated 未来版本可能移除。详见模块 README 安全声明。\n * @param password - 密码\n * @param salt - 盐值\n * @returns 32 字符十六进制密钥\n */\n deriveKey: (password: string, salt: string) => string\n /** 校验密钥格式是否合法(32 字符十六进制) */\n isValidKey: (key: string) => boolean\n /** 校验 IV 格式是否合法(32 字符十六进制) */\n isValidIV: (iv: string) => boolean\n}\n\n/**\n * 密码哈希操作接口\n *\n * 通过 `crypto.password` 访问,需先调用 `crypto.init()`。\n * 使用迭代加盐的方式生成密码哈希。\n */\nexport interface PasswordOperations {\n /**\n * 对密码进行哈希\n *\n * 输出格式: `$hai$<iterations>$<salt>$<hash>`\n *\n * @param password - 明文密码(不能为空)\n * @param config - 可选配置(盐值长度、迭代次数)\n * @returns 成功时返回格式化的哈希字符串;失败时返回 INVALID_INPUT 或 HASH_FAILED\n */\n hash: (password: string, config?: PasswordConfig) => HaiResult<string>\n /**\n * 验证密码是否匹配\n *\n * 自动从哈希字符串中解析迭代次数和盐值进行重新计算。\n *\n * @param password - 待验证的明文密码\n * @param hash - 存储的哈希值(格式: `$hai$<iterations>$<salt>$<hash>`)\n * @returns 成功时返回 boolean;失败时返回 INVALID_INPUT 或 VERIFY_FAILED\n */\n verify: (password: string, hash: string) => HaiResult<boolean>\n}\n\n// ─── 传输加密 ───\n\n/**\n * 传输加密操作接口(端到端混合加密)。\n *\n * 通过 `crypto.transport` 访问,需先调用 `crypto.init()`。\n *\n * @remarks\n * 使用流程(直接使用底层 transport 工厂时):\n *\n * 1. 先 `await crypto.init()`,确保 `crypto.asymmetric` / `crypto.symmetric` 已就绪。\n * 2. 服务端调用 `crypto.transport.createServer()` 创建 `TransportEncryptionManager`;该管理器负责持有服务端密钥对,并管理客户端公钥。\n * 3. 服务端暴露一个 POST 密钥协商端点:接收 `{ clientPublicKey }`,调用 `manager.registerClientKey()` 注册客户端公钥,再返回 `{ serverPublicKey: manager.getServerPublicKey(), clientId }`。\n * 4. 客户端调用 `crypto.transport.createClient({ keyExchangeUrl })` 创建会话;首次 `client.init()` 或 `client.encryptedFetch()` 会自动完成密钥协商。\n * 5. 协商完成后,客户端每次请求都会附带 `X-Client-Id`;若请求有 body,则 body 会被包装成 `{ encryptedKey, ciphertext, iv }`,并设置 `X-Encrypted: true`。\n * 6. 服务端在业务逻辑前调用 `manager.decryptRequest()` 解密请求体,在返回前调用 `manager.encryptResponse(clientId, data)` 为当前客户端重新加密响应。\n * 7. 客户端收到 `X-Encrypted: true` 的响应后会自动解密;调用 `client.destroy()` 可清空当前会话,下次请求会重新协商。\n *\n * 常规应用优先使用上层封装,而不是手写 HTTP 协商细节:\n * - `serv.createApp({ transport: { crypto } })`\n * - `kit.createHandle({ crypto: { crypto, transport: true } })`\n * - `apiClient.init({ transport: { crypto } })`\n *\n * @example 服务端\n * ```ts\n * const result = crypto.transport.createServer()\n * if (!result.success) throw result.error\n * const manager = result.data\n * ```\n *\n * @example 客户端\n * ```ts\n * const client = crypto.transport.createClient({\n * keyExchangeUrl: 'https://api.example.com/api/v1/_hai/key-exchange',\n * })\n * const resp = await client.encryptedFetch('https://api.example.com/api/v1/echo', {\n * method: 'POST', body: JSON.stringify({ hello: 'world' }),\n * })\n * ```\n */\nexport interface TransportOperations {\n /**\n * 创建服务端传输加密管理器。\n *\n * options.maxClients:默认内存 keyStore 的最大客户端数(默认 10000)。\n * 成功返回 manager;密钥生成失败返回 `HaiCommonError.INTERNAL_ERROR`。\n *\n * @remarks\n * 通常在服务启动阶段创建一次,并交给 HTTP 中间件 / 路由处理器复用。\n */\n createServer: (options?: { maxClients?: number }) => HaiResult<TransportEncryptionManager>\n /**\n * 创建客户端传输加密会话。\n *\n * options.keyExchangeUrl:密钥协商端点完整 URL。\n * options.fetch:实际发送 HTTP 请求的 fetch(默认 `globalThis.fetch`)。\n *\n * @remarks\n * 返回的是“单会话”客户端:同一个实例会复用已协商得到的 `clientId` 与服务端公钥;\n * 调用 `destroy()` 后会回到未协商状态。\n */\n createClient: (options: { keyExchangeUrl: string, fetch?: typeof fetch }) => TransportClient\n /** 协议常量(headers、密钥协商默认路径)。 */\n readonly protocol: typeof TRANSPORT_PROTOCOL_T\n}\n\n// ─── 函数接口 ───\n\n/**\n * 加密模块函数接口\n *\n * `crypto` 服务对象的类型定义。使用前必须调用 `init()` 初始化。\n *\n * @example\n * ```ts\n * import { crypto } from '@h-ai/crypto'\n *\n * await crypto.init()\n * const hash = crypto.hash.hash('hello')\n * await crypto.close()\n * ```\n */\nexport interface CryptoFunctions {\n /**\n * 初始化加密模块\n *\n * 创建非对称/哈希/对称/密码哈希操作实例。\n * 重复调用会先关闭再重新初始化。\n *\n * @returns 成功时返回 ok(undefined);失败时返回 INIT_FAILED\n */\n init: () => Promise<HaiResult<void>>\n /**\n * 关闭加密模块,释放内部状态\n *\n * 关闭后再访问 asymmetric/hash/symmetric/password 会返回 NOT_INITIALIZED 错误。\n */\n close: () => Promise<void>\n /** 是否已初始化 */\n readonly isInitialized: boolean\n /** 非对称加密操作(未初始化时所有方法返回 NOT_INITIALIZED) */\n readonly asymmetric: AsymmetricOperations\n /** 哈希操作(未初始化时所有方法返回 NOT_INITIALIZED) */\n readonly hash: HashOperations\n /** 对称加密操作(未初始化时所有方法返回 NOT_INITIALIZED) */\n readonly symmetric: SymmetricOperations\n /** 密码哈希操作(未初始化时所有方法返回 NOT_INITIALIZED) */\n readonly password: PasswordOperations\n /** 传输加密操作(端到端混合加密;createServer 在未初始化时返回 NOT_INITIALIZED) */\n readonly transport: TransportOperations\n}\n","/**\n * @h-ai/crypto — 密码操作\n *\n * 提供迭代加盐(SM3)密码哈希与校验功能。\n * @module crypto-password\n */\n\nimport type { HaiResult } from '@h-ai/core'\n\nimport type { HashOperations, PasswordConfig, PasswordOperations } from './crypto-types.js'\nimport { core, err, ok } from '@h-ai/core'\n\nimport { cryptoM } from './crypto-i18n.js'\nimport { HaiCryptoError } from './crypto-types.js'\n\n// ─── 常量 ───\n\n/** 迭代次数最小值(防止退化为 0 迭代导致明文等价泄漏) */\nconst MIN_ITERATIONS = 1\n/** 迭代次数最大值(防止伪造哈希触发 CPU 饱和) */\nconst MAX_ITERATIONS = 1_000_000\n/** 盐值长度范围,限制异常输入 */\nconst MIN_SALT_LENGTH = 8\nconst MAX_SALT_LENGTH = 128\n\n// ─── 依赖接口 ───\n\n/** createPasswordFunctions 所需的外部依赖 */\ninterface PasswordDeps {\n /** 哈希操作实例,用于迭代哈希计算 */\n hash: HashOperations\n}\n\n// ─── 工具函数 ───\n\n/**\n * 生成加密安全的随机盐值\n *\n * 使用 Web Crypto API(crypto.getRandomValues)从大小写字母和数字中随机选取字符。\n *\n * @param length - 盐值长度(字符数)\n * @returns 随机盐值字符串\n */\nfunction generateSalt(length: number): string {\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'\n const randomBytes = new Uint8Array(length)\n globalThis.crypto.getRandomValues(randomBytes)\n let salt = ''\n for (let i = 0; i < length; i++) {\n salt += chars.charAt(randomBytes[i] % chars.length)\n }\n return salt\n}\n\n/**\n * 对数据进行多次迭代哈希(密钥拉伸)\n *\n * 首次输入为 salt + data,后续每次用前一轮的哈希结果作为输入。\n * 任一轮哈希计算失败则立即返回错误。\n *\n * @param hash - 哈希操作实例\n * @param data - 原始数据(通常为密码)\n * @param salt - 盐值\n * @param iterations - 迭代次数\n * @returns 成功时返回最终哈希值(64 字符十六进制)\n */\nfunction iterateHash(\n hash: HashOperations,\n data: string,\n salt: string,\n iterations: number,\n): HaiResult<string> {\n let current = salt + data\n for (let i = 0; i < iterations; i++) {\n const result = hash.hash(current)\n if (!result.success) {\n return result\n }\n current = result.data\n }\n return ok(current)\n}\n\n// ─── 密码操作工厂 ───\n\n/**\n * 创建密码哈希操作实例\n *\n * 内部使用迭代加盐的方式生成密码哈希,格式为 `$hai$<iterations>$<salt>$<hash>`。\n *\n * @param deps - 依赖(需要注入哈希操作实例)\n * @returns PasswordOperations 接口实现\n */\nexport function createPasswordFunctions(deps: PasswordDeps): PasswordOperations {\n const { hash: hashOps } = deps\n\n return {\n /**\n * 对密码进行迭代加盐哈希\n *\n * 输出格式: `$hai$<iterations>$<salt>$<hash>`\n *\n * @param password - 明文密码(不能为空)\n * @param config - 可选配置(盐值长度、迭代次数)\n * @returns 成功时返回格式化的哈希字符串;失败时返回 INVALID_INPUT 或 HASH_FAILED\n */\n hash(password: string, config: PasswordConfig = {}): HaiResult<string> {\n const { saltLength = 16, iterations = 10000 } = config\n\n try {\n if (!password) {\n return err(\n HaiCryptoError.INVALID_INPUT,\n cryptoM('crypto_passwordEmpty'),\n )\n }\n\n if (!Number.isInteger(iterations) || iterations < MIN_ITERATIONS || iterations > MAX_ITERATIONS) {\n return err(\n HaiCryptoError.INVALID_INPUT,\n cryptoM('crypto_hashFormatInvalid'),\n )\n }\n if (!Number.isInteger(saltLength) || saltLength < MIN_SALT_LENGTH || saltLength > MAX_SALT_LENGTH) {\n return err(\n HaiCryptoError.INVALID_INPUT,\n cryptoM('crypto_hashFormatInvalid'),\n )\n }\n\n const salt = generateSalt(saltLength)\n const hashResult = iterateHash(hashOps, password, salt, iterations)\n if (!hashResult.success) {\n return hashResult\n }\n\n const formatted = `$hai$${iterations}$${salt}$${hashResult.data}`\n return ok(formatted)\n }\n catch (error) {\n return err(\n HaiCryptoError.HASH_FAILED,\n cryptoM('crypto_passwordHashFailed'),\n error,\n )\n }\n },\n\n /**\n * 验证密码是否匹配已存储的哈希\n *\n * 从哈希字符串中解析迭代次数和盐值,重新计算后比较。\n * 格式要求: `$hai$<iterations>$<salt>$<hash>`\n *\n * @param password - 待验证的明文密码\n * @param hash - 存储的哈希值\n * @returns 成功时返回 boolean;失败时返回 INVALID_INPUT 或 VERIFY_FAILED\n */\n verify(password: string, hash: string): HaiResult<boolean> {\n try {\n if (!password || !hash) {\n return err(\n HaiCryptoError.INVALID_INPUT,\n cryptoM('crypto_passwordHashEmpty'),\n )\n }\n\n const parts = hash.split('$')\n if (parts.length !== 5 || parts[1] !== 'hai') {\n return err(\n HaiCryptoError.INVALID_INPUT,\n cryptoM('crypto_hashFormatInvalid'),\n )\n }\n\n const storedIterations = Number.parseInt(parts[2], 10)\n const salt = parts[3]\n const storedHash = parts[4]\n\n if (\n Number.isNaN(storedIterations)\n || storedIterations < MIN_ITERATIONS\n || storedIterations > MAX_ITERATIONS\n || !salt\n || !storedHash\n ) {\n return err(\n HaiCryptoError.INVALID_INPUT,\n cryptoM('crypto_hashFormatInvalid'),\n )\n }\n\n const hashResult = iterateHash(hashOps, password, salt, storedIterations)\n if (!hashResult.success) {\n return hashResult\n }\n\n return ok(core.string.constantTimeEqual(hashResult.data, storedHash))\n }\n catch (error) {\n return err(\n HaiCryptoError.VERIFY_FAILED,\n cryptoM('crypto_passwordVerifyFailed'),\n error,\n )\n }\n },\n }\n}\n","/**\n * @h-ai/crypto — 内部工具函数\n *\n * 提供 SM2/SM4 共用的编码转换辅助函数。 仅供模块内部使用,不对外导出。\n * @module crypto-utils\n */\n\n/**\n * 判断字符串是否为 Base64 格式\n *\n * 使用简单启发式:包含 +、/ 或以 = 结尾视为 base64。\n *\n * @param str - 待检测字符串\n */\nexport function isBase64(str: string): boolean {\n return str.includes('+') || str.includes('/') || str.endsWith('=')\n}\n\n/**\n * Hex 字符串转 Base64 编码\n *\n * 使用 Web 标准 API btoa,前后端通用(Node 16+ / 所有现代浏览器)。\n *\n * @param hex - 十六进制字符串(长度必须为偶数)\n * @returns Base64 编码字符串\n */\nexport function hexToBase64(hex: string): string {\n const bytes = new Uint8Array(hex.length / 2)\n for (let i = 0; i < hex.length; i += 2) {\n bytes[i / 2] = Number.parseInt(hex.slice(i, i + 2), 16)\n }\n return btoa(String.fromCharCode(...bytes))\n}\n\n/**\n * Base64 编码转 Hex 字符串\n *\n * 使用 Web 标准 API atob,前后端通用(Node 16+ / 所有现代浏览器)。\n *\n * @param base64 - Base64 编码字符串\n * @returns 小写十六进制字符串\n */\nexport function base64ToHex(base64: string): string {\n const binary = atob(base64)\n const bytes = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i)\n }\n return Array.from(bytes)\n .map(b => b.toString(16).padStart(2, '0'))\n .join('')\n}\n","/**\n * @h-ai/crypto — SM2 非对称加密\n *\n * 提供 SM2 密钥对生成、加解密、签名与验签操作。\n * @module crypto-sm2\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { AsymmetricEncryptOptions, AsymmetricOperations, KeyPair, SignOptions } from './crypto-types.js'\n\nimport { err, ok } from '@h-ai/core'\n// @ts-expect-error sm-crypto 无类型定义\nimport smCrypto from 'sm-crypto'\n\nimport { cryptoM } from './crypto-i18n.js'\nimport {\n\n HaiCryptoError,\n\n} from './crypto-types.js'\nimport { base64ToHex, hexToBase64, isBase64 } from './crypto-utils.js'\n\nconst { sm2 } = smCrypto\nconst SM2_PUBLIC_KEY_REGEX = /^[0-9a-f]{128}$/i\nconst SM2_PRIVATE_KEY_REGEX = /^[0-9a-f]{64}$/i\n\n// ─── SM2 算法实现 ───\n\n/**\n * 创建 SM2 算法操作实例\n *\n * 基于 sm-crypto 库实现 SM2 非对称加密、签名与验签。\n * 公钥支持带/不带 04 前缀两种格式(内部统一补齐)。\n * 密文支持 hex/base64 两种格式(解密时自动检测)。\n *\n * @returns AsymmetricOperations 接口实现\n */\nexport function createSM2(): AsymmetricOperations {\n return {\n /**\n * 生成 SM2 密钥对\n *\n * @returns 成功时返回包含公钥(130 字符含 04 前缀)和私钥(64 字符)的密钥对\n */\n generateKeyPair(): HaiResult<KeyPair> {\n try {\n const keyPair = sm2.generateKeyPairHex()\n return ok({\n publicKey: keyPair.publicKey,\n privateKey: keyPair.privateKey,\n })\n }\n catch (error) {\n return err(\n HaiCryptoError.KEY_GENERATION_FAILED,\n cryptoM('crypto_sm2KeyPairGenerateFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n },\n\n /**\n * SM2 非对称加密\n *\n * 公钥自动补齐 04 前缀;支持 hex/base64 输出。\n *\n * @param data - 待加密明文\n * @param publicKey - 公钥(支持带/不带 04 前缀)\n * @param options - 加密选项(密文模式、输出格式)\n * @returns 成功时返回密文;失败时返回 INVALID_KEY 或 ENCRYPTION_FAILED\n */\n encrypt(\n data: string,\n publicKey: string,\n options: AsymmetricEncryptOptions = {},\n ): HaiResult<string> {\n const { cipherMode = 1, outputFormat = 'hex' } = options\n\n if (!this.isValidPublicKey(publicKey)) {\n return err(\n HaiCryptoError.INVALID_KEY,\n cryptoM('crypto_sm2PublicKeyInvalid'),\n )\n }\n\n try {\n // 确保公钥带 04 前缀\n const key = publicKey.startsWith('04') ? publicKey : `04${publicKey}`\n const encrypted = sm2.doEncrypt(data, key, cipherMode)\n\n if (!encrypted) {\n return err(\n HaiCryptoError.ENCRYPTION_FAILED,\n cryptoM('crypto_sm2EncryptEmpty'),\n )\n }\n\n if (outputFormat === 'base64') {\n return ok(hexToBase64(encrypted))\n }\n\n return ok(encrypted)\n }\n catch (error) {\n return err(\n HaiCryptoError.ENCRYPTION_FAILED,\n cryptoM('crypto_sm2EncryptFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n },\n\n /**\n * SM2 非对称解密\n *\n * 自动检测 base64 格式输入并转换为 hex 后解密。\n *\n * @param ciphertext - 密文(hex 或 base64)\n * @param privateKey - 私钥(64 字符十六进制)\n * @param options - 解密选项(密文模式需与加密时一致)\n * @returns 成功时返回明文;失败时返回 INVALID_KEY 或 DECRYPTION_FAILED\n */\n decrypt(\n ciphertext: string,\n privateKey: string,\n options: AsymmetricEncryptOptions = {},\n ): HaiResult<string> {\n const { cipherMode = 1 } = options\n\n if (!this.isValidPrivateKey(privateKey)) {\n return err(\n HaiCryptoError.INVALID_KEY,\n cryptoM('crypto_sm2PrivateKeyInvalid'),\n )\n }\n\n try {\n // 自动检测并转换 base64 格式\n let input = ciphertext\n if (isBase64(ciphertext)) {\n input = base64ToHex(ciphertext)\n }\n\n const decrypted = sm2.doDecrypt(input, privateKey, cipherMode)\n\n if (decrypted === false || decrypted === null || decrypted === undefined) {\n return err(\n HaiCryptoError.DECRYPTION_FAILED,\n cryptoM('crypto_sm2DecryptFailed'),\n )\n }\n\n return ok(decrypted)\n }\n catch (error) {\n return err(\n HaiCryptoError.DECRYPTION_FAILED,\n cryptoM('crypto_sm2DecryptFailedWithError', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n },\n\n /**\n * SM2 数字签名\n *\n * 默认对数据先做哈希(hash=true),使用 userId 作为签名附加参数。\n *\n * @param data - 待签名数据\n * @param privateKey - 私钥(64 字符十六进制)\n * @param options - 签名选项(hash 开关、userId)\n * @returns 成功时返回签名字符串;失败时返回 INVALID_KEY 或 SIGN_FAILED\n */\n sign(\n data: string,\n privateKey: string,\n options: SignOptions = {},\n ): HaiResult<string> {\n const { hash = true, userId = '1234567812345678' } = options\n\n if (!this.isValidPrivateKey(privateKey)) {\n return err(\n HaiCryptoError.INVALID_KEY,\n cryptoM('crypto_sm2PrivateKeyInvalid'),\n )\n }\n\n try {\n const signature = sm2.doSignature(data, privateKey, { hash, userId })\n\n if (!signature) {\n return err(\n HaiCryptoError.SIGN_FAILED,\n cryptoM('crypto_sm2SignEmpty'),\n )\n }\n\n return ok(signature)\n }\n catch (error) {\n return err(\n HaiCryptoError.SIGN_FAILED,\n cryptoM('crypto_sm2SignFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n },\n\n /**\n * SM2 签名验证\n *\n * 公钥自动补齐 04 前缀;hash/userId 需与签名时一致。\n *\n * @param data - 原始数据\n * @param signature - 签名值\n * @param publicKey - 公钥(支持带/不带 04 前缀)\n * @param options - 验签选项(hash 开关、userId)\n * @returns 成功时返回 boolean;失败时返回 INVALID_KEY 或 VERIFY_FAILED\n */\n verify(\n data: string,\n signature: string,\n publicKey: string,\n options: SignOptions = {},\n ): HaiResult<boolean> {\n const { hash = true, userId = '1234567812345678' } = options\n\n if (!this.isValidPublicKey(publicKey)) {\n return err(\n HaiCryptoError.INVALID_KEY,\n cryptoM('crypto_sm2PublicKeyInvalid'),\n )\n }\n\n try {\n // 确保公钥带 04 前缀\n const key = publicKey.startsWith('04') ? publicKey : `04${publicKey}`\n const isValid = sm2.doVerifySignature(data, signature, key, { hash, userId })\n return ok(!!isValid)\n }\n catch (error) {\n return err(\n HaiCryptoError.VERIFY_FAILED,\n cryptoM('crypto_sm2VerifyFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n },\n\n /**\n * 校验公钥格式是否合法\n *\n * 合法格式:128 字符十六进制(无前缀)或 130 字符(含 04 前缀)。\n *\n * @param key - 待校验公钥\n * @returns 格式合法返回 true\n */\n isValidPublicKey(key: string): boolean {\n if (!key || typeof key !== 'string')\n return false\n // 公钥长度:无前缀 128 字符,带 04 前缀 130 字符\n const cleanKey = key.startsWith('04') ? key.slice(2) : key\n return SM2_PUBLIC_KEY_REGEX.test(cleanKey)\n },\n\n /**\n * 校验私钥格式是否合法\n *\n * 合法格式:64 字符十六进制。\n *\n * @param key - 待校验私钥\n * @returns 格式合法返回 true\n */\n isValidPrivateKey(key: string): boolean {\n if (!key || typeof key !== 'string')\n return false\n // 私钥长度:64 字符\n return SM2_PRIVATE_KEY_REGEX.test(key)\n },\n }\n}\n","/**\n * @h-ai/crypto — SM3 哈希\n *\n * 提供 SM3 消息摘要与 HMAC 操作。\n * @module crypto-sm3\n */\n\nimport type { HaiResult } from '@h-ai/core'\n\nimport type { HashOperations, HashOptions } from './crypto-types.js'\nimport { core, err, ok } from '@h-ai/core'\n// @ts-expect-error sm-crypto 无类型定义\nimport smCrypto from 'sm-crypto'\n\nimport { cryptoM } from './crypto-i18n.js'\nimport {\n HaiCryptoError,\n\n} from './crypto-types.js'\n\nconst { sm3 } = smCrypto\n\n// ─── SM3 算法实现 ───\n\n/**\n * 创建 SM3 算法操作实例\n *\n * 基于 sm-crypto 库实现 SM3 哈希、HMAC 与哈希验证。\n * 支持字符串(UTF-8/Hex)和 Uint8Array 输入。\n * HMAC 实现遵循 RFC 2104 标准。\n *\n * @returns HashOperations 接口实现\n */\nexport function createSM3(): HashOperations {\n return {\n /**\n * 计算 SM3 哈希\n *\n * 支持字符串(UTF-8/Hex)和 Uint8Array 输入。\n *\n * @param data - 待哈希数据\n * @param options - 输入编码与输出格式\n * @returns 成功时返回 64 字符十六进制哈希值;失败时返回 HASH_FAILED\n */\n hash(\n data: string | Uint8Array,\n options: HashOptions = {},\n ): HaiResult<string> {\n const { inputEncoding = 'utf8' } = options\n\n try {\n let input: string | number[]\n\n if (data instanceof Uint8Array) {\n // Uint8Array 转为数字数组(sm-crypto 支持的格式)\n input = Array.from(data)\n }\n else if (inputEncoding === 'hex') {\n // 十六进制字符串转为数字数组\n input = hexToBytes(data)\n }\n else {\n // UTF-8 字符串直接传入\n input = data\n }\n\n const result = sm3(input)\n\n if (!result) {\n return err(\n HaiCryptoError.HASH_FAILED,\n cryptoM('crypto_sm3HashEmpty'),\n )\n }\n\n return ok(result)\n }\n catch (error) {\n return err(\n HaiCryptoError.HASH_FAILED,\n cryptoM('crypto_sm3HashFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n },\n\n /**\n * 计算 HMAC-SM3 消息认证码\n *\n * 实现遵循 RFC 2104;密钥超过块大小(64 字节)时先对密钥做哈希。\n *\n * @param data - 待计算数据\n * @param key - HMAC 密钥\n * @returns 成功时返回 64 字符十六进制 HMAC 值;失败时返回 HMAC_FAILED\n */\n hmac(data: string, key: string): HaiResult<string> {\n try {\n const blockSize = 64\n const opad = 0x5C\n const ipad = 0x36\n\n // 处理密钥\n let keyBytes: number[]\n if (key.length > blockSize) {\n const hashedKey = sm3(key)\n keyBytes = hexToBytes(hashedKey)\n }\n else {\n keyBytes = stringToBytes(key)\n }\n\n // 填充密钥到块大小\n while (keyBytes.length < blockSize) {\n keyBytes.push(0)\n }\n\n // 计算 iKeyPad 和 oKeyPad\n const iKeyPad = keyBytes.map(b => b ^ ipad)\n const oKeyPad = keyBytes.map(b => b ^ opad)\n\n // 计算内层哈希:H(iKeyPad || data)\n const innerInput = iKeyPad.concat(stringToBytes(data))\n const innerHash = sm3(innerInput)\n\n // 计算外层哈希:H(oKeyPad || innerHash)\n const outerInput = oKeyPad.concat(hexToBytes(innerHash))\n const result = sm3(outerInput)\n\n return ok(result)\n }\n catch (error) {\n return err(\n HaiCryptoError.HMAC_FAILED,\n cryptoM('crypto_sm3HmacFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n },\n\n /**\n * 验证数据的哈希是否匹配\n *\n * 对数据做 SM3 哈希后与期望值比较(忽略大小写)。\n *\n * @param data - 原始数据\n * @param expectedHash - 期望的哈希值\n * @returns 成功时返回 boolean;失败时返回 HASH_FAILED\n */\n verify(data: string, expectedHash: string): HaiResult<boolean> {\n try {\n const hashResult = sm3(data)\n return ok(core.string.constantTimeEqual(hashResult.toLowerCase(), expectedHash.toLowerCase()))\n }\n catch (error) {\n return err(\n HaiCryptoError.HASH_FAILED,\n cryptoM('crypto_sm3VerifyFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n },\n }\n}\n\n// ─── 辅助函数 ───\n\n/**\n * 十六进制字符串转字节数组\n *\n * @param hex - 十六进制字符串(长度必须为偶数)\n * @returns 字节数组\n */\nfunction hexToBytes(hex: string): number[] {\n const bytes: number[] = []\n for (let i = 0; i < hex.length; i += 2) {\n bytes.push(Number.parseInt(hex.slice(i, i + 2), 16))\n }\n return bytes\n}\n\n/**\n * UTF-8 字符串转字节数组\n *\n * 使用 TextEncoder 进行编码转换。\n *\n * @param str - UTF-8 字符串\n * @returns 字节数组\n */\nfunction stringToBytes(str: string): number[] {\n const encoder = new TextEncoder()\n return Array.from(encoder.encode(str))\n}\n","/**\n * @h-ai/crypto — SM4 对称加密\n *\n * 提供 SM4 对称加解密操作(CBC/ECB 模式)。\n * @module crypto-sm4\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { EncryptWithIVResult, SymmetricOperations, SymmetricOptions } from './crypto-types.js'\n\nimport { err, ok } from '@h-ai/core'\n// @ts-expect-error sm-crypto 无类型定义\nimport smCrypto from 'sm-crypto'\n\nimport { cryptoM } from './crypto-i18n.js'\nimport {\n\n HaiCryptoError,\n\n} from './crypto-types.js'\nimport { base64ToHex, hexToBase64, isBase64 } from './crypto-utils.js'\n\nconst { sm3, sm4 } = smCrypto\nconst SM4_HEX_32_REGEX = /^[0-9a-f]{32}$/i\n\n// ─── SM4 算法实现 ───\n\n/**\n * 创建 SM4 算法操作实例\n *\n * 基于 sm-crypto 库实现 SM4 对称加密/解密。\n * 支持 ECB(默认)和 CBC 两种模式,使用 PKCS#7 填充。\n * 密文支持 hex/base64 两种格式(解密时自动检测)。\n *\n * @returns SymmetricOperations 接口实现\n */\nexport function createSM4(): SymmetricOperations {\n return {\n /** 生成随机密钥(16 字节 = 32 个十六进制字符) */\n generateKey(): string {\n return generateRandomHex(16)\n },\n\n /** 生成随机 IV(16 字节 = 32 个十六进制字符) */\n generateIV(): string {\n return generateRandomHex(16)\n },\n\n /**\n * SM4 对称加密\n *\n * 支持 ECB(默认)和 CBC 两种模式,使用 PKCS#7 填充。\n * CBC 模式需提供合法 IV。\n *\n * ⚠️ 安全警告:**ECB 默认模式不安全**—相同明文块产生相同密文块,泄漏结构信息。\n * 生产场景请优先使用 `encryptWithIV()`(自动随机 IV 的 CBC)或显式传入\n * `{ mode: 'cbc', iv }`。ECB 模式仅保留兼容性,未来版本可能移除默认值。\n *\n * @param data - 待加密明文\n * @param key - 密钥(32 字符十六进制)\n * @param options - 加密模式/IV/输出格式\n * @returns 成功时返回密文;失败时返回 INVALID_KEY/INVALID_IV/ENCRYPTION_FAILED\n */\n encrypt(\n data: string,\n key: string,\n options: SymmetricOptions = {},\n ): HaiResult<string> {\n const {\n mode = 'ecb',\n iv,\n outputFormat = 'hex',\n } = options\n\n if (!this.isValidKey(key)) {\n return err(\n HaiCryptoError.INVALID_KEY,\n cryptoM('crypto_sm4KeyInvalid'),\n )\n }\n\n if (mode === 'cbc' && !iv) {\n return err(\n HaiCryptoError.INVALID_IV,\n cryptoM('crypto_sm4CbcNeedIv'),\n )\n }\n\n if (mode === 'cbc' && iv && !this.isValidIV(iv)) {\n return err(\n HaiCryptoError.INVALID_IV,\n cryptoM('crypto_sm4IvInvalid'),\n )\n }\n\n try {\n const sm4Options: Record<string, unknown> = {\n mode,\n padding: 'pkcs#7',\n }\n\n if (mode === 'cbc' && iv) {\n sm4Options.iv = iv\n }\n\n const encrypted = sm4.encrypt(data, key, sm4Options)\n\n if (!encrypted) {\n return err(\n HaiCryptoError.ENCRYPTION_FAILED,\n cryptoM('crypto_sm4EncryptEmpty'),\n )\n }\n\n if (outputFormat === 'base64') {\n return ok(hexToBase64(encrypted))\n }\n\n return ok(encrypted)\n }\n catch (error) {\n return err(\n HaiCryptoError.ENCRYPTION_FAILED,\n cryptoM('crypto_sm4EncryptFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n },\n\n /**\n * SM4 对称解密\n *\n * 自动检测 base64 格式输入并转换为 hex。\n * 解密模式和 IV 需与加密时一致。\n *\n * @param ciphertext - 密文(hex 或 base64)\n * @param key - 密钥(32 字符十六进制)\n * @param options - 解密模式/IV\n * @returns 成功时返回明文;失败时返回 INVALID_KEY/INVALID_IV/DECRYPTION_FAILED\n */\n decrypt(\n ciphertext: string,\n key: string,\n options: SymmetricOptions = {},\n ): HaiResult<string> {\n const { mode = 'ecb', iv } = options\n\n if (!this.isValidKey(key)) {\n return err(\n HaiCryptoError.INVALID_KEY,\n cryptoM('crypto_sm4KeyInvalid'),\n )\n }\n\n if (mode === 'cbc' && !iv) {\n return err(\n HaiCryptoError.INVALID_IV,\n cryptoM('crypto_sm4CbcNeedIv'),\n )\n }\n\n try {\n // 自动检测并转换 base64 格式\n let input = ciphertext\n if (isBase64(ciphertext)) {\n input = base64ToHex(ciphertext)\n }\n\n const sm4Options: Record<string, unknown> = {\n mode,\n padding: 'pkcs#7',\n }\n\n if (mode === 'cbc' && iv) {\n sm4Options.iv = iv\n }\n\n const decrypted = sm4.decrypt(input, key, sm4Options)\n\n if (decrypted === false || decrypted === null || decrypted === undefined) {\n return err(\n HaiCryptoError.DECRYPTION_FAILED,\n cryptoM('crypto_sm4DecryptFailed'),\n )\n }\n\n return ok(decrypted)\n }\n catch (error) {\n return err(\n HaiCryptoError.DECRYPTION_FAILED,\n cryptoM('crypto_sm4DecryptFailedWithError', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n },\n\n /**\n * 带 IV 加密(CBC 模式,自动生成随机 IV)\n *\n * @param data - 待加密明文\n * @param key - 密钥(32 字符十六进制)\n * @returns 成功时返回 { ciphertext, iv };失败时同 encrypt\n */\n encryptWithIV(\n data: string,\n key: string,\n ): HaiResult<EncryptWithIVResult> {\n const iv = this.generateIV()\n const result = this.encrypt(data, key, { mode: 'cbc', iv })\n\n if (!result.success) {\n return result\n }\n\n return ok({ ciphertext: result.data, iv })\n },\n\n /**\n * 带 IV 解密(CBC 模式)\n *\n * @param ciphertext - 密文\n * @param key - 密钥\n * @param iv - 加密时使用的 IV\n * @returns 成功时返回明文;失败时同 decrypt\n */\n decryptWithIV(\n ciphertext: string,\n key: string,\n iv: string,\n ): HaiResult<string> {\n return this.decrypt(ciphertext, key, { mode: 'cbc', iv })\n },\n\n /**\n * 从密码和盐值派生密钥\n *\n * 内部仅执行单次 SM3 哈希(password + salt),取前 32 字符作为密钥。\n *\n * ⚠️ 安全警告:**此实现不是标准 KDF**,不具备密码爆破抗性(无迭代、无内存硬化)。\n * - **禁止用于密码存储**:密码散列请用 `crypto.password.hash()`。\n * - **禁止用于高价值密钥派生**:如需从密码派生加密密钥,请在应用层自行实现 PBKDF2 / scrypt / Argon2。\n * - 仅适用于测试、迭代兼容或不敏感的场景。\n *\n * @deprecated 未来版本可能移除。密码散列请用 `crypto.password.hash`;密钥派生请使用标准 KDF。\n * @param password - 密码\n * @param salt - 盐值\n * @returns 32 字符十六进制密钥\n */\n deriveKey(password: string, salt: string): string {\n const combined = password + salt\n const hash = sm3(combined)\n // 取前 32 个十六进制字符(16 字节)\n return hash.slice(0, 32)\n },\n\n /** 校验密钥格式是否合法(32 字符十六进制) */\n isValidKey(key: string): boolean {\n return SM4_HEX_32_REGEX.test(key)\n },\n\n /** 校验 IV 格式是否合法(32 字符十六进制) */\n isValidIV(iv: string): boolean {\n return SM4_HEX_32_REGEX.test(iv)\n },\n }\n}\n\n// ─── 辅助函数 ───\n\n/**\n * 生成加密安全的随机十六进制字符串\n *\n * 使用 Web Crypto API(crypto.getRandomValues),前后端通用。\n *\n * @param byteLength - 字节数(输出字符数为 byteLength × 2)\n * @returns 小写十六进制字符串\n */\nfunction generateRandomHex(byteLength: number): string {\n const bytes = new Uint8Array(byteLength)\n // Web Crypto API,前后端通用\n crypto.getRandomValues(bytes)\n return Array.from(bytes)\n .map(b => b.toString(16).padStart(2, '0'))\n .join('')\n}\n","/**\n * @h-ai/crypto — 传输加密类型与协议常量\n *\n * 提供 SM2 + SM4(或等效非对称 + 对称)混合传输加密所需的接口与协议常量,\n * 由 kit / serv / api-client 共享,确保两端协议完全一致。\n *\n * @module crypto-transport-types\n */\n\nimport type { HaiResult } from '@h-ai/core'\n\n// ─── 协议常量(kit / serv / api-client 必须严格一致) ───\n\n/**\n * 传输加密协议常量。\n *\n * 所有使用端必须复用这组常量,避免「header 名拼写漂移导致两端协议错配」。\n */\nexport const TRANSPORT_PROTOCOL = {\n /** 客户端 ID 请求头名。 */\n CLIENT_ID_HEADER: 'X-Client-Id',\n /** 标识响应体已加密的响应头名。 */\n ENCRYPTED_HEADER: 'X-Encrypted',\n /** `X-Encrypted` 响应头的开启值。 */\n ENCRYPTED_HEADER_VALUE: 'true',\n /** 密钥协商端点的默认子路径(相对于挂载前缀)。 */\n DEFAULT_KEY_EXCHANGE_PATH: '/_hai/key-exchange',\n} as const\n\n/**\n * 密钥协商请求体(客户端 → 服务端)。\n */\nexport interface KeyExchangeRequest {\n readonly clientPublicKey: string\n}\n\n/**\n * 密钥协商响应体(服务端 → 客户端)。\n */\nexport interface KeyExchangeResponse {\n readonly serverPublicKey: string\n readonly clientId: string\n}\n\n// ─── 加解密载荷 ───\n\n/** 非对称密钥对。 */\nexport interface TransportKeyPair {\n publicKey: string\n privateKey: string\n}\n\n/**\n * 端到端传输的加密载荷格式。\n *\n * `encryptedKey` 用对端非对称公钥加密的对称会话密钥;`ciphertext` + `iv`\n * 为该会话密钥加密的明文。两端必须使用同一份字段命名。\n */\nexport interface EncryptedPayload {\n readonly encryptedKey: string\n readonly ciphertext: string\n readonly iv: string\n}\n\n// ─── 注入式服务接口 ───\n\n/**\n * 传输加密所需的非对称 + 对称能力子集。\n *\n * 不直接依赖 `@h-ai/crypto` 的具体实现,便于测试时注入 mock;\n * 实际使用时 `crypto` 模块的实例本身即可结构兼容。\n */\nexport interface TransportCryptoServiceLike {\n asymmetric: {\n generateKeyPair: () => HaiResult<TransportKeyPair>\n encrypt: (data: string, publicKey: string) => HaiResult<string>\n decrypt: (ciphertext: string, privateKey: string) => HaiResult<string>\n }\n symmetric: {\n generateKey: () => string\n encryptWithIV: (data: string, key: string) => HaiResult<{ ciphertext: string, iv: string }>\n decryptWithIV: (ciphertext: string, key: string, iv: string) => HaiResult<string>\n }\n}\n\n// ─── 客户端密钥存储(可插拔,支持分布式) ───\n\n/**\n * 客户端公钥存储抽象。\n *\n * 默认实现为进程内 Map({@link createInMemoryKeyStore}),多节点部署时建议\n * 接入 Redis / 数据库实现以保证跨节点一致性。\n *\n * 设计原则:方法均为异步签名,避免后续替换为分布式实现时大改接口;\n * 内存实现以 `Promise.resolve` 包裹即可。\n */\nexport interface TransportKeyStore {\n /** 注册新客户端,返回服务端生成的 `clientId`。 */\n register: (publicKey: string) => Promise<string>\n /** 查询已注册客户端公钥。 */\n get: (clientId: string) => Promise<string | undefined>\n /** 主动删除(可选,便于客户端登出时清理)。 */\n delete?: (clientId: string) => Promise<void>\n /** 释放底层资源(关闭连接、清理定时器等)。 */\n close?: () => Promise<void>\n}\n\n// ─── 管理器与客户端公开接口 ───\n\n/**\n * 服务端传输加密管理器。\n *\n * 由 {@link createTransportEncryption} 创建;负责服务端密钥对持有、客户端密钥\n * 注册与请求/响应的加解密。\n *\n * @remarks\n * 典型调用顺序:\n *\n * 1. `registerClientKey(clientPublicKey)`:在密钥协商端点中保存客户端公钥,并生成 `clientId`。\n * 2. `getServerPublicKey()`:把服务端公钥返回给客户端,供后续请求加密会话密钥。\n * 3. `decryptRequest(payload)`:普通业务请求进入业务逻辑前,先把密文请求体解成明文。\n * 4. `encryptResponse(clientId, data)`:业务处理完成后,按当前客户端公钥重新加密响应体。\n * 5. `close()`:服务关闭时释放底层 keyStore 资源。\n */\nexport interface TransportEncryptionManager {\n getServerPublicKey: () => string\n registerClientKey: (clientPublicKey: string) => Promise<string>\n getClientPublicKey: (clientId: string) => Promise<string | undefined>\n encryptResponse: (clientId: string, data: string) => Promise<HaiResult<EncryptedPayload>>\n decryptRequest: (payload: EncryptedPayload) => HaiResult<string>\n /** 关闭:释放 keyStore 资源。 */\n close: () => Promise<void>\n}\n\n/**\n * 客户端传输加密会话。\n *\n * 由 {@link createTransportClient} 创建;包装宿主 `fetch`,\n * 自动完成首次密钥协商并对后续请求自动加解密。\n *\n * @remarks\n * 典型调用顺序:\n *\n * 1. `init()`(可选):预先完成一次密钥协商。\n * 2. `encryptedFetch()`:业务请求统一走这里;若当前会话尚未 ready,会先自动执行 `init()`。\n * 3. `ready()`:查看当前会话是否已经拿到 `clientId` 与服务端公钥。\n * 4. `destroy()`:登出、切租户或切环境时清空会话;下一次请求会重新协商。\n */\nexport interface TransportClient {\n /**\n * 完成密钥协商;多次调用幂等(同一会话只协商一次)。\n *\n * 通常无需手动调用:`encryptedFetch` 在首次请求前会自动 `init()`。\n */\n init: () => Promise<HaiResult<void>>\n /** 包装后的 fetch;签名与全局 `fetch` 一致,请求/响应自动加解密。 */\n encryptedFetch: typeof fetch\n /** 是否已完成密钥协商。 */\n ready: () => boolean\n /** 销毁会话(清空客户端密钥)。 */\n destroy: () => void\n}\n","/**\n * @h-ai/crypto — 传输加密客户端实现\n *\n * 提供浏览器 / Node 环境下使用的 `encryptedFetch` 包装:\n * - 首次调用前自动与服务端做一次密钥协商;\n * - 之后所有出站请求自动以混合加密包裹;\n * - 标记为 `X-Encrypted: true` 的响应自动解密。\n *\n * 与服务端协议常量统一来自 {@link TRANSPORT_PROTOCOL},确保不漂移。\n *\n * @module crypto-transport-client\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type {\n EncryptedPayload,\n KeyExchangeResponse,\n TransportClient,\n TransportCryptoServiceLike,\n TransportKeyPair,\n} from './crypto-transport-types.js'\nimport { err, HaiCommonError, ok } from '@h-ai/core'\nimport { TRANSPORT_PROTOCOL } from './crypto-transport-types.js'\n\n/** {@link createTransportClient} 的配置项。 */\nexport interface CreateTransportClientOptions {\n /** 加密能力实现(通常直接传 `crypto` 实例)。 */\n crypto: TransportCryptoServiceLike\n /** 密钥协商完整 URL,例如 `https://api.example.com/_hai/key-exchange`。 */\n keyExchangeUrl: string\n /**\n * 实际发送 HTTP 请求的 fetch 实现;默认使用全局 `fetch`。\n *\n * 在测试中可注入 mock;在 Node < 18 环境中需注入 polyfill。\n */\n fetch?: typeof fetch\n}\n\n/**\n * 创建传输加密客户端。\n *\n * 返回的 `encryptedFetch` 与全局 `fetch` 同签名,可直接替换业务代码中的 `fetch`。\n * 内部首次请求前会自动完成密钥协商(线程安全;并发请求只触发一次协商)。\n *\n * @remarks\n * 内部流程:\n *\n * 1. `createTransportClient()` 只创建本地会话状态,不会立刻发起网络请求。\n * 2. 首次 `init()` / `encryptedFetch()` 会进入 `ensureReady()`;同一时刻只允许一个协商 Promise,避免并发重复协商。\n * 3. `doInit()` 会生成客户端非对称密钥对,并向 `keyExchangeUrl` POST `{ clientPublicKey }`。\n * 4. 服务端返回 `{ serverPublicKey, clientId }` 后,会话进入 ready 状态;后续请求复用这组协商结果。\n * 5. `encryptedFetch()` 对普通业务请求附加 `X-Client-Id`;只有请求存在 body 时,才会把 body 加密成 `{ encryptedKey, ciphertext, iv }`。\n * 6. 响应带 `X-Encrypted: true` 时自动解密;不带该标记时直接透传,便于与未启用 transport 的接口共存。\n */\nexport function createTransportClient(options: CreateTransportClientOptions): TransportClient {\n const baseFetch = options.fetch ?? fetch\n let keyPair: TransportKeyPair | null = null\n let serverPublicKey: string | null = null\n let clientId: string | null = null\n /** 进行中的协商 Promise;用于并发去重。 */\n let initPromise: Promise<HaiResult<void>> | null = null\n\n async function doInit(): Promise<HaiResult<void>> {\n const kpResult = options.crypto.asymmetric.generateKeyPair()\n if (!kpResult.success)\n return err(HaiCommonError.INTERNAL_ERROR, 'Failed to generate client key pair', kpResult.error)\n const localKeyPair = kpResult.data\n\n let response: Response\n try {\n response = await baseFetch(options.keyExchangeUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ clientPublicKey: localKeyPair.publicKey }),\n })\n }\n catch (cause) {\n return err(HaiCommonError.INTERNAL_ERROR, 'Key exchange request failed', cause)\n }\n\n if (!response.ok)\n return err(HaiCommonError.INTERNAL_ERROR, `Key exchange returned HTTP ${response.status}`)\n\n let body: KeyExchangeResponse\n try {\n body = await response.json() as KeyExchangeResponse\n }\n catch (cause) {\n return err(HaiCommonError.INTERNAL_ERROR, 'Key exchange response is not valid JSON', cause)\n }\n if (!body.serverPublicKey || !body.clientId)\n return err(HaiCommonError.INTERNAL_ERROR, 'Key exchange response missing fields')\n\n keyPair = localKeyPair\n serverPublicKey = body.serverPublicKey\n clientId = body.clientId\n return ok(undefined)\n }\n\n async function ensureReady(): Promise<HaiResult<void>> {\n if (clientId && serverPublicKey)\n return ok(undefined)\n if (!initPromise) {\n initPromise = doInit().then((result) => {\n // 失败时清空 promise,允许下次重试;成功时保留即可。\n if (!result.success)\n initPromise = null\n return result\n })\n }\n return initPromise\n }\n\n function encryptBody(plaintext: string): HaiResult<EncryptedPayload> {\n if (!serverPublicKey)\n return err(HaiCommonError.INTERNAL_ERROR, 'Transport client not initialized')\n const symKey = options.crypto.symmetric.generateKey()\n const encResult = options.crypto.symmetric.encryptWithIV(plaintext, symKey)\n if (!encResult.success)\n return err(HaiCommonError.INTERNAL_ERROR, 'Failed to encrypt request body', encResult.error)\n const keyEncResult = options.crypto.asymmetric.encrypt(symKey, serverPublicKey)\n if (!keyEncResult.success)\n return err(HaiCommonError.INTERNAL_ERROR, 'Failed to encrypt session key', keyEncResult.error)\n return ok({\n encryptedKey: keyEncResult.data,\n ciphertext: encResult.data.ciphertext,\n iv: encResult.data.iv,\n })\n }\n\n function decryptPayload(payload: EncryptedPayload): HaiResult<string> {\n if (!keyPair)\n return err(HaiCommonError.INTERNAL_ERROR, 'Transport client not initialized')\n const keyDec = options.crypto.asymmetric.decrypt(payload.encryptedKey, keyPair.privateKey)\n if (!keyDec.success)\n return err(HaiCommonError.INTERNAL_ERROR, 'Failed to decrypt session key', keyDec.error)\n const dec = options.crypto.symmetric.decryptWithIV(payload.ciphertext, keyDec.data, payload.iv)\n if (!dec.success)\n return err(HaiCommonError.INTERNAL_ERROR, 'Failed to decrypt response body', dec.error)\n return ok(dec.data)\n }\n\n const encryptedFetch: typeof fetch = async (input, init) => {\n const requestInput = isRequestLike(input) ? input : undefined\n // 密钥协商请求本身不加密,避免无限递归。\n const targetUrl = typeof input === 'string'\n ? input\n : input instanceof URL\n ? input.toString()\n : requestInput?.url ?? String(input)\n if (targetUrl === options.keyExchangeUrl)\n return baseFetch(input, init)\n\n const ready = await ensureReady()\n if (!ready.success)\n throw new Error(ready.error.message)\n\n // 复制并改造 init:附加 X-Client-Id;若有 body,则加密。\n const headers = new Headers(init?.headers ?? requestInput?.headers)\n headers.set(TRANSPORT_PROTOCOL.CLIENT_ID_HEADER, clientId!)\n\n // 兼容 oRPC 等场景:body 可能在 Request 上而非 init.body。\n let rawBody: BodyInit | null | undefined = init?.body\n if (rawBody == null && requestInput) {\n const method = (init?.method ?? requestInput.method).toUpperCase()\n if (method !== 'GET' && method !== 'HEAD') {\n const text = await requestInput.clone().text()\n if (text)\n rawBody = text\n }\n }\n\n let nextBody: BodyInit | null | undefined = rawBody\n if (rawBody != null) {\n const plaintext = await bodyToText(rawBody)\n const encResult = encryptBody(plaintext)\n if (!encResult.success)\n throw new Error(encResult.error.message)\n nextBody = JSON.stringify(encResult.data)\n headers.set('Content-Type', 'application/json')\n headers.set(TRANSPORT_PROTOCOL.ENCRYPTED_HEADER, TRANSPORT_PROTOCOL.ENCRYPTED_HEADER_VALUE)\n }\n\n // 当 input 是已带 body 的 Request 时,必须改用 URL 字符串作为 input,\n // 否则底层 fetch 会优先读取原始 Request 上的明文 body,覆盖我们的密文。\n const finalInput: RequestInfo | URL = requestInput ? requestInput.url : input\n const finalInit: RequestInit = {\n ...init,\n method: init?.method ?? requestInput?.method,\n headers,\n body: nextBody,\n cache: init?.cache ?? requestInput?.cache,\n credentials: init?.credentials ?? requestInput?.credentials,\n integrity: init?.integrity ?? requestInput?.integrity,\n keepalive: init?.keepalive ?? requestInput?.keepalive,\n mode: init?.mode ?? requestInput?.mode,\n redirect: init?.redirect ?? requestInput?.redirect,\n referrer: init?.referrer ?? requestInput?.referrer,\n referrerPolicy: init?.referrerPolicy ?? requestInput?.referrerPolicy,\n signal: init?.signal ?? requestInput?.signal,\n }\n const response = await baseFetch(finalInput, finalInit)\n\n // 响应未加密:直接返回。\n if (response.headers.get(TRANSPORT_PROTOCOL.ENCRYPTED_HEADER) !== TRANSPORT_PROTOCOL.ENCRYPTED_HEADER_VALUE)\n return response\n\n const cloned = response.clone()\n let payload: unknown\n try {\n payload = await cloned.json()\n }\n catch {\n return response\n }\n if (!isEncryptedPayload(payload))\n return response\n\n const decResult = decryptPayload(payload)\n if (!decResult.success)\n throw new Error(decResult.error.message)\n\n // 透传原响应头但去掉加密标记;Content-Type 还原为下游可能期望的 JSON。\n const respHeaders = new Headers(response.headers)\n respHeaders.delete(TRANSPORT_PROTOCOL.ENCRYPTED_HEADER)\n respHeaders.delete('Content-Length')\n return new Response(decResult.data, {\n status: response.status,\n statusText: response.statusText,\n headers: respHeaders,\n })\n }\n\n return {\n init: ensureReady,\n encryptedFetch,\n ready: () => clientId !== null && serverPublicKey !== null,\n destroy() {\n keyPair = null\n serverPublicKey = null\n clientId = null\n initPromise = null\n },\n }\n}\n\n/** 把任意 `BodyInit` 转为字符串明文,便于统一加密。 */\nasync function bodyToText(body: BodyInit): Promise<string> {\n if (typeof body === 'string')\n return body\n if (body instanceof URLSearchParams)\n return body.toString()\n if (body instanceof Blob)\n return body.text()\n if (body instanceof ArrayBuffer)\n return new TextDecoder().decode(body)\n if (ArrayBuffer.isView(body))\n return new TextDecoder().decode(body.buffer as ArrayBuffer)\n // FormData / ReadableStream:转为 Response 再读 text,由运行时序列化。\n return new Response(body as BodyInit).text()\n}\n\nfunction isRequestLike(input: RequestInfo | URL): input is Request {\n if (typeof input !== 'object' || input === null)\n return false\n\n const candidate = input as Partial<Request>\n const headers = candidate.headers as { get?: unknown } | undefined\n return typeof candidate.url === 'string'\n && typeof headers?.get === 'function'\n && typeof candidate.method === 'string'\n && typeof candidate.clone === 'function'\n}\n\nfunction isEncryptedPayload(payload: unknown): payload is EncryptedPayload {\n if (!payload || typeof payload !== 'object')\n return false\n const p = payload as Record<string, unknown>\n return typeof p.encryptedKey === 'string' && typeof p.ciphertext === 'string' && typeof p.iv === 'string'\n}\n","/**\n * @h-ai/crypto — 传输加密服务端实现\n *\n * 提供:\n * - {@link createInMemoryKeyStore}:默认内存版 {@link TransportKeyStore}(含 LRU 淘汰)。\n * - {@link createTransportEncryption}:服务端管理器工厂。\n *\n * @module crypto-transport-server\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type {\n EncryptedPayload,\n TransportCryptoServiceLike,\n TransportEncryptionManager,\n TransportKeyPair,\n TransportKeyStore,\n} from './crypto-transport-types.js'\nimport { err, HaiCommonError, ok } from '@h-ai/core'\n\n/**\n * 创建进程内 LRU 客户端密钥存储。\n *\n * ⚠️ 进程内实现:多节点部署时需让客户端首次请求后保持「会话粘性」(sticky session),\n * 否则后续请求路由到其他节点会因找不到客户端公钥而失败。需要跨节点请改用\n * Redis / 数据库实现 {@link TransportKeyStore}。\n *\n * @param maxClients - 最大客户端数(默认 10000),超过后按注册顺序淘汰最早条目。\n */\nexport function createInMemoryKeyStore(maxClients = 10000): TransportKeyStore {\n const clientKeys = new Map<string, string>()\n let counter = 0\n return {\n async register(publicKey) {\n counter++\n const clientId = `c_${counter}_${Date.now()}`\n if (clientKeys.size >= maxClients) {\n const oldest = clientKeys.keys().next().value\n if (oldest !== undefined)\n clientKeys.delete(oldest)\n }\n clientKeys.set(clientId, publicKey)\n return clientId\n },\n async get(clientId) {\n return clientKeys.get(clientId)\n },\n async delete(clientId) {\n clientKeys.delete(clientId)\n },\n async close() {\n clientKeys.clear()\n },\n }\n}\n\n/** {@link createTransportEncryption} 的配置项。 */\nexport interface CreateTransportEncryptionOptions {\n /**\n * 客户端公钥存储;默认使用 {@link createInMemoryKeyStore}。\n *\n * 多节点部署时通过此项注入 Redis 等共享存储以保证跨节点一致。\n */\n keyStore?: TransportKeyStore\n /** 默认内存 keyStore 的最大容量(仅当 `keyStore` 未提供时生效)。 */\n maxClients?: number\n}\n\n/**\n * 创建传输加密管理器。\n *\n * 启动时生成服务端非对称密钥对,所有客户端公钥由 `keyStore` 管理。\n *\n * @param cryptoService - 注入的非对称 + 对称加密实现(通常直接传入 `crypto` 实例)。\n * @param options - 可选配置。\n * @returns 成功返回管理器;密钥对生成失败返回 `HaiCommonError.INTERNAL_ERROR`。\n *\n * @remarks\n * 内部流程:\n *\n * 1. 创建时先生成一对服务端非对称密钥,并准备 `keyStore`。\n * 2. 上层在密钥协商端点中调用 `registerClientKey()` 保存客户端公钥,再把 `getServerPublicKey()` 返回给客户端。\n * 3. 普通业务请求到达时,上层先根据 `clientId` 确认客户端已注册,再调用 `decryptRequest()` 拿到明文请求体。\n * 4. 业务逻辑完成后,上层调用 `encryptResponse(clientId, data)` 为该客户端生成密文响应。\n * 5. `close()` 负责清理 `keyStore` 等底层资源。\n *\n * 若使用 `@h-ai/serv` / `@h-ai/kit`,上述 HTTP 协商与请求包装流程通常已由上层封装完成。\n */\nexport function createTransportEncryption(\n cryptoService: TransportCryptoServiceLike,\n options: CreateTransportEncryptionOptions = {},\n): HaiResult<TransportEncryptionManager> {\n const keyPairResult = cryptoService.asymmetric.generateKeyPair()\n if (!keyPairResult.success)\n return err(HaiCommonError.INTERNAL_ERROR, 'Failed to generate transport key pair', keyPairResult.error)\n const serverKeyPair: TransportKeyPair = keyPairResult.data\n const keyStore = options.keyStore ?? createInMemoryKeyStore(options.maxClients)\n\n const manager: TransportEncryptionManager = {\n getServerPublicKey() {\n return serverKeyPair.publicKey\n },\n\n async registerClientKey(clientPublicKey) {\n return keyStore.register(clientPublicKey)\n },\n\n async getClientPublicKey(clientId) {\n return keyStore.get(clientId)\n },\n\n async encryptResponse(clientId, data) {\n const clientPublicKey = await keyStore.get(clientId)\n if (!clientPublicKey)\n return err(HaiCommonError.NOT_FOUND, `Unknown transport client: ${clientId}`)\n\n // 1. 生成随机会话密钥;2. 用会话密钥加密内容;3. 用客户端公钥加密会话密钥。\n const symmetricKey = cryptoService.symmetric.generateKey()\n const encResult = cryptoService.symmetric.encryptWithIV(data, symmetricKey)\n if (!encResult.success)\n return err(HaiCommonError.INTERNAL_ERROR, 'Failed to encrypt response payload', encResult.error)\n const keyEncResult = cryptoService.asymmetric.encrypt(symmetricKey, clientPublicKey)\n if (!keyEncResult.success)\n return err(HaiCommonError.INTERNAL_ERROR, 'Failed to encrypt session key', keyEncResult.error)\n\n const payload: EncryptedPayload = {\n encryptedKey: keyEncResult.data,\n ciphertext: encResult.data.ciphertext,\n iv: encResult.data.iv,\n }\n return ok(payload)\n },\n\n decryptRequest(payload) {\n // 1. 用服务端私钥解出会话密钥;2. 用会话密钥解出明文。\n const keyDecResult = cryptoService.asymmetric.decrypt(payload.encryptedKey, serverKeyPair.privateKey)\n if (!keyDecResult.success)\n return err(HaiCommonError.INTERNAL_ERROR, 'Failed to decrypt session key', keyDecResult.error)\n const decResult = cryptoService.symmetric.decryptWithIV(payload.ciphertext, keyDecResult.data, payload.iv)\n if (!decResult.success)\n return err(HaiCommonError.INTERNAL_ERROR, 'Failed to decrypt request payload', decResult.error)\n return ok(decResult.data)\n },\n\n async close() {\n await keyStore.close?.()\n },\n }\n\n return ok(manager)\n}\n\n/**\n * 判断对象是否为合法 {@link EncryptedPayload}。\n *\n * 字段必须为非空字符串。用于服务端在调用 `decryptRequest` 前做形状校验,\n * 把畸形请求拦截在加密层之外。\n */\nexport function isValidEncryptedPayload(payload: unknown): payload is EncryptedPayload {\n if (!payload || typeof payload !== 'object')\n return false\n const p = payload as Record<string, unknown>\n return (\n typeof p.encryptedKey === 'string' && p.encryptedKey.length > 0\n && typeof p.ciphertext === 'string' && p.ciphertext.length > 0\n && typeof p.iv === 'string' && p.iv.length > 0\n )\n}\n","/**\n * @h-ai/crypto — 加密服务主入口\n *\n * 提供统一的 `crypto` 对象,聚合所有结构化加密操作。\n * @module crypto-main\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { AsymmetricOperations, CryptoFunctions, HashOperations, PasswordOperations, SymmetricOperations, TransportOperations } from './crypto-types.js'\n\nimport { core, err, ok } from '@h-ai/core'\n\nimport { cryptoM } from './crypto-i18n.js'\nimport { createPasswordFunctions } from './crypto-password.js'\nimport { createSM2 } from './crypto-sm2.js'\nimport { createSM3 } from './crypto-sm3.js'\nimport { createSM4 } from './crypto-sm4.js'\nimport {\n\n HaiCryptoError,\n\n} from './crypto-types.js'\nimport { createTransportClient } from './transport/crypto-transport-client.js'\nimport { createTransportEncryption } from './transport/crypto-transport-server.js'\nimport { TRANSPORT_PROTOCOL } from './transport/crypto-transport-types.js'\n\nconst logger = core.logger.child({ module: 'crypto', scope: 'main' })\n\n// ─── 内部状态 ───\n\n/** 是否已初始化 */\nlet initialized = false\n/** 并发初始化防护标志 */\nlet initInProgress = false\n/** 当前非对称加密操作实例 */\nlet currentAsymmetric: AsymmetricOperations | null = null\n/** 当前哈希操作实例 */\nlet currentHash: HashOperations | null = null\n/** 当前对称加密操作实例 */\nlet currentSymmetric: SymmetricOperations | null = null\n/** 当前密码哈希操作实例 */\nlet currentPassword: PasswordOperations | null = null\n\n// ─── 未初始化占位 ───\n\nconst notInitialized = core.module.createNotInitializedKit(\n HaiCryptoError.NOT_INITIALIZED,\n () => cryptoM('crypto_notInitialized'),\n)\n\nconst notInitializedAsymmetric = notInitialized.proxy<AsymmetricOperations>('sync')\nconst notInitializedHash = notInitialized.proxy<HashOperations>('sync')\nconst notInitializedSymmetric = notInitialized.proxy<SymmetricOperations>('sync')\nconst notInitializedPassword = notInitialized.proxy<PasswordOperations>('sync')\n\n// ─── 传输加密 ───\n// 直接复用顶层 `crypto`:未初始化时 asymmetric/symmetric 会自动返回\n// NOT_INITIALIZED 错误,无需额外 proxy。\n\n// 通过函数声明(hoisted)延迟引用 `crypto`,避免 use-before-define 报错;\n// 实际调用发生在 init 之后,闭包持有的引用是安全的。\nfunction getCrypto(): CryptoFunctions {\n // eslint-disable-next-line ts/no-use-before-define\n return crypto\n}\nconst transportOperations: TransportOperations = {\n createServer: options => createTransportEncryption(getCrypto(), options),\n createClient: options => createTransportClient({ crypto: getCrypto(), ...options }),\n protocol: TRANSPORT_PROTOCOL,\n}\n\n// ─── 服务对象 ───\n\n/**\n * 加密模块服务对象(统一入口)\n *\n * 使用前必须调用 `crypto.init()` 进行初始化。\n * 未初始化时访问 asymmetric/hash/symmetric/password 的任何方法均返回 NOT_INITIALIZED 错误。\n *\n * @example\n * ```ts\n * import { crypto } from '@h-ai/crypto'\n *\n * await crypto.init()\n * const hash = crypto.hash.hash('hello')\n * const keyPair = crypto.asymmetric.generateKeyPair()\n * await crypto.close()\n * ```\n */\nexport const crypto: CryptoFunctions = {\n /**\n * 初始化加密模块\n *\n * 创建非对称/哈希/对称/密码哈希操作实例。\n * 重复调用会先关闭再重新初始化。\n *\n * @returns 成功时返回 ok(undefined);失败时返回 INIT_FAILED\n */\n async init(): Promise<HaiResult<void>> {\n // 并发初始化防护:避免多次 init 同时执行导致资源泄漏\n if (initInProgress) {\n logger.warn('Crypto init already in progress, skipping concurrent call')\n return err(\n HaiCryptoError.INIT_FAILED,\n cryptoM('crypto_initFailed', { params: { error: 'Concurrent initialization detected' } }),\n )\n }\n initInProgress = true\n\n try {\n if (initialized) {\n logger.warn('Crypto module is already initialized, reinitializing')\n await crypto.close()\n }\n\n logger.info('Initializing crypto module')\n\n currentAsymmetric = createSM2()\n currentHash = createSM3()\n currentSymmetric = createSM4()\n currentPassword = createPasswordFunctions({ hash: currentHash })\n initialized = true\n logger.info('Crypto module initialized')\n return ok(undefined)\n }\n catch (error) {\n // 清理部分赋值的状态\n currentAsymmetric = null\n currentHash = null\n currentSymmetric = null\n currentPassword = null\n initialized = false\n logger.error('Crypto module initialization failed', { error })\n return err(\n HaiCryptoError.INIT_FAILED,\n cryptoM('crypto_initFailed', {\n params: { error: error instanceof Error ? error.message : String(error) },\n }),\n error,\n )\n }\n finally {\n initInProgress = false\n }\n },\n\n /** 非对称加密操作(未初始化时所有方法返回 NOT_INITIALIZED) */\n get asymmetric(): AsymmetricOperations { return currentAsymmetric ?? notInitializedAsymmetric },\n /** 哈希操作(未初始化时所有方法返回 NOT_INITIALIZED) */\n get hash(): HashOperations { return currentHash ?? notInitializedHash },\n /** 对称加密操作(未初始化时所有方法返回 NOT_INITIALIZED) */\n get symmetric(): SymmetricOperations { return currentSymmetric ?? notInitializedSymmetric },\n /** 密码哈希操作(未初始化时所有方法返回 NOT_INITIALIZED) */\n get password(): PasswordOperations { return currentPassword ?? notInitializedPassword },\n /**\n * 传输加密操作(端到端混合加密)\n *\n * createServer 内部直接复用 asymmetric/symmetric,因此未初始化时\n * 自动通过 asymmetric proxy 返回 NOT_INITIALIZED 错误。\n */\n transport: transportOperations,\n /** 是否已初始化 */\n get isInitialized() { return initialized },\n\n /**\n * 关闭加密模块,释放内部状态\n *\n * 关闭后访问 asymmetric/hash/symmetric/password 会返回 NOT_INITIALIZED 错误。\n */\n async close() {\n if (!initialized) {\n logger.info('Crypto module already closed, skipping')\n return\n }\n\n logger.info('Closing crypto module')\n\n currentAsymmetric = null\n currentHash = null\n currentSymmetric = null\n currentPassword = null\n initialized = false\n\n logger.info('Crypto module closed')\n },\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@h-ai/crypto",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.0-alpha.
|
|
4
|
+
"version": "0.1.0-alpha.16",
|
|
5
5
|
"description": "Hai Framework cryptography module (asymmetric, symmetric, and hash).",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"exports": {
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"sm-crypto": "^0.4.0",
|
|
24
|
-
"@h-ai/core": "0.1.0-alpha.
|
|
24
|
+
"@h-ai/core": "0.1.0-alpha.16"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/node": "^25.1.0",
|