pythonencryptionaesctr-mode

Best way to replace files in place safely and efficiently?


I am trying to encrypt a file in place using cryptography module, so I dont have to buffer the ciphertext of the file which can be memory intensive and then i will have to replace the original file with it's encrypted one.so my solution is encrypting a chunk of plaintext then trying to replace it with its ciphertext 16 bytes at a time(AES-CTR mode). The problem seems that the loop is an infinite loop.

pointer = 0
with open(path, "r+b") as file:
   print("...ENCRYPTING")
   while file:
        file_data = file.read(16)
        pointer += 16
        ciphertext = aes_enc.update(file_data)
        file.seek(pointer-16)
        file.write(ciphertext)
    print("...Complete...")

Solution

  • As Cyril Jouve already mentions, check for if not file_data

    Reading in blocks of 16 bytes is relatively slow. I guess you have enough memory to read larger blocks like 4096, 8192 ...

    Unless you have very large files and limited diskspace I think there is no benefit in reading and writing in the same file. In case of an error and if the os has already written data to disk you will have lost the original data and will have an incomplete encrypted file of which you don't know which part is encrypted.

    It's easier and saver to create a new encrypted file an then delete and rename if there were no errors.

    Encrypt to a new file, catch exceptions, check existence and size of the encrypted file, delete source and rename encrypted file only if all is oké.

    import os
    
    path = r'D:\test.dat'
    
    input_path = path
    encrypt_path = path + '_encrypt'
    
    try:
        with open(input_path, "rb") as input_file:
            with open(encrypt_path, "wb") as encrypt_file:
    
                print("...ENCRYPTING")
    
                while True:
    
                    file_data = input_file.read(4096)
                    if not file_data:
                        break
    
                    ciphertext = aes_enc.update(file_data)
                    encrypt_file.write(ciphertext)
    
                print("...Complete...")
    
        if os.path.exists(encrypt_path):
            if os.path.getsize(input_path) == os.path.getsize(encrypt_path):
                print(f'Deleting {input_path}')
                os.remove(input_path)
                print(f'Renaming {encrypt_path} to {input_path}')
                os.rename(encrypt_path, input_path)
    
    except Exception as e:
        print(f'EXCEPTION: {str(e)}')