# SM4 算法 API
**本文引用的文件**
- [TsSM4.js](file://src/utils/TsSM4.js)
- [TsCrypto.js](file://src/utils/TsCrypto.js)
- [TsGlobalConfig.js](file://src/utils/TsGlobalConfig.js)
- [index.js](file://index.js)
- [package.json](file://package.json)
- [README.md](file://README.md)
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能与安全考量](#性能与安全考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件为 SM4 对称加密算法模块的完整 API 参考文档,覆盖以下内容:
- 方法签名与参数类型(明文、密钥、IV 向量、输出类型)
- 返回值类型与数据格式
- CBC 与 ECB 两种加密模式支持
- 自动填充与去填充机制
- 字节序与位运算处理细节
- 与 Base64 编解码的集成方式与数据格式转换
- 安全性考虑、性能特征与适用场景
- 扩展与自定义方法建议
## 项目结构
该工具包通过统一入口导出多个工具模块,其中 SM4 模块位于 src/utils/TsSM4.js,并在 index.js 中集中导出。
```mermaid
graph TB
A["index.js
统一导出入口"] --> B["TsSM4.js
SM4 实现"]
A --> C["TsCrypto.js
基于 SM4 的加密器封装"]
A --> D["TsGlobalConfig.js
全局配置含 base64Key"]
E["package.json
依赖声明"] --> F["base64-js@1.5.1"]
B --> F
C --> B
C --> D
```
图表来源
- [index.js:1-16](file://index.js#L1-L16)
- [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)
- [package.json:1-24](file://package.json#L1-L24)
章节来源
- [index.js:1-16](file://index.js#L1-L16)
- [package.json:1-24](file://package.json#L1-L24)
## 核心组件
- TsSM4:SM4 对称加密算法实现,支持 CBC/ECB 模式、PKCS#7 填充、Base64 文本输出。
- Crypt:字符串与字节数组、Base64 之间的编解码辅助工具。
- TsCrypto:基于 SM4 的应用层加密器,使用全局配置中的 base64Key 初始化。
章节来源
- [TsSM4.js:96-455](file://src/utils/TsSM4.js#L96-L455)
- [TsCrypto.js:5-34](file://src/utils/TsCrypto.js#L5-L34)
- [TsGlobalConfig.js:5-33](file://src/utils/TsGlobalConfig.js#L5-L33)
## 架构总览
SM4 模块以面向对象的方式组织,内部包含:
- 常量表:S 盒、轮常数 CK、初始常数 FK
- 工具类 Crypt:UTF-8 字符串与 Uint8Array 的互转、Base64 与 Uint8Array 的互转
- 主类 TsSM4:密钥展开、轮函数、填充/去填充、CBC/ECB 加解密流程
```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
+constructor(config)
+doBlockCrypt(blockData, roundKeys) Uint32Array
+spawnEncryptRoundKeys() void
+rotateLeft(x, y) Number
+linearTransform1(b) Number
+linearTransform2(b) Number
+tauTransform(a) Number
+tTransform1(z) Number
+tTransform2(z) Number
+padding(originalBuffer) Uint8Array
+dePadding(paddedBuffer) Uint8Array
+uint8ToUint32Block(uint8Array, baseIndex) Uint32Array
+encrypt(plaintext) String
+decrypt(ciphertext) String
}
TsSM4 --> Crypt : "使用"
```
图表来源
- [TsSM4.js:39-94](file://src/utils/TsSM4.js#L39-L94)
- [TsSM4.js:96-455](file://src/utils/TsSM4.js#L96-L455)
## 详细组件分析
### 类:TsSM4(SM4 算法主类)
- 职责
- 密钥展开与轮密钥生成
- 轮函数与线性变换
- PKCS#7 填充与去填充
- CBC/ECB 模式加解密
- 输出类型(Base64 或 UTF-8 文本)
- 关键成员
- key:16 字节密钥(Uint8Array)
- iv:16 字节 IV(Uint8Array),CBC 模式必需
- mode:'cbc' 或 'ecb'
- cipherType:'base64' 或 'text'
- encryptRoundKeys / decryptRoundKeys:32 轮密钥数组(Uint32Array)
- 关键方法
- constructor(config)
- 参数:config.keyBuffer(必填,16 字节)、config.iv(可选,16 字节)、config.mode('cbc'|'ecb')、config.outType('base64'|'text')
- 行为:校验长度、初始化轮密钥、准备正向/逆向轮密钥
- encrypt(plaintext: String): String
- 行为:UTF-8 编码 -> PKCS#7 填充 -> 分块处理 -> CBC/ECB -> 输出类型转换
- 返回:Base64 字符串或 UTF-8 文本
- decrypt(ciphertext: String): String
- 行为:根据 cipherType 解码 -> 分块处理 -> CBC/ECB -> 去填充 -> UTF-8 解码
- 返回:明文字符串
- 数据流与算法要点
- 字节序:大端序(MSB 在前),按 4 字节组合为 Uint32
- 轮函数:32 轮迭代,使用 S 盒替换与线性变换
- CBC 链接:前一分组密文作为下一分组的 IV
- 填充:按 16 字节对齐,填充长度为填充字节数
章节来源
- [TsSM4.js:96-156](file://src/utils/TsSM4.js#L96-L156)
- [TsSM4.js:158-180](file://src/utils/TsSM4.js#L158-L180)
- [TsSM4.js:189-207](file://src/utils/TsSM4.js#L189-L207)
- [TsSM4.js:217-241](file://src/utils/TsSM4.js#L217-L241)
- [TsSM4.js:250-277](file://src/utils/TsSM4.js#L250-L277)
- [TsSM4.js:287-312](file://src/utils/TsSM4.js#L287-L312)
- [TsSM4.js:322-329](file://src/utils/TsSM4.js#L322-L329)
- [TsSM4.js:338-387](file://src/utils/TsSM4.js#L338-L387)
- [TsSM4.js:395-452](file://src/utils/TsSM4.js#L395-L452)
### 类:Crypt(编解码工具)
- 字符串与字节数组
- stringToArrayBufferInUtf8(str: String): Uint8Array
- utf8ArrayBufferToString(buf: Uint8Array): String
- Base64 与字节数组
- arrayBufferToBase64(buf: Uint8Array): String
- base64ToArrayBuffer(str: String): Uint8Array
章节来源
- [TsSM4.js:39-94](file://src/utils/TsSM4.js#L39-L94)
### 类:TsCrypto(应用层封装)
- 使用全局配置中的 base64Key 初始化 SM4(ECB 模式,输出 Base64)
- 提供 encrypt/content 和 decrypt/base64 接口
章节来源
- [TsCrypto.js:5-34](file://src/utils/TsCrypto.js#L5-L34)
- [TsGlobalConfig.js:5-33](file://src/utils/TsGlobalConfig.js#L5-L33)
### API 规范与使用示例
- 构造函数
- 名称:TsSM4(config)
- 参数:
- keyBuffer: Uint8Array(必须,16 字节)
- iv?: String(可选,16 字节;CBC 模式必需)
- mode?: 'cbc'|'ecb'(默认 'cbc')
- outType?: 'base64'|'text'(默认 'base64')
- 返回:TsSM4 实例
- 异常:当 keyBuffer 长度不为 16 或 iv 长度不为 16 时抛出错误
- 加密
- 名称:encrypt(plaintext: String): String
- 输入:明文字符串(UTF-8)
- 处理:填充 -> 分块 -> CBC/ECB -> 输出类型转换
- 输出:Base64 字符串或 UTF-8 文本(取决于 outType)
- 解密
- 名称:decrypt(ciphertext: String): String
- 输入:密文字符串(Base64 或 UTF-8,取决于 outType)
- 处理:解码 -> 分块 -> CBC/ECB -> 去填充 -> UTF-8
- 输出:明文字符串
- 示例(路径)
- CBC 模式加密:[TsSM4.js:338-387](file://src/utils/TsSM4.js#L338-L387)
- ECB 模式加密:[TsSM4.js:368-378](file://src/utils/TsSM4.js#L368-L378)
- CBC 模式解密:[TsSM4.js:395-452](file://src/utils/TsSM4.js#L395-L452)
- ECB 模式解密:[TsSM4.js:434-447](file://src/utils/TsSM4.js#L434-L447)
- 应用层封装使用:[TsCrypto.js:19-30](file://src/utils/TsCrypto.js#L19-L30)
章节来源
- [TsSM4.js:96-156](file://src/utils/TsSM4.js#L96-L156)
- [TsSM4.js:338-452](file://src/utils/TsSM4.js#L338-L452)
- [TsCrypto.js:19-30](file://src/utils/TsCrypto.js#L19-L30)
### 流程图:CBC 模式加密
```mermaid
flowchart TD
Start(["开始"]) --> Encode["UTF-8 编码明文"]
Encode --> Pad["PKCS#7 填充到 16 字节倍数"]
Pad --> InitChain["初始化链寄存器为 IVCBC"]
InitChain --> Loop{"遍历每个 16 字节块"}
Loop --> |是| Xor["与上一密文块异或CBC"]
Xor --> Round["32 轮加密轮函数+S 盒+线性变换"]
Round --> Save["保存当前密文块"]
Save --> Next["下一个明文块"]
Next --> Loop
Loop --> |否| OutType["根据 outType 输出Base64 或文本"]
OutType --> End(["结束"])
```
图表来源
- [TsSM4.js:338-387](file://src/utils/TsSM4.js#L338-L387)
### 流程图:ECB 模式解密
```mermaid
flowchart TD
Start(["开始"]) --> Decode["根据 outType 解码Base64 或文本"]
Decode --> Blocks["按 16 字节分块"]
Blocks --> DecryptLoop{"遍历每个 16 字节块"}
DecryptLoop --> |是| Round["32 轮解密逆序轮密钥"]
Round --> Save["保存明文块"]
Save --> Next["下一个块"]
Next --> DecryptLoop
DecryptLoop --> |否| Depad["去填充移除 PKCS#7"]
Depad --> Utf8["UTF-8 解码"]
Utf8 --> End(["结束"])
```
图表来源
- [TsSM4.js:395-452](file://src/utils/TsSM4.js#L395-L452)
### 序列图:应用层加密调用
```mermaid
sequenceDiagram
participant App as "应用"
participant Crypto as "TsCrypto"
participant SM4 as "TsSM4"
participant Config as "TsGlobalConfig"
App->>Crypto : "new TsCrypto()"
Crypto->>Config : "getConfig()"
Config-->>Crypto : "{base64Key}"
Crypto->>Crypto : "base64Key -> Uint8Array"
Crypto->>SM4 : "new TsSM4({keyBuffer, mode : 'ecb', outType : 'base64'})"
App->>Crypto : "encrypt(明文)"
Crypto->>SM4 : "encrypt(明文)"
SM4-->>Crypto : "密文(Base64)"
Crypto-->>App : "密文(Base64)"
```
图表来源
- [TsCrypto.js:7-13](file://src/utils/TsCrypto.js#L7-L13)
- [TsGlobalConfig.js:19-29](file://src/utils/TsGlobalConfig.js#L19-L29)
- [TsSM4.js:96-156](file://src/utils/TsSM4.js#L96-L156)
## 依赖关系分析
- 内部依赖
- TsCrypto 依赖 TsSM4 与 TsGlobalConfig
- TsSM4 依赖 Crypt 与 base64-js
- 外部依赖
- base64-js@1.5.1:Base64 编解码
- umi-request@1.4.0:HTTP 请求(在 https 模块中使用)
```mermaid
graph LR
TsCrypto["TsCrypto.js"] --> TsSM4["TsSM4.js"]
TsCrypto --> TsGlobalConfig["TsGlobalConfig.js"]
TsSM4 --> Base64["base64-js@1.5.1"]
Package["package.json"] --> Base64
```
图表来源
- [TsCrypto.js:1-3](file://src/utils/TsCrypto.js#L1-L3)
- [TsSM4.js:1](file://src/utils/TsSM4.js#L1)
- [package.json:19-22](file://package.json#L19-L22)
章节来源
- [TsCrypto.js:1-3](file://src/utils/TsCrypto.js#L1-L3)
- [package.json:19-22](file://package.json#L19-L22)
## 性能与安全考量
- 性能特征
- 32 轮迭代,每块 16 字节,适合小批量数据快速加解密
- 使用 TypedArray 进行位运算,避免频繁装箱开销
- Base64 编解码在浏览器与 Node 环境均可用
- 安全性考虑
- CBC 模式需要随机且唯一的 IV;若 IV 固定,会降低安全性
- 密钥长度固定为 16 字节,需确保密钥熵足够
- 填充采用 PKCS#7,需确保去填充逻辑正确
- 适用场景
- 小型数据加密(如配置项、令牌、短消息)
- 与 HTTP 加密传输结合使用(参考 README 中的 HttpUtil 配置)
章节来源
- [TsSM4.js:343-378](file://src/utils/TsSM4.js#L343-L378)
- [TsSM4.js:408-447](file://src/utils/TsSM4.js#L408-L447)
- [README.md:12-26](file://README.md#L12-L26)
## 故障排查指南
- 常见错误
- 密钥长度不为 16 字节:构造函数抛错
- IV 非空但长度不为 16 字节:CBC 模式抛错
- 输出类型与输入不匹配:解密失败或结果异常
- 排查步骤
- 确认密钥与 IV 均为 16 字节
- 确认 outType 与实际输入一致
- 检查 Base64 编码是否完整
- 核对 CBC/ECB 模式选择与业务需求一致
章节来源
- [TsSM4.js:102-105](file://src/utils/TsSM4.js#L102-L105)
- [TsSM4.js:116-122](file://src/utils/TsSM4.js#L116-L122)
- [TsSM4.js:345-347](file://src/utils/TsSM4.js#L345-L347)
- [TsSM4.js:410-412](file://src/utils/TsSM4.js#L410-L412)
## 结论
本模块提供了完整的 SM4 对称加密能力,支持 CBC/ECB 模式与 PKCS#7 填充,具备良好的跨平台兼容性(浏览器/Node)。通过 TsCrypto 可直接用于业务场景,推荐在 CBC 模式下使用随机 IV,并严格管理密钥与输出类型,以确保安全性与一致性。
## 附录
### API 一览(方法签名与参数)
- TsSM4(config)
- config.keyBuffer: Uint8Array(16 字节)
- config.iv?: String(16 字节;CBC 必需)
- config.mode?: 'cbc'|'ecb'
- config.outType?: 'base64'|'text'
- encrypt(plaintext: String): String
- decrypt(ciphertext: String): String
章节来源
- [TsSM4.js:96-156](file://src/utils/TsSM4.js#L96-L156)
- [TsSM4.js:338-452](file://src/utils/TsSM4.js#L338-L452)
### 数据格式与转换
- 字节序:大端序(MSB 在前)
- 填充:PKCS#7(1-16 字节)
- 输出类型:
- 'base64':Base64 字符串
- 'text':UTF-8 文本(浏览器/Node 环境均支持)
章节来源
- [TsSM4.js:322-329](file://src/utils/TsSM4.js#L322-L329)
- [TsSM4.js:287-312](file://src/utils/TsSM4.js#L287-L312)
- [TsSM4.js:381-386](file://src/utils/TsSM4.js#L381-L386)
- [TsSM4.js:398-404](file://src/utils/TsSM4.js#L398-L404)
### 扩展与自定义
- 支持自定义 IV(CBC 模式)
- 支持自定义输出类型(Base64 或文本)
- 可在应用层封装更多模式(如 GCM/CTR),但当前实现仅支持 CBC/ECB
章节来源
- [TsSM4.js:115-141](file://src/utils/TsSM4.js#L115-L141)
- [TsCrypto.js:7-13](file://src/utils/TsCrypto.js#L7-L13)