Python – PyCrypto: Decrypt only with public key in file (no private+public key)

encryptionpublic-key-encryptionpycryptopython

Hello everyone.

I am trying to play a bit with RSA public and private keys and encryption/decryption with PyCrypto and I have encountered and issue that seems kind of strange to me (it probably makes a lot of sense the way it's working now, but I don't know much about RSA asymmetric encryption and that's why it's puzzling me). It is the inability I have encountered to decrypt something having only the public key.

Here's the thing: I have a server and a client. I want the server to "recognize" and register the client and show it in a list of "known devices". The client will have the public key of the server and the server will have the public key of the client, so when the client communicates with the server, it will encrypt its data with his client's private key and with the server's public key. By doing this, only the proper server will be able to open the data (with its private key) and will be able to verify that the sender is actually the client that claims to be… well… or at least, that's what I think, because I'm pretty newbie in this asymmetric encryption. The idea is that when one of those clients wakes up, it will send its public key (encrypted with the server's public key, of course, but that's probably not relevant at this point… yet) saying "Hey, I'm a new client and this is my public key. Register that key with my UUID" and the server will obey, associating that public key with the client's UUID and use that key to decrypt data coming from that client. I just want to transmit the client's public key, keeping its private key secret, secret, secret (it's private, right?)

I am doing some tests with openssl and very simple Python scripts that use PyCrypto (actually, not even in a server/client architecture or anything… just trying to encrypt something with a private key and decrypt it with the public key)

First of all, I have created a public/private key set with:

openssl genrsa -out ~/myTestKey.pem -passout pass:"f00bar" -des3 2048

Ok, first thing that puzzles me a bit… It generates only one file, with both the private and the public keys… Well… O'right… whatever. I can extract the public key with:

openssl rsa -pubout -in ~/myTestKey.pem -passin pass:"f00bar" -out ~/myTestKey.pub

So I thought I had my couple of private (private+public, actually) and public keys in ~/myTestKey.pem and ~/myTestKey.pub respectively. Well… apparently I'm doing something wrong, because PyCrypto doesn't like this assembly. And I don't know why.

I have two very simple test scripts, "encryptor.py" and "decryptor.py". The "encryptor.py" should encrypt something with the private key, and "decryptor.py", decrypt it with the public key. I know… I'm a parangon of originality…

So, I encrypt the string "Loren ipsum" with my "encryptor.py" (with private key):

———– encryptor.py —————-

#!/usr/bin/python

from Crypto.PublicKey import RSA

def encrypt(message):
    externKey="/home/borrajax/myTestKey.pem"
    privatekey = open(externKey, "r")
    encryptor = RSA.importKey(privatekey, passphrase="f00bar")
    encriptedData=encryptor.encrypt(message, 0)
    file = open("/tmp/cryptThingy.txt", "wb")
    file.write(encriptedData[0])
    file.close()

if __name__ == "__main__":
    encryptedThingy=encrypt("Loren ipsum")

And it works fine. Well… I suppose so, because in the file "/tmp/cryptThingy.txt" I get a lot of gibberish. It looks really, really encrypted to me.

But when I try to decrypt it using just the file that contains just the public key…

———– decryptor.py —————

#!/usr/bin/python

from Crypto.PublicKey import RSA

def decrypt():
    externKey="/home/borrajax/myTestKey.pub"
    publickey = open(externKey, "r")
    decryptor = RSA.importKey(publickey, passphrase="f00bar")
    retval=None

    file = open("/tmp/cryptThingy.txt", "rb")
    retval = decryptor.decrypt(file.read())
    file.close()
    return retval


if __name__ == "__main__":
    decryptedThingy=decrypt()   
    print "Decrypted: %s" % decryptedThingy

PyCrypto yells at me with a:

  File "/usr/local/lib/python2.7/dist-packages/pycrypto-2.5-py2.7-linux-i686.egg/Crypto/PublicKey/RSA.py", line 107, in _decrypt
    mp = self.key._decrypt(cp)
TypeError: Private key not available in this object

Yeah, of course it's not available! I extracted the public key! It took me 2 hours finding how to do it properly!!

What am I missing? As I said, I'm pretty newbie in this public/private asymmetric key encryption so I might have a core "conceptual error"… Any hint will be appreciated.

¡Thank you in advance!

Best Answer

You have it the wrong way round, you encrypt with the public key, and decrypt with the private key.

The publicly available encrypting-key is widely distributed, while the private decrypting-key is known only to the recipient. Messages are encrypted with the recipient's public key and can be decrypted only with the corresponding private key. Source

The idea is that you give the sending side the public key (which anyone can have, so you can distribute it in the open) then you encrypt the data with it, then decrypt it on your end with your private key (which only you have). This way the data stays secure.

You can encrypt something with the private key as the private key contains the information required to make the public key, but it would be unusual to do so, as normally the person encrypting the data does not have the private key.