PKCS11Interop:SHA256+RSA分两步与一步签名的差异疑问
问题解析:CKM_SHA256+CKM_RSA_PKCS 与 CKM_SHA256_RSA_PKCS 的签名差异
你碰到的这个问题本质上是没搞懂PKCS#1 v1.5标准中RSA签名的完整流程——单独哈希再签名的操作,跳过了关键的EMSA-PKCS1-v1_5编码步骤,而组合机制CKM_SHA256_RSA_PKCS会自动完成这个标准流程,所以结果自然不一样。
两种实现的核心流程差异
- 分开操作(CKM_SHA256 + CKM_RSA_PKCS):你先计算出文档的SHA-256原始哈希(32字节),然后直接把这个哈希值传给
CKM_RSA_PKCS签名机制。这里的CKM_RSA_PKCS会把哈希值当作普通消息来处理,执行的是针对任意消息的PKCS#1 v1.5填充,而不是针对哈希值的标准编码。 - 组合操作(CKM_SHA256_RSA_PKCS):这个是PKCS#11定义的组合签名机制,会自动完成完整的标准流程:
- 计算文档的SHA-256哈希值
- 对哈希值执行EMSA-PKCS1-v1_5编码(这就是你疑惑的“添加的信息”)
- 用RSA私钥对编码后的结果执行签名模幂运算
EMSA-PKCS1-v1_5编码给哈希添加了什么?
按照PKCS#1 v1.5的规范,SHA-256哈希值经过编码后会变成一个和RSA密钥长度一致的字节块,结构如下:
0x00 0x01 [k - mLen - 3个0xFF字节] 0x00 [ASN.1 DER哈希算法标识符] [原始SHA-256哈希值]
其中:
k是你的RSA密钥长度(比如2048位密钥对应256字节)mLen是ASN.1标识符 + 原始哈希的总长度(SHA-256的话,标识符固定是19字节,哈希32字节,总共51字节)- 中间的
0xFF字节是填充位,用来把整个编码块凑到密钥长度
SHA-256对应的ASN.1 DER标识符是固定的19字节:
30 31 30 0D 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20
这个标识符的作用是告诉验证方“这个签名是基于SHA-256哈希算法生成的”,是标准签名验证流程中必须的信息。
为什么结果完全不同?
当你直接用CKM_RSA_PKCS签原始哈希时,CKM_RSA_PKCS会对32字节的哈希值执行普通消息的PKCS#1填充,填充的结构和EMSA编码完全不一样(普通消息填充是0x00 0x02 [随机非零字节] 0x00 [消息]),最后对这个填充后的块做RSA签名。
而CKM_SHA256_RSA_PKCS是对编码后的哈希块做签名,这个块包含了固定的算法标识符和标准填充,和普通消息填充的结果天差地别,最终的签名自然完全不同。
如何让分开操作的结果和组合机制一致?
如果你一定要手动拆分步骤,不能直接签原始哈希,必须先给SHA-256哈希值加上EMSA-PKCS1-v1_5编码,再把编码后的字节块传给CKM_RSA_PKCS签名,这样得到的结果才会和CKM_SHA256_RSA_PKCS完全一致。
内容的提问来源于stack exchange,提问作者Alexander Poschenrieder




