如何使用OpenSSL兼容的方式使用Python / PyCrypto AES加密/解密文件? [英] How to AES encrypt/decrypt files using Python/PyCrypto in an OpenSSL-compatible way?
问题描述
openssl aes-256- cbc -salt -in filename -out filename.enc
openssl aes-256-cbc -d -in filename.enc -out filename
Python支持AES格式的PyCrypto包,但它只提供工具。如何使用Python / PyCrypto来加密文件,方法是使用OpenSSL进行解密,以及解密使用OpenSSL进行加密的文件?
警告
此加密方案很弱。它没有提供充分的安全性。
不要使用它,除非您有绝对的兼容性。
鉴于Python的普及,起初我感到失望的是,这个问题没有完整的答案被发现。我花了相当数量的阅读不同的答案在这个委员会,以及其他资源,以获得正确的。我以为我可能会分享这个结果,以供将来参考,也许可以查看;我绝不是加密专家!但是,下面的代码可以无缝地工作:
from hashlib import md5
from Crypto.Cipher import AES
从Crypto import Random
def derived_key_and_iv(password,salt,key_length,iv_length):
d = d_i =''
while len(d) key_length + iv_length:
d_i = md5(d_i + password + salt).digest()
d + = d_i
返回d [:key_length],d [key_length:key_length + iv_length]
def encrypt(in_file,out_file,password,key_length = 32):
bs = AES.block_size
salt = Random.new()。read(bs - len('Salted__' )
key,iv = deriv_key_and_iv(password,salt,key_length,bs)
cipher = AES.new(key,AES.MODE_CBC,iv)
out_file.write('Salted__'+
finished = False
而未完成:
chunk = in_file.read(1024 * bs)
如果len(chunk)== 0或len(chunk)%bs != 0:
padding_length =(bs - len(chunk)%bs)或bs
chunk + = padding_length * chr(padding_length)
finished = True
out_file.write
def decrypt(in_file,out_file,password,key_length = 32):
bs = AES.block_size
salt = in_file.read(bs) [长度('盐渍__'):]
key,iv = deriv_key_and_iv(password,salt,key_length,bs)
cipher = AES.new(key,AES.MODE_CBC,iv)
next_chunk =''
finished = False
而未完成:
chunk,next_chunk = next_chunk,cipher.decrypt(in_file.read(1024 * bs))
如果len(next_chunk)== 0:
padding_length = ord(chunk [-1])$ b $ b chunk = chunk [: - padding_length]
finished = True
out_file.write(chunk)
用法:
(in_filename,'rb')as in_file,open(out_filename,'wb')as out_file:
encrypt(in_file,out_file,password)
with open(in_filename,'rb')as in_file,open (out_filename,'wb')as out_file:
decrypt(in_file,out_file,password)
如果你看到有机会改进或扩展它更灵活(例如
警告
这个加密方案很弱。它没有提供充分的安全性。不要使用它,除非您有绝对的兼容性。
There are many ways to use AES, resulting in frequent incompatibilities between different implementations. OpenSSL provides a popular (but insecure – see below!) command line interface for AES encryption/decryption:
openssl aes-256-cbc -salt -in filename -out filename.enc
openssl aes-256-cbc -d -in filename.enc -out filename
Python has support for AES in the shape of the PyCrypto package, but it only provides the tools. How to use Python/PyCrypto to encrypt files in a way that OpenSSL can be used to decrypt them, and to decrypt files that have been encrypted using OpenSSL?
WARNING
THIS ENCRYPTION SCHEME IS WEAK. IT DOES NOT PROVIDE ADEQUATE SECURITY. DO NOT USE IT UNLESS YOU ABSOLUTELY HAVE TO FOR BACKWARD COMPATIBILITY.
Given the popularity of Python, at first I was disappointed that there was no complete answer to this question to be found. It took me a fair amount of reading different answers on this board, as well as other resources, to get it right. I thought I might share the result for future reference and perhaps review; I'm by no means a cryptography expert! However, the code below appears to work seamlessly:
from hashlib import md5
from Crypto.Cipher import AES
from Crypto import Random
def derive_key_and_iv(password, salt, key_length, iv_length):
d = d_i = ''
while len(d) < key_length + iv_length:
d_i = md5(d_i + password + salt).digest()
d += d_i
return d[:key_length], d[key_length:key_length+iv_length]
def encrypt(in_file, out_file, password, key_length=32):
bs = AES.block_size
salt = Random.new().read(bs - len('Salted__'))
key, iv = derive_key_and_iv(password, salt, key_length, bs)
cipher = AES.new(key, AES.MODE_CBC, iv)
out_file.write('Salted__' + salt)
finished = False
while not finished:
chunk = in_file.read(1024 * bs)
if len(chunk) == 0 or len(chunk) % bs != 0:
padding_length = (bs - len(chunk) % bs) or bs
chunk += padding_length * chr(padding_length)
finished = True
out_file.write(cipher.encrypt(chunk))
def decrypt(in_file, out_file, password, key_length=32):
bs = AES.block_size
salt = in_file.read(bs)[len('Salted__'):]
key, iv = derive_key_and_iv(password, salt, key_length, bs)
cipher = AES.new(key, AES.MODE_CBC, iv)
next_chunk = ''
finished = False
while not finished:
chunk, next_chunk = next_chunk, cipher.decrypt(in_file.read(1024 * bs))
if len(next_chunk) == 0:
padding_length = ord(chunk[-1])
chunk = chunk[:-padding_length]
finished = True
out_file.write(chunk)
Usage:
with open(in_filename, 'rb') as in_file, open(out_filename, 'wb') as out_file:
encrypt(in_file, out_file, password)
with open(in_filename, 'rb') as in_file, open(out_filename, 'wb') as out_file:
decrypt(in_file, out_file, password)
If you see a chance to improve on this or extend it to be more flexible (e.g. make it work without salt, or provide Python 3 compatibility), please feel free to do so.
WARNING
THIS ENCRYPTION SCHEME IS WEAK. IT DOES NOT PROVIDE ADEQUATE SECURITY. DO NOT USE IT UNLESS YOU ABSOLUTELY HAVE TO FOR BACKWARD COMPATIBILITY.
这篇关于如何使用OpenSSL兼容的方式使用Python / PyCrypto AES加密/解密文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!