如何使用 Python 加密大文件?

Posted

技术标签:

【中文标题】如何使用 Python 加密大文件?【英文标题】:How to encrypt large file using Python? 【发布时间】:2021-11-17 14:45:10 【问题描述】:

我正在尝试加密大于 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 更好(更简单)的解决方案?

【问题讨论】:

这能回答你的问题吗? Cryptography token object raises exception and cannot decrypt even though the tokens are identical @buran 不。我生成了一次密钥并将其存储在我使用 read_key() 从中读取的文件中。我之前在寻找答案时看到了这个问题。我找不到任何有用的东西。 【参考方案1】:

Fernet 不应该以流媒体方式使用。他们在文档中解释了这一点:

From the documentation (last section):

限制

Fernet 非常适合加密可轻松放入内存的数据。作为一项设计功能,它不会暴露未经身份验证的字节。这意味着完整的消息内容必须在内存中可用,这使得 Fernet 目前通常不适合非常大的文件。

【讨论】:

【参考方案2】:

由于内存的限制,我们可以使用块来加密和解密。

#
# encrypt
#
key = b'Ke0Ft_85-bXQ8GLOOsEI6JeT2mD-GeI8pkcP_re8wio='
in_file_name = 'plain.txt'
out_file_name = 'encypted.txt'
with open(in_file_name, "rb") as fin, open(out_file_name, "wb") as fout:
    while True:
        block = fin.read(524288)
        if not block:
            break
        f = Fernet(key)
        output = f.encrypt(block)
        fout.write(output)

#
# decrypt
#
in_file_name = 'encrypted.txt'
out_file_name = 'plain2.txt'
with open(in_file_name, "rb") as fin, open(out_file_name, "wb") as fout:
    while True:
        block = fin.read(699148)
        if not block:
            break
        f = Fernet(key)
        output = f.decrypt(block)
        fout.write(output)

【讨论】:

以上是关于如何使用 Python 加密大文件?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中使用 RSA 加密文件(大数据)

python:如何加密文件?

如何在Laravel中加密大文件?

怎样对 Python 源码加密

你如何在 Go 中加密大文件/字节流?

如何检查 zip 文件是不是使用 python 的标准库 zipfile 加密?