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 的设计哲学,说白了就三条原则:
- 安全默认:所有密钥默认不可导出,默认只给最小权限。我曾经在测试环境忘了给加解密权限,线上告警全红了,尴尬。
- 简单一致:每个操作都遵循「密钥 ID + 数据 + 可选参数」的模式。你只要记住这个套路,所有 API 的签名几乎一模一样。
- 向后兼容:新密钥 ID 兼容老格式,但推荐用新格式。迁移时最好先跑一遍兼容性测试,别直接上生产。
注意! 新 SDK 把 KeyUsage 设计成了位掩码(bitmask),比如 ENCRYPT | DECRYPT。但老 SDK 用的是字符串数组。迁移时别直接赋值,要按位或。我有个同事直接复制了老代码,结果密钥成了只读,丑哭。
3.4 密钥类型与 API 映射图
为了让你看得更直观,我画了一张关系图。左侧是密钥类型,右侧是对应的 API 操作,中间用箭头表示它们之间的关系。
3.5 核心参数速查表
很多同学说 KeySpec 结构体太复杂。其实很简单,看下面这个表就够了。我平时迁移新项目时,都会打印出来贴桌上。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| algorithm | string | 是 | 如 'AES'、'SM4'、'RSA' |
| keySize | int | 看算法 | 对称密钥必须,非对称默认 2048 |
| keyUsage | bitmask | 是 | 如 0x01 | 0x02(位或) |
| exportable | bool | 否 | 默认 false,设为 true 才能导出私钥 |
| metadata | dict | 否 | 自定义标签,方便搜索 |
另外,创建非对称密钥对时,返回的 KeyId 同时代表公钥和私钥。签名时自动用私钥,验证时自动用公钥。这个设计我觉得很优雅——你根本不用关心哪个是哪把。
核心思路:新 SDK 把密钥抽象成「对象」,所有操作都通过 KeyId 发起。你不用管密钥存在哪里、怎么存储的。这就是所谓的「密钥即服务」哲学。
3.6 迁移时容易踩的坑
最后说一个我亲身经历的坑。新 SDK 里 Encrypt 函数默认输出的 CiphertextBlob 里面已经包含了初始化向量(IV)。老 SDK 是把 IV 和密文分开返回的。我迁移时没注意,直接把老代码里的 IV 塞给了新接口,结果解密总是失败。折腾了半天才查文档发现,新 SDK 把 IV 嵌在密文里了。
所以不管你觉得自己多熟练,第一步一定要先把新 SDK 的 KeyType 枚举和 EncryptResult 结构体完整读一遍。别凭印象改代码,代价太大了。