Question

I am trying to encrypt an integer using RSA.

I observed that I can encrypt a string but cannot encrypt an Integer.

here are the relevant code snippets:

Could not encrypt the integer, 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
>>> 

Now, I represent that number as a hex string, it works:

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

Using the inspect module I checked the source code of the encrypt function of RSA object and it says it can encrypt both a string or an integer plaintext:

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

So, why is it that when I try to encrypt a number using RSA object, it gives an error?

Why does it expect the input to be in long format and not int?

Was it helpful?

Solution

The traceback tells clearly the rsa.encrypt wants an argument of long type. If it is a string, it will turns it to long type.

rsa.encrypt(4L,"")

This will work and the 4L is still a number but it is of type long.

I think the reason to ask a long is, to perform an encryption, you have to do some padding and then perform on the padded number. The number is very long, for sha1, it is multiples of 512. So for a number at least 512 int can not satisfy the need. So long is asked. And you can see from your result of inspect, it only do type conversion to string, no int. So if you pass an int, it is wrong. You have no method except hacking the source code of the module.

For a long, it returns a long. Maybe you can use this to do the encoding:

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

Also you can change the integer to bytes: rsa.encrypt(input, '')[0].encode('hex'). The input is struct.pack('b', 4).

OTHER TIPS

Python 2.x has two types of integers:

  • The int type, which matches the C type long on the local platform. The precision is limited, but it is at least 32 bits.
  • The long type, which has infinite precision.

The encrypt and decrypt method of the RSA key object in PyCrypto only works with long or binary strings, not with int. That is documented in the PyCrypto's API.

In theory, you could fix your code by forcing the integers to the required type using the function long(), but it is worth pointing out that your code will not be secure.

RSA encryption should be done with OAEP padding and byte strings as input/ouput.

The input variable should be (byte string or long), however, unfortunately, it seems that in Python3 you cannot define long variables using l, L, or long() anymore.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top