使用pkcs#11 api对sha256哈希进行RSA签名?

6
我目前正在使用pyPkcs11来签署文件。 以下调用适用于使用RSA和sha256签署普通文件:
session.sign(privKey, toSign, Mechanism(CKM_SHA256_RSA_PKCS, None)

但是我的一些文件已经被哈希(sha256)了,签名需要给出与此openSSL命令给出的相同输出:

openssl pkeyutl -sign -pkeyopt digest:sha256 -in <inFilePath> -inkey <keyPath> -out <outFilePath>

我尝试了以下调用,但在签名之前没有生成文件的哈希值。
session.sign(privKey, toSign, Mechanism(CKM_RSA_PKCS, None)

但结果并不是我所期望的,根据这篇帖子的第一个答案 《PKCS#11中的CKM_RSA_PKCS与CKM_RSA_X_509机制》

而CKM_RSA_PKCS则执行PKCS#1标准中定义的填充。该填充在EMSA-PKCS1-v1_5的第3、4和5步中定义。这意味着该机制只能接受比模数小11个字节的消息。要创建有效的RSASSA-PKCS1-v1_5签名,您需要自行执行EMSA-PKCS1-v1_5的第1和2步。

经过一些研究,我的文件似乎包含了由RFC 3447描述的签名的第一步,因此缺少的部分是第二步,即生成ASN.1值。 我可以强制使用pkcs11进行此操作吗?如何操作? PKCS#11文档似乎没有包含任何相关信息。
3个回答

10

我看到有两种方法可以做到这一点;适当的方法取决于标记(并非所有标记/包装器都具备所有机制)。

如在这个其他答案中所解释的,您可以将从中开始的32字节SHA-256转换为完整的填充消息表示。基本上,根据PKCS#1 for RSASSA-PKCS1-v1_5中对EMSA-PKCS1-v1_5的引用所解释的,如果RSA密钥是k个字节(我假设_k_≥51+11=62个字节,即至少8⋅62-7=489位的公共模数,这是必要的安全性),您应该:
  1. 在左侧附加19个字节的字符串
返回翻译文本:
30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20

生成一个51个八位字节的字符串,实际上是哈希类型和值的ASN.1 DER编码

DigestInfo ::= SEQUENCE {
digestAlgorithm DigestAlgorithm,
digest OCTET STRING
}
2. 在左侧进一步添加k-51个八位字节的字符串(其中k-51-3个为FF

00 01 FF FF FF FF..FF FF FF FF 00

生成一个k个八位字节的字符串 3. 使用机制CKM_RSA_X_509进行签名(长度为k个八位字节)。

  • 或者,作为替代:按照[1.]的方式执行;跳过[2.];并在[3.]中使用机制CKM_RSA_PKCS(长度为51个八位字节)。
免责声明:我没有检查过,最近也没有使用PKCS#11设备。
注意:虽然对于正确实现的PKCS#1 v1.5签名填充没有已知攻击,但其使用正逐渐受到贬低;例如法国当局建议
引用: RecomSignAsym-1. 建议使用具有安全证明的非对称签名机制。
或者,用英文表达: It is recommended to use asymmetric signature mechanisms featuring a security proof.
他们提到了RSA-SSA-PSS(错误)。作为额外奖励,该机制的PKCS#11实现是CKM_RSA_PKCS_PSS,它接受哈希而不是要签名的数据,所以所需的操作很简单。

谢谢,我会尽快完成。关于备注,由于文件和签名机制不是内部选择,而是由客户决定,所以我无法控制它们。 - Charles-Edouard Lecat
1
我不明白。如果CKM_RSA_PKCS_PSS接受哈希作为输入,那么CK_RSA_PKCS_PSS_PARAMS结构体中的hashAlg成员有什么用途?"hashAlg:PSS编码中使用的哈希算法:如果签名机制不包括消息哈希,则此值必须是应用程序用于生成消息哈希的机制"(来源:Pkcs11文档) - kingsjester
1
好的,我有答案:CKM_<hash>RSA_PKCS_PSS是一个以<hash>开头,后跟CKM_RSA_PKCS_PSS的C_Digest。CKM_RSA_PKCS_PSS使用hashAlg(两次),mgf和saltLen进行填充。此外,似乎CKM<hash>_RSA_PKCS_PSS不仅将<hash>用于C_digest,还将其作为填充的默认hashAlg。 - kingsjester
1
@kingsjester: 【修正我之前删除的评论】CK_RSA_PKCS_PSS_PARAMS的hashAlg用于确定在EMSA-PSS中使用的哈希算法,以生成内部量H。这应该与_外部_用于生成消息哈希mHash的哈希算法相匹配。MGF1中使用的哈希由值CK_RSA_PKCS_MGF_TYPE指定(最好匹配)。 - fgrieu
@fgrieu-onstrike 是的,这是个好主意,MGF匹配是不必要的才能成功进行签名/验证(我已经测试过)。另一方面,如果 hashAlg != <应用程序用于生成消息哈希的机制>,在 C_SignInit 之后会出现 CKR_MECHANISM_PARAM_INVALID(也经过了测试)。 - kingsjester

2

很抱歉,没有PKCS#11函数可以实现您想要的功能。

我所知道的唯一解决方案是,手动将PKCS#1 v1.5填充应用于您的哈希值,然后使用CKM_RSA_X_509(原始或教科书式RSA)机制对块进行签名。


谢谢,我担心这将是唯一的解决方案。 - Charles-Edouard Lecat

0

与其发出命令,

openssl pkeyutl -sign -pkeyopt digest:sha256 -in <inFilePath> -inkey <keyPath> -out <outFilePath>

尝试

 openssl dgst --sha256 -sign <keyPath> -sha256 -out <signature file> <inFilePath>

这将生成256字节的签名,可能与通过Pkcs11 C_Sign生成的签名相同


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接