为啥在使用私钥加密时不能使用 RSA OAEP 填充?

Posted

技术标签:

【中文标题】为啥在使用私钥加密时不能使用 RSA OAEP 填充?【英文标题】:Why can't I use RSA OAEP padding when encrypting with a private key?为什么在使用私钥加密时不能使用 RSA OAEP 填充? 【发布时间】:2019-01-26 02:01:27 【问题描述】:

我正在生成一个使用 RSA 使用私钥加密的许可证密钥有效负载,然后使用公钥对其进行解密,以在我的面向用户的软件中使用许可证有效负载。我正在加密而不是签名,所以我只需要向我的用户传递一个字符串,而不是传递密钥和签名。

但是我在使用带有私钥加密的 OAEP 填充时遇到了问题:

require 'openssl'

padding = OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING
priv = OpenSSL::PKey::RSA.new 2048
pub = priv.public_key

# FIXME: Why can't I use OAEP padding with private key encryption?
data = 'customer:foo@example.com;allowances:25;users:5;locked:true;'
enc = priv.private_encrypt data, padding
dec = pub.public_decrypt enc, padding

puts dec == data

回复:https://repl.it/repls/LavishEarnestWifi.

运行此程序会引发错误:unknown padding type。使用公钥加密允许我使用 OAEP,但不能使用私钥。但是,使用 PKCS1 填充是可行的。我认为使用 PKCS1 不安全,建议使用 OAEP?我希望能够加密相同的有效负载并获得不同的许可证密钥,就像使用 OAEP 填充一样。

我做错了什么?这是个坏主意吗?

【问题讨论】:

【参考方案1】:

是的,这是一件坏事;只有在使用针对签名生成的填充方案时,签名生成才被证明是安全的。实际上,用于签名生成和加密的 PKCS#1 v1.5 填充是不同的,即使它们经常被赋予相同的名称。

您似乎正在寻找的是具有(部分)消息恢复的签名方案。那些不再经常使用了。原因之一是 ECDSA 签名比 RSA 签名小得多(ECC 密钥大小的两倍,对于非常安全的 256 位曲线来说,大约是 64 字节)。


有一些签名生成方法可以指定here (ISO 9796) 来恢复消息。这些有点陈旧和危险,特别是如果攻击者可以以某种方式影响输入消息。一般来说,它们就足够了。对于一个真正安全的方案,有 [PSS 提供消息恢复,正式名称为 EMSR-PSS,指定为in section 1.3 of the paper: PSS: Provably secure encoding method for digital signatures by Bellare and Rogaway。

不幸的是,这些似乎不能直接用于 Ruby,因此您可能必须实现或链接到填充方案。也就是说,由于 OAEP 也不可用,这很难取消他们的资格。一般来说,我会选择 ECDSA,并将消息与较小的签名格式结合起来。


请注意,私钥操作与 RSA 公钥操作完全不同。它们通常依赖于 CRT 参数的存在。此外,可能更重要的是,它们需要被设计为保护私钥免受侧信道攻击等攻击。只使用私钥而不是公钥不是一个好主意。

有关使用 OAEP 生成签名的讨论,请参阅讨论 here。有关使用私钥的 RSA 加密是否等于生成签名的信息,请参阅我自己的自答 Q/A here。

【讨论】:

您是说使用私钥加密实际上不是加密,而是签名,这就是为什么PKCS1_OAEP_PADDING 不可用的原因?如果是签名,如何通过公钥解密恢复明文?为什么不好? 是的,我就是这么说的。不仅在这里,还有on the crypto site。 除非使用带有消息恢复的方案,否则无法恢复明文。消息恢复本身还不错;使用错误的填充机制来生成签名但是很糟糕。 OAEP 不是为签名生成而设计的。 RSA 的很多安全性都来源于填充;没有填充的 RSA 甚至不是远程安全的(如果消息可以有任何价值)。 好的,感谢您的澄清。我不知道。使用 PKCS1_PADDING 的 RSA 私钥加密是否也很不安全,或者这样可以吗? 没有诸如PKCS#1之类的填充。 PKCS#1 is a standard 定义了使用 RSA 的方法。它是 RSA 实验室的第一个标准,由 Rivest、Shamir 和 Adleman 创立——RSA 中的 RSA。它定义了多种填充方法,包括 RSAES-PKCS1-v1_5(用于加密)和 RSASSA-PKCS1-v1_5(用于带有附录的签名方案)。现在“附录”是消息本身,表明您需要完整的消息来执行签名验证。使用 RSAES-PKCS1-v1_5 填充来生成签名也不是一个好主意。 实际上,您可能已经看到,在 PKCS#1 中也定义了 PSS 和 OAEP。如果您指定 PKCS#1 进行加密,那么您希望使用 RSAES-PKCS1-v1_5,但某些库实际上会部分使用 RSASSA-PKCS1-v1_5 来支持一些奇怪的 SSL 签名方案,该方案同时使用 MD5 和 SHA1 连接在一起。

以上是关于为啥在使用私钥加密时不能使用 RSA OAEP 填充?的主要内容,如果未能解决你的问题,请参考以下文章

解密 C# 中使用 RSA-OAEP 在 JavaScript 中加密的数据时出现 OAEP 填充错误

Nodejs 使用node-rsa 加密数据

Nodejs 使用node-rsa 加密数据

如何使用 RSA 私钥解密 JWT

使用Java和JavaScript之间的OAEP进行RSA加密

如何在 Crypto++ 中使用 RSA OAEP SHA-256 加密/解密数据