我试图加密大于1GB的文件。我不想把这些都读到记忆里。我选择了Fernet (cryptography.fernet)来完成这个任务,因为它是最推荐的(比异步解决方案更快)。
钥匙是我造的。然后我创建了一个用于加密的脚本:
key = Fernet(read_key())
with open(source, "rb") as src, open(destination, "wb") as dest:
for chunk in iter(lambda: src.read(4096), b""):
encrypted = key.encrypt(chunk)
dest.write(encrypted)为了解密:
key = Fernet(read_key())
with open(source, "rb") as src, open(destination, "wb") as dest:
for chunk in iter(lambda: src.read(4096), b""):
decrypted = key.decrypt(chunk)
dest.write(decrypted)加密工作-不奇怪,但解密不是。首先,我认为它可能有用,但它不是。我猜加密后块大小会增加,然后当我读取4096字节时,它并不是一个完整的加密块。我想解密时出错了:
Traceback (most recent call last):
File "/redacted/path/venv/lib/python3.7/site-packages/cryptography/fernet.py", line 119, in _verify_signature
h.verify(data[-32:])
File "/redacted/path/venv/lib/python3.7/site-packages/cryptography/hazmat/primitives/hmac.py", line 74, in verify
ctx.verify(signature)
File "/redacted/path/venv/lib/python3.7/site-packages/cryptography/hazmat/backends/openssl/hmac.py", line 75, in verify
raise InvalidSignature("Signature did not match digest.")
cryptography.exceptions.InvalidSignature: Signature did not match digest.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/redacted/path/main.py", line 63, in <module>
decrypted = key.decrypt(chunk)
File "/redacted/path/venv/lib/python3.7/site-packages/cryptography/fernet.py", line 80, in decrypt
return self._decrypt_data(data, timestamp, time_info)
File "/redacted/path/venv/lib/python3.7/site-packages/cryptography/fernet.py", line 137, in _decrypt_data
self._verify_signature(data)
File "/redacted/path/venv/lib/python3.7/site-packages/cryptography/fernet.py", line 121, in _verify_signature
raise InvalidToken
cryptography.fernet.InvalidToken有办法解决这个问题吗?也许有一种比fernet更好(更简单)的解决方案?
发布于 2021-09-24 10:34:25
Fernet不应该以流媒体的方式使用。他们在文件中解释说:
限制 Fernet是加密数据的理想选择,它可以很好地存储在内存中。作为设计特性,它不公开未经身份验证的字节。这意味着完整的消息内容必须在内存中可用,这使得Fernet目前通常不适合处理非常大的文件。
发布于 2022-02-10 16:03:58
我只是遇到了同样的问题-我感觉到你的痛苦兄弟。
Fernet有一些问题使其与您的方法不兼容:
这防止您在加密和解密时使用相同的“块大小”,因为解密块大小必须更大。不幸的是,使用urlsafe_b64decode/urlsafe_b64encode处理数据也不起作用,因为:
也许有一种简单的方法可以计算出这个摘要有多大,并调整解密块的大小以适应这种情况--但我想避免使用“魔术常量”,因为这感觉很恶心。
我所确定的解决方案实际上是相当优雅的。它的工作如下:
加密:
n字节的数据(raw_chunk)n字节以创建m字节块(enc_chunk)。len(enc_chunk).to_bytes(4, "big")将加密块的大小写入文件b""的时候解密:
4字节的数据(size)b"",则中断int.from_bytes(size, "big") (num_bytes)将这4个字节转换为整数num_bytes发布于 2022-02-23 19:48:01
只要将输入数据分割成块并将块长度存储在加密文件中,就可以轻松地将任何非流算法(如Fernet)转化为流算法,这已经是@tlonny的建议了。只有当您能够提供任何格式的加密数据文件时,才有可能这样做。
可以通过不同的方式将块大小转换为字节。其中之一是使用struct.pack()和struct.unpack(),就像我在下面的代码中所做的那样。另一种方法是使用int(size).to_bytes(4, 'little')和size = int().from_bytes(size_bytes, 'little')。
下面的代码已经完全实现了encrypt()和decrypt()以及使用示例(加密2MB的随机数据切片成64 KB块)。
def encrypt(key, fin, fout, *, block = 1 << 16):
import cryptography.fernet, struct
fernet = cryptography.fernet.Fernet(key)
with open(fin, 'rb') as fi, open(fout, 'wb') as fo:
while True:
chunk = fi.read(block)
if len(chunk) == 0:
break
enc = fernet.encrypt(chunk)
fo.write(struct.pack('<I', len(enc)))
fo.write(enc)
if len(chunk) < block:
break
def decrypt(key, fin, fout):
import cryptography.fernet, struct
fernet = cryptography.fernet.Fernet(key)
with open(fin, 'rb') as fi, open(fout, 'wb') as fo:
while True:
size_data = fi.read(4)
if len(size_data) == 0:
break
chunk = fi.read(struct.unpack('<I', size_data)[0])
dec = fernet.decrypt(chunk)
fo.write(dec)
def test():
import cryptography.fernet, secrets
key = cryptography.fernet.Fernet.generate_key()
with open('data.in', 'wb') as f:
data = secrets.token_bytes(1 << 21)
f.write(data)
encrypt(key, 'data.in', 'data.enc')
decrypt(key, 'data.enc', 'data.out')
with open('data.out', 'rb') as f:
assert data == f.read()
if __name__ == '__main__':
test()https://stackoverflow.com/questions/69312922
复制相似问题