Search code examples
python-2.7rsapycrypto

RSA-2048 decrypt not working - PKCS1_OAEP "Incorrect decryption."


The code is supposed to set up a service that listens for connections from a voting website. It is a server listening for connections from outside (clients). When the client connects, the client waits for the version number to be sent. Once my server/listener sends the version number, the client responds with a 256 byte block that is RSA 2048 bit encrypted using the public key I provide. That block then has to be decoded and (later) I will read the contents. I am stuck in that I can't get it decrypted:

I get this:

starting connection...

connection from ('50.28.6.244', 35338)

sending version number...

receiving encrypted block

Traceback (most recent call last):

File "voteListener.py", line 97, in

Main(private_key)

File "voteListener.py", line 49, in Main

decodedfile = decode_msg(data, privatekey)

File "voteListener.py", line 58, in decode_msg

ciphertext = cipher.decrypt(msg)

File "C:\Python27\lib\site-packages\Crypto\Cipher\PKCS1_OAEP.py", line 227, in decrypt

raise ValueError("Incorrect decryption.")

ValueError: Incorrect decryption.

C:\Users\STEXAS\Desktop\vote>pause

Press any key to continue . . .

My code:

import socket
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from os import path


def Main(privatekey):
    host = "0.0.0.0"
    port = 8192
    version = "VOTIFIER 1.9"
    print("starting connection...")
    while True:
        s = socket.socket()
        s.bind((host, port))
        s.listen(1)
        c, addr = s.accept()
        print("connection from %s" % str(addr))
        print("sending version number...")
        c.send(version)
        c.send('\n')

        print("receiving encrypted block")
        data = c.recv(256)
        c.close()
        s.close()
        decodedfile = decode_msg(data, privatekey)

        with open("votes.txt", 'wb') as f:
            f.write(decodedfile)
        print("File writen")


def decode_msg(ciphertext, priv_key):
    cipher = PKCS1_OAEP.new(priv_key)
    msg = cipher.decrypt(ciphertext)
    return msg


def read_private_key():
    with open("keys\mykey.pem", 'rb') as f:
        data = f.read()
    key = RSA.importKey(data)
    return key


def generate_key_pair():
    """Generates a 2048 bit RSA key pair and saves the keys to disk"""
    pair = RSA.generate(2048)

    f = open("keys\mykey.pem", "wb")  # private key
    f.write(pair.exportKey('PEM'))
    f.close()

    pub_key = pair.publickey().exportKey(format='PEM')
    keytext = str(pub_key).strip("-----BEGIN PUBLIC KEY-----").strip("-----END PUBLIC KEY-----").replace('\n', "")
    with open("keys\public.txt", 'wb') as f:  # the plain text public key for providing to server list
        f.write(keytext)
    with open("keys\public.pem", 'wb') as f:  # public key
        f.write(pub_key)


if __name__ == "__main__":
    private_key = None

    if not path.exists("keys\mykey.pem"):
        generate_key_pair()

    if path.exists("keys\mykey.pem"):
        private_key = read_private_key()

    if private_key is not None:
        Main(private_key)
    else:
        print("Error with Keys... no key was generated or found!")

Solution

  • The clients (and i suppose the Java versions of Votifier) were using RSAES PKCS1 v1.5. Added a method to decode using that scheme and changed the call to that method:

    In Main():

    decodedfile = decode_msg_v1_5(data, privatekey)
    

    New method:

    def decode_msg_v1_5(ciphertext, privateKey):
        """  Should consider using the more robust PKCS1 OAEP. """
        sentinel = Random.new().read(256)      # data length is 256
        cipher = PKCS1_v1_5.new(privateKey)
        messagereceived = cipher.decrypt(ciphertext, sentinel)
        return messagereceived