密钥类型分类:公钥、私钥、对称密钥、秘密密钥

刚入行那会儿,我总觉得“对称密钥”和“秘密密钥”是一回事。直到有一次做硬件安全模块(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 中密钥对象的分类体系画出来了。你从上往下看,根是通用对象句柄,接着分三类,再往下是具体的算法类型。这样脑子里就有个清晰的树形结构了。

PKCS#11 密钥对象分类树 CK_OBJECT_HANDLE CKO_PUBLIC_KEY CKO_PRIVATE_KEY CKO_SECRET_KEY CKK_RSA CKK_EC CKK_DSA CKK_RSA CKK_EC CKK_DH CKK_AES CKK_GENERIC_ SECRET CKK_DES3 分类依据说明 • CKA_CLASS 确定对象大类(公钥/私钥/秘密密钥) • CKA_KEY_TYPE 确定具体算法类型(如 AES, RSA, EC) • 同一算法(如 RSA)既有公钥对象也有私钥对象 注:秘密密钥子节点只列出常见类型,完整列表见PKCS#11标准

实际适配时的决策路径

在嵌入式设备上做密钥边界适配时,我一般会按以下步骤做分类决策:

  1. 先看 CKA_CLASS:是公开、私密还是秘密?
  2. 再看 CKA_KEY_TYPE:判断具体算法。
  3. 检查 CKA_:密钥是存在 里(硬件)还是只存在于会话中(软件临时)。
  4. 最后确认 CKA_PRIVATE:是否需要用户登录才能访问(私钥对象通常要)。

我个人的避坑指南:如果是 HSM 适配,私钥对象一定设置 CKA_PRIVATE = TRUE,否则未登录用户就能看到私钥句柄,这在安全审计里属于严重漏洞。我曾经因为忘记这个属性,导致产品拿不到 FIPS 认证。

小结

这四种密钥类型在 PKCS#11 里其实构成了一个自然的分类体系:秘密密钥是最宽泛的容器(包括对称密钥),公钥和私钥则专门服务于非对称场景。你只要记住 CKA_CLASS 决定“是什么”,CKA_KEY_TYPE 决定“用什么算法”,往后写适配代码就不会晕了。