44

I need help using RSA encryption and decryption in Python.

I am creating a private/public key pair, encrypting a message with keys and writing message to a file. Then I am reading ciphertext from file and decrypting text using key.

I am having trouble with the decryption portion. As you can see in my code below, when I put in decrypted = key.decrypt(message) that the program works, yet the decrypted message is encrypted again. It seems like it is not reading the ciphertext from the file.

Can anyone help me write this code so decryption reads ciphertext from file and then uses key to decrypt ciphertext?

import Crypto from Crypto.PublicKey import RSA from Crypto import Random random_generator = Random.new().read key = RSA.generate(1024, random_generator) #generate public and private keys publickey = key.publickey # pub key export for exchange encrypted = publickey.encrypt('encrypt this message', 32) #message to encrypt is in the above line 'encrypt this message' print 'encrypted message:', encrypted #ciphertext f = open ('encryption.txt', 'w'w) f.write(str(encrypted)) #write ciphertext to file f.close() #decrypted code below f = open ('encryption.txt', 'r') message = f.read() decrypted = key.decrypt(message) print 'decrypted', decrypted f = open ('encryption.txt', 'w') f.write(str(message)) f.write(str(decrypted)) f.close() 
6
  • 3
    I am having trouble with the decryption portion is not a good description of your problem. Please read How to ask. You should edit your question to include your inputs, outputs and your expected outputs. Commented May 5, 2015 at 15:11
  • The edit helped, but it would still help if you included the output of your program, and the output you expect Commented May 5, 2015 at 15:25
  • 1
    You have multiple typos in your code. So what did you actually try? Commented May 5, 2015 at 15:30
  • 1
    Bear in mind that this is "Textbook RSA" which is weak, especially for short messages. Padding (via PKCS#1) remedies these problems which PyCrypto (and PyCryptodome, the maintained fork) can do. Commented Jan 24, 2017 at 23:03
  • related: How to encrypt a string using the key Commented Jul 15, 2018 at 6:01

7 Answers 7

56

In order to make it work you need to convert key from str to tuple before decryption(ast.literal_eval function). Here is fixed code:

import Crypto from Crypto.PublicKey import RSA from Crypto import Random import ast random_generator = Random.new().read key = RSA.generate(1024, random_generator) #generate pub and priv key publickey = key.publickey() # pub key export for exchange encrypted = publickey.encrypt('encrypt this message', 32) #message to encrypt is in the above line 'encrypt this message' print('encrypted message:', encrypted) #ciphertext f = open ('encryption.txt', 'w') f.write(str(encrypted)) #write ciphertext to file f.close() #decrypted code below f = open('encryption.txt', 'r') message = f.read() decrypted = key.decrypt(ast.literal_eval(str(encrypted))) print('decrypted', decrypted) f = open ('encryption.txt', 'w') f.write(str(message)) f.write(str(decrypted)) f.close() 
Sign up to request clarification or add additional context in comments.

5 Comments

It worked! thank you so much! i would have never guessed to add that . I appreciate your help!
@Alysson PyCrypto documentation says about publickey.encrypt(): "you should not directly encrypt data with this method" and it recommends PKCS#1 OAEP instead (for a code example, follow the link)
Could you please make a version for Python 3.3+?
encrypted = publickey.encrypt('encrypt this message', 32) - unsupported operand type(s) for pow(): 'str', 'int', 'int'
From the import, I presume this is using PyCryptodome. How is it then that their documentation for RSA and more specifically RSA.RsaKey does not document an encrpyt and decrypt functions. They seem strangely absent. See link: pycryptodome.readthedocs.io/en/latest/src/public_key/…
14

PKCS#1 OAEP is an asymmetric cipher based on RSA and the OAEP padding

from Crypto.PublicKey import RSA from Crypto import Random from Crypto.Cipher import PKCS1_OAEP def rsa_encrypt_decrypt(): key = RSA.generate(2048) private_key = key.export_key('PEM') public_key = key.publickey().exportKey('PEM') message = input('plain text for RSA encryption and decryption:') message = str.encode(message) rsa_public_key = RSA.importKey(public_key) rsa_public_key = PKCS1_OAEP.new(rsa_public_key) encrypted_text = rsa_public_key.encrypt(message) #encrypted_text = b64encode(encrypted_text) print('your encrypted_text is : {}'.format(encrypted_text)) rsa_private_key = RSA.importKey(private_key) rsa_private_key = PKCS1_OAEP.new(rsa_private_key) decrypted_text = rsa_private_key.decrypt(encrypted_text) print('your decrypted_text is : {}'.format(decrypted_text)) 

3 Comments

Is t possible to you this approach for encrypting a whole file
_RSAobj object has no 'export_key' attribute
RSA encryption only works on small block sizes so to do a whole file you would need to encrypt it in chunks , this is pretty slow. Its better to use a hybrid encryption scheme where you encrypt the data with a random AES key then encrypt the AES and Nonce with the RSA key , you can store the encrypted key and nonce with the encrypted data for convenience. AES is usually hardware accelerated. pyNACL has a box object that does this for you
12
# coding: utf-8 from __future__ import unicode_literals import base64 import os import six from Crypto import Random from Crypto.PublicKey import RSA class PublicKeyFileExists(Exception): pass class RSAEncryption(object): PRIVATE_KEY_FILE_PATH = None PUBLIC_KEY_FILE_PATH = None def encrypt(self, message): public_key = self._get_public_key() public_key_object = RSA.importKey(public_key) random_phrase = 'M' encrypted_message = public_key_object.encrypt(self._to_format_for_encrypt(message), random_phrase)[0] # use base64 for save encrypted_message in database without problems with encoding return base64.b64encode(encrypted_message) def decrypt(self, encoded_encrypted_message): encrypted_message = base64.b64decode(encoded_encrypted_message) private_key = self._get_private_key() private_key_object = RSA.importKey(private_key) decrypted_message = private_key_object.decrypt(encrypted_message) return six.text_type(decrypted_message, encoding='utf8') def generate_keys(self): """Be careful rewrite your keys""" random_generator = Random.new().read key = RSA.generate(1024, random_generator) private, public = key.exportKey(), key.publickey().exportKey() if os.path.isfile(self.PUBLIC_KEY_FILE_PATH): raise PublicKeyFileExists('Файл с публичным ключом существует. Удалите ключ') self.create_directories() with open(self.PRIVATE_KEY_FILE_PATH, 'w') as private_file: private_file.write(private) with open(self.PUBLIC_KEY_FILE_PATH, 'w') as public_file: public_file.write(public) return private, public def create_directories(self, for_private_key=True): public_key_path = self.PUBLIC_KEY_FILE_PATH.rsplit('/', 1) if not os.path.exists(public_key_path): os.makedirs(public_key_path) if for_private_key: private_key_path = self.PRIVATE_KEY_FILE_PATH.rsplit('/', 1) if not os.path.exists(private_key_path): os.makedirs(private_key_path) def _get_public_key(self): """run generate_keys() before get keys """ with open(self.PUBLIC_KEY_FILE_PATH, 'r') as _file: return _file.read() def _get_private_key(self): """run generate_keys() before get keys """ with open(self.PRIVATE_KEY_FILE_PATH, 'r') as _file: return _file.read() def _to_format_for_encrypt(self, value): if isinstance(value, int): return six.binary_type(value) for str_type in six.string_types: if isinstance(value, str_type): return value.encode('utf8') if isinstance(value, six.binary_type): return value 

And use

KEYS_DIRECTORY = settings.SURVEY_DIR_WITH_ENCRYPTED_KEYS class TestingEncryption(RSAEncryption): PRIVATE_KEY_FILE_PATH = KEYS_DIRECTORY + 'private.key' PUBLIC_KEY_FILE_PATH = KEYS_DIRECTORY + 'public.key' # django/flask from django.core.files import File class ProductionEncryption(RSAEncryption): PUBLIC_KEY_FILE_PATH = settings.SURVEY_DIR_WITH_ENCRYPTED_KEYS + 'public.key' def _get_private_key(self): """run generate_keys() before get keys """ from corportal.utils import global_elements private_key = global_elements.request.FILES.get('private_key') if private_key: private_key_file = File(private_key) return private_key_file.read() message = 'Hello мой friend' encrypted_mes = ProductionEncryption().encrypt(message) decrypted_mes = ProductionEncryption().decrypt(message) 

Comments

6

Here is my implementation for python 3 and pycrypto

from Crypto.PublicKey import RSA key = RSA.generate(4096) f = open('/home/john/Desktop/my_rsa_public.pem', 'wb') f.write(key.publickey().exportKey('PEM')) f.close() f = open('/home/john/Desktop/my_rsa_private.pem', 'wb') f.write(key.exportKey('PEM')) f.close() f = open('/home/john/Desktop/my_rsa_public.pem', 'rb') f1 = open('/home/john/Desktop/my_rsa_private.pem', 'rb') key = RSA.importKey(f.read()) key1 = RSA.importKey(f1.read()) x = key.encrypt(b"dddddd",32) print(x) z = key1.decrypt(x) print(z) 

4 Comments

Can you please explain how to Base 64 encode the encrypted result?
Which Crypto module have you used (e.g. pycrypto)?
pycryptodome pycryptodome.readthedocs.io/en/latest is the full documentation
To base64 encode the result, you can import base64 and then base64.b64encode(encrypted).
2
from Crypto.PublicKey import RSA from Crypto.Cipher import PKCS1_OAEP secret_message = b'ATTACK AT DAWN' ### First, make a key and save it key = RSA.generate(2048) with open( 'mykey.pem', 'wb' ) as f: f.write( key.exportKey( 'PEM' )) ### Then use key to encrypt and save our message public_crypter = PKCS1_OAEP.new( key ) enc_data = public_crypter.encrypt( secret_message ) with open( 'encrypted.txt', 'wb' ) as f: f.write( enc_data ) ### And later on load and decode with open( 'mykey.pem', 'r' ) as f: key = RSA.importKey( f.read() ) with open( 'encrypted.txt', 'rb' ) as f: encrypted_data = f.read() public_crypter = PKCS1_OAEP.new( key ) decrypted_data = public_crypter.decrypt( encrypted_data ) 

2 Comments

Code only answers are generally not useful.
If you are trying to decrypt a message but getting "Incorrect decryption" error try using PKCS1_v1_5 instead of PKCS1_OAEP. You also must change decrypt to include a second parameter ("sentinel"), you can use a random string.
0

You can use simple way for genarate RSA . Use rsa library

pip install rsa 

1 Comment

Add some detail such as a link to the documentation of else this is not a helpful response. There are already too many overlapping libraries with RSA implementations so making this distinction will be valuable.
-3

Watch out using Crypto!!! It is a wonderful library but it has an issue in python3.8 'cause from the library time was removed the attribute clock(). To fix it just modify the source in /usr/lib/python3.8/site-packages/Crypto/Random/_UserFriendlyRNG.pyline 77 changing t = time.clock() int t = time.perf_counter()

1 Comment

Welcome to stackoverflow! Your post is not descriptive enough to answer the OP's question. See how to write good answers.