secure-crypto-top-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +238 -0
- package/dist/base-v1-7dHNy.d.mts +183 -0
- package/dist/base-v1-7dHNy.d.ts +183 -0
- package/dist/client.d.mts +72 -0
- package/dist/client.d.ts +72 -0
- package/dist/client.js +1436 -0
- package/dist/client.js.map +1 -0
- package/dist/client.mjs +1406 -0
- package/dist/client.mjs.map +1 -0
- package/dist/index.d.mts +162 -0
- package/dist/index.d.ts +162 -0
- package/dist/index.js +1393 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1335 -0
- package/dist/index.mjs.map +1 -0
- package/dist/key-store-BCmOK04m.d.ts +49 -0
- package/dist/key-store-BF0_3do0.d.mts +49 -0
- package/dist/server.d.mts +60 -0
- package/dist/server.d.ts +60 -0
- package/dist/server.js +1369 -0
- package/dist/server.js.map +1 -0
- package/dist/server.mjs +1338 -0
- package/dist/server.mjs.map +1 -0
- package/package.json +70 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Atengliyun
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# 🔐 secure-crypto-top-sdk
|
|
2
|
+
|
|
3
|
+
> **可插拔多算法 + 多协议(自定义 / TOP 风格)端到端加密 SDK**
|
|
4
|
+
> AES-GCM/CBC · SM4 · SM3 · HMAC · RSA-OAEP 混合加密 · Fastify 集成
|
|
5
|
+
|
|
6
|
+
[](https://www.npmjs.com/package/secure-crypto-top-sdk)
|
|
7
|
+
[](./LICENSE)
|
|
8
|
+
|
|
9
|
+
## ✨ 特性
|
|
10
|
+
|
|
11
|
+
| 能力 | 说明 |
|
|
12
|
+
|---|---|
|
|
13
|
+
| **多算法可插拔** | `aes-256-gcm`、`aes-256-cbc`、`aes-128-cbc`、`sm4-cbc`、`rsa-oaep-aes-256-gcm` |
|
|
14
|
+
| **多签名算法** | `hmac-sha256`、`hmac-sha512`、`md5`、`sha256`、`sm3` |
|
|
15
|
+
| **多协议并存** | `custom`(自家信封) + `top`(TOP 风格,白名单排序 + biz_content 整体加密) |
|
|
16
|
+
| **多 App 注册** | 一个服务端可托管多个 app,每个 app 独立密钥 / 独立算法白名单 |
|
|
17
|
+
| **混合加密** | RSA-OAEP 包装 AES-256-GCM 临时密钥 → 前向安全 |
|
|
18
|
+
| **Fastify 插件** | 一行 `app.register(...)` 启用端到端加密网关 |
|
|
19
|
+
| **浏览器 SDK** | 同一份协议,浏览器 / Node / Fastify 互通 |
|
|
20
|
+
| **零外部依赖** | 算法层全部纯 Node `crypto` / 纯 JS(SM3、SM4)实现,体积小 |
|
|
21
|
+
|
|
22
|
+
## 📦 安装
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install secure-crypto-top-sdk
|
|
26
|
+
# 或
|
|
27
|
+
pnpm add secure-crypto-top-sdk
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 🚀 快速开始
|
|
31
|
+
|
|
32
|
+
### 1. Node.js 端:多协议 / 多算法(独立工具)
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { buildProtocolRequest, parseAndVerifyProtocol, buildProtocolResponse } from 'secure-crypto-top-sdk';
|
|
36
|
+
|
|
37
|
+
const apps = [{ appKey: 'demo-app', appSecret: 'my-secret-1234567890' }];
|
|
38
|
+
|
|
39
|
+
// 客户端构造请求(TOP 协议 + AES-256-GCM + HMAC-SHA256)
|
|
40
|
+
const env = await buildProtocolRequest(
|
|
41
|
+
{
|
|
42
|
+
method: 'POST',
|
|
43
|
+
path: 'user.login',
|
|
44
|
+
biz: { username: 'alice', password: 'p@ss' },
|
|
45
|
+
cipher: 'aes-256-gcm',
|
|
46
|
+
digest: 'hmac-sha256',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
appKey: 'demo-app',
|
|
50
|
+
appSecret: 'my-secret-1234567890',
|
|
51
|
+
encryptionKey: Buffer.alloc(32, 1), // 32 字节对称密钥
|
|
52
|
+
hmacSecret: 'my-secret-1234567890',
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
// 服务端解析 + 验签
|
|
57
|
+
const verified = await parseAndVerifyProtocol(env, { apps });
|
|
58
|
+
console.log(verified.biz); // { username: 'alice', password: 'p@ss' }
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
切换到 **国密 SM4 + SM3**:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
const env = await buildProtocolRequest(
|
|
65
|
+
{ method: 'POST', path: 'user.pay', biz: { orderId: 'O1' }, cipher: 'sm4-cbc', digest: 'sm3' },
|
|
66
|
+
{ appKey: 'demo-app', appSecret: 'my-secret', encryptionKey: Buffer.alloc(16, 1), hmacSecret: 'my-secret' }
|
|
67
|
+
);
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
切换到 **custom 协议**(兼容老 secure-crypto-sdk):
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
const env = await buildProtocolRequest(
|
|
74
|
+
{ method: 'POST', path: '/api/v1/echo', body: { foo: 'bar' }, protocol: 'custom' },
|
|
75
|
+
{ appKey: 'demo-app', appSecret: 'my-secret', encryptionKey: Buffer.alloc(32, 1), hmacSecret: 'my-secret' }
|
|
76
|
+
);
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 2. Fastify 网关(推荐)
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
import Fastify from 'fastify';
|
|
83
|
+
import secureCryptoPlugin from 'secure-crypto-top-sdk/server';
|
|
84
|
+
|
|
85
|
+
const app = Fastify({ logger: true });
|
|
86
|
+
|
|
87
|
+
await app.register(secureCryptoPlugin, {
|
|
88
|
+
apps: [
|
|
89
|
+
{
|
|
90
|
+
appKey: 'demo-app',
|
|
91
|
+
appSecret: 'demo-secret-1234567890',
|
|
92
|
+
allowedCiphers: ['aes-256-gcm', 'sm4-cbc'], // 限制可用加密算法
|
|
93
|
+
allowedDigests: ['hmac-sha256', 'sm3'], // 限制可用签名算法
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
appKey: 'legacy',
|
|
97
|
+
appSecret: 'legacy-secret',
|
|
98
|
+
allowedCiphers: ['aes-256-cbc'], // 老接口:仅 CBC
|
|
99
|
+
allowedDigests: ['md5'],
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
defaultProtocol: 'top',
|
|
103
|
+
bypassPaths: ['/health', '/docs'],
|
|
104
|
+
// redis: redisClient, // 可选:nonce 防重放
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
app.post('/api/v1/top/login', async (req) => {
|
|
108
|
+
// 业务 handler 里直接读明文
|
|
109
|
+
const { username, password } = req.body as any;
|
|
110
|
+
// ...
|
|
111
|
+
return { success: true, userId: 1 };
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### 3. 浏览器端
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
import { SecureClient } from 'secure-crypto-top-sdk/client';
|
|
119
|
+
|
|
120
|
+
const client = new SecureClient({
|
|
121
|
+
baseURL: 'https://api.example.com',
|
|
122
|
+
encryptionKey: 'a1b2c3...64字符hex', // 32 字节 hex
|
|
123
|
+
hmacSecret: 'my-hmac-secret-1234567890', // >= 32 字符
|
|
124
|
+
appKey: 'demo-app',
|
|
125
|
+
protocol: 'top', // 默认 'top'
|
|
126
|
+
cipher: 'aes-256-gcm',
|
|
127
|
+
digest: 'hmac-sha256',
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const data = await client.post('/api/v1/top/login', { username: 'alice', password: 'p@ss' });
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## 🔄 协议格式
|
|
134
|
+
|
|
135
|
+
### TOP 风格(默认)
|
|
136
|
+
|
|
137
|
+
```jsonc
|
|
138
|
+
{
|
|
139
|
+
"protocol": "top",
|
|
140
|
+
"method": "user.login", // API 名
|
|
141
|
+
"app_key": "demo-app",
|
|
142
|
+
"timestamp": 1718000000000,
|
|
143
|
+
"v": "2.0",
|
|
144
|
+
"sign_method": "hmac-sha256", // 或 sm3 / hmac-sha512
|
|
145
|
+
"cipher": "aes-256-gcm", // 或 aes-256-cbc / sm4-cbc
|
|
146
|
+
"biz_content": "<base64密文>", // 业务参数整体加密后 base64
|
|
147
|
+
"iv": "<base64>",
|
|
148
|
+
"authTag": "<base64>", // GCM 才有
|
|
149
|
+
"sign": "<hex 签名>"
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**签名拼接规则:**
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
signSource = sortedBizParams(biz + systemParams) + appSecret + biz_content
|
|
157
|
+
sign = digest(signSource, appSecret)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
> 不同厂商的"加 secret"位置(头/尾/不参与)略有差异,可修改 `src/protocol/top/signer.ts` 适配。
|
|
161
|
+
|
|
162
|
+
### Custom 风格(兼容旧 SDK)
|
|
163
|
+
|
|
164
|
+
```jsonc
|
|
165
|
+
{
|
|
166
|
+
"protocol": "custom",
|
|
167
|
+
"encryptedPayload": "<base64 整包密文>", // 加密 {path, method, body, query}
|
|
168
|
+
"iv": "<base64>",
|
|
169
|
+
"authTag": "<base64>",
|
|
170
|
+
"signature": "<hex>",
|
|
171
|
+
"timestamp": 1718000000000,
|
|
172
|
+
"nonce": "<uuid>"
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
签名:`timestamp + nonce + encrypted + iv + authTag`
|
|
177
|
+
|
|
178
|
+
## 🔌 扩展新算法
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
// 1. 实现 Cipher 接口
|
|
182
|
+
import type { Cipher, CipherMeta } from 'secure-crypto-top-sdk';
|
|
183
|
+
|
|
184
|
+
const meta: CipherMeta = { name: 'chacha20-poly1305', keyLength: 32, ivLength: 12, hasAuthTag: true, blockSize: 1 };
|
|
185
|
+
const myCipher: Cipher = { name: 'chacha20-poly1305', meta, /* ... */ };
|
|
186
|
+
|
|
187
|
+
// 2. 注册
|
|
188
|
+
import { cipherRegistry } from 'secure-crypto-top-sdk';
|
|
189
|
+
cipherRegistry.set('chacha20-poly1305', myCipher);
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## 🧪 测试
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
pnpm test # vitest
|
|
196
|
+
pnpm demo:server # 启动 demo 服务
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## 📁 目录结构
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
secure-crypto-top-sdk/
|
|
203
|
+
├── src/
|
|
204
|
+
│ ├── algorithms/
|
|
205
|
+
│ │ ├── cipher/ # AES-GCM/CBC、SM4、RSA-OAEP 混合
|
|
206
|
+
│ │ ├── digest/ # HMAC、MD5/SHA、SM3
|
|
207
|
+
│ │ ├── registry.ts # 算法注册表
|
|
208
|
+
│ │ └── types.ts
|
|
209
|
+
│ ├── protocol/
|
|
210
|
+
│ │ ├── custom/ # 自家协议
|
|
211
|
+
│ │ ├── top/ # TOP 风格协议
|
|
212
|
+
│ │ ├── base.ts # ProtocolStrategy 接口
|
|
213
|
+
│ │ └── registry.ts
|
|
214
|
+
│ ├── config/ # AppRegistry / KeyStore
|
|
215
|
+
│ ├── client/ # 浏览器 SecureClient
|
|
216
|
+
│ ├── server/ # Fastify 插件 + 独立工具
|
|
217
|
+
│ ├── types/
|
|
218
|
+
│ ├── errors/
|
|
219
|
+
│ └── index.ts
|
|
220
|
+
├── demo/ # demo-server.ts / demo-client.ts
|
|
221
|
+
├── tests/ # vitest
|
|
222
|
+
├── package.json
|
|
223
|
+
├── tsconfig.json
|
|
224
|
+
└── tsup.config.ts
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## 🔒 安全建议
|
|
228
|
+
|
|
229
|
+
1. **生产环境**:`KeyStore.setHex` 显式注入密钥,**不要**用 `deriveFromApp`(它从 appSecret 派生对称密钥,弱于独立密钥)。
|
|
230
|
+
2. **MD5 / SHA-256 摘要**:仅用于兼容老接口,默认应在 `allowedDigests` 中显式开启。
|
|
231
|
+
3. **CBC 模式**:每次加密必须用新随机 IV(SDK 内已自动处理)。
|
|
232
|
+
4. **混合加密**:用 `rsa-oaep-aes-256-gcm`,每次请求 AES key 临时生成,提供前向安全。
|
|
233
|
+
5. **重放防护**:传 `redis` 给 Fastify 插件,启用 nonce 校验。
|
|
234
|
+
6. **时间窗口**:默认 5 分钟,生产建议 ≤ 60 秒。
|
|
235
|
+
|
|
236
|
+
## 📄 License
|
|
237
|
+
|
|
238
|
+
MIT © 2026 Atengliyun
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 算法可插拔层 - 公共类型定义
|
|
3
|
+
*/
|
|
4
|
+
/** 支持的加密算法(可按需扩展) */
|
|
5
|
+
type CipherAlgorithm = 'aes-256-gcm' | 'aes-256-cbc' | 'aes-128-cbc' | 'sm4-cbc' | 'rsa-oaep-aes-256-gcm';
|
|
6
|
+
/** 支持的摘要/签名算法 */
|
|
7
|
+
type DigestAlgorithm = 'hmac-sha256' | 'hmac-sha512' | 'md5' | 'sha256' | 'sm3';
|
|
8
|
+
/** 加密算法元信息 */
|
|
9
|
+
interface CipherMeta {
|
|
10
|
+
name: CipherAlgorithm;
|
|
11
|
+
/** 密钥字节长度(对混合加密而言,指的是"对称密钥"长度) */
|
|
12
|
+
keyLength: number;
|
|
13
|
+
/** IV 字节长度,0 表示 IV 由算法内部生成/不需要 */
|
|
14
|
+
ivLength: number;
|
|
15
|
+
/** 是否有 authTag(GCM 模式) */
|
|
16
|
+
hasAuthTag: boolean;
|
|
17
|
+
/** 块大小(分组密码;流密码为 1) */
|
|
18
|
+
blockSize: number;
|
|
19
|
+
}
|
|
20
|
+
/** 摘要算法元信息 */
|
|
21
|
+
interface DigestMeta {
|
|
22
|
+
name: DigestAlgorithm;
|
|
23
|
+
/** 输出字节长度 */
|
|
24
|
+
outputLength: number;
|
|
25
|
+
/** 是否需要密钥(hmac 系列) */
|
|
26
|
+
keyed: boolean;
|
|
27
|
+
/** 建议的最小密钥长度 */
|
|
28
|
+
minKeyLength: number;
|
|
29
|
+
}
|
|
30
|
+
interface EncryptResult {
|
|
31
|
+
/** 密文 */
|
|
32
|
+
data: Buffer;
|
|
33
|
+
/** IV(明文传输,可能由算法内部生成) */
|
|
34
|
+
iv: Buffer;
|
|
35
|
+
/** authTag(仅 GCM 等 AEAD 模式) */
|
|
36
|
+
tag?: Buffer;
|
|
37
|
+
/** 对于混合加密(rsa-oaep-aes-256-gcm),这里放加密后的对称密钥 */
|
|
38
|
+
encryptedKey?: Buffer;
|
|
39
|
+
}
|
|
40
|
+
interface EncryptParams {
|
|
41
|
+
/** 关联数据(AEAD) */
|
|
42
|
+
aad?: Buffer;
|
|
43
|
+
/** 调用方传入的对称密钥(必填,除非混合加密 + 走 RSA 派生) */
|
|
44
|
+
key?: Buffer;
|
|
45
|
+
/** 接收方 RSA 公钥(混合加密场景) */
|
|
46
|
+
rsaPublicKeyPem?: string;
|
|
47
|
+
/** 直接传入 IV(可选,默认内部随机生成) */
|
|
48
|
+
iv?: Buffer;
|
|
49
|
+
}
|
|
50
|
+
interface DecryptParams {
|
|
51
|
+
aad?: Buffer;
|
|
52
|
+
/** RSA 私钥 PEM(混合加密场景) */
|
|
53
|
+
rsaPrivateKeyPem?: string;
|
|
54
|
+
/** 对称密钥(必填,除非混合加密 + 走 RSA 私钥派生) */
|
|
55
|
+
key?: Buffer;
|
|
56
|
+
/** IV(必填) */
|
|
57
|
+
iv: Buffer;
|
|
58
|
+
/** GCM authTag */
|
|
59
|
+
tag?: Buffer;
|
|
60
|
+
/** 混合加密时,RSA 加密的对称密钥 */
|
|
61
|
+
encryptedKey?: Buffer;
|
|
62
|
+
}
|
|
63
|
+
/** 一个加密算法的统一接口 */
|
|
64
|
+
interface Cipher {
|
|
65
|
+
readonly name: CipherAlgorithm;
|
|
66
|
+
readonly meta: CipherMeta;
|
|
67
|
+
/** 生成新的对称密钥(返回 Buffer) */
|
|
68
|
+
generateKey?(): Buffer;
|
|
69
|
+
/** 生成随机 IV */
|
|
70
|
+
generateIv(): Buffer;
|
|
71
|
+
encrypt(plain: Buffer, params?: EncryptParams): EncryptResult;
|
|
72
|
+
decrypt(cipher: Buffer, params: DecryptParams): Buffer;
|
|
73
|
+
}
|
|
74
|
+
interface Digest {
|
|
75
|
+
readonly name: DigestAlgorithm;
|
|
76
|
+
readonly meta: DigestMeta;
|
|
77
|
+
/** 计算摘要/签名,默认输出 hex */
|
|
78
|
+
sign(data: string | Buffer, key?: string | Buffer): string;
|
|
79
|
+
/** 校验摘要/签名 */
|
|
80
|
+
verify(sig: string, data: string | Buffer, key?: string | Buffer): boolean;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* 全局类型定义:算法枚举、协议枚举、App 配置等
|
|
85
|
+
*/
|
|
86
|
+
|
|
87
|
+
/** 一个接入应用(app) 的服务端配置 */
|
|
88
|
+
interface AppConfig {
|
|
89
|
+
/** 应用唯一标识 */
|
|
90
|
+
appKey: string;
|
|
91
|
+
/** 应用密钥(用于服务端校验签名 / 解密 biz_content) */
|
|
92
|
+
appSecret: string;
|
|
93
|
+
/** 是否启用 */
|
|
94
|
+
enabled?: boolean;
|
|
95
|
+
/** 允许的加密算法白名单,留空表示允许所有已注册算法 */
|
|
96
|
+
allowedCiphers?: CipherAlgorithm[];
|
|
97
|
+
/** 允许的摘要/签名算法白名单,留空表示允许所有 */
|
|
98
|
+
allowedDigests?: DigestAlgorithm[];
|
|
99
|
+
/** 允许的协议,留空表示所有已注册协议 */
|
|
100
|
+
allowedProtocols?: ProtocolKind[];
|
|
101
|
+
/** 自定义属性 */
|
|
102
|
+
metadata?: Record<string, unknown>;
|
|
103
|
+
}
|
|
104
|
+
/** ServerContext:服务端钩子里使用的上下文 */
|
|
105
|
+
interface ServerContext {
|
|
106
|
+
app: AppConfig;
|
|
107
|
+
cipher: CipherAlgorithm;
|
|
108
|
+
digest: DigestAlgorithm;
|
|
109
|
+
protocol: ProtocolKind;
|
|
110
|
+
}
|
|
111
|
+
interface NonceStore {
|
|
112
|
+
set(key: string, value: string, ...args: any[]): Promise<any>;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
type ProtocolKind = 'custom' | 'top';
|
|
116
|
+
/** 协议策略的统一接口 */
|
|
117
|
+
interface ProtocolStrategy {
|
|
118
|
+
readonly kind: ProtocolKind;
|
|
119
|
+
/**
|
|
120
|
+
* 客户端:组装请求信封
|
|
121
|
+
* @param input 业务参数 + 加密/签名算法
|
|
122
|
+
* @param ctx 客户端上下文(密钥等)
|
|
123
|
+
*/
|
|
124
|
+
buildRequest(input: ProtocolRequestInput, ctx: ProtocolClientContext): Promise<Record<string, unknown>>;
|
|
125
|
+
/**
|
|
126
|
+
* 服务端:从原始 body 中解析、验签、解密
|
|
127
|
+
* 返回解出来的业务参数,挂到 req.secureRequest
|
|
128
|
+
*/
|
|
129
|
+
parseAndVerify(raw: Record<string, unknown>, ctx: ProtocolServerContext): Promise<ProtocolVerifyResult>;
|
|
130
|
+
/**
|
|
131
|
+
* 服务端:把响应加密成信封
|
|
132
|
+
*/
|
|
133
|
+
buildResponse(biz: unknown, ctx: ProtocolServerContext): Promise<Record<string, unknown>>;
|
|
134
|
+
}
|
|
135
|
+
interface ProtocolClientContext {
|
|
136
|
+
appKey: string;
|
|
137
|
+
appSecret: string;
|
|
138
|
+
/** 加密密钥 Buffer(对混合加密,rsaPublicKeyPem 走 params) */
|
|
139
|
+
encryptionKey: Buffer;
|
|
140
|
+
/** HMAC/签名密钥(hex 字符串) */
|
|
141
|
+
hmacSecret: string;
|
|
142
|
+
/** RSA 公钥 PEM(混合加密场景) */
|
|
143
|
+
rsaPublicKeyPem?: string;
|
|
144
|
+
}
|
|
145
|
+
interface ProtocolServerContext {
|
|
146
|
+
app: AppConfig;
|
|
147
|
+
encryptionKey: Buffer;
|
|
148
|
+
hmacSecret: string;
|
|
149
|
+
rsaPrivateKeyPem?: string;
|
|
150
|
+
nonceStore?: NonceStore;
|
|
151
|
+
requestWindowMs: number;
|
|
152
|
+
}
|
|
153
|
+
interface ProtocolRequestInput {
|
|
154
|
+
/** HTTP method */
|
|
155
|
+
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
|
156
|
+
/** API 路径(/api/v1/...) */
|
|
157
|
+
path: string;
|
|
158
|
+
/** 业务参数(会被序列化到 envelope) */
|
|
159
|
+
biz: Record<string, unknown>;
|
|
160
|
+
/** 业务 body(可选) */
|
|
161
|
+
body?: unknown;
|
|
162
|
+
/** 用户 session(可选,TOP 协议需要) */
|
|
163
|
+
session?: string;
|
|
164
|
+
/** 业务 query */
|
|
165
|
+
query?: Record<string, string>;
|
|
166
|
+
/** 算法协商(可选,默认走客户端 / app 配置) */
|
|
167
|
+
cipher?: CipherAlgorithm;
|
|
168
|
+
digest?: DigestAlgorithm;
|
|
169
|
+
/** 协议类型(custom | top) */
|
|
170
|
+
protocol?: ProtocolKind;
|
|
171
|
+
}
|
|
172
|
+
interface ProtocolVerifyResult {
|
|
173
|
+
appKey: string;
|
|
174
|
+
method: string;
|
|
175
|
+
path: string;
|
|
176
|
+
body?: unknown;
|
|
177
|
+
query?: Record<string, string>;
|
|
178
|
+
session?: string;
|
|
179
|
+
/** 解析出来的子协议字段(TOP: biz_content 解密结果;custom: 整个载荷) */
|
|
180
|
+
biz: unknown;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export type { AppConfig as A, CipherAlgorithm as C, DigestAlgorithm as D, EncryptParams as E, NonceStore as N, ProtocolKind as P, ServerContext as S, Cipher as a, Digest as b, ProtocolStrategy as c, ProtocolRequestInput as d, ProtocolVerifyResult as e, CipherMeta as f, DecryptParams as g, DigestMeta as h, EncryptResult as i, ProtocolClientContext as j, ProtocolServerContext as k };
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 算法可插拔层 - 公共类型定义
|
|
3
|
+
*/
|
|
4
|
+
/** 支持的加密算法(可按需扩展) */
|
|
5
|
+
type CipherAlgorithm = 'aes-256-gcm' | 'aes-256-cbc' | 'aes-128-cbc' | 'sm4-cbc' | 'rsa-oaep-aes-256-gcm';
|
|
6
|
+
/** 支持的摘要/签名算法 */
|
|
7
|
+
type DigestAlgorithm = 'hmac-sha256' | 'hmac-sha512' | 'md5' | 'sha256' | 'sm3';
|
|
8
|
+
/** 加密算法元信息 */
|
|
9
|
+
interface CipherMeta {
|
|
10
|
+
name: CipherAlgorithm;
|
|
11
|
+
/** 密钥字节长度(对混合加密而言,指的是"对称密钥"长度) */
|
|
12
|
+
keyLength: number;
|
|
13
|
+
/** IV 字节长度,0 表示 IV 由算法内部生成/不需要 */
|
|
14
|
+
ivLength: number;
|
|
15
|
+
/** 是否有 authTag(GCM 模式) */
|
|
16
|
+
hasAuthTag: boolean;
|
|
17
|
+
/** 块大小(分组密码;流密码为 1) */
|
|
18
|
+
blockSize: number;
|
|
19
|
+
}
|
|
20
|
+
/** 摘要算法元信息 */
|
|
21
|
+
interface DigestMeta {
|
|
22
|
+
name: DigestAlgorithm;
|
|
23
|
+
/** 输出字节长度 */
|
|
24
|
+
outputLength: number;
|
|
25
|
+
/** 是否需要密钥(hmac 系列) */
|
|
26
|
+
keyed: boolean;
|
|
27
|
+
/** 建议的最小密钥长度 */
|
|
28
|
+
minKeyLength: number;
|
|
29
|
+
}
|
|
30
|
+
interface EncryptResult {
|
|
31
|
+
/** 密文 */
|
|
32
|
+
data: Buffer;
|
|
33
|
+
/** IV(明文传输,可能由算法内部生成) */
|
|
34
|
+
iv: Buffer;
|
|
35
|
+
/** authTag(仅 GCM 等 AEAD 模式) */
|
|
36
|
+
tag?: Buffer;
|
|
37
|
+
/** 对于混合加密(rsa-oaep-aes-256-gcm),这里放加密后的对称密钥 */
|
|
38
|
+
encryptedKey?: Buffer;
|
|
39
|
+
}
|
|
40
|
+
interface EncryptParams {
|
|
41
|
+
/** 关联数据(AEAD) */
|
|
42
|
+
aad?: Buffer;
|
|
43
|
+
/** 调用方传入的对称密钥(必填,除非混合加密 + 走 RSA 派生) */
|
|
44
|
+
key?: Buffer;
|
|
45
|
+
/** 接收方 RSA 公钥(混合加密场景) */
|
|
46
|
+
rsaPublicKeyPem?: string;
|
|
47
|
+
/** 直接传入 IV(可选,默认内部随机生成) */
|
|
48
|
+
iv?: Buffer;
|
|
49
|
+
}
|
|
50
|
+
interface DecryptParams {
|
|
51
|
+
aad?: Buffer;
|
|
52
|
+
/** RSA 私钥 PEM(混合加密场景) */
|
|
53
|
+
rsaPrivateKeyPem?: string;
|
|
54
|
+
/** 对称密钥(必填,除非混合加密 + 走 RSA 私钥派生) */
|
|
55
|
+
key?: Buffer;
|
|
56
|
+
/** IV(必填) */
|
|
57
|
+
iv: Buffer;
|
|
58
|
+
/** GCM authTag */
|
|
59
|
+
tag?: Buffer;
|
|
60
|
+
/** 混合加密时,RSA 加密的对称密钥 */
|
|
61
|
+
encryptedKey?: Buffer;
|
|
62
|
+
}
|
|
63
|
+
/** 一个加密算法的统一接口 */
|
|
64
|
+
interface Cipher {
|
|
65
|
+
readonly name: CipherAlgorithm;
|
|
66
|
+
readonly meta: CipherMeta;
|
|
67
|
+
/** 生成新的对称密钥(返回 Buffer) */
|
|
68
|
+
generateKey?(): Buffer;
|
|
69
|
+
/** 生成随机 IV */
|
|
70
|
+
generateIv(): Buffer;
|
|
71
|
+
encrypt(plain: Buffer, params?: EncryptParams): EncryptResult;
|
|
72
|
+
decrypt(cipher: Buffer, params: DecryptParams): Buffer;
|
|
73
|
+
}
|
|
74
|
+
interface Digest {
|
|
75
|
+
readonly name: DigestAlgorithm;
|
|
76
|
+
readonly meta: DigestMeta;
|
|
77
|
+
/** 计算摘要/签名,默认输出 hex */
|
|
78
|
+
sign(data: string | Buffer, key?: string | Buffer): string;
|
|
79
|
+
/** 校验摘要/签名 */
|
|
80
|
+
verify(sig: string, data: string | Buffer, key?: string | Buffer): boolean;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* 全局类型定义:算法枚举、协议枚举、App 配置等
|
|
85
|
+
*/
|
|
86
|
+
|
|
87
|
+
/** 一个接入应用(app) 的服务端配置 */
|
|
88
|
+
interface AppConfig {
|
|
89
|
+
/** 应用唯一标识 */
|
|
90
|
+
appKey: string;
|
|
91
|
+
/** 应用密钥(用于服务端校验签名 / 解密 biz_content) */
|
|
92
|
+
appSecret: string;
|
|
93
|
+
/** 是否启用 */
|
|
94
|
+
enabled?: boolean;
|
|
95
|
+
/** 允许的加密算法白名单,留空表示允许所有已注册算法 */
|
|
96
|
+
allowedCiphers?: CipherAlgorithm[];
|
|
97
|
+
/** 允许的摘要/签名算法白名单,留空表示允许所有 */
|
|
98
|
+
allowedDigests?: DigestAlgorithm[];
|
|
99
|
+
/** 允许的协议,留空表示所有已注册协议 */
|
|
100
|
+
allowedProtocols?: ProtocolKind[];
|
|
101
|
+
/** 自定义属性 */
|
|
102
|
+
metadata?: Record<string, unknown>;
|
|
103
|
+
}
|
|
104
|
+
/** ServerContext:服务端钩子里使用的上下文 */
|
|
105
|
+
interface ServerContext {
|
|
106
|
+
app: AppConfig;
|
|
107
|
+
cipher: CipherAlgorithm;
|
|
108
|
+
digest: DigestAlgorithm;
|
|
109
|
+
protocol: ProtocolKind;
|
|
110
|
+
}
|
|
111
|
+
interface NonceStore {
|
|
112
|
+
set(key: string, value: string, ...args: any[]): Promise<any>;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
type ProtocolKind = 'custom' | 'top';
|
|
116
|
+
/** 协议策略的统一接口 */
|
|
117
|
+
interface ProtocolStrategy {
|
|
118
|
+
readonly kind: ProtocolKind;
|
|
119
|
+
/**
|
|
120
|
+
* 客户端:组装请求信封
|
|
121
|
+
* @param input 业务参数 + 加密/签名算法
|
|
122
|
+
* @param ctx 客户端上下文(密钥等)
|
|
123
|
+
*/
|
|
124
|
+
buildRequest(input: ProtocolRequestInput, ctx: ProtocolClientContext): Promise<Record<string, unknown>>;
|
|
125
|
+
/**
|
|
126
|
+
* 服务端:从原始 body 中解析、验签、解密
|
|
127
|
+
* 返回解出来的业务参数,挂到 req.secureRequest
|
|
128
|
+
*/
|
|
129
|
+
parseAndVerify(raw: Record<string, unknown>, ctx: ProtocolServerContext): Promise<ProtocolVerifyResult>;
|
|
130
|
+
/**
|
|
131
|
+
* 服务端:把响应加密成信封
|
|
132
|
+
*/
|
|
133
|
+
buildResponse(biz: unknown, ctx: ProtocolServerContext): Promise<Record<string, unknown>>;
|
|
134
|
+
}
|
|
135
|
+
interface ProtocolClientContext {
|
|
136
|
+
appKey: string;
|
|
137
|
+
appSecret: string;
|
|
138
|
+
/** 加密密钥 Buffer(对混合加密,rsaPublicKeyPem 走 params) */
|
|
139
|
+
encryptionKey: Buffer;
|
|
140
|
+
/** HMAC/签名密钥(hex 字符串) */
|
|
141
|
+
hmacSecret: string;
|
|
142
|
+
/** RSA 公钥 PEM(混合加密场景) */
|
|
143
|
+
rsaPublicKeyPem?: string;
|
|
144
|
+
}
|
|
145
|
+
interface ProtocolServerContext {
|
|
146
|
+
app: AppConfig;
|
|
147
|
+
encryptionKey: Buffer;
|
|
148
|
+
hmacSecret: string;
|
|
149
|
+
rsaPrivateKeyPem?: string;
|
|
150
|
+
nonceStore?: NonceStore;
|
|
151
|
+
requestWindowMs: number;
|
|
152
|
+
}
|
|
153
|
+
interface ProtocolRequestInput {
|
|
154
|
+
/** HTTP method */
|
|
155
|
+
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
|
156
|
+
/** API 路径(/api/v1/...) */
|
|
157
|
+
path: string;
|
|
158
|
+
/** 业务参数(会被序列化到 envelope) */
|
|
159
|
+
biz: Record<string, unknown>;
|
|
160
|
+
/** 业务 body(可选) */
|
|
161
|
+
body?: unknown;
|
|
162
|
+
/** 用户 session(可选,TOP 协议需要) */
|
|
163
|
+
session?: string;
|
|
164
|
+
/** 业务 query */
|
|
165
|
+
query?: Record<string, string>;
|
|
166
|
+
/** 算法协商(可选,默认走客户端 / app 配置) */
|
|
167
|
+
cipher?: CipherAlgorithm;
|
|
168
|
+
digest?: DigestAlgorithm;
|
|
169
|
+
/** 协议类型(custom | top) */
|
|
170
|
+
protocol?: ProtocolKind;
|
|
171
|
+
}
|
|
172
|
+
interface ProtocolVerifyResult {
|
|
173
|
+
appKey: string;
|
|
174
|
+
method: string;
|
|
175
|
+
path: string;
|
|
176
|
+
body?: unknown;
|
|
177
|
+
query?: Record<string, string>;
|
|
178
|
+
session?: string;
|
|
179
|
+
/** 解析出来的子协议字段(TOP: biz_content 解密结果;custom: 整个载荷) */
|
|
180
|
+
biz: unknown;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export type { AppConfig as A, CipherAlgorithm as C, DigestAlgorithm as D, EncryptParams as E, NonceStore as N, ProtocolKind as P, ServerContext as S, Cipher as a, Digest as b, ProtocolStrategy as c, ProtocolRequestInput as d, ProtocolVerifyResult as e, CipherMeta as f, DecryptParams as g, DigestMeta as h, EncryptResult as i, ProtocolClientContext as j, ProtocolServerContext as k };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { P as ProtocolKind, C as CipherAlgorithm, D as DigestAlgorithm } from './base-v1-7dHNy.mjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 浏览器端客户端公共类型
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
interface BaseClientConfig {
|
|
8
|
+
baseURL: string;
|
|
9
|
+
/** 加密密钥 - 64 字符 hex(32 字节) */
|
|
10
|
+
encryptionKey: string;
|
|
11
|
+
/** 签名密钥(>= 32 字符) */
|
|
12
|
+
hmacSecret: string;
|
|
13
|
+
/** 应用标识(TOP 协议需要) */
|
|
14
|
+
appKey?: string;
|
|
15
|
+
/** 客户端默认协议 */
|
|
16
|
+
protocol?: ProtocolKind;
|
|
17
|
+
/** 默认加密算法 */
|
|
18
|
+
cipher?: CipherAlgorithm;
|
|
19
|
+
/** 默认签名算法 */
|
|
20
|
+
digest?: DigestAlgorithm;
|
|
21
|
+
defaultHeaders?: Record<string, string>;
|
|
22
|
+
requestWindowMs?: number;
|
|
23
|
+
/** RSA 公钥 PEM(混合加密场景) */
|
|
24
|
+
rsaPublicKeyPem?: string;
|
|
25
|
+
fetchImpl?: typeof fetch;
|
|
26
|
+
}
|
|
27
|
+
interface RequestOptions {
|
|
28
|
+
session?: string;
|
|
29
|
+
cipher?: CipherAlgorithm;
|
|
30
|
+
digest?: DigestAlgorithm;
|
|
31
|
+
protocol?: ProtocolKind;
|
|
32
|
+
headers?: Record<string, string>;
|
|
33
|
+
signal?: AbortSignal;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* 浏览器端 / 通用 fetch 客户端
|
|
38
|
+
*
|
|
39
|
+
* 支持:
|
|
40
|
+
* - 多种协议(protocol: 'custom' | 'top'),通过 envelope.protocol 字段协商
|
|
41
|
+
* - 多种加密/签名算法(可按请求级别覆盖)
|
|
42
|
+
* - 自动加密请求 + 解密响应 + 验签
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
declare class SecureClient {
|
|
46
|
+
protected readonly baseURL: string;
|
|
47
|
+
protected readonly encryptionKey: Buffer;
|
|
48
|
+
protected readonly hmacSecret: string;
|
|
49
|
+
protected readonly appKey?: string;
|
|
50
|
+
protected readonly defaultProtocol: ProtocolKind;
|
|
51
|
+
protected readonly defaultCipher: BaseClientConfig['cipher'];
|
|
52
|
+
protected readonly defaultDigest: BaseClientConfig['digest'];
|
|
53
|
+
protected readonly defaultHeaders: Record<string, string>;
|
|
54
|
+
protected readonly requestWindowMs: number;
|
|
55
|
+
protected readonly rsaPublicKeyPem?: string;
|
|
56
|
+
protected readonly fetchImpl: typeof fetch;
|
|
57
|
+
constructor(config: BaseClientConfig);
|
|
58
|
+
/**
|
|
59
|
+
* 发起加密请求并解密响应
|
|
60
|
+
*/
|
|
61
|
+
request<T = unknown>(method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH', path: string, options?: RequestOptions & {
|
|
62
|
+
body?: unknown;
|
|
63
|
+
}): Promise<T>;
|
|
64
|
+
protected decryptResponseOnly(envelope: any, protocolKind: ProtocolKind): Promise<unknown>;
|
|
65
|
+
get<T = unknown>(path: string, options?: RequestOptions): Promise<T>;
|
|
66
|
+
post<T = unknown>(path: string, body?: unknown, options?: RequestOptions): Promise<T>;
|
|
67
|
+
put<T = unknown>(path: string, body?: unknown, options?: RequestOptions): Promise<T>;
|
|
68
|
+
delete<T = unknown>(path: string, options?: RequestOptions): Promise<T>;
|
|
69
|
+
patch<T = unknown>(path: string, body?: unknown, options?: RequestOptions): Promise<T>;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export { type BaseClientConfig, type RequestOptions, SecureClient };
|