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


项目信息

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