在Python中使用RSA加密文件 [英] Encrypting a file with RSA in Python

查看:815
本文介绍了在Python中使用RSA加密文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用PyCrypto实现了使用RSA的文件加密。



我知道这有点错误,首先是因为RSA非常慢,第二个原因是PyCrypto RSA可以只能加密128个字符,所以你必须以128个字符的块来爆炸文件。



这是迄今为止的代码:


$ b $来自Crypto.PublicKey导入的

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

而1:
#一次读128个字符。
s = file_to_encrypt [step * 128:(step + 1)* 128]
如果不是s:break
#使用RSA加密并将结果追加到列表中。
#RSA加密返回一个包含1个字符串的元组,所以我获取字符串。
to_join.append(o.encrypt(s,0)[0])
step + = 1

#加入结果。
#我希望\r\r\r序列不会出现在加密的结果中,
#当我将字符串分解回来进行解密。
encrypted ='\r\r\r'.join(to_join)
#写加密文件。
open('encrypted_file.ext','wb')。写(加密)

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



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

解决方案

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




  • 要加密文件,随机生成块或流密码(例如AES)的密钥。存储使用此密码加密的数据,并存储使用公共密钥加密的密钥加密的有效载荷旁边。

  • 要签名文件,请计算加密摘要(例如SHA-256)。使用私钥对文件的摘要进行签名并存储在文件旁边。



所以这里是一个加密如何看起来的草图(警告,未经测试的代码,直接在浏览器中输入):

 从Crypto.Cipher导入os 
导入AES
来自Crypto.PublicKey import RSA
import Crypto.Util.number
def encrypt_file(rsa,input,output):
#生成秘密密钥
secret_key = os.urandom (16)
#填充(见下面的说明)
plaintext_length =(Crypto.Util.number.size(rsa.n) - 2)/ 8
padding ='\xff'+ os.urandom(16)
padding + ='\0'*(plaintext_length - len(padding) - len(secret_key))
#用RSA加密秘密密钥
encrypted_secret_key = rsa
#写出加密的秘密密钥,前面加上一个长度指示
output.write(str(len(encrypted_secret_key))+'\\\
')
output.write(encrypted_secret_key)
#加密文件(见下文关于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 。不幸的是,它只支持一次加密。对于大文件,最好通过块加密块;您可以一次加密一个块(16个字节用于AES),但是您需要一个更好的加密库。



请注意,一般来说,您应该不直接用RSA加密数据。最明显的问题是攻击者知道公钥,因此可以尝试猜测明文(如果攻击者认为明文可能是 swordfish ,则攻击者可以加密 swordfish 与RSA公钥,并将结果与​​RSA加密的输出进行比较)。如果要将文件发送给多个收件人,则会出现另一个问题,即如果RSA加密步骤是确定性的,则攻击者可以知道明文是相同的,因为密文是相同的。针对这些问题的正常防范是使用 填充方案 ,其中包括将一些随机秘密数据添加到明文中;这个数据称为填充。攻击者然后不能猜测随机数据,并且看到每个加密的不同结果,因为相同的明文从未被加密两次;就合法收件人而言,填充只是可以丢弃的数据。



在这种情况下,上述问题可能不适用。但是,使用无保护的RSA还有其他的缺点。特别是,如果公共指数非常小(PyCrypto使用65537不是这种情况),或者对于许多不同的收件人加密相同的材料(再次,可能不是这样,因为每个消息都有自己的密钥),那么一个简单的数学计算将允许攻击者恢复RSA明文。为了避免这种攻击,使用RSA加密的值需要与RSA模数足够接近,以便加密操作实际上执行模幂运算。我提出的填充确保通过使最适合于0xff的最高字节; ,尽管在​​现实世界中,您应该使用一个批准的填充模式( OAEP )。


I'm implementing file encryption with RSA, using PyCrypto.

I know it's somewhat wrong, first of all because RSA is very slow and second because PyCrypto RSA can only encrypt 128 characters, so you have to explode the file in 128 characters chunks.

This is the code so far:

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)

So my question is : are there any better methods for using Private/ Public key encryption ON FILES ?

I heard about Mcrypt and OpenSSL, but I don't know if they can encrypt files.

解决方案

Public-key cryptography is usually used for small amounts of data only. It is slow, and can be hard to use right. The usual practice is to use other methods to reduce the asymmetric problem to one where the security is provided by a shared key, then use public-key cryptography to protect that shared key. For example:

  • To encrypt a file, randomly generate a secret key for a block or stream cipher (e.g. AES). Store the data encrypted with this cipher, and store the secret key encrypted with the public key alongside the encrypted payload.
  • To sign a file, compute a cryptographic digest (e.g. SHA-256). Sign the digest of the file with the private key and store that alongside the file.

So here's a sketch of how encryption can look like (warning, untested code, typed directly in the browser):

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()))

The iv is an initialization vector for the CBC mode of operation. It needs to be unique per key per message. Normally, it's sent alongside the data in cleartext. Here, since the key is only ever used once, you can use a known IV.

The API of the block cipher is described in PEP 272. Unfortunately, it only supports all-at-once encryption. For large files, it would be better to encrypt chunk by chunk; you can encrypt as little as a block at a time (16 bytes for AES), but you need a better crypto library for that.

Note that in general, you should not directly encrypt data with RSA. The most obvious concern is that the attacker knows the public key and can therefore attempt to guess the plaintext (if the attacker thinks the plaintext may be swordfish, then the attacker can encrypt swordfish with the RSA public key, and compare the result with the output of the RSA encryption). Another concern which would arise if you wanted to send the file to multiple recipients is that if the RSA encryption step is deterministic, then the attacker can tell that the plaintexts are the same because the ciphertexts are the same. The normal defense against these problems is to use a padding scheme, which consists of adding some random secret data to the plaintext; this data is called padding. The attacker then cannot guess the random data, and sees different outcomes for every encryption because the same plaintext is never encrypted twice; as far as the legitimate recipient is concerned, the padding is just data that can be thrown away.

Here, it may appear that the above concerns do not apply in this scenario. However, there are other weaknesses that can arise from using RSA unprotected. In particular, if the public exponent is very small (not the case here as PyCrypto uses 65537) or you encrypt the same material for many different recipients (again, probably not the case here since each message has its own secret key), then a simple mathematical calculation would allow the attacker to recover the RSA plaintext. To avoid this attack, the value that is encrypted with RSA needs to be "close enough" to the RSA modulus, so that the encryption operation actually performs a modular exponentiation. The padding I propose ensures that by making the highest-order byte that fits 0xff; this is believed to be safe, although in the real world you should used an approved padding mode (OAEP).

这篇关于在Python中使用RSA加密文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