Search code examples
pythoncryptographypycrypto

Printing RSA Decrypted byte string with Crypto?


I have these sequence of commands through the shell that work fine:

fishgills@fishgills-Mac  ~  cat /tmp/secret_message
Helloo there.%
fishgills@fishgills-Mac  ~  openssl rsautl -encrypt -inkey ~/Documents/test_pub.pem  -pubin -in /tmp/secret_message -out /tmp/test.enc
fishgills@fishgills-Mac  ~  openssl rsautl -decrypt -inkey ~/Documents/test.pem -in /tmp/test.enc
Helloo there.%
fishgills@fishgills-Mac  ~ 

As you can see, everything works fine. Encrypt the message and is able to decrypt it.

So in python, I'm trying to do the same:

from Crypto.PublicKey import RSA

rsakey = RSA.importKey(open("/Users/fishgills/Documents/test.pem", 'rb').read())
raw_data = open("/tmp/test.enc", 'rb').read()
decrypted = rsakey.decrypt(raw_data)
print decrypted

And the program's output is:

fishgills@fishgills-Mac  ~  python main.py ~/Documents/test.pem
�%��u�9��炿��:og:_�Z��WF/��W �v��������a�Jw+�J�Th�N9`V���5t##Go0�
#��A2e*����a�����a�ň��ߘhQX��U�7AB��B�Q�X�l��    ����rkK����� �kKj��\u���PILT�@���Rj���0:��߰9˕�Helloo there.

You can see the message in there... but there's a pile of junk. PyCrypto documentation says that the decrypt method returns a byte string but I haven't been able to decode it properly, I get things like:

Traceback (most recent call last):
  File "main.py", line 9, in <module>
    print decrypted.decode("utf-8")
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/encodings/utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode byte 0xd7 in position 1: invalid continuation byte

Anyone able to point me in the right direction?


Solution

  • OpenSSL uses PKCS#1 v1.5 padding by default. However, as the documentation for Crypto.PublicKey says:

    Attention: this function [decrypt(self, ciphertext)] performs the plain, primitive RSA decryption (textbook). In real applications, you always need to use proper cryptographic padding, and you should not directly decrypt data with this method.

    So you if you want to decrypt your message in Python, you need to use a module that takes this padding into account.

    def test_decrypt():
        from Crypto.PublicKey import RSA
        from Crypto.Cipher import PKCS1_v1_5
        key = RSA.importKey(open('test.pem').read())
        cipher = PKCS1_v1_5.new(key)
        return cipher.decrypt(open("test.enc", 'rb').read(),'** decryption error **')
    
    test_decrypt()
    

    (Note: As per the Python documentation, you would be better off using PKCS#1 OAEP instead of PKCS#1 v1.5. In OpenSSL, you can do this by adding -oaep to the command line options. The decryption code in Python is very similar, and you can refer to the documentation for example code.)