13 KiB
SM4 算法模块 (TsSM4)
**本文档引用的文件** - [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)目录
简介
SM4 算法模块是基于中国国家密码标准的对称加密算法实现,采用 128 位分组长度和 128 位密钥长度。该模块提供了完整的 SM4 加密解密功能,支持 CBC 和 ECB 两种工作模式,并实现了 PKCS7 自动填充算法。模块设计遵循现代 JavaScript 最佳实践,使用 ES6 类语法和 TypedArray 数据结构,确保高性能和内存效率。
本模块在企业级应用中用于数据加密、安全通信和敏感信息保护,特别适用于需要符合中国国家标准的加密需求场景。
项目结构
该项目采用模块化组织方式,主要包含以下核心文件:
graph TB
subgraph "核心模块"
SM4[TsSM4.js<br/>主加密模块]
Crypto[TsCrypto.js<br/>加密服务封装]
Global[TsGlobalConfig.js<br/>全局配置]
end
subgraph "工具模块"
Common[TsCommon.js<br/>通用工具]
Storage[TsStorage.js<br/>存储工具]
HttpUtil[TsHttpUtil.js<br/>HTTP工具]
end
subgraph "入口文件"
Index[index.js<br/>模块导出]
Package[package.json<br/>依赖管理]
end
SM4 --> Crypto
Crypto --> Global
Index --> SM4
Index --> Crypto
Index --> Common
Index --> Storage
Index --> HttpUtil
Package --> SM4
Package --> Crypto
图表来源
章节来源
核心组件
主要类结构
TsSM4 模块包含两个核心类:Crypt 工具类和 TsSM4 加密类。
classDiagram
class Crypt {
+stringToArrayBufferInUtf8(str) Uint8Array
+utf8ArrayBufferToString(buffer) String
+arrayBufferToBase64(buffer) String
+base64ToArrayBuffer(base64) Uint8Array
}
class TsSM4 {
-Uint8Array key
-Uint8Array iv
-String mode
-String cipherType
-Uint32Array encryptRoundKeys
-Uint32Array decryptRoundKeys
+constructor(config)
+doBlockCrypt(blockData, roundKeys) Uint32Array
+spawnEncryptRoundKeys() Uint32Array
+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
}
class TsCrypto {
-SM4 sm4
+constructor()
+encrypt(content) String
+decrypt(base64) String
}
TsSM4 --> Crypt : "使用"
TsCrypto --> TsSM4 : "封装"
图表来源
关键常量定义
模块定义了 SM4 算法的核心常量:
- Sbox 替换表: 16×16 的 S 盒替换表,用于字节替换操作
- CK 常量数组: 32 个轮常量,用于密钥扩展
- FK 固定常量: 4 个固定常量,用于初始密钥处理
章节来源
架构概览
整体架构设计
graph TB
subgraph "应用层"
App[业务应用]
Config[配置管理]
end
subgraph "加密服务层"
CryptoService[TsCrypto]
SM4Engine[TsSM4]
end
subgraph "数据转换层"
Base64[Base64 编码]
UTF8[UTF-8 编码]
ByteArray[字节数组]
end
subgraph "底层实现"
SBox[S 盒表]
RoundKeys[轮密钥]
Transform[变换函数]
end
App --> CryptoService
Config --> CryptoService
CryptoService --> SM4Engine
SM4Engine --> Base64
SM4Engine --> UTF8
SM4Engine --> ByteArray
SM4Engine --> SBox
SM4Engine --> RoundKeys
SM4Engine --> Transform
图表来源
数据流处理
sequenceDiagram
participant Client as 应用客户端
participant Crypto as TsCrypto
participant SM4 as TsSM4
participant Crypt as Crypt工具
Client->>Crypto : encrypt(明文)
Crypto->>SM4 : encrypt(明文)
SM4->>Crypt : stringToArrayBufferInUtf8(明文)
Crypt-->>SM4 : UTF-8 字节数组
SM4->>SM4 : padding(填充)
SM4->>SM4 : CBC/ECB 模式处理
SM4->>Crypt : arrayBufferToBase64(密文)
Crypt-->>SM4 : Base64 字符串
SM4-->>Crypto : 密文字符串
Crypto-->>Client : 密文字符串
图表来源
详细组件分析
SM4 核心算法实现
密钥扩展算法
密钥扩展是 SM4 算法的核心步骤,负责从原始密钥生成 32 个轮密钥。
flowchart TD
Start([开始密钥扩展]) --> ExtractMK["提取 MK 密钥<br/>mk[0..3] = key[0..15]"]
ExtractMK --> InitK["初始化 K 数组<br/>k[0..3] = mk ⊕ FK"]
InitK --> Loop{"循环 i = 0..31"}
Loop --> CalcK["计算 k[i+4] = k[i] ⊕ T(k[i+1] ⊕ k[i+2] ⊕ k[i+3] ⊕ CK[i])"]
CalcK --> SaveKey["保存轮密钥<br/>encryptRoundKeys[i] = k[i+4]"]
SaveKey --> Loop
Loop --> |完成| ReverseKeys["反转密钥顺序<br/>decryptRoundKeys = reverse(encryptRoundKeys)"]
ReverseKeys --> End([结束])
图表来源
轮函数实现
每个 SM4 轮包含多个变换操作:
flowchart TD
BlockIn[16字节明文块] --> SplitBlock["分割为4个32位字<br/>block[0..3]"]
SplitBlock --> RoundLoop{"i = 0..31"}
RoundLoop --> XOROp["x[i+4] = x[i] ⊕ T(x[i+1] ⊕ x[i+2] ⊕ x[i+3] ⊕ RK[i])"]
XOROp --> RoundLoop
RoundLoop --> |完成| FinalBlock["组合最终块<br/>y[0..3] = x[32..35]"]
FinalBlock --> BlockOut[16字节密文块]
图表来源
变换函数详解
τ 变换 (字节替换)
τ 变换使用 S 盒进行非线性替换:
- 输入: 32位值
- 处理: 将每个字节通过 S 盒查找替换
- 输出: 32位值
L 线性变换
L 变换实现位移和异或操作:
- L1: b ⊕ (b <<< 2) ⊕ (b <<< 10) ⊕ (b <<< 18) ⊕ (b <<< 24)
- L2: b ⊕ (b <<< 13) ⊕ (b <<< 23)
T 组合变换
T 变换结合 τ 和 L 变换:
- T1: L1(τ(z))
- T2: L2(τ(z))
章节来源
工作模式实现
CBC 模式
CBC (Cipher Block Chaining) 模式提供链式加密:
sequenceDiagram
participant P as 明文块
participant IV as 初始化向量
participant XOR as 异或运算
participant ENC as 加密器
participant C as 密文块
P1->>XOR : 明文1 ⊕ IV
XOR->>ENC : (明文1 ⊕ IV)
ENC-->>C : 密文1
C->>XOR : 密文1 ⊕ 明文2
XOR->>ENC : (密文1 ⊕ 明文2) ⊕ IV
ENC-->>C : 密文2
Note over IV,C : 每次使用前一个密文作为链输入
图表来源
ECB 模式
ECB (Electronic Codebook) 模式提供独立块加密:
flowchart TD
Plain1[明文块1] --> Encrypt1[独立加密]
Plain2[明文块2] --> Encrypt2[独立加密]
Plain3[明文块3] --> Encrypt3[独立加密]
Encrypt1 --> Cipher1[密文块1]
Encrypt2 --> Cipher2[密文块2]
Encrypt3 --> Cipher3[密文块3]
Note1[相同明文块产生相同密文块]
Note2[无链式依赖]
图表来源
PKCS7 填充算法
PKCS7 是一种标准的块填充方案:
flowchart TD
Start([开始填充]) --> CheckNull{"输入为空?"}
CheckNull --> |是| ReturnNull[返回 null]
CheckNull --> |否| CalcPad["计算填充长度<br/>padLen = 16 - (len % 16)"]
CalcPad --> CreateBuffer["创建新缓冲区<br/>长度 = 原长度 + padLen"]
CreateBuffer --> CopyData["复制原数据到新缓冲区"]
CopyData --> FillPad["填充 padLen 个字节<br/>每个字节值为 padLen"]
FillPad --> ReturnBuffer[返回填充后的缓冲区]
ReturnNull --> End([结束])
ReturnBuffer --> End
图表来源
章节来源
数据类型转换
字节数组与 32 位整数转换
flowchart TD
Uint8Array[Uint8Array] --> SplitBytes["按字节分割<br/>每4字节组成一个32位整数"]
SplitBytes --> ShiftLeft["左移操作<br/>高位字节 << 24, 16, 8, 0"]
ShiftLeft --> ORCombine["按位或组合<br/>形成32位整数"]
ORCombine --> Uint32Array[Uint32Array]
Uint32Array --> SplitBits["按位拆分<br/>32位整数拆分为4个字节"]
SplitBits --> ShiftRight["右移操作<br/>高位字节 >> 24, 16, 8, 0"]
ShiftRight --> ANDMask["按位与掩码<br/>& 0xFF"]
ANDMask --> Uint8Array[Uint8Array]
图表来源
章节来源
依赖关系分析
外部依赖
graph TB
subgraph "外部库"
Base64[base64-js@1.5.1<br/>Base64 编解码]
UmiRequest[umi-request@1.4.0<br/>HTTP 请求]
end
subgraph "内部模块"
SM4[TsSM4.js<br/>SM4 加密算法]
Crypto[TsCrypto.js<br/>加密服务封装]
Global[TsGlobalConfig.js<br/>全局配置]
Common[TsCommon.js<br/>通用工具]
Storage[TsStorage.js<br/>存储工具]
HttpUtil[TsHttpUtil.js<br/>HTTP 工具]
end
SM4 --> Base64
Crypto --> Base64
Crypto --> Global
HttpUtil --> UmiRequest
图表来源
内部模块依赖
graph LR
SM4[TsSM4] --> Crypt[Crypt 工具类]
Crypto[TsCrypto] --> SM4
Crypto --> Global[全局配置]
HttpUtil[TsHttpUtil] --> SM4
HttpUtil --> Crypto
图表来源
章节来源
性能考虑
内存使用分析
数据结构内存占用
| 数据结构 | 大小 | 用途 |
|---|---|---|
| Uint8Array | 1 字节/元素 | 原始字节数据 |
| Uint32Array | 4 字节/元素 | 32位整数运算 |
| Sbox 表 | 256 字节 | 字节替换表 |
| 轮密钥数组 | 128 字节 | 32个轮密钥 |
| 中间变量 | ~144 字节 | 临时计算结果 |
内存优化策略
- TypedArray 使用: 优先使用 TypedArray 减少内存开销
- 就地计算: 尽可能重用数组避免额外分配
- 批量处理: 一次处理多个块提高缓存利用率
性能特征
时间复杂度
- 密钥扩展: O(1) - 固定 32 次迭代
- 单块加密: O(1) - 固定 32 轮运算
- 整体加密: O(n) - n 为块数量
空间复杂度
- 内存使用: O(n) - n 为输入数据大小
- 额外开销: O(1) - 固定大小的中间变量
并发处理
模块当前不支持并发操作,建议:
- 为每个并发任务创建独立的 TsSM4 实例
- 避免在多线程环境中共享同一实例
- 考虑使用 Web Workers 处理大量数据
故障排除指南
常见错误及解决方案
密钥长度错误
问题: 密钥长度不是 16 字节 解决: 确保密钥为 16 字节长度 位置: TsSM4.js:103-105
IV 参数错误
问题: CBC 模式下 IV 长度不正确 解决: 确保 IV 为 16 字节长度 位置: TsSM4.js:119-121
填充数据错误
问题: 去填充时数据格式不正确 解决: 确保使用相同的填充算法进行加解密 位置: TsSM4.js:309-311
调试技巧
- 启用详细日志: 在开发环境中输出中间计算结果
- 单元测试: 为关键函数编写测试用例
- 边界测试: 测试空数据、单块数据、多块数据等场景
章节来源
结论
SM4 算法模块提供了完整、高效的中国国家标准加密实现。模块具有以下特点:
技术优势
- 标准兼容: 完全符合 SM4 算法规范
- 性能优秀: 使用 TypedArray 和优化算法
- 接口友好: 提供简洁的加密解密接口
- 模式完整: 支持 CBC 和 ECB 两种工作模式
应用场景
- 企业数据加密
- 网络通信安全
- 敏感信息保护
- 符合国家标准的系统集成
发展建议
- 添加更多模式: 考虑支持 OFB、CFB 等模式
- 性能优化: 实现 SIMD 指令集优化
- 安全性增强: 添加完整性校验机制
- 文档完善: 提供更详细的使用示例
该模块为企业级应用提供了可靠的加密解决方案,满足了中国国家标准的要求,同时保持了良好的性能和易用性。