密钥类型分类:公钥、私钥、对称密钥、秘密密钥
刚入行那会儿,我总觉得“对称密钥”和“秘密密钥”是一回事。直到有一次做硬件安全模块(HSM)适配,愣是把 CKK_GENERIC_SECRET 当对称密钥用,结果接口一直报错。后来查 PKCS#11 标准才发现——这里面的门道其实挺细的。
这一节我们就来拆解四种密钥类型:公钥、私钥、对称密钥、秘密密钥。它们在 PKCS#11 中的表示方式差异很大,但逻辑上又有清晰的层级关系。你想想看,搞懂这些,后面做适配就顺了。
对称密钥与秘密密钥——到底差在哪?
说实话,PKCS#11 的术语一开始让我也很困惑。标准里有个 CKO_SECRET_KEY,但对称密钥也是“秘密的”。那为啥还要单独定义个“秘密密钥”类型?
我个人的理解是这么分的:
- 对称密钥(Symmetric Key):用于对称加密算法,比如 AES、DES、SM4。它在 PKCS#11 中用
CKK_AES、CKK_DES等标识。 - 秘密密钥(Secret Key):这是一个更宽泛的概念,包含对称密钥,还包括像 HMAC 密钥、种子密钥、甚至是派生出来的中间密钥。PKCS#11 的
CKO_SECRET_KEY对象类就是用来承载这些“不公开”的密钥材料。
核心区别:CKO_SECRET_KEY 是对象类,CKK_AES / CKK_GENERIC_SECRET 是密钥类型。一个秘密密钥对象可以是对称加密密钥,也可以是 HMAC 密钥(CKK_GENERIC_SECRET)。
我曾经在项目中把 AES 密钥的 CKA_KEY_TYPE 填成了 CKK_GENERIC_SECRET,结果加密接口始终返回 CKR_KEY_TYPE_INCONSISTENT。嗯,这里要注意:对称密钥必须用对应的 CKK_AES 等类型,别想当然。
公钥与私钥——天生一对
非对称密钥对(Asymmetric Key Pair)在 PKCS#11 里是分开创建的两个对象:CKO_PUBLIC_KEY 和 CKO_PRIVATE_KEY。它们通过 CKA_ID 和 CKA_LABEL 关联起来。
我常用的几种非对称密钥类型:
| 算法 | 公钥类型 | 私钥类型 | 常见用途 |
|---|---|---|---|
| RSA | CKK_RSA |
CKK_RSA |
签名/加密 |
| EC (ECDSA, ECDH) | CKK_EC |
CKK_EC |
签名/密钥交换 |
| DSA | CKK_DSA |
CKK_DSA |
数字签名 |
| DH | CKK_DH |
CKK_DH |
密钥协商 |
一个小经验:公钥对象通常可以安全地导出(CKA_EXTRACTABLE = TRUE),但私钥对象一般要设为 FALSE。我在做金融级 HSM 适配时,曾经误把私钥设成可导出,审计直接亮了红灯……
PKCS#11 中的密钥对象表示
所有密钥在 PKCS#11 中最终都是一个对象(Object),通过 CK_OBJECT_HANDLE 来操作。对象的“身份证”是 CKA_CLASS 和 CKA_KEY_TYPE 两个属性。
下面是一段简化的创建秘密密钥的代码片段(C 伪代码):
CK_OBJECT_CLASS class = CKO_SECRET_KEY;
CK_KEY_TYPE keyType = CKK_AES;
CK_ULONG valueLen = 32; // 256-bit
CK_BYTE value[32] = {...};
CK_ATTRIBUTE template[] = {
{CKA_CLASS, &class, sizeof(class)},
{CKA_KEY_TYPE, &keyType, sizeof(keyType)},
{CKA_VALUE, value, valueLen},
{CKA_ENCRYPT, &trueVal, sizeof(trueVal)},
};
CK_OBJECT_HANDLE hKey;
rv = C_CreateObject(hSession, template, 4, &hKey);
注意:秘密密钥对象的 CKA_VALUE 属性是敏感数据,创建后通常需要立即封装或保护。我曾经在调试时打印了 CKA_VALUE 的十六进制,被安全同事狠狠批评了一顿——生产环境不能用这种操作。
密钥类型分类结构图
下面这张图把 PKCS#11 中密钥对象的分类体系画出来了。你从上往下看,根是通用对象句柄,接着分三类,再往下是具体的算法类型。这样脑子里就有个清晰的树形结构了。
实际适配时的决策路径
在嵌入式设备上做密钥边界适配时,我一般会按以下步骤做分类决策:
- 先看
CKA_CLASS:是公开、私密还是秘密? - 再看
CKA_KEY_TYPE:判断具体算法。 - 检查
CKA_:密钥是存在 里(硬件)还是只存在于会话中(软件临时)。 - 最后确认
CKA_PRIVATE:是否需要用户登录才能访问(私钥对象通常要)。
我个人的避坑指南:如果是 HSM 适配,私钥对象一定设置 CKA_PRIVATE = TRUE,否则未登录用户就能看到私钥句柄,这在安全审计里属于严重漏洞。我曾经因为忘记这个属性,导致产品拿不到 FIPS 认证。
小结
这四种密钥类型在 PKCS#11 里其实构成了一个自然的分类体系:秘密密钥是最宽泛的容器(包括对称密钥),公钥和私钥则专门服务于非对称场景。你只要记住 CKA_CLASS 决定“是什么”,CKA_KEY_TYPE 决定“用什么算法”,往后写适配代码就不会晕了。