基于 Spring Boot 的对称密码服务化封装:CipherKit 设计与实现

基于 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 设定的设计目标包括:

  1. 接口标准化:以 HTTP/REST 形式暴露加解密能力,与语言、平台解耦
  2. 算法全覆盖:SM4、AES 主流工作模式与填充方案一站式提供
  3. 多格式互转 :明文、密钥、IV 的 TEXT / HEX / Base64 编码在协议层自由切换
  4. 工程化底座:集成接口幂等、操作日志、统一响应、异常处理等生产级能力
  5. 低集成成本:业务系统以 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 固定值 SM4AES
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 编码的密文,dataTypeBASE64


七、工程实践建议

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 规约、部署形态等维度提出改进建议。


项目信息

技术交流与建议欢迎通过 Issue 区交流。如本文对你有帮助,欢迎 ⭐ Star 支持项目持续迭代。