重复RSA en / decryption有时会出现Plaintext Too Large错误

时间:2016-04-12 13:30:17

标签: python cryptography rsa private-key public-key

背景:

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

我的第一个问题是:

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

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

有人能告诉我为什么size()方法返回的大小与我输入的大小不同吗?

这种陌生感不会打扰我,但它可能是关于我的主要问题发生了什么的线索:

为了我的目标,发送者(Alice)将应用几个步骤,例如:克。

  1. 应用Bob的公钥(加密)
  2. 应用Alice的私钥(解密)
  3. (我假设所有键的大小都相同。)

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

    1. 应用Alice的公钥(加密)
    2. 应用Bob的私钥(解密)
    3. 任何en / decryption步骤的结果都会产生256个字节(2048位)的str

        

      注意:有时候结果会更短,例如: G。 255个字节;正如我发现这意味着在开始时剥离零字节;填充它们解决了这个问题。

      如果我将其用作下一步的输入,则可以使用

      • 总是,如果只使用加密
      • 总是,如果只使用解密
      • 如果组合加密和解密,这大部分时间都有效;
        但有时会失败,提出ValueError: Plaintext too large

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

      我的问题是:

      1. 为什么size()方法会返回2047 2048位密钥? (见上文。)
      2. 为什么encrypt()decrypt()方法有时有输入2048位的问题(虽然它们在处理它时几乎没有问题)?
      3. 如果输入是前一次调用相同类型的结果(例如encrypt(encrypt(x))永不失败),为什么从不有任何麻烦?
      4. 如果我的级联这些调用的方法由于逻辑原因而被绑定失败,我还没有看到,如何在不大量增加每个步骤的输入的情况下进行应用公钥和私钥的级联(例如,组块)?
      5. 以下是我正在使用的一些代码,用于演示问题:

        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)
        

1 个答案:

答案 0 :(得分:2)

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

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

c1 := Enc(m,e1,n1)
c2 := Dec(c1,d2,n2)
send c2

现在,如果n2 < n1,那么它可能会导致c1 > n2,因此无法解密。这并非在所有情况下都会发生,取决于n1n2之间的距离。

如果n2 > n1,那么&#34;发送&#34;将&#34;工作&#34;,但在接收端,你将颠倒模数的顺序,从而再次运行创建一个大于模数的恢复消息的可能性。它看起来像这样:

r1 := Enc(c2,e2,n2)
r2 := Dec(r1,d1,n1)
return r2

毋庸置疑,您不应该设计依赖于偶然性的协议。

协议应该的样子

您之后使用的协议称为 encrypt-then-sign 。以下问题和答案提供了关于此问题的知识和链接的良好缓存:Should we sign-then-encrypt, or encrypt-then-sign?

无论您决定什么,都需要使用填充版本的加密和签名生成。在pycrypto中,您应该使用Crypto.Cipher.PKCS1_OAEP for encryptionCrypto.Signature.PKCS1_PSS for the digital signature。请记住,已签名的数据必须可在接收方进行验证。这意味着无法使用私钥#34;进行加密,因为接收方无法检查它们针对任何内容加密的数据。

发信人:

c := Enc-OAEP(m,e1,n1)
s := Sign-PSS(hash(c),d2,n2)
send c, s

接收器:

ch := Verify-PSS(s,e2,n2)
if ch == hash(c):
    mr := Dec-OAEP(c,d1,n1)
    return mr
else:
    throw Error
  

为什么size()方法为2048位密钥返回2047?

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