重复 RSA en/decryption 有时会因明文太大错误而失败

Repeated RSA en/decryption fails sometimes with Plaintext Too Large error

背景:

我正在尝试对短明文(例如 32 字节)应用一系列 RSA 加密和解密步骤。每个步骤都有一个专用的 RSA 密钥,例如。 G。 2048 字节。为此,我正在使用 Crypto Python 包。

我的第一个问题是:

 keyAlice = RSA.generate(2048)
 print keyAlice.size()

这会打印 2047 而不是 2048。我必须提供的数字必须是 256 的倍数,因此尝试使用 2049 作为输入失败。

谁能告诉我为什么 size() 方法 return 的大小与我输入的不同?

这种奇怪现象不会打扰我,但它可能是关于我的主要问题的线索:

对于我的目标,发件人 (Alice) 应应用几个步骤,例如。 g.

  1. 应用 Bob 的 public 密钥(加密)
  2. 应用爱丽丝的私钥(解密)

(我假设所有键的大小都相同。)

接收者 (Bob) 然后可以应用逆函数:

  1. 应用 Alice 的 public 密钥(加密)
  2. 应用 Bob 的私钥(解密)

任何 en/decryption 步骤的结果都会产生一个 str 的 256 字节(2048 位)。

Note: Sometimes the result is shorter, e. g. 255 bytes; as I found out this means stripped zero-bytes at the beginning; padding them solves the issue.

如果我将其用作下一步的输入,则有效

我试图找出这种 ValueError 在哪些情况下发生,哪种 种类 的输入使它发生,但这种情况很少发生(约 3%案例),我没有找到简单的解释(因此没有解决方法)。

我的问题是:

  1. 为什么 size() 方法 return 2047 用于 2048 位密钥? (见上文。)
  2. 为什么 encrypt()decrypt() 方法 有时 对 2048 位的输入有问题(虽然它们在处理它时大多没有问题)?
  3. 为什么如果输入是先前相同类型调用的结果(例如 encrypt(encrypt(x)) 永远不会失败),为什么他们从不遇到任何问题?
  4. 万一我级联这些调用的方法由于我还没有看到的逻辑原因而注定失败,我如何才能级联应用 public 和私钥而不会使输入膨​​胀每一步都很大(例如通过分块)?

这是我正在使用的一些代码,它演示了这个问题:

import Crypto.Random
from Crypto.PublicKey import RSA

s = 0.
for i in range(1000):
  keyAlice = RSA.generate(2048)
  keyBob = RSA.generate(2048)
  x = Crypto.Random.get_random_bytes(32)
  j = 0
  try:
    while True:
      x, = keyAlice.encrypt(x, 0)
      j += 1
      x = keyBob.decrypt(x)
      j += 1
  except ValueError:
    s += j
    print j, s / (i+1)

RSA 是一种代数密码系统。它适用于数字而不是字节。加密通过 Enc(m,e,n) := m<sup>e</sup> mod n = c 其中 m 是消息,e 是 public 指数,n 是 modulus,c 是密文。重要的是要注意 m < n 必须严格为真。否则无法解密
为了完整起见,解密是 Dec(c,d,n) := c<sup>d</sup> mod n = Enc(c,d,n) 完全相同的操作,其中 d 是私有指数。

如果您有两个不同的键,那么您的操作将如下所示:

c<sub>1</sub> := Enc(m,e<sub>1</sub>,n<sub>1</sub>)
c<sub>2</sub> := Dec(c<sub>1</sub>,d<sub>2</sub>,n<sub>2</sub>)
send c<sub>2</sub>

现在,如果 n<sub>2</sub> < n<sub>1</sub>,那么它可以导致c<sub>1</sub> > n<sub>2</sub> 因此不可解密。这并非在所有情况下都会发生,取决于 n<sub>1</sub>n<sub>2[ 之间的距离有多远=75=] 是.

如果n<sub>2</sub> > n<sub>1</sub>,那么"sending"会"work",但在接收端,您可能会颠倒 moduli 的顺序,因此 运行 可能会再次创建一条大于 [=93] 的已恢复消息=]乌鲁斯。它看起来像这样:

r<sub>1</sub> := Enc(c<sub>2</sub>,e<sub>2</sub>,n<sub>2</sub>)
r<sub>2</sub> := Dec(r<sub>1</sub>,d<sub>1</sub>,n<sub>1</sub>)
return r<sub>2</sub>

不用说,你不应该设计依赖于机会的协议。


协议应该是什么样的

您所采用的协议称为加密然后签名。以下问题和答案提供了有关该问题的知识和链接的良好缓存:Should we sign-then-encrypt, or encrypt-then-sign?

无论您做出什么决定,您都需要使用加密和签名生成的填充版本。在 pycrypto 中,你应该使用 Crypto.Cipher.PKCS1_OAEP for encryption and Crypto.Signature.PKCS1_PSS for the digital signature。请记住,已签名的数据必须可用于接收方的验证。这意味着不可能 "encrypt with the private key",因为接收者无法检查他们从中加密的数据是否与任何东西相对应。

发件人:

c := Enc-OAEP(m,e<sub>1</sub>,n<sub>1</sub>)
s := Sign-PSS(hash(c),d<sub>2</sub>,n<sub>2</sub>)
send c, s

接收者:

c<sub>h</sub> := Verify-PSS(s,e<sub>2</sub>,n<sub>2</sub>)
if c<sub>h</sub> == hash(c):
    m<sub>r</sub> := Dec-OAEP(c,d<sub>1</sub>,n<sub>1</sub>)
    return m<sub>r</sub>
else:
    throw Error

Why does the size() method return 2047 for a 2048-bit key?

这看起来像是一个错误,不应该像 this code 中那样发生。虽然,这是一个相当小的错误。