在 RSASSA-PSS 和 RSASSA-PKCS1-v1_5 之间切换是否应该注意其他参数?

Should switching between RSASSA-PSS and RSASSA-PKCS1-v1_5 be mindful of other parameters?

我不确定是应该在这里还是在 Security Stackexchange 中提问。

无论如何,我最近在使用 TPM 处理 RSA 签名时遇到了一个问题,我将填充方案从 RSASSA-PKCS1-v1_5 切换为 RSASSA-PSS。我认为这应该没什么区别,但我注意到 TSS.MSR(.NET TPM 库)中的一个示例不再起作用。我在 https://github.com/microsoft/TSS.MSR/issues/109.

发起了一个关于它的问题

但我想检查一下,是否有人可以分享意见,除了更改填充方案之外是否需要做或注意一些明显的事情?

我认为不是,这也暗示在诸如 .NET RSA 库等参数中,例如https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.rsasignaturepadding 以及如何使用它

using(var rsaKey = RSA.Create(keySizeInBits: 2048))
{
   byte[] message = /* Random data. */
   var sig = rsaKey.SignData(message, HashAlgorithmName.SHA256, RSASignaturePadding.Pss);
}

我从 https://security.stackexchange.com/questions/183179/what-is-rsa-oaep-rsa-pss-in-simple-terms, https://crypto.stackexchange.com/questions/77881/are-rsa-pss-parameters-standardized 和其他地方的问题中看到填充实际上是如何发生的更复杂。但假设它是库的一个实现细节,并且似乎签名检查不匹配或不起作用,一个结论是可能需要检查这个 TSS.NET 库中的各种内部参数,例如填充。因此,因此我想确保自己这个结论是正确的,并且可能没有什么非常明显的东西。举个例子:不要使用 SHA-256 或将 salt 大小明确设置为 nn(好吧,这可能是一个通常不应该关心的实现细节)。

附录:

这是在接受 Maarten Bodewes 的精彩笔记后写的。

将哈希从 SHA-256 切换到 SHA-1 并没有消除链接示例中验证签名的失败。不过,正如预期的那样,“nameSize”或摘要更改为 20 个字节。因此,如果在示例或库中的某处没有正确处理一些“挥之不去的默认值”,仅此一点(可能是部分解决方案)并不是切换到 RSASSA-PSS 填充方案失败的原因。

任务继续。 :)

padding其实有一些配置选项,需要在使用函数的时候提前设置。

奇怪的是,这些“选项”在标准中并没有针对PSS功能进行描述。然而,它们列为 PSS 填充机制:

Options:

  Hash     hash function (hLen denotes the length in octets of the hash
           function output)
  MGF      mask generation function
  sLen     intended length in octets of the salt

但是,这仍然没有完全配置 PSS,因为 MGF 本身是一种算法,并且该算法也有参数。

所以最好看一下参数的ASN.1结构以获得一个好主意:

RSASSA-PSS-params ::= SEQUENCE {
   hashAlgorithm      [0] HashAlgorithm      DEFAULT sha1,
   maskGenAlgorithm   [1] MaskGenAlgorithm   DEFAULT mgf1SHA1,
   saltLength         [2] INTEGER            DEFAULT 20,
   trailerField       [3] TrailerField       DEFAULT trailerFieldBC
}

幸运的是只有一个Mask Generation Function:MGF1。 trailer字段也只指定了一个:trailerFieldBC,所以主要是为了以后的变化而指定的。

如您所见,其中有两个哈希函数,一个用于消息/输入数据本身,一个用于掩码生成函数 (MGF)。因此哈希值又是 MGF1 的一个配置参数。该标准表明最好对消息哈希和 MGF1 哈希使用相同的哈希函数。但是,算法可能会使用默认值,正如您在结构中看到的那样,它是 SHA-1。据我所知,Java 始终对 MGF1 使用 SHA-1,但 .NET 使用与消息哈希相同的哈希。

同样,盐长度通常设置为hLen,散列的输出大小。它默认为 20,但这是因为这是 SHA-1 的输出大小。零的值也是一个选项,不过我觉得一般还是留到20吧。

所以是的,很遗憾,您确实需要检查是否使用了相同的参数。一个好的库应该清楚地指定使用什么,或者至少可以选择明确地配置它们。但是,如果这是对一个好库的要求,那么就会存在许多坏库。此外,您绝对不应尝试从签名本身获取此类信息或在验证过程中猜测多种算法,因为这会将安全性降低到可能的最不安全算法。

最后,当您找到安全且兼容的 PSS 方案后,我建议您在代码中明确指定 使用哪组参数。这可以使用显式参数来完成(即使默认值用于特定库)。如果前者不可能,您也可以在注释中指明参数。单独记录您的方案并在评论中指出它不会有什么坏处。