3. 新 SDK 密钥接口概览

老一代 SDK 的密钥接口,说实话,我用得挺憋屈的。你想创建一个密钥,得先查半天文档,看看到底该调用哪个函数,参数顺序还不能搞错。新 SDK 出来以后,我第一件事就是把它的密钥类型和 API 全部撸了一遍。这一章我就给你讲讲新 SDK 到底是怎么设计密钥体系的。

3.1 密钥类型:三大类,一次说清楚

新 SDK 把密钥分成了三类。别小看这个分类,它直接影响你该调哪个 API。我记得最开始我没有仔细区分,直接把对称密钥的 Spec 传给了签名函数,结果跑起来就报错。

密钥类型子类型典型算法主要用途
对称密钥块加密 / 流加密AES-256, SM4数据加密、解密
非对称密钥签名 / 加密RSA-4096, ECDSA P-256, SM2数字签名、密钥交换
证书 / 密钥对X.509, 带私钥对RSA, EC身份认证、TLS

注意看最后一行——新 SDK 把 SM 系列算法当成一等公民了。我有个项目必须走国密,以前得自己封装一层,现在原生支持,省了不少事。

3.2 API 设计:少即是多

新 SDK 的 API 数量比老版少了将近一半。为什么?因为它把很多参数变成了可选,用统一的结构体传参。我个人习惯是喜欢这种设计的,不用记一长串函数名。

  • 创建密钥:CreateKey(keySpec, keyUsage, material?) — 一个接口搞定所有类型
  • 使用密钥:Encrypt(keyId, plaintext, params) / Decrypt(keyId, ciphertext, params)
  • 签名验签:Sign(keyId, digest) → signature / Verify(keyId, signature, digest) → bool
  • 删除密钥:DeleteKey(keyId, force?) — 默认软删除,加 force 才算硬删

你想想看,原来老 SDK 光是创建密钥就有 5 个不同函数,现在一个 CreateKey 配上 KeySpec 结构体就全搞定了。这背后其实是设计哲学变了。

避坑提示:我曾经在迁移时,发现老 SDK 的 GenerateKey 把密钥明文直接放内存里,新 SDK 默认托管在 HSM 中。如果你不传 material 参数,根本拿不到私钥明文。这个坑我踩了一下午才反应过来。

3.3 设计哲学:安全、简单、一致

新 SDK 的设计哲学,说白了就三条原则:

  1. 安全默认:所有密钥默认不可导出,默认只给最小权限。我曾经在测试环境忘了给加解密权限,线上告警全红了,尴尬。
  2. 简单一致:每个操作都遵循「密钥 ID + 数据 + 可选参数」的模式。你只要记住这个套路,所有 API 的签名几乎一模一样。
  3. 向后兼容:新密钥 ID 兼容老格式,但推荐用新格式。迁移时最好先跑一遍兼容性测试,别直接上生产。

注意! 新 SDK 把 KeyUsage 设计成了位掩码(bitmask),比如 ENCRYPT | DECRYPT。但老 SDK 用的是字符串数组。迁移时别直接赋值,要按位或。我有个同事直接复制了老代码,结果密钥成了只读,丑哭。

3.4 密钥类型与 API 映射图

为了让你看得更直观,我画了一张关系图。左侧是密钥类型,右侧是对应的 API 操作,中间用箭头表示它们之间的关系。

新SDK密钥类型 → API映射 对称密钥 非对称密钥 证书/密钥对 CreateKey Encrypt / Decrypt Sign / Verify DeleteKey 说明: 每种密钥类型都可以调用 CreateKey 创建,但只有对称密钥可以直接 Encrypt/Decrypt;非对称密钥用于签名,也支持加密(但效率低)。证书/密钥对主要用于 Sign/Verify。 DeleteKey 对所有类型通用,但建议先做软删除确认。

3.5 核心参数速查表

很多同学说 KeySpec 结构体太复杂。其实很简单,看下面这个表就够了。我平时迁移新项目时,都会打印出来贴桌上。

参数类型必填说明
algorithmstring是如 'AES'、'SM4'、'RSA'
keySizeint看算法对称密钥必须,非对称默认 2048
keyUsagebitmask是如 0x01 | 0x02(位或)
exportablebool否默认 false,设为 true 才能导出私钥
metadatadict否自定义标签,方便搜索

另外,创建非对称密钥对时,返回的 KeyId 同时代表公钥和私钥。签名时自动用私钥,验证时自动用公钥。这个设计我觉得很优雅——你根本不用关心哪个是哪把。

核心思路:新 SDK 把密钥抽象成「对象」,所有操作都通过 KeyId 发起。你不用管密钥存在哪里、怎么存储的。这就是所谓的「密钥即服务」哲学。

3.6 迁移时容易踩的坑

最后说一个我亲身经历的坑。新 SDK 里 Encrypt 函数默认输出的 CiphertextBlob 里面已经包含了初始化向量(IV)。老 SDK 是把 IV 和密文分开返回的。我迁移时没注意,直接把老代码里的 IV 塞给了新接口,结果解密总是失败。折腾了半天才查文档发现,新 SDK 把 IV 嵌在密文里了。

所以不管你觉得自己多熟练,第一步一定要先把新 SDK 的 KeyType 枚举和 EncryptResult 结构体完整读一遍。别凭印象改代码,代价太大了。