我有一个基于网络的自制文件系统,允许用户以 zip 格式下载文件;但是,我在生产系统上不存在的本地盒子上进行开发时发现了一个问题。
在 linux 中,这不是问题(本地开发盒是 windows 系统)。
我有以下代码
algo = CipherType('AES-256', 'CBC')
decrypt = DecryptCipher(algo, cur_share.key[:32], cur_share.key[-16:])
file = open(settings.STORAGE_ROOT + 'f_' + str(cur_file.id), 'rb')
temp_file = open(temp_file_path, 'wb+')
data = file.read(settings.READ_SIZE)
while data:
dec_data = decrypt.update(data)
temp_file.write(dec_data)
data = file.read(settings.READ_SIZE)
# Takes a dump right here!
# error in cipher operation (wrong final block length)
final_data = decrypt.finish()
temp_file.write(final_data)
file.close()
temp_file.close()
上面的代码打开一个文件,并且(使用当前文件共享的密钥)解密该文件并将其写入一个临时位置(稍后将被填充到一个 zip 文件中)。
我的问题上file = open(settings.STORAGE_ROOT + 'f_' + str(cur_file.id), 'rb')
线了。'rb'
如果我不指定文件将不会在数据读取循环中结束,Windows 会非常关心二进制文件;但是,由于某种原因,因为我也在写入temp_file
它,所以永远不会完全读取到文件的末尾......除非我在 b 之后添加 a + 'rb+'
。
如果我将代码更改为file = open(settings.STORAGE_ROOT + 'f_' + str(cur_file.id), 'rb+')
一切正常,并且代码成功地抓取了整个二进制文件并将其解密。如果我不添加加号,它会失败并且无法读取整个文件......
代码的另一部分(用于下载单个文件)读取(并且无论操作系统如何都可以完美运行):
algo = CipherType('AES-256', 'CBC')
decrypt = DecryptCipher(algo, cur_share.key[:32], cur_share.key[-16:])
file = open(settings.STORAGE_ROOT + 'f_' + str(cur_file.id), 'rb')
filename = smart_str(cur_file.name, errors='replace')
response = HttpResponse(mimetype='application/octet-stream')
response['Content-Disposition'] = 'attachment; filename="' + filename + '"'
data = file.read(settings.READ_SIZE)
while data:
dec_data = decrypt.update(data)
response.write(dec_data)
data = file.read(settings.READ_SIZE)
# no dumps to be taken when finishing up the decrypt process...
final_data = decrypt.finish()
temp_file.write(final_data)
file.close()
temp_file.close()
澄清
密码错误可能是因为文件没有被完整读取。例如,我有一个 500MB 的文件,我一次读取64*1024
一个字节。我一直读到我没有收到更多字节,当我没有b
在 Windows 中指定时,它会在循环中循环两次并返回一些糟糕的数据(因为 python 认为它正在与字符串文件而不是二进制文件交互)。
当我指定b
完全读取文件需要 10-15 秒时,它会成功完成,并且代码正常完成。
当我在从源文件读取时(如第一个示例中)同时写入另一个文件时,如果我没有指定rb+
它会显示与甚至没有指定相同的行为b
,即它只从文件中读取几个段在关闭手柄并继续之前,我最终得到一个不完整的文件并且解密失败。