基于 Spring Boot 的对称密码服务化封装:CipherKit 设计与实现
摘要:在企业级 Java 应用中,对称加解密能力普遍以工具类(Util)形式散落于各业务系统,存在实现重复、密钥格式不统一、国密与国际算法兼容性差异显著等问题。本文介绍的开源项目 CipherKit 将对称加解密能力抽象为标准化的 RESTful 服务,对 SM4 / AES 的多种工作模式与填充方案进行系统化封装,支持明文、密钥、IV 的多编码输入,并通过注解式 AOP 机制提供接口幂等与操作审计能力,为企业构建统一的密码基础设施提供参考实现。
关键词:对称加密;SM4;AES;国密算法;Spring Boot;密码服务化;Bouncy Castle
一、背景与动机
1.1 工程现状
对称加解密是几乎所有后端系统的"必备能力",但其实现方式在企业内长期处于碎片化状态:
- 同一集团内不同业务线各自封装独立的
Sm4Util/AesUtil,核心逻辑高度雷同 - 密钥格式(
TEXT/HEX/Base64)在系统间无法互通,需要额外的转换层 - 填充方案(
PKCS5Padding/PKCS7Padding/NoPadding)与工作模式(ECB/CBC/CTR)的组合因人而异,跨系统联调成本高 - 国密合规场景下,JDK 原生不支持 SM4,需引入 Bouncy Castle 等三方库,集成路径缺乏统一规范
这种"散点式"实现导致三个典型问题:重复建设 、一致性难以保障 、安全风险(错误的实现可能引入隐蔽的密钥泄露或数据被篡改)。
1.2 国密合规背景
随着《密码法》与金融行业 GM/T 系列标准的推进,金融、政务、央企等领域对 SM2 / SM3 / SM4 国密算法的应用要求日趋严格。对称加密侧的 SM4 因其 128-bit 分组与 128-bit 密钥的简洁特性,已成为数据存储加密、传输通道加密的标准选择。
然而 SM4 在 JDK 原生 javax.crypto 中并未提供默认实现,开发者必须借助 Bouncy Castle 等扩展库,对工程能力提出了额外要求。
1.3 设计目标
基于上述背景,CipherKit 设定的设计目标包括:
- 接口标准化:以 HTTP/REST 形式暴露加解密能力,与语言、平台解耦
- 算法全覆盖:SM4、AES 主流工作模式与填充方案一站式提供
- 多格式互转 :明文、密钥、IV 的
TEXT/HEX/Base64编码在协议层自由切换 - 工程化底座:集成接口幂等、操作日志、统一响应、异常处理等生产级能力
- 低集成成本:业务系统以 HTTP 调用方式接入,无需引入任何客户端 SDK
二、技术选型
| 维度 | 选型 | 理由 |
|---|---|---|
| 服务框架 | Spring Boot 2.7.x | 生态成熟,JDK 8 兼容,企业内接受度最高 |
| 密码学库 | Bouncy Castle (bcprov-jdk18on) |
国密算法标准实现,PKCS#7 完整支持 |
| 工具库 | Hutool | 简化 Hex/Base64 编码、对象转换等通用逻辑 |
| 构建工具 | Maven | 与 Spring Boot 体系深度集成 |
| 部署形态 | JAR / Docker | 覆盖传统部署与容器化场景 |
JDK 1.8 兼容性是显式约束:当前企业内仍有大量运行在 JDK 8 的存量系统,需保证 CipherKit 可在最低 JDK 8 环境运行。
三、核心特性
- 国密 SM4 全模式支持 --- ECB / CBC / CTR 工作模式,覆盖
NoPadding/PKCS5Padding/PKCS7Padding三种填充方案 - 国际 AES 完整覆盖 --- ECB / CBC 工作模式,PKCS5 / PKCS7 填充
- 多编码输入 --- 明文、密钥、IV 均支持
TEXT/HEX/Base64三种编码,服务端自动归一化为字节序列 - 统一响应规约 --- 基于
Result<T>的标准响应结构,全局异常统一捕获 - 注解式横切能力 ---
@Repeat接口幂等拦截、@Log操作审计日志 - 零外部 SDK 依赖 --- 业务系统以 HTTP 调用接入,跨语言、跨平台透明
- 双部署形态 --- JAR 进程直跑 / Docker 容器化部署
四、算法与模式矩阵
4.1 支持矩阵
| 算法 | 模式 | 填充方案 | IV 必需 |
|---|---|---|---|
| SM4 | ECB | PKCS5Padding | ❌ |
| SM4 | ECB | PKCS7Padding | ❌ |
| SM4 | CBC | PKCS5Padding | ✅ |
| SM4 | CBC | PKCS7Padding | ✅ |
| SM4 | CTR | NoPadding | ✅ |
| AES | ECB | PKCS5Padding | ❌ |
| AES | ECB | PKCS7Padding | ❌ |
| AES | CBC | PKCS5Padding | ✅ |
| AES | CBC | PKCS7Padding | ✅ |
4.2 关键约定
- 密钥长度统一 128 bit(16 字节)------SM4 标准分组宽度;AES-128 兼顾性能与安全性
- 加密输出统一 Base64------便于跨系统、跨语言传输,避免二进制数据在 JSON / 文本协议中的编码歧义
- PKCS5Padding 与 PKCS7Padding 在 16 字节分组下完全等价 ------Java 中
Cipher仅对 AES 支持PKCS5Padding名称但实际语义即 PKCS#7;CipherKit 同时声明两种命名以兼容不同团队的代码习惯
4.3 模式选型建议
| 模式 | 适用场景 | 注意事项 |
|---|---|---|
| ECB | 单分组独立加解密、测试场景 | 不推荐用于生产数据------相同明文分组产生相同密文,泄露统计特征 |
| CBC | 通用业务数据加密 | 需安全随机生成 IV 并与密文一同传输;不提供完整性保护 |
| CTR | 流式数据、并行加解密 | 需严格保证 IV/Nonce 全局唯一,否则破坏机密性 |
完整性与机密性需同时保障时,建议叠加 HMAC 或采用 AEAD 模式(后续路线图)。
五、架构设计
5.1 分层架构
┌─────────────────────────────────────────────────┐
│ HTTP Request(任意语言 / 任意端) │
└──────────────────────┬──────────────────────────┘
↓
┌────────────────────────────┐
│ Controller 接入层 │ ← Sm4Controller(未来 *Controller)
└──────────────┬─────────────┘
↓
┌────────────────────────────┐
│ Service 业务编排层 │ ← @Repeat 幂等 + @Log 审计
└──────────────┬─────────────┘
↓
┌────────────────────────────┐
│ Util 算法与编解码层 │ ← Sm4Util + DecideUtil
└──────────────┬─────────────┘
↓
┌──────────────────────────────────────────┐
│ Result<T> 统一响应 + GlobalException │
└──────────────────────────────────────────┘
5.2 关键设计决策
① 格式归一化下沉至 DecideUtil
请求侧 dataType / keyType / ivType 在协议层被显式声明,由 DecideUtil 统一归一化为字节数组后传入算法层。算法层只消费 byte[],不感知任何文本编码 ------新增编码格式仅需扩展 DecideUtil,算法实现零改动,符合开闭原则。
② 横切能力以注解形式暴露
@Repeat(基于请求特征的去重拦截)与 @Log(基于方法签名的审计日志)作为方法级注解,由 AOP 切面统一处理。新增业务接口时一行注解即可获得幂等与日志能力,避免在每个方法内重复编写模板代码,降低出错概率。
③ 统一响应规约
Result<T> 封装 { success, code, msg, data } 四要素,全局异常由 GlobalExceptionHandler 统一转换。前端 / 客户端只需识别一套响应结构,业务方错误码与服务端异常解耦。
④ 密钥不进数据库
CipherKit 自身不持久化任何密钥与明文,加解密所需的 key / iv 由调用方在请求中提供。职责边界清晰:CipherKit 提供"计算"能力,密钥管理由调用方的 KMS / 配置中心承担。
六、API 规约
6.1 统一响应结构
json
{
"success": true,
"code": 200,
"msg": "操作成功",
"data": { ... }
}
状态码语义:
| 状态码 | 含义 |
|---|---|
| 200 | 业务处理成功 |
| 500 | 业务异常(参数错误、算法不支持等) |
| 701 | 重复提交(被 @Repeat 拦截) |
6.2 加密接口
http
POST /sm4/encrypt
Content-Type: application/json
| 字段 | 必填 | 说明 |
|---|---|---|
algorithmName |
✅ | 固定值 SM4 或 AES |
mode |
✅ | ECB / CBC / CTR |
iv |
⚠️ | CBC/CTR 模式必填,16 字节 |
key |
✅ | 16 字节(128 bit) |
keyType |
✅ | TEXT / HEX / BASE64 |
data |
✅ | 待加密明文 |
dataType |
✅ | TEXT / HEX / BASE64 |
调用示例:
bash
curl -X POST http://localhost:8080/sm4/encrypt \
-H "Content-Type: application/json" \
-d '{
"algorithmName": "SM4",
"mode": "CBC",
"iv": "fedcba98765432100123456789abcdef",
"key": "0123456789abcdeffedcba9876543210",
"keyType": "HEX",
"data": "Hello, CipherKit!",
"dataType": "TEXT"
}'
响应:
json
{
"success": true,
"code": 200,
"msg": "操作成功",
"data": { "data": "uZ6S2xKQv3YpZ4n7sXh9YQ==" }
}
6.3 解密接口
http
POST /sm4/decrypt
请求字段与加密接口一致,data 字段填入 Base64 编码的密文,dataType 传 BASE64。
七、工程实践建议
7.1 密钥管理
- 密钥不进代码------通过配置中心(Apollo / Nacos / Vault)下发,运行时注入
- 密钥不进数据库------CipherKit 自身不持久化密钥
- 传输层加密------CipherKit 部署在内网独立服务,对外仅暴露 HTTPS,建议前置 Nginx + mTLS
7.2 IV 生成
CBC / CTR 模式下 IV 应由密码学安全随机数生成器 (SecureRandom)产生,长度固定 16 字节。严禁使用固定 IV 或可预测 IV(如时间戳),否则将破坏语义安全性。
7.3 部署架构
┌────────────┐ HTTPS ┌──────────────┐
│ 业务集群 │ ──────────→ │ CipherKit │ ← 配置中心注入密钥
└────────────┘ └──────────────┘
↓
[操作日志 / 监控]
建议 CipherKit 与业务系统独立部署、独立扩缩容,并接入统一的日志与监控体系。
八、后续规划
| 阶段 | 能力 |
|---|---|
| ✅ v0.0.1 | SM4 / AES 对称加密,9 种算法组合(已发布) |
| 🔜 v0.1.0 | 非对称算法:RSA / SM2 |
| 🔜 v0.2.0 | 摘要算法:MD5 / SHA-256 / SM3 |
| 🔜 v0.3.0 | 签名验签能力 |
| 🔜 v0.4.0 | 接口鉴权:API Key / OAuth2 |
| 🔜 v0.5.0 | 密钥托管:对接 Vault / KMS |
九、结语
CipherKit 并非"再造一个 Bouncy Castle",而是将 Spring Boot 的工程化能力与密码学库的系统化封装进行整合,以服务化的方式为业务系统提供统一、标准、可治理的对称加解密能力。
对于正在推进国密合规改造、面临多业务线加解密能力整合、或希望降低密码学集成复杂度的团队,CipherKit 提供了一个可落地、可演进的参考实现。欢迎在生产环境中试用,并就算法覆盖、API 规约、部署形态等维度提出改进建议。
项目信息
- 项目地址 :https://gitee.com/gzzzxx/cipherkit
- 问题反馈 :https://gitee.com/gzzzxx/cipherkit/issues
- 开源协议:Apache License 2.0
技术交流与建议欢迎通过 Issue 区交流。如本文对你有帮助,欢迎 ⭐ Star 支持项目持续迭代。