18 KiB
18 KiB
加密模块 (TsCrypto)
**本文引用的文件列表** - [TsCrypto.js](file://src/utils/TsCrypto.js) - [TsSM4.js](file://src/utils/TsSM4.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)目录
简介
本文件为加密模块(TsCrypto)的全面技术文档,聚焦于基于 SM4 算法的加密与解密实现,覆盖 CBC 与 ECB 模式支持与配置、Base64 编解码机制、自动填充与去填充算法,以及与全局配置系统、存储系统和 HTTP 请求模块的集成方式。文档同时提供完整的 API 接口说明、使用示例、性能与安全最佳实践,并解释加密开关控制、token 加密传输等典型应用场景。
项目结构
该工具包采用按功能模块划分的组织方式:
- utils:通用工具与加密核心实现
- TsCrypto.js:对外暴露的加密模块入口,封装 SM4 并与全局配置联动
- TsSM4.js:SM4 算法实现,含填充/去填充、CBC/ECB 模式、Base64 文本编解码
- TsGlobalConfig.js:全局配置读取与设置
- TsStorage.js:本地存储与加密开关、token 的持久化
- TsCommon.js:通用工具函数(如 JSON 解析、URL 参数解析等)
- https:HTTP 请求封装与加密开关集成
- TsHttpUtil.js:统一请求处理、参数预处理、加解密与响应解密
- index.js:导出模块集合
- package.json:依赖声明(base64-js、umi-request)
graph TB
subgraph "工具包(utils)"
Crypto["TsCrypto.js"]
SM4["TsSM4.js"]
GConf["TsGlobalConfig.js"]
Store["TsStorage.js"]
Common["TsCommon.js"]
end
subgraph "HTTP(https)"
HttpUtil["TsHttpUtil.js"]
end
Index["index.js"]
Package["package.json"]
Crypto --> SM4
Crypto --> GConf
HttpUtil --> Crypto
HttpUtil --> Store
HttpUtil --> GConf
HttpUtil --> Common
Index --> Crypto
Index --> SM4
Index --> GConf
Index --> Store
Index --> HttpUtil
Package --> SM4
Package --> HttpUtil
图表来源
- TsCrypto.js:1-34
- TsSM4.js:1-456
- TsGlobalConfig.js:1-34
- TsStorage.js:1-55
- TsHttpUtil.js:1-171
- index.js:1-16
- package.json:1-24
章节来源
核心组件
- TsCrypto:对外加密模块,负责初始化 SM4 实例(默认 ECB 模式、Base64 输出),并提供 encrypt/decrypt 方法。
- TsSM4:SM4 算法核心,支持 CBC/ECB 模式、Base64/text 输出、自动 PKCS#7 填充与去填充、UTF-8 字符串编解码。
- TsGlobalConfig:全局配置读取与合并,提供 base64Key、prefix、httpParams、onHttpError 等。
- TsStorage:本地存储封装,提供用户 token、加密开关等键值存取。
- TsHttpUtil:HTTP 请求封装,集成加密开关、请求体加密、响应体解密、token 注入等。
章节来源
架构总览
加密模块在工具包中的位置与交互如下:
- TsCrypto 初始化时从全局配置读取 base64Key,转换为字节后注入 SM4;默认模式为 ECB,输出为 Base64。
- TsHttpUtil 在发送请求前根据存储的加密开关决定是否对请求体进行加密;收到响应后若标记为加密,则进行解密并尝试 JSON 解析。
- TsStorage 提供加密开关与 token 的持久化,便于跨页面/会话保持状态。
- TsGlobalConfig 提供全局配置(如前缀、附加参数、错误回调)以影响 HTTP 请求行为。
sequenceDiagram
participant Client as "调用方"
participant HttpUtil as "TsHttpUtil"
participant Store as "TsStorage"
participant Crypto as "TsCrypto"
participant SM4 as "TsSM4"
participant Server as "后端服务"
Client->>HttpUtil : "post(url, data)"
HttpUtil->>Store : "getEncryptBody()"
alt "加密开关开启"
HttpUtil->>Crypto : "encrypt(JSON.stringify(data))"
Crypto->>SM4 : "encrypt(UTF-8字节)"
SM4-->>Crypto : "Base64密文"
Crypto-->>HttpUtil : "Base64密文"
HttpUtil->>Server : "POST { encryptData : Base64密文 }"
else "加密开关关闭"
HttpUtil->>Server : "POST data"
end
Server-->>HttpUtil : "响应 { code, data, encrypt? }"
alt "响应标记为加密"
HttpUtil->>Crypto : "decrypt(data)"
Crypto->>SM4 : "decrypt(Base64密文)"
SM4-->>Crypto : "明文字节数组"
Crypto-->>HttpUtil : "明文字符串"
HttpUtil->>HttpUtil : "parseJSON(可选)"
end
HttpUtil-->>Client : "{ data, recordsTotal }"
图表来源
详细组件分析
TsCrypto 组件分析
- 角色定位:对外加密模块,封装 SM4 并与全局配置联动。
- 关键点:
- 构造函数中从全局配置读取 base64Key,转换为字节数组后传入 SM4。
- 默认模式为 ECB,输出类型为 Base64。
- 对外提供 encrypt/content 与 decrypt/base64 两个方法,分别委托给 SM4 的对应逻辑。
- 适用场景:作为 HTTP 请求层的加密前置,或独立用于数据加密/解密。
classDiagram
class TsCrypto {
+constructor()
+encrypt(content) String
+decrypt(base64) String
}
class TsSM4 {
+constructor(config)
+encrypt(plaintext) String
+decrypt(ciphertext) String
-padding(buffer) Uint8Array
-dePadding(buffer) Uint8Array
-uint8ToUint32Block(arr, idx) Uint32Array
-doBlockCrypt(block, roundKeys) Uint32Array
-spawnEncryptRoundKeys() void
-tTransform1(z) Uint32
-tTransform2(z) Uint32
-linearTransform1(x) Uint32
-linearTransform2(x) Uint32
-rotateLeft(x,y) Uint32
}
class GlobalConfig {
+getConfig() Object
+setConfig(obj) void
}
TsCrypto --> TsSM4 : "组合"
TsCrypto --> GlobalConfig : "读取配置"
图表来源
章节来源
TsSM4 组件分析
- 角色定位:SM4 算法实现,支持 CBC/ECB 模式、Base64/text 输出、UTF-8 编解码、PKCS#7 填充/去填充。
- 关键点:
- 支持 CBC/ECB 模式选择,默认 CBC;CBC 需要 16 字节 IV,否则抛错。
- 输出类型支持 Base64 与 text;输入统一为 UTF-8 字节流。
- 填充/去填充:按 16 字节块进行 PKCS#7 填充与去填充。
- 字符串编解码:通过 Crypt 工具类在 UTF-8 与 Base64 之间转换。
- 性能与复杂度:
- 每块 16 字节,循环 32 轮;时间复杂度 O(n),空间复杂度 O(n)。
- 填充/去填充为线性处理,开销较小。
- 安全性:
- CBC 模式下 IV 必须为 16 字节,且建议随机生成;当前实现未内置 IV 生成,需确保传入合法 IV。
- ECB 模式不推荐用于长文本或重复明文场景,易暴露模式特征。
flowchart TD
Start(["开始"]) --> ToUtf8["UTF-8 编码为字节数组"]
ToUtf8 --> Pad["PKCS#7 填充到 16 字节倍数"]
Pad --> Mode{"模式选择"}
Mode --> |CBC| CbcLoop["逐块 CBC 循环<br/>链式 XOR + 轮函数"]
Mode --> |ECB| EcbLoop["逐块 ECB 循环<br/>直接轮函数"]
CbcLoop --> OutSel{"输出类型"}
EcbLoop --> OutSel
OutSel --> |Base64| ToBase64["Base64 编码"]
OutSel --> |text| ToText["UTF-8 解码"]
ToBase64 --> End(["结束"])
ToText --> End
图表来源
章节来源
TsGlobalConfig 组件分析
- 角色定位:全局配置中心,提供默认配置与运行时合并。
- 关键点:
- 默认 base64Key、prefix、httpParams、onHttpError 等。
- getConfig 返回 window.httpConfig 或默认配置;setConfig 合并传入对象。
- 与加密模块的关系:
- TsCrypto 通过 getConfig().base64Key 读取密钥;TsHttpUtil 通过 getConfig().prefix/httpParams/onHttpError 影响请求行为。
章节来源
TsStorage 组件分析
- 角色定位:本地存储封装,提供 token 与加密开关的持久化。
- 关键点:
- save/get:统一 JSON 序列化/反序列化。
- saveUserToken/getUserToken:token 的便捷存取。
- saveEncryptBody/getEncryptBody:加密开关的持久化,影响 HTTP 请求是否加密请求体。
章节来源
TsHttpUtil 组件分析
- 角色定位:HTTP 请求封装,集成加密开关、请求体加密、响应体解密、token 注入。
- 关键点:
- dealParamsBody:对 GET 参数与 POST 数据进行预处理;当加密开关开启时,将 data 包装为 { encryptData: TsCrypto.encrypt(JSON.stringify(data)) }。
- req:发起请求,自动拼接 prefix、注入 token、处理响应;若响应标记为加密,则调用 TsCrypto.decrypt 并尝试 JSON 解析。
- 错误处理:根据状态码映射错误信息,或调用全局 onHttpError 回调。
- 与加密模块的协作:
- 使用 TsCrypto.encrypt/decrypt 完成请求体与响应体的加解密。
- 通过 TsStorage 控制加密开关,通过 TsGlobalConfig 控制前缀与附加参数。
章节来源
依赖关系分析
- TsCrypto 依赖 TsSM4 与 TsGlobalConfig。
- TsHttpUtil 依赖 TsCrypto、TsStorage、TsGlobalConfig、TsCommon。
- TsSM4 依赖 base64-js(用于 Base64 编解码)。
- index.js 将各模块统一导出,供外部使用。
- package.json 声明 base64-js 与 umi-request 依赖。
graph LR
TsCrypto["TsCrypto.js"] --> TsSM4["TsSM4.js"]
TsCrypto --> TsGlobalConfig["TsGlobalConfig.js"]
TsHttpUtil["TsHttpUtil.js"] --> TsCrypto
TsHttpUtil --> TsStorage["TsStorage.js"]
TsHttpUtil --> TsGlobalConfig
TsHttpUtil --> TsCommon["TsCommon.js"]
TsSM4 --> Base64["base64-js(依赖)"]
index_js["index.js"] --> TsCrypto
index_js --> TsSM4
index_js --> TsGlobalConfig
index_js --> TsStorage
index_js --> TsHttpUtil
package_json["package.json"] --> Base64
package_json --> UmiReq["umi-request(依赖)"]
图表来源
章节来源
性能考量
- 时间复杂度:SM4 每块 16 字节,32 轮,整体 O(n);填充/去填充为线性处理,开销较小。
- 内存占用:主要为输入/输出字节数组与中间块数组,空间复杂度 O(n)。
- Base64 编解码:在浏览器与 Node 环境均可用 base64-js,性能稳定。
- CBC/ECB 选择:CBC 增加链式处理,但无额外显著性能损耗;ECB 更简单但安全性较低。
- 建议:
- 对大文本分块处理(当前实现按块处理,已具备良好扩展性)。
- 在浏览器端避免频繁重复加密,必要时缓存结果。
- 使用 CBC 模式并确保 IV 正确(当前实现要求 16 字节 IV,否则抛错)。
故障排查指南
- “iv 错误”异常
- 现象:CBC 模式下抛出 iv 错误。
- 原因:未正确传入 16 字节 IV 或未传入 IV。
- 处理:确保传入长度为 16 的 IV,或切换至 ECB 模式。
- 参考路径:TsSM4.js:345-347、TsSM4.js:410-412
- “密钥长度不为 16 字节”
- 现象:构造 SM4 实例时抛出密钥长度错误。
- 原因:base64Key 解码后不是 16 字节。
- 处理:确认 base64Key 来自后端并符合规范。
- 参考路径:TsSM4.js:103-105
- “响应未解密”
- 现象:响应未按预期解密。
- 原因:响应未标记为加密或密钥不一致。
- 处理:确认后端响应标记 encrypt 且密钥一致。
- 参考路径:TsHttpUtil.js:119-122
- “加密开关无效”
- 现象:请求未加密。
- 原因:加密开关未启用或未持久化。
- 处理:调用 saveEncryptBody(true) 并确认存储生效。
- 参考路径:TsStorage.js:17-23、TsHttpUtil.js:82-86
章节来源
结论
本加密模块以 TsCrypto 为核心,结合 TsSM4 的 SM4 算法实现,提供了 CBC/ECB 模式、Base64 编解码、PKCS#7 填充与去填充、UTF-8 字符串编解码能力,并与全局配置系统、存储系统、HTTP 请求模块形成完整闭环。通过加密开关与 token 注入,满足了请求体加密与安全传输的常见需求。建议在生产环境中优先使用 CBC 模式并妥善管理 IV 与密钥,遵循最小暴露原则与安全最佳实践。
附录
API 接口文档
- TsCrypto.encrypt(content)
- 功能:对明文字符串进行加密,返回 Base64 字符串。
- 输入:明文字符串。
- 输出:Base64 密文字符串。
- 参考路径:TsCrypto.js:19-21、TsSM4.js:338-387
- TsCrypto.decrypt(base64)
- 功能:对 Base64 密文进行解密,返回明文字符串。
- 输入:Base64 密文字符串。
- 输出:明文字符串。
- 参考路径:TsCrypto.js:28-30、TsSM4.js:395-452
- TsSM4.encrypt(plaintext)
- 功能:支持 CBC/ECB 模式、Base64/text 输出、UTF-8 编解码与 PKCS#7 填充。
- 输入:明文字符串。
- 输出:Base64 或 UTF-8 字符串(取决于 cipherType)。
- 参考路径:TsSM4.js:338-387
- TsSM4.decrypt(ciphertext)
- 功能:支持 CBC/ECB 模式、Base64/text 输入、UTF-8 编解码与 PKCS#7 去填充。
- 输入:Base64 或 UTF-8 密文字符串。
- 输出:明文字符串。
- 参考路径:TsSM4.js:395-452
- TsGlobalConfig.getConfig()/setConfig(obj)
- 功能:读取/设置全局配置,包括 base64Key、prefix、httpParams、onHttpError。
- 参考路径:TsGlobalConfig.js:19-33
- TsStorage.saveEncryptBody(bool)/getEncryptBody()
- 功能:设置/获取加密开关,影响 HTTP 请求是否加密请求体。
- 参考路径:TsStorage.js:17-23
- TsHttpUtil.post/get/form(req)
- 功能:统一发起 HTTP 请求,自动处理加密开关、请求体加密、响应体解密、token 注入。
- 参考路径:TsHttpUtil.js:152-165
使用示例
- 启用请求体加密
- 设置加密开关:调用 saveEncryptBody(true)。
- 发送请求:post(url, data) 自动将 data 包装为 { encryptData: TsCrypto.encrypt(JSON.stringify(data)) }。
- 参考路径:TsStorage.js:17-23、TsHttpUtil.js:82-86
- 响应体解密
- 若后端响应标记为加密,则自动调用 TsCrypto.decrypt 并尝试 JSON 解析。
- 参考路径:TsHttpUtil.js:119-122
- 自定义密钥与前缀
- 通过 setConfig({ base64Key, prefix }) 配置密钥与请求前缀。
- 参考路径:TsGlobalConfig.js:27-29、TsHttpUtil.js:100-106
安全最佳实践
- CBC 模式
- 使用 16 字节 IV,建议随机生成并随消息传输或在协议中约定。
- 避免重复使用相同的 IV 与密钥组合。
- ECB 模式
- 不适用于长文本或存在重复明文的场景,易泄露模式特征。
- 密钥管理
- base64Key 应来自可信后端,定期轮换;避免硬编码在前端。
- 响应校验
- 对响应进行完整性校验(如 HMAC),防止篡改。
- 日志与调试
- 生产环境避免打印密文与敏感信息;仅在开发环境启用严格日志级别。