我正在尝试使用 PyCryptodome 加密和解密文件,但没有成功。我可以很好地加密字符串和数据,但是当尝试加密文件时它会失败。我有两个问题,第一是我无法加密较大的字符串。我试图通过使用缓冲区读取文件来解决问题。其次,当我尝试将其加密为较小的缓冲区时,它只会给我一个错误“raise ValueError(“长度不正确的密文。”)“
我的代码如下所示:
from Crypto.Cipher import PKCS1_OAEP
import binascii
import ast
file_to_encrypt = "file_example_MP3_700KB.mp3"
buffer_size = 65536 # 64kb
input_file = open(file_to_encrypt, "rb")
output_file = open(file_to_encrypt + ".encrypted", "wb")
# Import keys
pub = open("publickey.txt", "rb")
pubKey = RSA.importKey(pub.read())
pub.close()
priv = open("privatekey.txt", "rb")
keyPair = RSA.importKey(priv.read())
priv.close()
# --------------------------------------------------------------
# Encrypt
encryptor = PKCS1_OAEP.new(pubKey)
buffer = input_file.read(buffer_size)
while len(buffer) > 0:
encrypted = encryptor.encrypt(buffer)
output_file.write(encrypted)
buffer = input_file.read(buffer_size)
input_file.close()
output_file.close()
# --------------------------------------------------------------
input_file = open(file_to_encrypt + ".encrypted", "rb")
output_file = open(file_to_encrypt + ".decrypted", "wb")
# Decrypt
decryptor = PKCS1_OAEP.new(keyPair)
buffer = input_file.read(buffer_size)
while len(buffer) > 0:
decrypted = decryptor.decrypt(ast.literal_eval(str(buffer)))
output_file.write(decrypted)
buffer = input_file.read(buffer_size)
input_file.close()
output_file.close()
# --------------------------------------------------------------
生成密钥如下所示:
from Crypto.Cipher import PKCS1_OAEP
import binascii
import ast
# key generation
keyPair = RSA.generate(3072*2)
pubKey = keyPair.publickey()
# --------------------------------------------------------------
# Export keys
pub = open("publickey.txt", "wb")
pub.write(pubKey.exportKey('PEM'))
pub.close()
priv = open("privatekey.txt", "wb")
priv.write(keyPair.exportKey('PEM'))
priv.close()
# --------------------------------------------------------------
# Import keys
pub = open("publickey.txt", "rb")
pubKey = RSA.importKey(pub.read())
pub.close()
priv = open("privatekey.txt", "rb")
keyPair = RSA.importKey(priv.read())
priv.close()
# --------------------------------------------------------------
# encryption
msg = '550011'
encryptor = PKCS1_OAEP.new(pubKey)
encrypted = encryptor.encrypt(msg.encode())
# --------------------------------------------------------------
# decryption
decryptor = PKCS1_OAEP.new(keyPair)
decrypted = str(decryptor.decrypt(ast.literal_eval(str(encrypted))))[2:-1]
# --------------------------------------------------------------
print("Encrypted:", binascii.hexlify(encrypted))
print("Decrypted:", decrypted)
if msg == decrypted:
print("PASSED!")
else:
print("FAILED!")
更改 buffer_size 解决了第一个问题(我尝试加密的数据太大。) 但加密后我仍然无法解密我的文件。
生成和导入密钥效果很好。用它们加密和解密也可以正常工作。只要我只加密小字符串而不是文件。
正如 Topaco 所说,这不是一个好主意,因为耗时等。无论如何,您可以简单地将文件切成块,对其进行加密并以可以检索块的方式对其进行编码,即通过创建每个加密块一个新行。请注意,我们需要确保加密的块不包含任何
\n
(换行符)。为此,我们可以简单地对加密块进行hexify并将其编码为UTF-8
。也就是说,这在尺寸和时间上都不是一种有效的技术。
安装pycryptodome并下载
file_example_MP3_700KB.mp3
# Optional, use a venv
python -m venv rsa_env
source rsa_env/bin/activate or ./rsa_env/Scripts/activate
# Install the needed package
pip install pycryptodome
from Crypto.Cipher import PKCS1_OAEP
from Crypto.PublicKey import RSA
# key generation
key_pair = RSA.generate(2048)
public_key = key_pair.publickey()
# --------------------------------------------------------------
# Export keys
with open("publickey.txt", "wb") as public_key_file:
public_key_file.write(public_key.exportKey('PEM'))
with open("privatekey.txt", "wb") as private_key_file:
private_key_file.write(key_pair.exportKey('PEM'))
# --------------------------------------------------------------
del key_pair
del public_key
# Import keys
with open("publickey.txt", "rb") as public_key_file:
public_key = RSA.importKey(public_key_file.read())
with open("privatekey.txt", "rb") as private_key_file:
key_pair = RSA.importKey(private_key_file.read())
# --------------------------------------------------------------
# encryption
MESSAGE = b'550011'
scrambler = PKCS1_OAEP.new(public_key)
encrypted = scrambler.encrypt(MESSAGE)
# --------------------------------------------------------------
# decryption
descrambler = PKCS1_OAEP.new(key_pair)
decrypted = descrambler.decrypt(encrypted)
# --------------------------------------------------------------
print("Encrypted:", encrypted)
print("Decrypted:", decrypted)
if MESSAGE == decrypted:
print("PASSED!")
else:
print("FAILED!")
from Crypto.Cipher import PKCS1_OAEP
from Crypto.PublicKey import RSA
# https://file-examples.com/index.php/sample-audio-files/sample-mp3-download/
FILE_TO_ENCRYPT = "file_example_MP3_700KB.mp3"
PATH_TO_PUBLIC_KEY = "publickey.txt"
def load_public_key(path):
with open(path, "rb") as public_key_file:
return RSA.importKey(public_key_file.read())
def public_key_bytes_length(public_key) -> int:
key: bytes = public_key.public_key().export_key()
return len(key[key.index(b'\n'):key.rindex(b'\n')])
def encrypt_file(public_key, file_path, encrypted_file_path):
scrambler = PKCS1_OAEP.new(public_key)
# It is just a guest
buffer_size = public_key_bytes_length(public_key) // 2
with open(file_path, "rb") as input_file:
with open(encrypted_file_path, "wb") as output_file:
while True:
to_encrypt = input_file.read(buffer_size)
# We reached the end
if len(to_encrypt) == 0:
break
encrypted = scrambler.encrypt(to_encrypt)
output_file.write(encrypted.hex().encode('utf-8'))
output_file.write(b'\n')
if __name__ == "__main__":
encrypt_file(
load_public_key(PATH_TO_PUBLIC_KEY),
FILE_TO_ENCRYPT,
f"{FILE_TO_ENCRYPT}.encrypted"
)
from Crypto.Cipher import PKCS1_OAEP
from Crypto.PublicKey import RSA
FILE_TO_DECRYPT = "file_example_MP3_700KB.mp3.encrypted"
PATH_TO_PRIVATE_KEY = "privatekey.txt"
def load_private_key(path):
with open(path, "rb") as private_key_file:
return RSA.importKey(private_key_file.read())
def decrypt_file(private_key, file_path, decrypted_file_path):
descrambler = PKCS1_OAEP.new(private_key)
with open(file_path, "rb") as input_file:
with open(decrypted_file_path, "wb") as output_file:
while True:
to_decrypt = input_file.readline()
# We reached the end
if len(to_decrypt) == 0:
break
to_decrypt = bytes.fromhex(
# Remove newline and decode the line
to_decrypt[:-1].decode('utf-8')
)
decrypted = descrambler.decrypt(to_decrypt)
output_file.write(decrypted)
if __name__ == "__main__":
decrypt_file(
load_private_key(PATH_TO_PRIVATE_KEY),
FILE_TO_DECRYPT,
f"{FILE_TO_DECRYPT}.decrypted.mp3"
)