3. 密码敏捷架构的参考模型与分层设计

密码敏捷不是把算法“换得更快”,而是让算法替换这件事在系统里变得可控、可验证、可回退。要做到这一点,架构上必须先把“谁负责什么”切清楚。本节给出一个可落地的四层参考模型:密码服务抽象层、策略决策层、算法插件层、密钥管理层。四层之间通过稳定接口解耦,业务系统只依赖抽象层的服务契约,不直接依赖某个具体算法实现。

先明确一个基本判断:密码敏捷的难点往往不在“新算法能不能算对”,而在“旧数据能不能继续解、旧系统能不能平滑过渡、出问题时能不能快速切回”。因此参考模型的设计目标有三个:接口稳定(业务代码不随算法变化而改)、策略外置(用哪种算法由配置和规则决定,而不是写死在代码里)、密钥与算法解耦(同一把逻辑密钥可以在不同算法下以不同密钥材料形态存在)。

业务应用(支付、身份认证、数据存储、通道加密) 只调用统一密码服务接口,不感知具体算法 ① 密码服务抽象层(Crypto Service Abstraction) 统一服务契约 encrypt/decrypt/sign/verify 算法无关的数据封装 密文头 + 算法标识 + 版本 能力查询与降级 支持算法列表 / 兼容旧密文 审计与错误归一 统一错误码 / 调用留痕 ② 策略决策层(Policy Decision) 策略规则库 场景→算法族→最低强度 算法选择与协商 按数据等级/合规要求选型 迁移与灰度控制 双算法并行 / 比例放量 回退开关 一键切回 ③ 算法插件层(Algorithm Plugin) SM4 插件 分组密码 AES-GCM 插件 AEAD SM2 / ECDSA 签名验签 SM3 / SHA-256 杂凑 插件注册表 版本/能力声明 ④ 密钥管理层(Key Management) 逻辑密钥ID · 密钥材料版本 · 生命周期(生成/激活/轮换/归档/销毁) · HSM/KMS 托管 下发算法决策 按算法取密钥材料

下面逐层说明职责边界,并给出实际落地时的关键设计点。

① 密码服务抽象层:把“算法”挡在业务之外

抽象层是业务系统唯一可见的密码入口。它对外暴露的是与算法无关的服务契约,例如 encrypt(plaintext, keyId, context)、sign(data, keyId, purpose),而不是 sm4_encrypt 或 aes_gcm_encrypt。这一层最核心的产物是自描述密文格式:密文头部携带算法标识、算法版本、密钥ID、IV/Nonce 长度等元数据,解密时先读头再路由到对应插件。这样即使底层算法从 SM4-CBC 换成 SM4-GCM,旧密文仍能被正确识别和解开。

抽象层还要承担能力查询与错误归一。业务方可以问“当前环境支持哪些算法族”,抽象层返回能力清单;插件抛出的底层异常(如填充错误、密钥不存在、算法未注册)统一映射为稳定的错误码,避免业务代码去判断具体算法库的异常类型。一个常见的实现细节是:抽象层不缓存密钥明文,只持有密钥ID引用,真正取材料交给密钥管理层,从而缩小敏感数据的暴露面。

② 策略决策层:用规则而不是硬编码决定算法

策略层回答“这次操作该用哪个算法、哪个密钥版本、是否允许降级”。典型策略以“场景 + 数据等级 + 合规要求”为输入,输出算法族与最低强度。例如:

policy:
  scene: "payment_transaction"
  data_class: "L3_sensitive"
  require: ["AEAD", "key_len >= 128"]
  preferred: ["SM4-GCM", "AES-256-GCM"]
  fallback: "deny"          # 不满足强度要求时拒绝,而非降级
  migration:
    mode: "dual_write"      # 新旧算法并行写入
    rollout_ratio: 0.2      # 20% 流量走新算法
    rollback_on_error_rate: 0.01

这段示例策略表达了三件事:首选国密算法、允许 AES 作为备选、迁移期采用双写加灰度放量,并且错误率超过 1% 自动回退。策略层与抽象层之间是“决策—执行”关系:抽象层每次调用前向策略层请求决策结果(通常带短时缓存),策略层返回算法标识与密钥版本,抽象层据此路由到插件。把回退开关放在策略层而不是散落在业务代码里,是敏捷架构能否真正“敢换”的关键。

③ 算法插件层:可注册、可版本化、可替换

插件层是算法的实际实现载体。每个插件实现统一接口(初始化、加解密、签名验签、杂凑、自检),并向注册表声明自己的能力:算法标识、支持的模式、密钥长度、是否支持流式处理、版本号。注册表是插件层的中枢,抽象层通过它把“算法标识”解析为具体实现。插件应满足三个工程约束:一是无状态或显式状态,避免全局变量导致并发问题;二是启动自检,用已知向量验证实现正确性,自检失败则拒绝注册;三是版本共存,同一算法族允许多个版本并存,由密文头中的版本号决定解密走哪个实现。

插件化的直接收益是替换成本可控:新增一个算法只需实现接口并注册,抽象层与业务代码零改动;下线一个算法只需在策略层禁止新数据使用它,同时保留插件用于解密历史数据,待存量数据迁移完成后再摘除。

④ 密钥管理层:算法无关的密钥生命周期

密钥管理层管理的是“逻辑密钥”,而不是“某算法的密钥字节”。一把逻辑密钥有稳定的密钥ID,其下可以挂多个版本的密钥材料,每个版本绑定具体算法与用途。这样当算法替换时,业务侧引用的密钥ID不变,密钥管理层负责生成新算法对应的材料并推进版本。生命周期通常包括生成、激活、轮换、归档、销毁五个状态,轮换时新旧版本并存一段时间以支持解密旧数据。密钥材料应托管在 HSM 或 KMS 中,插件层通过受控接口按“密钥ID + 版本 + 用途”取用,且取用行为留痕。

四层的依赖方向是单向的:业务依赖抽象层,抽象层依赖策略层与插件注册表,插件层依赖密钥管理层。反向依赖(例如插件直接读业务配置、密钥管理层调用业务代码)会破坏敏捷性,应在评审中明确禁止。

一次调用的完整链路

以“支付报文加密”为例:业务调用抽象层 encrypt(payload, keyId="pay-key-01", scene="payment_transaction");抽象层向策略层请求决策,得到“SM4-GCM、密钥版本 v3、允许双写”;抽象层从注册表解析 SM4-GCM 插件,向密钥管理层申请 pay-key-01/v3 的材料;插件完成加密,抽象层组装带算法标识与版本号的密文头返回。迁移期若策略要求双写,抽象层会再走一次 AES-256-GCM 路径,产出两份密文供新旧系统分别消费。整个过程业务代码只感知一次调用和一份返回结构。

判断这套架构是否真正“敏捷”,可以看三个可观察指标:替换一个算法时业务代码改动行数是否为零;存量密文在算法下线后是否仍可解密;策略变更后生效延迟是否在可接受范围内(通常要求秒级到分钟级)。若三者都满足,说明分层边界是清晰的;若某一项不满足,问题往往出在抽象层泄漏了算法细节,或策略被硬编码进了插件与业务。