【问题标题】:Python RSA encrypt integersPython RSA加密整数
【发布时间】:2013-07-14 17:35:50
【问题描述】:

我正在尝试使用 RSA 加密整数。

我观察到我可以加密字符串但不能加密整数。

这里是相关代码sn-ps:

无法加密整数,4:

crypto:~$ python
Python 2.7.3 (default, Aug  1 2012, 05:14:39) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from Crypto.PublicKey import RSA
>>> input=4
>>> rsa=RSA.generate(1024)
>>> print rsa.encrypt(input,"")[0].encode('hex')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/dist-packages/Crypto/PublicKey/pubkey.py", line 64, in encrypt
    ciphertext=self._encrypt(plaintext, K)
  File "/usr/lib/python2.7/dist-packages/Crypto/PublicKey/RSA.py", line 71, in _encrypt
    return (self.key._encrypt(c),)
TypeError: must be long, not int
>>> 

现在,我将该数字表示为十六进制字符串,它可以工作:

crypto:~$ python
Python 2.7.3 (default, Aug  1 2012, 05:14:39) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from Crypto.PublicKey import RSA
>>> input='\x04'
>>> rsa=RSA.generate(1024)
>>> print rsa.encrypt(input,"")[0].encode('hex')
09f7d33972b0b6b72136f8aef0c8ba4446afad0dcf65337cd8b6c48c3758f5455e19e9c1ecbd058d7f83bcaa1f860b1ea0197d83f91fa958e6c9a2664a7ebee77c41fbfc4d3960e98afc0d94d1af8a230c4d86fce53f4c7ac72ae40a8acb101b40de6d46fe8e3cb7265f253b410a95a255e5fad0d0438d1fc62ad1feb96d331f

使用检查模块,我检查了 RSA 对象的加密函数的源代码,它说它可以加密字符串或整数明文:

crypto:~$ python
Python 2.7.3 (default, Aug  1 2012, 05:14:39) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import inspect
>>> from Crypto.PublicKey import RSA
>>> rsa=RSA.generate(1024)
>>> rsa
<_RSAobj @0x29c1368 n(1024),e,d,p,q,u,private>
>>> print inspect.getsource(rsa.encrypt)
    def encrypt(self, plaintext, K):
        """encrypt(plaintext:string|long, K:string|long) : tuple
        Encrypt the string or integer plaintext.  K is a random
        parameter required by some algorithms.
        """
        wasString=0
        if isinstance(plaintext, types.StringType):
            plaintext=bytes_to_long(plaintext) ; wasString=1
        if isinstance(K, types.StringType):
            K=bytes_to_long(K)
        ciphertext=self._encrypt(plaintext, K)
        if wasString: return tuple(map(long_to_bytes, ciphertext))
        else: return ciphertext

那么,为什么当我尝试使用 RSA 对象加密数字时,它会报错?

为什么它期望输入是长格式而不是整数?

【问题讨论】:

    标签: python rsa pycrypto


    【解决方案1】:

    回溯清楚地表明rsa.encrypt 想要一个长类型的参数。如果它是一个字符串,它将把它变成长类型。

    rsa.encrypt(4L,"")
    

    这会起作用,4L 仍然是一个数字,但它是 long 类型。

    我认为要求 long 的原因是,要执行加密,您必须进行一些填充,然后对填充的数字执行。数字很​​长,对于sha1来说是512的倍数。所以对于一个数字来说至少512 int是不能满足需要的。问了这么久。您可以从检查结果中看到,它只对字符串进行类型转换,而不是 int。所以如果你传递一个int,那就错了。除了破解模块的源代码之外,您没有其他方法。

    对于长,它返回一个长。也许您可以使用它来进行编码:

    hex(rsa.encrypt(4L, '')[0]).rstrip('L').lstrip(0x)
    '31bf11047cbe9115541e29acb5046d98f2a9bdc44d4768668e9119f8eca24bf24dfc4ac070950734e819675f93e1809859b750df63e8bc71afc7c83edfc6d2f59f495c8e378e0633f07e21672a7e862cfa77a6aede48075dec0cd2b1d8c016dade779f1ea8bd9ffa8ef314c4e391b0f5860cf06cb0f991d2875c49722e98b94f'
    

    您还可以将整数更改为字节:rsa.encrypt(input, '')[0].encode('hex')。输入是struct.pack('b', 4)

    【讨论】:

    • 是的,我知道它需要一个 long 类型的参数。我的问题是,为什么它期望 long 而不是 int?其次,我不提供输入的原因是因为您不能在长对象上调用 encode('hex') 。这将导致错误。而我正在开发的程序,它总是会在 rsa.encrypt 的输出上调用 encode('hex') 方法。这就是为什么,我需要一种方法将我的输入作为整数发送。 \x04 会和数字 4 一样吗?
    • 感谢您的更新。加密脚本的源代码已经写好了。它要求我输入将被加密的输入。现在,源代码正在对加密结果使用 encode('hex'),正如我在上面的代码 sn-p 中提到的那样。正如我所说,我需要一种将数字作为输入发送到加密脚本的方法,同时它不应该是长格式。这是因为加密脚本在加密输出上使用了 encode('hex')。如果你提供 long 作为输入,它会给出一个错误。我的问题是,如何将数字作为字符串格式的输入?
    • 查看答案更新。这就是你想要的,我确定。 :) 我已经测试过它生成的结果与传入 int 的结果相同。完全符合您在评论中提到的内容。 4 是 \x04。 @NeonFlash
    【解决方案2】:

    Python 2.x 有两种类型的整数:

    • int 类型,与本地平台上的 C 类型 long 匹配。精度有限,但至少为 32 位。
    • long 类型,具有无限精度。

    PyCrypto 中 RSA 密钥对象的 encryptdecrypt 方法仅适用于 long 或二进制字符串,不适用于 int。这在PyCrypto's API 中有记录。

    理论上,您可以通过使用函数long() 将整数强制为所需类型来修复您的代码,但值得指出的是您的代码并不安全。

    RSA 加密应该使用OAEP padding 和字节字符串作为输入/输出。

    【讨论】:

    • 是的,我可以提供我的输入。但问题是这样的:如果输入是长格式,rsa.encrypt(input,"")[0].encode('hex') 会出错,因为你不能在长对象上调用编码方法。这就是我正在使用的自定义加密脚本的编写方式。因此,我将输入作为数字传递给脚本的唯一另一种方法是字符串格式。所以,我想知道如何将自定义加密脚本的输入作为字符串格式的数字输入?我正在使用 \x04 发送数字 4 作为输入,还有其他方法吗?如果我说“4”,是一样的吗?
    • @neon-flash hex(rsa.encrypt(long(input),"")[0])[2:] 怎么样?同样,这根本不安全......
    • 我不能像之前说的那样修改这个加密服务的源代码。它已经在另一台机器上运行,我只能给它一个输入。由于它期望输入为字符串格式,我只想知道一种将数字作为输入发送的方法。我可以把它打包成一个字节发送出去。
    【解决方案3】:

    The input variable should be (byte string or long),然而,不幸的是,在 Python3 中您似乎无法再使用 l、L 或 long() 定义长变量。

    【讨论】:

      猜你喜欢
      • 2013-07-04
      • 2017-06-20
      • 2012-07-13
      • 2011-09-12
      • 1970-01-01
      • 2015-07-15
      • 1970-01-01
      • 2015-03-16
      • 1970-01-01
      相关资源
      最近更新 更多