公钥加密通常仅用于少量数据。它很慢,并且很难正确使用。通常的做法是使用其他方法将不对称问题简化为共享密钥提供安全性的方法,然后使用公共密钥加密技术来保护该共享密钥。例如:
因此,这是加密的样子(警告,未经测试的代码,直接在浏览器中键入)的草图:
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()))
的iv
是一个 用于CBC操作模式。每个消息的每个键都必须唯一。通常,它与数据一起以明文形式发送。在这里,由于密钥仅使用过一次,因此您可以使用已知的IV。
分组密码的API在PEP 272中进行了描述。不幸的是,它仅支持一次加密。对于大文件,最好逐块加密。您一次最多可以加密一个块(AES为16个字节),但是您需要一个更好的加密库。
请注意,通常,您不应直接使用RSA加密数据。最明显的问题是,攻击者知道公钥,因此可以尝试猜测明文(如果攻击者认为明文可能是swordfish
,则攻击者可以swordfish
使用RSA公钥进行加密,并将结果与??密码的输出进行比较。 RSA加密)。如果您想将文件发送给多个收件人,则会引起的另一个问题是,如果RSA加密步骤是确定性的,则攻击者可以说出明文是相同的,因为密文是相同的。解决这些问题的正常方法是使用 ,其中包括向明文添加一些随机机密数据;此数据称为填充。然后,攻击者无法猜测随机数据,并且每次加密都会看到不同的结果,因为同一明文永远不会被加密两次;就合法接收者而言,填充只是可以丢弃的数据。
在这里,上述问题似乎不适用于这种情况。但是,使用不受保护的RSA可能还会导致其他缺点。特别是,如果公共指数很小(此处不是PyCrypto使用65537的情况),或者您为许多不同的收件人加密相同的材料(同样,此处可能不是这种情况,因为每个消息都有其自己的密钥),则简单的数学计算将使攻击者能够恢复RSA明文。为了避免这种攻击,使用RSA加密的值必须与RSA模数“足够接近”,以便加密操作实际上执行模幂。我建议的填充可确保通过使高位字节适合0xff来确保填充。这被认为是安全的,尽管在现实世界中,您应该使用批准的填充模式(OAEP)。