352 lines
14 KiB
Markdown
352 lines
14 KiB
Markdown
# 加密配置
|
||
|
||
<cite>
|
||
**本文引用的文件列表**
|
||
- [TsSM4.js](file://src/utils/TsSM4.js)
|
||
- [TsCrypto.js](file://src/utils/TsCrypto.js)
|
||
- [TsGlobalConfig.js](file://src/utils/TsGlobalConfig.js)
|
||
- [TsHttpUtil.js](file://src/https/TsHttpUtil.js)
|
||
- [TsStorage.js](file://src/utils/TsStorage.js)
|
||
- [index.js](file://index.js)
|
||
- [package.json](file://package.json)
|
||
- [README.md](file://README.md)
|
||
</cite>
|
||
|
||
## 目录
|
||
1. [简介](#简介)
|
||
2. [项目结构](#项目结构)
|
||
3. [核心组件](#核心组件)
|
||
4. [架构总览](#架构总览)
|
||
5. [详细组件分析](#详细组件分析)
|
||
6. [依赖关系分析](#依赖关系分析)
|
||
7. [性能考量](#性能考量)
|
||
8. [故障排查指南](#故障排查指南)
|
||
9. [结论](#结论)
|
||
10. [附录](#附录)
|
||
|
||
## 简介
|
||
本指南围绕项目中的 SM4 加密配置展开,系统性说明 CBC 与 ECB 模式的配置与使用差异、base64Key 的作用与长度要求、安全性考量,以及在数据传输加密与存储加密等场景下的配置建议。同时覆盖加密模式切换、与全局配置的关系与继承机制、最佳实践(密钥管理、性能优化、安全加固)、以及测试与验证方法。文档严格基于仓库源码进行分析与总结,避免臆测。
|
||
|
||
## 项目结构
|
||
该项目采用“工具类 + 组件化”的组织方式:
|
||
- 工具层:SM4 实现、通用加密封装、全局配置、本地存储、通用方法
|
||
- 业务集成层:HTTP 请求工具,负责在请求前后对数据进行加解密
|
||
- 入口导出:统一通过入口文件导出各模块
|
||
|
||
```mermaid
|
||
graph TB
|
||
subgraph "工具层"
|
||
SM4["TsSM4<br/>SM4 加密实现"]
|
||
Crypto["TsCrypto<br/>基于 SM4 的加密封装"]
|
||
GlobalCfg["TsGlobalConfig<br/>全局配置"]
|
||
Storage["TsStorage<br/>本地存储"]
|
||
Common["TsCommon<br/>通用方法"]
|
||
end
|
||
subgraph "业务集成层"
|
||
HttpUtil["TsHttpUtil<br/>HTTP 请求工具"]
|
||
end
|
||
SM4 --> Crypto
|
||
GlobalCfg --> Crypto
|
||
Crypto --> HttpUtil
|
||
Storage --> HttpUtil
|
||
Common --> HttpUtil
|
||
```
|
||
|
||
图表来源
|
||
- [TsSM4.js:1-456](file://src/utils/TsSM4.js#L1-L456)
|
||
- [TsCrypto.js:1-34](file://src/utils/TsCrypto.js#L1-L34)
|
||
- [TsGlobalConfig.js:1-34](file://src/utils/TsGlobalConfig.js#L1-L34)
|
||
- [TsHttpUtil.js:1-171](file://src/https/TsHttpUtil.js#L1-L171)
|
||
- [TsStorage.js:1-55](file://src/utils/TsStorage.js#L1-L55)
|
||
|
||
章节来源
|
||
- [index.js:1-16](file://index.js#L1-L16)
|
||
- [package.json:1-24](file://package.json#L1-L24)
|
||
|
||
## 核心组件
|
||
- SM4 加密实现:提供 CBC/ECB 模式、PKCS#7 填充、Base64 文本输出、密钥扩展与轮函数等完整实现
|
||
- 加密封装:基于 SM4 构建默认实例,读取全局配置中的 base64Key,并默认以 ECB 模式工作
|
||
- 全局配置:提供 base64Key、前缀、HTTP 参数注入、错误回调等配置项
|
||
- HTTP 工具:在请求体加密开关开启时,对请求体进行加密;在响应标记为加密时进行解密
|
||
- 本地存储:提供开关控制是否对请求体进行加密
|
||
|
||
章节来源
|
||
- [TsSM4.js:96-453](file://src/utils/TsSM4.js#L96-L453)
|
||
- [TsCrypto.js:5-31](file://src/utils/TsCrypto.js#L5-L31)
|
||
- [TsGlobalConfig.js:5-29](file://src/utils/TsGlobalConfig.js#L5-L29)
|
||
- [TsHttpUtil.js:50-91](file://src/https/TsHttpUtil.js#L50-L91)
|
||
- [TsStorage.js:17-23](file://src/utils/TsStorage.js#L17-L23)
|
||
|
||
## 架构总览
|
||
下图展示了从请求发起到加解密处理的关键流程,以及与全局配置、本地存储的关系。
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant Client as "调用方"
|
||
participant HttpUtil as "TsHttpUtil"
|
||
participant Storage as "TsStorage"
|
||
participant Crypto as "TsCrypto"
|
||
participant SM4 as "TsSM4"
|
||
participant Server as "后端服务"
|
||
Client->>HttpUtil : "post(url, data)"
|
||
HttpUtil->>Storage : "getEncryptBody()"
|
||
Storage-->>HttpUtil : "true/false"
|
||
alt "需要加密"
|
||
HttpUtil->>Crypto : "encrypt(JSON.stringify(data))"
|
||
Crypto->>SM4 : "encrypt(明文)"
|
||
SM4-->>Crypto : "密文(Base64)"
|
||
Crypto-->>HttpUtil : "密文(Base64)"
|
||
HttpUtil->>Server : "POST { encryptData : 密文 }"
|
||
else "无需加密"
|
||
HttpUtil->>Server : "POST data"
|
||
end
|
||
Server-->>HttpUtil : "响应 { code, data, encrypt? }"
|
||
alt "响应标记为加密"
|
||
HttpUtil->>Crypto : "decrypt(data)"
|
||
Crypto->>SM4 : "decrypt(密文)"
|
||
SM4-->>Crypto : "明文"
|
||
Crypto-->>HttpUtil : "明文"
|
||
HttpUtil-->>Client : "{ data, recordsTotal }"
|
||
else "未加密响应"
|
||
HttpUtil-->>Client : "{ data, recordsTotal }"
|
||
end
|
||
```
|
||
|
||
图表来源
|
||
- [TsHttpUtil.js:82-88](file://src/https/TsHttpUtil.js#L82-L88)
|
||
- [TsHttpUtil.js:119-122](file://src/https/TsHttpUtil.js#L119-L122)
|
||
- [TsCrypto.js:19-30](file://src/utils/TsCrypto.js#L19-L30)
|
||
- [TsSM4.js:338-387](file://src/utils/TsSM4.js#L338-L387)
|
||
- [TsSM4.js:395-452](file://src/utils/TsSM4.js#L395-L452)
|
||
- [TsStorage.js:17-23](file://src/utils/TsStorage.js#L17-L23)
|
||
|
||
## 详细组件分析
|
||
|
||
### SM4 加密实现(TsSM4)
|
||
- 模式支持:CBC、ECB 双模式,可通过构造参数选择
|
||
- IV 要求:CBC 模式必须提供 16 字节 IV;ECB 模式可省略 IV
|
||
- 密钥要求:必须为 16 字节(128 位),构造时会校验
|
||
- 输出类型:支持 Base64 与文本两种输出类型
|
||
- 填充策略:PKCS#7 填充,解密时自动去除
|
||
- 轮函数与密钥扩展:内置完整的 SM4 轮函数与轮密钥生成逻辑
|
||
|
||
```mermaid
|
||
classDiagram
|
||
class Crypt {
|
||
+stringToArrayBufferInUtf8(str) Uint8Array
|
||
+utf8ArrayBufferToString(buf) String
|
||
+arrayBufferToBase64(buf) String
|
||
+base64ToArrayBuffer(str) Uint8Array
|
||
}
|
||
class TsSM4 {
|
||
+Uint8Array key
|
||
+Uint8Array iv
|
||
+String mode
|
||
+String cipherType
|
||
+Uint32Array encryptRoundKeys
|
||
+Uint32Array decryptRoundKeys
|
||
+doBlockCrypt(blockData, roundKeys) Uint32Array
|
||
+spawnEncryptRoundKeys() void
|
||
+padding(buffer) Uint8Array
|
||
+dePadding(buffer) Uint8Array
|
||
+uint8ToUint32Block(arr, baseIndex) Uint32Array
|
||
+encrypt(plaintext) String
|
||
+decrypt(ciphertext) String
|
||
}
|
||
TsSM4 --> Crypt : "使用"
|
||
```
|
||
|
||
图表来源
|
||
- [TsSM4.js:39-94](file://src/utils/TsSM4.js#L39-L94)
|
||
- [TsSM4.js:96-453](file://src/utils/TsSM4.js#L96-L453)
|
||
|
||
章节来源
|
||
- [TsSM4.js:102-156](file://src/utils/TsSM4.js#L102-L156)
|
||
- [TsSM4.js:338-387](file://src/utils/TsSM4.js#L338-L387)
|
||
- [TsSM4.js:395-452](file://src/utils/TsSM4.js#L395-L452)
|
||
|
||
### 加密封装(TsCrypto)
|
||
- 默认使用 ECB 模式
|
||
- 从全局配置读取 base64Key 并转换为字节数组作为密钥
|
||
- 对外暴露 encrypt、decrypt 接口,内部委托给 TsSM4
|
||
|
||
章节来源
|
||
- [TsCrypto.js:7-13](file://src/utils/TsCrypto.js#L7-L13)
|
||
- [TsCrypto.js:19-30](file://src/utils/TsCrypto.js#L19-L30)
|
||
|
||
### 全局配置(TsGlobalConfig)
|
||
- 提供 base64Key、prefix、httpParams、onHttpError 等配置项
|
||
- 支持运行时 setConfig 合并默认配置
|
||
- HTTP 工具通过 getConfig 获取 prefix 与 httpParams 注入
|
||
|
||
章节来源
|
||
- [TsGlobalConfig.js:5-29](file://src/utils/TsGlobalConfig.js#L5-L29)
|
||
- [TsHttpUtil.js:100-106](file://src/https/TsHttpUtil.js#L100-L106)
|
||
- [TsHttpUtil.js:72-74](file://src/https/TsHttpUtil.js#L72-L74)
|
||
|
||
### HTTP 工具(TsHttpUtil)
|
||
- 在请求体加密开关开启时,将 data 包装为 { encryptData: 加密结果 }
|
||
- 在响应标记 encrypt 时,对 data 执行解密并解析 JSON
|
||
- 支持 GET/POST/form 等多种请求类型
|
||
|
||
章节来源
|
||
- [TsHttpUtil.js:82-88](file://src/https/TsHttpUtil.js#L82-L88)
|
||
- [TsHttpUtil.js:119-122](file://src/https/TsHttpUtil.js#L119-L122)
|
||
- [TsHttpUtil.js:142-154](file://src/https/TsHttpUtil.js#L142-L154)
|
||
- [TsHttpUtil.js:163-165](file://src/https/TsHttpUtil.js#L163-L165)
|
||
|
||
### 本地存储(TsStorage)
|
||
- 提供 getEncryptBody/saveEncryptBody 开关,用于控制请求体是否加密
|
||
- 与 HTTP 工具配合使用
|
||
|
||
章节来源
|
||
- [TsStorage.js:17-23](file://src/utils/TsStorage.js#L17-L23)
|
||
|
||
## 依赖关系分析
|
||
- TsCrypto 依赖 TsSM4 与 TsGlobalConfig
|
||
- TsHttpUtil 依赖 TsCrypto、TsStorage、TsGlobalConfig
|
||
- TsSM4 依赖 base64js(用于 Base64 编解码)
|
||
|
||
```mermaid
|
||
graph LR
|
||
base64js["base64js"] --> SM4["TsSM4"]
|
||
GlobalCfg["TsGlobalConfig"] --> Crypto["TsCrypto"]
|
||
SM4 --> Crypto
|
||
Crypto --> HttpUtil["TsHttpUtil"]
|
||
Storage["TsStorage"] --> HttpUtil
|
||
Common["TsCommon"] --> HttpUtil
|
||
```
|
||
|
||
图表来源
|
||
- [TsCrypto.js:1-3](file://src/utils/TsCrypto.js#L1-L3)
|
||
- [TsSM4.js:1](file://src/utils/TsSM4.js#L1)
|
||
- [TsHttpUtil.js:1-5](file://src/https/TsHttpUtil.js#L1-L5)
|
||
|
||
章节来源
|
||
- [package.json:19-22](file://package.json#L19-L22)
|
||
|
||
## 性能考量
|
||
- 模式选择
|
||
- ECB:每块独立加密,适合无状态、可并行处理的场景;但相同明文块会产生相同密文块,易受统计分析攻击
|
||
- CBC:引入链式传播,相同明文块不会产生相同密文块,更安全;但需 16 字节 IV,且加密过程串行
|
||
- 输出类型
|
||
- Base64 输出便于网络传输与日志记录,但会增加约 33% 的体积;文本输出取决于底层编码,通常体积更小
|
||
- 填充开销
|
||
- PKCS#7 填充会在明文末尾追加若干字节,对小数据影响较小
|
||
- 建议
|
||
- 优先使用 CBC 模式(若后端支持 IV),并在需要时启用 Base64 输出
|
||
- 对大体量数据,考虑分块或压缩后再加密,减少网络往返
|
||
|
||
## 故障排查指南
|
||
- 常见错误与定位
|
||
- “密钥长度不为 16 字节”:检查 base64Key 是否正确,确保解码后为 16 字节
|
||
- “IV 错误”:CBC 模式必须提供 16 字节 IV;确认传入的 iv 长度与编码
|
||
- “输出类型不匹配”:若后端返回非 Base64 内容,需将 cipherType 设置为文本
|
||
- “解密失败”:确认使用的密钥与模式一致,且数据未被篡改
|
||
- 定位步骤
|
||
- 确认全局配置中 base64Key 是否正确设置
|
||
- 检查请求体加密开关是否按预期开启
|
||
- 核对响应是否标记为加密,以及解密流程是否执行
|
||
- 使用最小化复现:仅传递一段固定明文,观察加解密结果一致性
|
||
|
||
章节来源
|
||
- [TsSM4.js:103-105](file://src/utils/TsSM4.js#L103-L105)
|
||
- [TsSM4.js:118-121](file://src/utils/TsSM4.js#L118-L121)
|
||
- [TsSM4.js:345-347](file://src/utils/TsSM4.js#L345-L347)
|
||
- [TsSM4.js:410-412](file://src/utils/TsSM4.js#L410-L412)
|
||
- [TsCrypto.js:8-12](file://src/utils/TsCrypto.js#L8-L12)
|
||
- [TsHttpUtil.js:82-88](file://src/https/TsHttpUtil.js#L82-L88)
|
||
- [TsHttpUtil.js:119-122](file://src/https/TsHttpUtil.js#L119-L122)
|
||
|
||
## 结论
|
||
本项目以 TsSM4 为核心,通过 TsCrypto 封装默认 ECB 模式与 base64Key,结合 TsHttpUtil 的请求体加密与响应解密能力,形成一套可配置、可扩展的加密方案。实际部署中应优先采用 CBC 模式并妥善管理 IV 与密钥,确保输出类型与后端一致,并通过全局配置集中管理密钥与前缀等参数。
|
||
|
||
## 附录
|
||
|
||
### 加密配置选项与说明
|
||
- base64Key
|
||
- 作用:作为 SM4 密钥的 Base64 字符串,构造时会被解码为 16 字节密钥
|
||
- 长度要求:解码后必须为 16 字节(128 位)
|
||
- 安全性:应由后端生成并下发,避免硬编码泄露;定期轮换
|
||
- 模式选择
|
||
- CBC:需提供 16 字节 IV;更安全,推荐用于大多数场景
|
||
- ECB:无需 IV;简单但安全性较低,仅在特定场景使用
|
||
- 输出类型
|
||
- Base64:便于网络传输与日志记录
|
||
- 文本:体积更小,但需确保后端一致
|
||
- IV 要求
|
||
- CBC 模式必须提供 16 字节 IV;ECB 模式可省略
|
||
|
||
章节来源
|
||
- [TsSM4.js:102-156](file://src/utils/TsSM4.js#L102-L156)
|
||
- [TsSM4.js:338-387](file://src/utils/TsSM4.js#L338-L387)
|
||
- [TsSM4.js:395-452](file://src/utils/TsSM4.js#L395-L452)
|
||
- [TsCrypto.js:8-12](file://src/utils/TsCrypto.js#L8-L12)
|
||
|
||
### 不同场景下的配置建议
|
||
- 数据传输加密(HTTP 请求体)
|
||
- 开启请求体加密开关
|
||
- 使用 CBC 模式并提供 16 字节 IV(若后端支持)
|
||
- 输出类型建议 Base64
|
||
- 存储加密(本地或数据库)
|
||
- 若明文为字符串,建议使用 ECB 模式简化处理
|
||
- 若存在重复明文块,建议使用 CBC 模式并随机 IV
|
||
- 输出类型根据存储介质选择(Base64 更通用)
|
||
|
||
章节来源
|
||
- [TsHttpUtil.js:82-88](file://src/https/TsHttpUtil.js#L82-L88)
|
||
- [TsStorage.js:17-23](file://src/utils/TsStorage.js#L17-L23)
|
||
|
||
### 加密模式切换与注意事项
|
||
- 切换方法
|
||
- 通过 TsCrypto 构造参数或直接创建 TsSM4 实例指定 mode 与 iv/cipherType
|
||
- 注意事项
|
||
- CBC 必须提供 16 字节 IV;ECB 可省略 IV
|
||
- 输出类型需与后端保持一致
|
||
- 切换模式后需同步后端解密逻辑
|
||
|
||
章节来源
|
||
- [TsCrypto.js:7-13](file://src/utils/TsCrypto.js#L7-L13)
|
||
- [TsSM4.js:128-141](file://src/utils/TsSM4.js#L128-L141)
|
||
- [TsSM4.js:343-378](file://src/utils/TsSM4.js#L343-L378)
|
||
- [TsSM4.js:408-447](file://src/utils/TsSM4.js#L408-L447)
|
||
|
||
### 最佳实践
|
||
- 密钥管理
|
||
- 使用强随机生成的 16 字节密钥,避免硬编码
|
||
- 通过安全渠道下发 base64Key,定期轮换
|
||
- 性能优化
|
||
- 对小数据优先使用 ECB;对大数据优先使用 CBC
|
||
- 合理选择输出类型,平衡体积与兼容性
|
||
- 安全加固
|
||
- CBC 模式务必使用随机 IV
|
||
- 对响应数据进行完整性校验(如 HMAC)
|
||
- 限制日志中输出密文,必要时仅输出摘要
|
||
|
||
### 加密配置与全局配置的关系与继承机制
|
||
- TsCrypto 默认从全局配置读取 base64Key,并以 ECB 模式初始化
|
||
- TsHttpUtil 通过 GlobalConfig.getConfig 获取 prefix 与 httpParams,用于请求拼接与参数注入
|
||
- setConfig 可合并默认配置,实现运行时动态调整
|
||
|
||
章节来源
|
||
- [TsCrypto.js:8-12](file://src/utils/TsCrypto.js#L8-L12)
|
||
- [TsGlobalConfig.js:19-29](file://src/utils/TsGlobalConfig.js#L19-L29)
|
||
- [TsHttpUtil.js:100-106](file://src/https/TsHttpUtil.js#L100-L106)
|
||
- [TsHttpUtil.js:72-74](file://src/https/TsHttpUtil.js#L72-L74)
|
||
|
||
### 测试方法与验证步骤
|
||
- 单元测试(建议)
|
||
- 使用固定明文与密钥,验证加解密一致性
|
||
- 分别测试 ECB 与 CBC 模式,确保 IV 正确性
|
||
- 验证 Base64 与文本输出类型的互操作
|
||
- 端到端测试(建议)
|
||
- 通过 HTTP 工具发起请求,开启请求体加密,验证响应解密
|
||
- 模拟后端响应标记为加密,验证解密流程
|
||
- 日志与监控
|
||
- 记录关键配置项(模式、输出类型、IV 是否提供)
|
||
- 对异常进行捕获与上报
|
||
|
||
章节来源
|
||
- [README.md:12-26](file://README.md#L12-L26)
|
||
- [TsHttpUtil.js:82-88](file://src/https/TsHttpUtil.js#L82-L88)
|
||
- [TsHttpUtil.js:119-122](file://src/https/TsHttpUtil.js#L119-L122) |