【问题标题】:Encrypting a file with RSA in Python在 Python 中使用 RSA 加密文件
【发布时间】:2011-09-12 16:33:14
【问题描述】:

我正在使用 PyCrypto 使用 RSA 实现文件加密。

我知道这有点不对,首先是因为 RSA 非常慢,其次是因为 PyCrypto RSA 只能加密 128 个字符,所以你必须将文件分解为 128 个字符块。

这是目前为止的代码:

from Crypto.PublicKey import RSA

file_to_encrypt = open('my_file.ext', 'rb').read()
pub_key = open('my_pub_key.pem', 'rb').read()
o = RSA.importKey(pub_key)

to_join = []
step = 0

while 1:
    # Read 128 characters at a time.
    s = file_to_encrypt[step*128:(step+1)*128]
    if not s: break
    # Encrypt with RSA and append the result to list.
    # RSA encryption returns a tuple containing 1 string, so i fetch the string.
    to_join.append(o.encrypt(s, 0)[0])
    step += 1

# Join the results.
# I hope the \r\r\r sequence won't appear in the encrypted result,
# when i explode the string back for decryption.
encrypted = '\r\r\r'.join(to_join)
# Write the encrypted file.
open('encrypted_file.ext', 'wb').write(encrypted)

所以我的问题是:有没有更好的方法在文件上使用私钥/公钥加密?

我听说过 Mcrypt 和 OpenSSL,但我不知道它们是否可以加密文件。

【问题讨论】:

  • 您应该使用像 AES 这样的对称密码来加密文件,然后使用 RSA 来加密 AES 密钥。
  • @Petey B:我希望我能喜欢该评论 100 次。
  • Gpg4win 做了@Petey B 说你应该做的事情。
  • 1.可以加密的数量是 RSA 模数大小的函数。 2.您要加密的块必须小于整数模数,因此如果一次加密 128 字节的块,则不能保证 1024 位模数的正确操作。 3. 你问是否有更好的方法,但你拒绝了这些建议。那么,你对“更好”的定义是什么?
  • @GregS:非常感谢您的建议!我知道我有点固执,但我听专家的意见。

标签: python encryption public-key-encryption


【解决方案1】:

公钥加密通常仅用于少量数据。它很慢,而且很难正确使用。通常的做法是使用其他方法将非对称问题减少到由共享密钥提供安全性的问题,然后使用公钥密码术来保护该共享密钥。例如:

  • 要加密文件,请为块或流密码(例如 AES)随机生成密钥。存储使用此密码加密的数据,并将使用公钥加密的密钥与加密的有效负载一起存储。
  • 要签署文件,请计算加密摘要(例如 SHA-256)。使用私钥签署文件摘要并将其与文件一起存储。

下面是加密的示意图(警告,未经测试的代码,直接在浏览器中输入):

import os
from Crypto.Cipher import AES
from Crypto.PublicKey import RSA
import Crypto.Util.number
def encrypt_file(rsa, input, output):
    # Generate secret key
    secret_key = os.urandom(16)
    # Padding (see explanations below)
    plaintext_length = (Crypto.Util.number.size(rsa.n) - 2) / 8
    padding = '\xff' + os.urandom(16)
    padding += '\0' * (plaintext_length - len(padding) - len(secret_key))
    # Encrypt the secret key with RSA
    encrypted_secret_key = rsa.encrypt(padding + secret_key, None)
    # Write out the encrypted secret key, preceded by a length indication
    output.write(str(len(encrypted_secret_key)) + '\n')
    output.write(encrypted_secret_key)
    # Encrypt the file (see below regarding iv)
    iv = '\x00' * 16
    aes_engine = AES.new(secret_key, AES.MODE_CBC, iv)
    output.write(aes_engine.encrypt(input.read()))

ivCBC mode of operationinitialization vector。每条消息的每个密钥都必须是唯一的。通常,它与数据一起以明文形式发送。在这里,由于密钥只使用一次,因此您可以使用已知的 IV。

分组密码的 API 在PEP 272 中描述。不幸的是,它只支持一次性加密。对于大文件,最好逐块加密;您一次只能加密一个块(AES 为 16 个字节),但您需要一个更好的加密库。

请注意,一般情况下,您不应直接使用 RSA 加密数据。最明显的担忧是攻击者知道公钥,因此可以尝试猜测明文(如果攻击者认为明文可能是swordfish,那么攻击者可以用RSA公钥加密swordfish,并比较结果与 RSA 加密的输出)。如果您想将文件发送给多个收件人,另一个问题是,如果 RSA 加密步骤是确定性的,那么攻击者可以判断明文是相同的,因为密文是相同的。针对这些问题的正常防御是使用padding scheme,其中包括在明文中添加一些随机秘密数据;该数据称为填充。然后攻击者无法猜测随机数据,并且每次加密都会看到不同的结果,因为相同的明文永远不会被加密两次;就合法接收者而言,填充只是可以丢弃的数据。

在这里,上述问题似乎不适用于这种情况。但是,使用不受保护的 RSA 可能会产生其他弱点。特别是,如果公共指数非常小(这里不是 PyCrypto 使用 65537 的情况)或者您为许多不同的接收者加密相同的材料(同样,这里可能不是这种情况,因为每条消息都有自己的密钥),然后simple mathematical calculation would allow the attacker to recover the RSA plaintext。为了避免这种攻击,使用 RSA 加密的值需要与 RSA 模数“足够接近”,以便加密操作实际上执行模幂运算。我建议的填充确保通过制作适合 0xff 的最高字节; this is believed to be safe,尽管在现实世界中您应该使用经过批准的填充模式 (OAEP)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-16
    • 2021-08-18
    • 1970-01-01
    • 2015-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多