如何使用OpenSSL兼容的方式使用Python / PyCrypto AES加密/解密文件? [英] How to AES encrypt/decrypt files using Python/PyCrypto in an OpenSSL-compatible way?

查看:261
本文介绍了如何使用OpenSSL兼容的方式使用Python / PyCrypto AES加密/解密文件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用AES有许多方法,导致不同实现之间频繁的不兼容。 OpenSSL为AES加密/解密提供了一个受欢迎的(但不安全的 - 见下文!)命令行界面:

  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屋!

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