You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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定义的组合签名机制,会自动完成完整的标准流程:
    1. 计算文档的SHA-256哈希值
    2. 对哈希值执行EMSA-PKCS1-v1_5编码(这就是你疑惑的“添加的信息”)
    3. 用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字节)
  • mLenASN.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

火山引擎 最新活动