0

I have a code that i made, but something is going wrong. I need encripty some folders to get more security in my business, I am using AES script in python. It's generate 2 files, encrypt.py and decrypt. Encryptation is working nice, but when i execute the decrypt, it's give me a error.

Here is my code:

import os
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import padding

backend = default_backend()
key = os.urandom(32)  # 256 bit
iv = os.urandom(16)  # 128 bit

# cryptografy
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend)
encryptor = cipher.encryptor()

# loop all files and folders
for root, dirs, files in os.walk('.'):
    # ignores main.py (that is the file name to not encrypt it)
    if 'main.py' in files:
        continue
    # crypt files
    for file in files:
        # create a new encryptor
        cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend)
        encryptor = cipher.encryptor()

        # read datas
        file_path = os.path.join(root, file)
        data = open(file_path, 'rb').read()

        # adding padding
        padder = padding.PKCS7(128).padder()
        padded_data = padder.update(data) + padder.finalize()

        # encrypts the data
        cipher_data = encryptor.update(padded_data) + encryptor.finalize()

        # writes the encrypted data to the file
        file = open(file_path, 'wb')
        file.write(cipher_data)
        file.close()

# write the code for decryption in the file
decryptor_file = open('decryptor.py', 'w')
decryptor_file.write("import os\n")
decryptor_file.write("from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes\n")
decryptor_file.write("from cryptography.hazmat.backends import default_backend\n")
decryptor_file.write("from cryptography.hazmat.primitives import padding\n\n")

decryptor_file.write("backend = default_backend()\n")
decryptor_file.write("key = \"" + key.hex() + "\"\n")
decryptor_file.write("iv = \"" + iv.hex() + "\"\n\n")

decryptor_file.write("# descryptografy\n")
decryptor_file.write("cipher = Cipher(algorithms.AES(bytes.fromhex(key)), modes.CBC(bytes.fromhex(iv)), backend=backend)\n")
decryptor_file.write("decryptor = cipher.decryptor()\n\n")

decryptor_file.write("# loops all files and folders\n")
decryptor_file.write("for root, dirs, files in os.walk('.'):\n")
decryptor_file.write("    # decrypt files\n")
decryptor_file.write("    for file in files:\n")
decryptor_file.write("        # data reading\n")
decryptor_file.write("        file_path = os.path.join(root, file)\n")
decryptor_file.write("        data = open(file_path, 'rb').read()\n\n")

decryptor_file.write("        # decrypt data \n")
decryptor_file.write("        decrypted_data = decryptor.update(data) + decryptor.finalize()\n\n")

decryptor_file.write("        # remove padding\n")
decryptor_file.write("        unpadder = padding.PKCS7(128).unpadder()\n")
decryptor_file.write("        unpadded_data = unpadder.update(decrypted_data) + unpadder.finalize()\n\n")

decryptor_file.write("        # writes the data descrypted in the file\n")
decryptor_file.write("        file = open(file_path, 'wb')\n")
decryptor_file.write("        file.write(unpadded_data)\n")
decryptor_file.write("        file.close()\n\n")

decryptor_file.close()

# shows a alert message
print('All files and folders have been encrypted and the decrypt file has been created!')

Error that i got:

Traceback (most recent call last):
  File "C:\Users\User\Desktop\cryptor\decryptor.py", line 23, in <module>
    decrypted_data = decryptor.update(data) + decryptor.finalize()
  File "C:\Program Files\Python38\lib\site-packages\cryptography\hazmat\primitives\ciphers\base.py", line 186, in finalize
    data = self._ctx.finalize()
  File "C:\Program Files\Python38\lib\site-packages\cryptography\hazmat\backends\openssl\ciphers.py", line 223, in finalize
    raise ValueError(
ValueError: The length of the provided data is not a multiple of the block length.

Some help is apreciated!

Edit:

I will post my code working using text.txt to be encrypted. Maybe it help someone to help me :)

import os
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import padding

backend = default_backend()
key = os.urandom(32) # 256 bit
iv = os.urandom(16) # 128 bit

# cryptography
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend)
encryptor = cipher.encryptor()

# read from file
file = open('text.txt', 'rb')
data = file.read()
file.close()

# adding the padding
padder = padding.PKCS7(128).padder()
padded_data = padder.update(data) + padder.finalize()

# encrypt the data
cipher_data = encryptor.update(padded_data) + encryptor.finalize()

# write the encrypted data to the file
file = open('crypto.txt', 'wb')
file.write(cipher_data)
file.close()

# delete the old file
os.remove('text.txt')

# display alert message
print('Your file has been encrypted!')

# create the decryption file
decryptor_file = open('decryptor.py', 'w')

