18 KiB
加密解密问题
**本文引用的文件** - [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) - [package.json](file://package.json) - [index.js](file://index.js) - [README.md](file://README.md)目录
简介
本指南专注于该代码库中的加密解密功能,特别是SM4算法的实现和使用。该工具包提供了完整的加密解密解决方案,包括密钥管理、数据加密、HTTP请求加密传输等功能。本文档将详细说明如何诊断和解决加密解密过程中可能遇到的各种问题。
项目结构
该项目采用模块化设计,主要包含以下核心模块:
graph TB
subgraph "核心模块"
Crypto[TsCrypto<br/>加密器]
SM4[TsSM4<br/>SM4算法实现]
HttpUtil[TsHttpUtil<br/>HTTP工具]
end
subgraph "配置管理"
GlobalConfig[TsGlobalConfig<br/>全局配置]
Storage[TsStorage<br/>本地存储]
end
subgraph "工具函数"
Common[TsCommon<br/>通用工具]
end
Crypto --> SM4
HttpUtil --> Crypto
HttpUtil --> GlobalConfig
HttpUtil --> Storage
Crypto --> GlobalConfig
Storage --> Common
图表来源
章节来源
核心组件
加密器 (TsCrypto)
加密器是整个加密系统的核心,负责协调SM4算法和密钥管理:
classDiagram
class TsCrypto {
-sm4 : SM4
+constructor()
+encrypt(content) : String
+decrypt(base64) : String
}
class SM4 {
-key : Uint8Array
-iv : Uint8Array
-mode : String
-cipherType : String
-encryptRoundKeys : Uint32Array
-decryptRoundKeys : Uint32Array
+constructor(config)
+encrypt(plaintext) : String
+decrypt(ciphertext) : String
}
TsCrypto --> SM4 : 使用
图表来源
HTTP加密传输
HTTP工具实现了端到端的加密传输机制:
sequenceDiagram
participant Client as 客户端
participant HttpUtil as HTTP工具
participant Crypto as 加密器
participant Server as 服务器
Client->>HttpUtil : 发送请求(启用加密)
HttpUtil->>Crypto : encrypt(JSON.stringify(data))
Crypto->>Crypto : SM4加密
Crypto-->>HttpUtil : 返回加密数据
HttpUtil->>Server : POST /api (encryptData)
Server->>Server : 解密响应数据
Server-->>HttpUtil : 返回加密响应
HttpUtil->>Crypto : decrypt(response.data)
Crypto-->>HttpUtil : 返回明文数据
HttpUtil-->>Client : 返回解析后的数据
图表来源
章节来源
架构概览
该系统的加密架构遵循分层设计原则:
graph TD
subgraph "应用层"
App[业务应用]
end
subgraph "HTTP层"
HttpUtil[HTTP工具]
EncryptSwitch[加密开关]
end
subgraph "加密层"
Crypto[加密器]
SM4[SM4算法]
Padding[填充算法]
end
subgraph "配置层"
Config[全局配置]
KeyStore[密钥存储]
end
subgraph "传输层"
Network[网络传输]
Base64[Base64编码]
end
App --> HttpUtil
HttpUtil --> EncryptSwitch
EncryptSwitch --> Crypto
Crypto --> SM4
SM4 --> Padding
Crypto --> Config
Config --> KeyStore
SM4 --> Base64
Base64 --> Network
图表来源
详细组件分析
SM4算法实现
SM4是中国国家密码标准的对称加密算法,具有以下特点:
核心算法特性
- 块大小: 128位 (16字节)
- 密钥长度: 128位 (16字节)
- 支持模式: ECB和CBC两种工作模式
- 填充方式: PKCS#7填充
- 输出格式: Base64编码
关键实现细节
flowchart TD
Start([开始加密]) --> Convert["转换字符串为UTF-8字节数组"]
Convert --> Pad["执行PKCS#7填充"]
Pad --> Mode{"选择加密模式"}
Mode --> |CBC| CBCInit["初始化IV链"]
Mode --> |ECB| ECBInit["直接处理块"]
CBCInit --> BlockLoop["遍历每个16字节块"]
ECBInit --> BlockLoop
BlockLoop --> XOR{"CBC模式需要XOR"}
XOR --> |是| XORCalc["与前一块结果XOR"]
XOR --> |否| DirectCrypt["直接加密"]
XORCalc --> SM4Crypt["SM4算法加密"]
DirectCrypt --> SM4Crypt
SM4Crypt --> Output{"输出格式"}
Output --> |Base64| Base64Encode["Base64编码"]
Output --> |Text| TextEncode["UTF-8编码"]
Base64Encode --> End([完成])
TextEncode --> End
图表来源
章节来源
加密器配置
加密器通过全局配置管理密钥和加密参数:
配置参数说明
| 参数名 | 类型 | 必需 | 默认值 | 描述 |
|---|---|---|---|---|
| base64Key | String | 是 | WmdUzPJXbngVNiaSsQrihg== | Base64编码的16字节密钥 |
| mode | String | 否 | ecb | 加密模式 (ecb/cbc) |
| cipherType | String | 否 | base64 | 输出格式 (base64/text) |
章节来源
HTTP加密传输机制
HTTP工具实现了透明的加密传输:
sequenceDiagram
participant App as 应用
participant Storage as 存储
participant HttpUtil as HTTP工具
participant Crypto as 加密器
participant Server as 服务器
App->>Storage : getEncryptBody()
Storage-->>App : true/false
App->>HttpUtil : post(url, data)
HttpUtil->>Storage : 检查加密开关
alt 加密开启
HttpUtil->>Crypto : encrypt(JSON.stringify(data))
Crypto->>Crypto : SM4加密
Crypto-->>HttpUtil : 加密结果
HttpUtil->>Server : POST encryptData
else 加密关闭
HttpUtil->>Server : POST 原始数据
end
Server-->>HttpUtil : 返回响应
HttpUtil->>Crypto : decrypt(response.data)
Crypto-->>HttpUtil : 明文数据
HttpUtil-->>App : 解析后的数据
图表来源
章节来源
依赖关系分析
项目依赖关系清晰明确,主要依赖如下:
graph LR
subgraph "外部依赖"
Base64[base64-js@1.5.1]
UmiRequest[umi-request@1.4.0]
end
subgraph "内部模块"
TsCrypto[TsCrypto.js]
TsSM4[TsSM4.js]
TsHttpUtil[TsHttpUtil.js]
TsGlobalConfig[TsGlobalConfig.js]
TsStorage[TsStorage.js]
end
Base64 --> TsCrypto
Base64 --> TsSM4
UmiRequest --> TsHttpUtil
TsCrypto --> TsSM4
TsHttpUtil --> TsCrypto
TsHttpUtil --> TsGlobalConfig
TsHttpUtil --> TsStorage
图表来源
章节来源
性能考虑
加密性能特征
- 算法复杂度: SM4算法的时间复杂度为O(n),其中n为数据块数量
- 内存使用: 主要受数据大小影响,每个块16字节
- CPU消耗: 对称加密算法,CPU开销相对较小
优化建议
- 批量处理: 对于大量小数据,考虑合并处理以减少开销
- 缓存策略: 对于重复的加密操作,可以考虑结果缓存
- 异步处理: 在大数据量场景下使用异步处理避免阻塞
故障排除指南
SM4加密失败
常见错误及解决方案
错误1: 密钥长度不正确
- 错误信息: "key should be a 16 bytes string"
- 原因: 密钥必须是16字节(128位)
- 解决方案:
- 验证密钥长度是否为16字节
- 确认Base64密钥解码后长度为16
- 检查密钥是否被意外截断或修改
错误2: IV参数错误
- 错误信息: "iv error"
- 原因: CBC模式下IV必须存在且长度为16字节
- 解决方案:
- 确保在CBC模式下提供正确的IV
- 验证IV长度为16字节
- 检查IV是否与加密端一致
错误3: 数据格式问题
- 错误信息: 解密时抛出异常
- 原因: 输入数据格式不符合预期
- 解决方案:
- 确认输入数据为正确的Base64字符串
- 验证数据完整性
- 检查是否有额外的空白字符
排查流程
flowchart TD
Start([开始排查]) --> CheckKey["检查密钥配置"]
CheckKey --> KeyOK{"密钥有效?"}
KeyOK --> |否| FixKey["修复密钥配置"]
KeyOK --> |是| CheckMode["检查加密模式"]
FixKey --> CheckMode
CheckMode --> ModeOK{"模式正确?"}
ModeOK --> |否| FixMode["修正加密模式"]
ModeOK --> |是| CheckData["验证数据格式"]
FixMode --> CheckData
CheckData --> DataOK{"数据格式正确?"}
DataOK --> |否| FixData["修正数据格式"]
DataOK --> |是| TestEncrypt["测试加密功能"]
FixData --> TestEncrypt
TestEncrypt --> Success{"问题解决?"}
Success --> |否| ContactSupport["联系技术支持"]
Success --> |是| End([完成])
图表来源
解密错误
常见解密问题
问题1: 解密结果为空或乱码
- 症状: 解密后返回空字符串或不可读字符
- 可能原因:
- 密钥不匹配
- 数据在传输过程中被篡改
- 编码格式不一致
问题2: 解密抛出异常
- 症状: 程序直接崩溃
- 可能原因:
- Base64字符串无效
- 数据长度不是16字节的倍数
- 填充数据损坏
问题3: 解密速度慢
- 症状: 解密过程耗时较长
- 可能原因:
- 数据量过大
- 系统资源不足
- 算法实现效率问题
解决方案
步骤1: 验证密钥配置
- 检查全局配置中的base64Key
- 确认密钥解码后长度为16字节
- 验证密钥与服务器端一致
步骤2: 检查数据完整性
- 验证Base64字符串格式
- 确认数据未被截断
- 检查是否有额外字符
步骤3: 测试解密流程
// 示例测试代码
try {
const testData = "your_base64_data_here";
const decrypted = crypto.decrypt(testData);
console.log("解密结果:", decrypted);
} catch (error) {
console.error("解密失败:", error.message);
}
Base64编码问题
常见Base64问题
问题1: 编码后数据长度异常
- 现象: Base64编码后的数据长度不符合预期
- 原因: 字符串编码问题或数据截断
问题2: 解码失败
- 现象: Base64解码时报错
- 原因: 包含非法字符或格式错误
问题3: 中文字符显示异常
- 现象: 中文字符在Base64中显示为乱码
- 原因: 编码/解码时未使用UTF-8
排查方法
方法1: 验证编码一致性
- 确保使用UTF-8编码
- 检查Base64字符集
- 验证填充字符处理
方法2: 测试编码流程
// 编码测试
const original = "测试数据";
const encoded = base64js.fromByteArray(utf8Encode(original));
const decoded = utf8Decode(base64js.toByteArray(encoded));
if (original === decoded) {
console.log("编码解码正常");
} else {
console.log("编码解码异常");
}
密钥配置错误
配置检查清单
检查项1: 密钥格式
- Base64密钥必须为44个字符(16字节)
- 不包含任何空白字符
- 符合Base64字符集
检查项2: 密钥内容
- 确认密钥未被修改
- 验证密钥与服务器端一致
- 检查是否有特殊字符
检查项3: 配置加载
- 确认全局配置正确加载
- 验证window.httpConfig设置
- 检查配置优先级
修复步骤
- 重新生成密钥: 使用安全的随机源生成新的16字节密钥
- 更新配置: 将新密钥设置到全局配置中
- 同步服务器: 更新服务器端的密钥配置
- 测试验证: 执行完整的加解密测试
加密模式选择不当
ECB vs CBC模式对比
| 特性 | ECB模式 | CBC模式 |
|---|---|---|
| 安全性 | 较低,相同明文产生相同密文 | 较高,引入随机性 |
| 性能 | 稍快 | 稍慢 |
| 实现复杂度 | 简单 | 需要IV |
| 适用场景 | 短小、独立的数据 | 一般数据传输 |
选择建议:
- CBC模式: 推荐用于大多数场景
- ECB模式: 仅适用于特殊需求或测试
填充算法不匹配
PKCS#7填充规则
PKCS#7填充确保数据长度为16字节的倍数:
- 填充值 = 16 - (明文字节长度 % 16)
- 最少填充1字节,最多填充16字节
常见问题:
- 填充长度计算错误
- 填充字节值不正确
- 去填充逻辑错误
解决方案:
- 严格遵循PKCS#7标准
- 验证填充字节的数值
- 确保去填充时正确处理边界情况
加密开关状态检查
开关状态验证
检查点1: 存储状态
// 检查加密开关状态
const encryptStatus = Storage.getEncryptBody();
console.log("加密开关状态:", encryptStatus);
检查点2: 请求流程
// 验证加密请求
const options = {
method: 'POST',
data: {key: 'value'}
};
// 检查是否被加密
if (Storage.getEncryptBody()) {
console.log("数据将被加密传输");
}
检查点3: 响应处理
// 验证解密响应
const response = await HttpUtil.post('/api', data);
console.log("响应数据:", response.data);
密钥存储位置验证
存储验证方法
验证1: 全局配置检查
const globalConfig = GlobalConfig.getConfig();
console.log("当前密钥:", globalConfig.base64Key);
验证2: 环境变量检查
// 检查运行环境
console.log("NODE_ENV:", process.env.NODE_ENV);
console.log("浏览器环境:", typeof window !== 'undefined');
验证3: 配置优先级
// 验证配置覆盖
const config = GlobalConfig.getConfig();
console.log("最终配置:", config);
加密数据格式验证
数据格式检查
检查1: 输入数据格式
// 验证输入数据
function validateInput(data) {
if (typeof data !== 'object') {
throw new Error('输入必须是对象');
}
const jsonStr = JSON.stringify(data);
if (jsonStr.length === 0) {
throw new Error('输入数据为空');
}
return jsonStr;
}
检查2: 输出数据格式
// 验证输出格式
function validateOutput(data) {
if (typeof data !== 'string') {
throw new Error('输出必须是字符串');
}
// 检查Base64格式
const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/;
if (!base64Regex.test(data)) {
throw new Error('输出不是有效的Base64格式');
}
return true;
}
检查3: 数据完整性
// 验证数据完整性
function verifyIntegrity(original, decrypted) {
return original === decrypted;
}
错误信息解读
常见错误类型
类型1: 配置错误
- 错误: "key should be a 16 bytes string"
- 含义: 密钥长度不正确
- 处理: 检查密钥配置和Base64解码
类型2: 模式错误
- 错误: "iv error"
- 含义: CBC模式缺少或错误的IV
- 处理: 提供正确的16字节IV
类型3: 数据格式错误
- 错误: 解码异常
- 含义: Base64数据格式不正确
- 处理: 验证数据格式和完整性
类型4: 算法错误
- 错误: 加密/解密失败
- 含义: 算法实现或参数配置问题
- 处理: 检查算法参数和实现
性能问题诊断
性能监控
监控指标:
- 加密时间: 单次加密耗时
- 解密时间: 单次解密耗时
- 内存使用: 加密过程中的内存占用
- CPU使用率: 加密操作的CPU消耗
诊断步骤:
- 基准测试: 测量不同数据大小下的性能
- 瓶颈识别: 使用性能分析工具定位瓶颈
- 优化实施: 根据分析结果进行优化
优化建议
建议1: 批处理优化
// 批量处理多个数据
function batchEncrypt(dataList) {
return dataList.map(data => crypto.encrypt(JSON.stringify(data)));
}
建议2: 缓存策略
// 缓存常用数据
const cache = new Map();
function cachedEncrypt(data) {
const key = JSON.stringify(data);
if (cache.has(key)) {
return cache.get(key);
}
const result = crypto.encrypt(JSON.stringify(data));
cache.set(key, result);
return result;
}
建议3: 异步处理
// 异步处理大数据
async function asyncEncrypt(data) {
return new Promise((resolve, reject) => {
setTimeout(() => {
try {
const result = crypto.encrypt(data);
resolve(result);
} catch (error) {
reject(error);
}
}, 0);
});
}
结论
该加密解密系统提供了完整的SM4加密解决方案,具有以下特点:
- 安全性: 采用国家标准的SM4算法,支持ECB和CBC两种模式
- 易用性: 提供简单的API接口,支持自动加密传输
- 可配置性: 支持多种配置选项,满足不同需求
- 可靠性: 完善的错误处理和验证机制
在使用过程中,重点关注密钥配置、数据格式、加密模式选择等方面的问题。通过本文档提供的故障排除指南,可以快速定位和解决大部分加密解密相关问题。
对于生产环境部署,建议:
- 使用强随机源生成密钥
- 定期轮换密钥
- 实施完善的日志记录
- 进行定期的安全审计
- 建立应急响应机制