【问题标题】:Decrypting AES CBC in python from OpenSSL AES从 OpenSSL AES 在 python 中解密 AES CBC
【发布时间】:2020-09-29 19:48:51
【问题描述】:

我需要用 python 解密在 OpenSSL 上加密的文件,但我不了解 pycrypto 的选项。

这就是我在 OpenSSL 中所做的事情

  1. openssl enc -aes-256-cbc -a -salt -pbkdf2 -iter 100000 -in "clear.txt" -out "crypt.txt" -pass pass:"mypassword"

  2. openssl enc -d -aes-256-cbc -a -pbkdf2 -iter 100000 -in "crypt.txt" -out "out.txt" -pass pass:"mypassword"

我试过了(显然行不通)

obj2 = AES.new("mypassword", AES.MODE_CBC)
output = obj2.decrypt(text)

我只想在python中做第二步,但是在查看示例时:

https://pypi.org/project/pycrypto/

obj2 = AES.new('This is a key123', AES.MODE_CBC, 'This is an IV456')
obj2.decrypt(ciphertext)

我不需要 IV,如何指定盐? pbkdf2 哈希?我也在看这个帖子

How to decrypt OpenSSL AES-encrypted files in Python?

但没有帮助。

谁能告诉我如何使用 python 做到这一点?

谢谢。

【问题讨论】:

    标签: python encryption openssl pycrypto pycryptodome


    【解决方案1】:

    OpenSSL 语句使用 PBKDF2 创建一个 32 字节的密钥和一个 16 字节的 IV。为此,会隐式生成一个随机的 8 字节盐,并应用指定的密码、迭代计数和摘要(默认值:SHA-256)。密钥/IV 对用于在 CBC 模式下使用 AES-256 和 PKCS7 填充加密明文,s。 here。结果以 OpenSSL 格式返回,该格式以 Salted__ 的 8 字节 ASCII 编码开头,然后是 8 字节盐和实际密文,均采用 Base64 编码。解密需要盐,以便重建密钥和IV。

    注意,OpenSSL 语句中的密码实际上是不带引号传递的,即在张贴的 OpenSSL 语句中,引号是密码的一部分。

    对于 Python 中的解密,必须首先从加密数据中确定 salt 和实际密文。使用盐可以重建密钥/IV 对。最后,密钥/IV 对可用于解密。

    示例:使用张贴的 OpenSSL 语句,明文

    The quick brown fox jumps over the lazy dog
    

    被加密成密文

    U2FsdGVkX18A+AhjLZpfOq2HilY+8MyrXcz3lHMdUII2cud0DnnIcAtomToclwWOtUUnoyTY2qCQQXQfwDYotw== 
    

    使用 Python 进行解密的方法如下(使用 PyCryptodome):

    from Crypto.Protocol.KDF import PBKDF2
    from Crypto.Hash import SHA256
    from Crypto.Util.Padding import unpad
    from Crypto.Cipher import AES
    import base64
    
    # Determine salt and ciphertext
    encryptedDataB64 = 'U2FsdGVkX18A+AhjLZpfOq2HilY+8MyrXcz3lHMdUII2cud0DnnIcAtomToclwWOtUUnoyTY2qCQQXQfwDYotw=='
    encryptedData = base64.b64decode(encryptedDataB64)
    salt = encryptedData[8:16]
    ciphertext = encryptedData[16:]
    
    # Reconstruct Key/IV-pair
    pbkdf2Hash = PBKDF2(b'"mypassword"', salt, 32 + 16, count=100000, hmac_hash_module=SHA256)
    key = pbkdf2Hash[0:32]
    iv = pbkdf2Hash[32:32 + 16]
    
    # Decrypt with AES-256 / CBC / PKCS7 Padding
    cipher = AES.new(key, AES.MODE_CBC, iv)
    decrypted = unpad(cipher.decrypt(ciphertext), 16)
    
    print(decrypted)
    

    编辑 - 关于您的评论:16 MB 应该是可能的,但对于较大的数据,密文通常会从文件中读取,解密后的数据会写入文件,与上面发布的示例。
    数据能否一步解密最终取决于可用内存。如果内存不够,数据必须分块处理。
    使用块时,不对加密数据进行 Base64 编码而是直接以二进制格式存储它们会更有意义。这可以通过在 OpenSSL 语句中省略 -a 选项来实现。否则,必须确保始终加载块大小的整数倍(相对于未解码的密文),其中 3 个字节的未解码密文对应于 4 个字节的 Base64 编码密文。

    在二进制存储密文的情况下:在解密过程中,第一步应该(二进制)读取第一个块(16 个字节)。由此,可以确定盐(字节 8 到 16),然后是密钥和 IV(类似于上面发布的代码)。
    密文的其余部分可以(二进制)以合适大小的块(=块大小的倍数,例如 1024 字节)读取。每个块都单独加密/解密,请参阅multiple encrypt/decrypt-calls。对于使用 Python 读取/写入块中的文件,请参见例如here
    更多细节最好在单独问题的范围内回答。

    【讨论】:

    • 谢谢。但我没有解释的一件事是我的 encryptedData 非常大。它是一个 16 MB 的文件。在您的解决方案中,我将不得不解密整个事情。我不确定python是否可以处理。由于它是一个块密码,我相信我们可以在块中解密。你知道怎么做吗?假设您的 encryptedDataB64 是一个非常大的文件。谢谢!
    • 谢谢伙计,我非常感谢您的说明和代码示例。该主题的线程不是很好。
    猜你喜欢
    • 2013-08-11
    • 2023-02-23
    • 1970-01-01
    • 2019-08-17
    • 2020-04-15
    • 1970-01-01
    • 2018-04-04
    • 1970-01-01
    • 2022-08-17
    相关资源
    最近更新 更多