# write the decryption code to the file
decryptor_file.write("import os\n")
decryptor_file.write("from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes\n")
decryptor_file.write("from cryptography.hazmat.backends import default_backend\n")
decryptor_file.write("from cryptography.hazmat.primitives import padding\n\n")

decryptor_file.write("backend = default_backend()\n")
decryptor_file.write("key = \"" + key.hex() + "\"\n")
decryptor_file.write("iv = \"" + iv.hex() + "\"\n\n")

decryptor_file.write("# decryption\n")
decryptor_file.write("cipher = Cipher(algorithms.AES(bytes.fromhex(key)), modes.CBC(bytes.fromhex(iv)), backend=backend)\n")
decryptor_file.write("decryptor = cipher.decryptor()\n\n")

decryptor_file.write("# read file\n")
decryptor_file.write("file = open('crypto.txt', 'rb')\n")
decryptor_file.write("data = file.read()\n")
decryptor_file.write("file.close()\n\n")

decryptor_file.write("# decrypt data\n")
decryptor_file.write("decrypted_data = decryptor.update(data) + decryptor.finalize()\n\n")

decryptor_file.write("# remove padding\n")
decryptor_file.write("unpadder = padding.PKCS7(128).unpadder()\n")
decryptor_file.write("unpadded_data = unpadder.update(decrypted_data) + unpadder.finalize()\n\n")

decryptor_file.write("# write decrypted data to file\n")
decryptor_file.write("file = open('text.txt', 'wb')\n")
decryptor_file.write("file.write(unpadded_data)\n")
decryptor_file.write("file.close()\n\n")

decryptor_file.close()
BloodHound
  • 15
  • 1
  • 6
  • 1
    Does this answer your question? [Why must all inputs to AES be multiples of 16?](https://stackoverflow.com/questions/17773450/why-must-all-inputs-to-aes-be-multiples-of-16) – CreepyRaccoon Dec 16 '22 at 09:10
  • @CreepyRaccoon I saw that before post, but I don’t know where I need change it in my code – BloodHound Dec 16 '22 at 09:25
  • I don't think `data = open(file_path, 'rb').read()` closes the file after reading the contents. Therefore the file is still open for reading when you start writing to it. At some point it closes, perhaps when the garbage collector processes the orphaned file object. I don't honestly know what happens in that case but it seems like a bug anyways. [Pathlib](https://docs.python.org/3/library/pathlib.html) has methods that read and write to files in one go, internally opening and closing them for you. – President James K. Polk Dec 16 '22 at 16:20
  • this is stranger because i have a code that encrypt a txt file and descrypt. that code worked well and was based on this here. – BloodHound Dec 16 '22 at 16:51
  • @CreepyRaccoon i put my code working with the txt file – BloodHound Dec 16 '22 at 22:43
  • use triple quoting to include a file contents. Your way of doing it is error prone. Or just use a python source file and copy it to the destination file – Jean-François Fabre Dec 16 '22 at 22:50
  • @Jean thanks for your reply! could you give me a answer how can i do that? – BloodHound Dec 17 '22 at 00:11

1 Answers1

0

It is working for me, I just had to move the lines below inside the for loop (for file in files:) in the decryptor.py file, just like you do in the encryptor.py, otherwise another error is triggered:

decryptor_file.write("# descryptografy\n")
decryptor_file.write("cipher = Cipher(algorithms.AES(bytes.fromhex(key)), modes.CBC(bytes.fromhex(iv)), backend=backend)\n")
decryptor_file.write("decryptor = cipher.decryptor()\n\n")

With this change, everything works fine!
The only way to reproduce your error is when trying to decrypt an already decrypted file, in that case, the padding does not match. Is it possible that you are doing this by mistake?

CreepyRaccoon
  • 826
  • 1
  • 9
  • 19
  • Hi Creepy, thanks for your answord. I put this code above inside the loop but i still getting the error: ValueError: The length of the provided data is not a multiple of the block length. And the files still encrypteds – BloodHound Dec 16 '22 at 22:19
  • Your new script for *text.txt* also works fine for me, I can only reproduce your error by encrypting the same file twice and then trying to decrypt it or decrypting it twice. – CreepyRaccoon Dec 17 '22 at 15:51
  • Your error does not make sense as you are properly padding the file for encryption and properly unpadding it to decrypt. So, I think you are trying this iteratively by changing things and it is very likely you have done this (what I described in my previous comment). Have you tried to encrypt *text.txt* from scratch, by manually adding the file on each try? – CreepyRaccoon Dec 17 '22 at 15:51
  • btw, try `jinja2` to create the template for your *decryptor.py*, it is easier to mantain and understand in that way (instead of adding each line as in `decryptor_file.write("....")`). – CreepyRaccoon Dec 17 '22 at 15:54