使用PyCrypto AES 256加密和解密

问题描述 投票:150回答:12

我正在尝试使用PyCrypto构建两个接受两个参数的函数:消息和密钥,然后对消息进行加密/解密。

我在网络上找到了几个链接可以帮助我,但是每个链接都有缺陷:

[This one at codekoala使用os.urandom,PyCrypto不建议这样做。

此外,不能保证我提供给函数的键具有期望的确切长度。我该怎么做才能做到这一点?

另外,有几种模式,推荐哪种?我不知道该用什么:/

最后,IV到底是什么?我可以提供不同的IV进行加密和解密,还是会返回不同的结果?

这是我到目前为止所做的:

from Crypto import Random
from Crypto.Cipher import AES
import base64

BLOCK_SIZE=32

def encrypt(message, passphrase):
    # passphrase MUST be 16, 24 or 32 bytes long, how can I do that ?
    IV = Random.new().read(BLOCK_SIZE)
    aes = AES.new(passphrase, AES.MODE_CFB, IV)
    return base64.b64encode(aes.encrypt(message))

def decrypt(encrypted, passphrase):
    IV = Random.new().read(BLOCK_SIZE)
    aes = AES.new(passphrase, AES.MODE_CFB, IV)
    return aes.decrypt(base64.b64decode(encrypted))
python encryption padding pycrypto initialization-vector
12个回答
132
投票

这是我的实现,并通过一些修复为我工作,并以32字节和iv到16字节增强了密钥和秘密短语的对齐方式:

import base64
import hashlib
from Crypto import Random
from Crypto.Cipher import AES

class AESCipher(object):

    def __init__(self, key): 
        self.bs = 32
        self.key = hashlib.sha256(key.encode()).digest()

    def encrypt(self, raw):
        raw = self._pad(raw)
        iv = Random.new().read(AES.block_size)
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return base64.b64encode(iv + cipher.encrypt(raw))

    def decrypt(self, enc):
        enc = base64.b64decode(enc)
        iv = enc[:AES.block_size]
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return self._unpad(cipher.decrypt(enc[AES.block_size:])).decode('utf-8')

    def _pad(self, s):
        return s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs)

    @staticmethod
    def _unpad(s):
        return s[:-ord(s[len(s)-1:])]

1
投票
from Crypto import Random from Crypto.Cipher import AES import base64 BLOCK_SIZE=16 def trans(key): return md5.new(key).digest() def encrypt(message, passphrase): passphrase = trans(passphrase) IV = Random.new().read(BLOCK_SIZE) aes = AES.new(passphrase, AES.MODE_CFB, IV) return base64.b64encode(IV + aes.encrypt(message)) def decrypt(encrypted, passphrase): passphrase = trans(passphrase) encrypted = base64.b64decode(encrypted) IV = encrypted[:BLOCK_SIZE] aes = AES.new(passphrase, AES.MODE_CFB, IV) return aes.decrypt(encrypted[BLOCK_SIZE:])

1
投票
我已经使用了CryptoPyCryptodomex库,并且运行速度很快...

import base64 import hashlib from Cryptodome.Cipher import AES as domeAES from Cryptodome.Random import get_random_bytes from Crypto import Random from Crypto.Cipher import AES as cryptoAES BLOCK_SIZE=16 key = "my_secret_key".encode() __key__ = hashlib.sha256(key).digest() print(__key__) def encrypt(raw): BS = cryptoAES.block_size pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS) raw = base64.b64encode(pad(raw).encode('utf8')) iv = get_random_bytes(cryptoAES.block_size) cipher = cryptoAES.new(key= __key__, mode= cryptoAES.MODE_CFB,iv= iv) a= base64.b64encode(iv + cipher.encrypt(raw)) IV = Random.new().read(BLOCK_SIZE) aes = domeAES.new(__key__, domeAES.MODE_CFB, IV) b = base64.b64encode(IV + aes.encrypt(a)) return b def decrypt(enc): passphrase = __key__ encrypted = base64.b64decode(enc) IV = encrypted[:BLOCK_SIZE] aes = domeAES.new(passphrase, domeAES.MODE_CFB, IV) enc = aes.decrypt(encrypted[BLOCK_SIZE:]) unpad = lambda s: s[:-ord(s[-1:])] enc = base64.b64decode(enc) iv = enc[:cryptoAES.block_size] cipher = cryptoAES.new(__key__, cryptoAES.MODE_CFB, iv) b= unpad(base64.b64decode(cipher.decrypt(enc[cryptoAES.block_size:])).decode('utf8')) return b encrypted_data =encrypt("Hi Steven!!!!!") print(encrypted_data) print("=======") decrypted_data = decrypt(encrypted_data) print(decrypted_data)



142
投票

当输入长度不是BLOCK_SIZE的倍数时,可能需要以下两个函数来填充(加密时)和取消填充(解密时)。>>

BS = 16
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS) 
unpad = lambda s : s[:-ord(s[len(s)-1:])]

所以您要询问密钥的长度?您可以使用密钥的md5sum而不是直接使用它。

更多,根据我使用PyCrypto的经验,在输入相同的情况下,IV用于混合加密输出,因此将IV选择为随机字符串,并将其用作加密输出的一部分,然后使用它解密邮件。

这是我的实现,希望它对您有用:

import base64
from Crypto.Cipher import AES
from Crypto import Random

class AESCipher:
    def __init__( self, key ):
        self.key = key

    def encrypt( self, raw ):
        raw = pad(raw)
        iv = Random.new().read( AES.block_size )
        cipher = AES.new( self.key, AES.MODE_CBC, iv )
        return base64.b64encode( iv + cipher.encrypt( raw ) ) 

    def decrypt( self, enc ):
        enc = base64.b64decode(enc)
        iv = enc[:16]
        cipher = AES.new(self.key, AES.MODE_CBC, iv )
        return unpad(cipher.decrypt( enc[16:] ))

11
投票

[让我解决您有关“模式”的问题。 AES256是一种分组密码


6
投票
您可以使用SHA-1或SHA-256之类的加密散列函数(

NOT


6
投票
对于想使用urlsafe_b64encode和urlsafe_b64decode的人,这是为我工作的版本(花了一些时间处理unicode问题之后)

5
投票
[为了他人的利益,这是我通过结合@Cyril和@Marcus的答案获得的解密实现。假定此消息是通过HTTP请求传入的,该消息带有加引号的cryptoText和base64编码。

4
投票
感谢其他启发但对我不起作用的答案。在花了数小时试图弄清楚它是如何工作之后,我想到了下面的实现,带有最新的

PyCryptodomex


2
投票
有点晚了,但是我认为这将非常有帮助。没有人提及像PKCS#7填充这样的使用方案。您可以使用它代替以前的功能来填充(加密时)和解锁(解密时)。i将在下面提供完整的源代码。

2
投票
对此承担另一种责任(从上面的解决方案中大量衍生而来,但是
© www.soinside.com 2019 - 2024. All rights reserved.