Reputation: 71
I want to encrypt/decrypt a set of data which is contained in a .csv file. I generate my RSA public/private keys with this code :
import Crypto
from Crypto.PublicKey import RSA
key = RSA.generate(2048)
k = key.exportKey('PEM')
p = key.publickey().exportKey('PEM')
with open('private.pem', 'w') as kf:
kf.write(k.decode())
kf.close()
with open('public.pem', 'w') as pf:
pf.write(p.decode())
pf.close()
with open('private.pem','r') as fk:
priv = fk.read()
fk.close()
with open('public.pem','r') as fp:
pub = fp.read()
fp.close()
privat = RSA.importKey(priv)
public = RSA.importKey(pub)
if key == privat:
print('Private key has been successfuly write')
if key.publickey() == public:
print('Public key has been successfuly write')
Then I encrypt with this code without any problem:
import Crypto
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
with open('public.pem','r') as fp:
pub = fp.read()
fp.close()
public = RSA.importKey(pub)
#stockage du fichier dans une variable rep
fichier = open('test.csv', 'r')
rep = fichier.read()
fichier.close()
#eliminations des spaces
rep = rep.replace(' ', '')
#encodage pour type bytes
rep = rep.encode()
#decoupage en mot de 10 chars
rep = [rep[i:i+10] for i in range(0, len(rep), 10)]
cipher = PKCS1_OAEP.new(public)
fichier2 = open('encrypted.csv', 'a')
for i in rep:
encrypted_line = cipher.encrypt(i)
fichier2.write(str(encrypted_line))
fichier2.write('\n')
fichier2.close()
I can modify how my data are separate by modifying this line :
rep = [rep[i:i+n] for i in range(0, len(rep), n)]
This line separate my data by groups of n chars
Here my code to decrypt the data, it raises:
ValueError: Ciphertext with incorrect length.
import Crypto
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
with open('private.pem','r') as fk:
priv = fk.read()
fk.close()
private = RSA.importKey(priv)
fichier = open('encrypted.csv', 'r')
rep = fichier.read().splitlines()
fichier.close()
cipher = PKCS1_OAEP.new(private)
fichier2 = open('decrypted.csv', 'a')
for i in rep:
decrypted_line = cipher.decrypt(i)
decrypted_line = decrypted_line.decode('utf-8')
fichier2.write(str(encrypted_line))
fichier2.close()
I tried to encode a sample file and it raised this ValueError . Then I try to work with a file which contain only one char directly on the Python interpreter. Encryption worked well but decryption broke with the same error as above.
Upvotes: 3
Views: 1858
Reputation: 55589
The main problem with the code is the use of newline characters to separate the chunks of encrypted data. The encrypted data may already contain newline characters, so attempting to split the encrypted data into lines may produce partial chunks, which will raise the ValueError
that you see when decrypted.
A second problem is that the encrypted files are being opened in text mode. When dealing with encrypted data open files in binary mode. Encrypted bytes
are unlikely to be decodable to str
, so using text mode will result in encoding or decoding errors.
This version of your code works:
import functools
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
if __name__ == '__main__':
# Encrypt
with open('public.pem', 'r') as fp:
pub = fp.read()
fp.close()
public = RSA.importKey(pub)
# tockage du fichier dans une variable rep
with open('test.csv', 'r') as fichier:
rep = fichier.read()
# liminations des spaces
rep = rep.replace(' ', '')
# ncodage pour type bytes
rep = rep.encode()
cipher = PKCS1_OAEP.new(public)
# decoupage en mot de 10 chars
rep = [rep[i:i+10] for i in range(0, len(rep), 10)]
# Open the file in binary mode so we can write bytes.
with open('encrypted.csv', 'wb') as fichier2:
for i in rep:
fichier2.write(cipher.encrypt(i))
# Decrypt
with open('private.pem', 'r') as fk:
priv = fk.read()
private = RSA.importKey(priv)
CHUNK_SIZE = 256
# Open the file in binary mode so we can read bytes.
with open('encrypted.csv', 'rb') as fichier:
# Create an iterator that will return chunks of the correct size.
chunker = iter(functools.partial(fichier.read, CHUNK_SIZE), b'')
rep = list(chunker)
cipher = PKCS1_OAEP.new(private)
with open('decrypted.csv', 'w') as fichier2:
for i in rep:
decrypted_line = cipher.decrypt(i)
fichier2.write(decrypted_line.decode())
Rather than splitting the encrypted data on newlines, this code reads from the file in chunks of 256 bytes, as the encryption process seems to generate 256 bytes for each chunk of input. I'm not a cryptologist, so it's possible this isn't always true. In that case it might be better to encrypt (or decrypt) all the data in a single step.
Upvotes: 1