安全高效地替换文件的最佳方法?

问题描述

我正在尝试使用cryptography模块对文件进行加密,因此我不必缓冲可能占用大量内存的文件密文,然后我将不得不用已加密的文件替换原始文件.so我的解决方案是加密一块明文,然后尝试一次用16个字节的密文替换它(AES-CTR模式)。问题似乎是循环是无限循环。

  • 那么如何解决这个问题。
  • 您还建议其他什么方法
  • 下面使用这种方法的副作用是什么。
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...")

解决方法

  • 那么如何解决这个问题。

正如西里尔·乔夫(Cyril Jouve)所述,请检查如果不是file_data

  • 您还建议其他什么方法。
  • 下面使用这种方法的副作用是什么。

以16字节为块的读取速度相对较慢。我想您有足够的内存来读取较大的块,例如4096、8192 ...

除非您有非常大的文件和有限的磁盘空间,否则我认为读取和写入同一文件没有任何好处。如果发生错误,并且如果os已经将数据写入磁盘,则您将丢失原始数据,并且将拥有不完整的加密文件,而您不知道该文件的哪个部分被加密。

创建一个新的加密文件,然后在没有错误的情况下将其删除并重命名,将更加容易和节省。

仅在一切正常的情况下,加密到新文件,捕获异常,检查加密文件的存在和大小,删除源并重命名加密文件。

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)}')
,

文件对象没有“真实性”,因此您不能将其用作循环的条件。

当read()返回一个空字节对象(https://docs.python.org/3/library/io.html#io.BufferedIOBase.read)时文件位于EOF

with open(path,"r+b") as file:
   print("...ENCRYPTING")
    while True:
        file_data = file.read(16)
        if not file_data:
            break
        ciphertext = aes_enc.update(file_data)
        file.seek(-len(file_data),os.SEEK_CUR)
        file.write(ciphertext)
    print("...Complete...")