在Python中实现OpenSSL AES加密

时间:2012-12-17 03:17:16

标签: python openssl aes pycrypto m2crypto

我正在尝试在Python中实现以下内容: openssl enc -e -aes-256-cbc -base64 -k“Secret Passphrase”-in plaintext.txt -out ciphertext.txt

openssl enc -d -aes-256-cbc -base64 -k“Secret Passphrase”-in ciphertext.txt -out verification.txt

我已经尝试了几个不同的模块,PyCrypto,M2Crypto等,但似乎无法正确组合将密码更改为正确的大小键并正确编码所有内容。我发现https://github.com/nvie/SimpleAES但是它基本上在命令行上运行OpenSSL,我宁愿避免使用。

1 个答案:

答案 0 :(得分:5)

可以通过标准base64模块轻松处理Base 64编码和解码。

PyCrypto和M2Crypto都支持CBC模式下的AES-256解密和加密。

唯一的非标准(也是最困难的)部分是从密码中推导出IV和密钥。 OpenSSL通过自己的EVP_BytesToKey函数完成它,该函数描述为in this man page

Python的等价物是:

def EVP_BytesToKey(password, salt, key_len, iv_len):
    """
    Derive the key and the IV from the given password and salt.
    """
    from hashlib import md5
    dtot =  md5(password + salt).digest()
    d = [ dtot ]
    while len(dtot)<(iv_len+key_len):
        d.append( md5(d[-1] + password + salt).digest() )
        dtot += d[-1]
    return dtot[:key_len], dtot[key_len:key_len+iv_len]

其中key_len为32,AES-256为iv_len为16。该函数返回密钥和IV,您可以使用它来解密有效负载。

OpenSSL在加密的有效载荷的前8个字节中放入并期望盐。

最后,CBC模式下的AES只能处理与16字节边界对齐的数据。使用的默认填充是PKCS#7。

因此加密的步骤是:

  1. 以盐形式生成8个字节的随机数据。
  2. 使用步骤1中的salt从密码中导出AES密钥和IV。
  3. 使用PKCS#7填充输入数据。
  4. 使用来自步骤2的密钥和IV在CBC模式下使用AES-256加密填充。
  5. 在Base64中编码并输出步骤1中的盐。
  6. 在Base64中编码并输出步骤4中的加密数据。
  7. 解密的步骤正好相反:

    1. 将输入数据从Base64解码为二进制字符串。
    2. 将解码数据的前8个字节视为盐。
    3. 使用步骤1中的salt从密码中导出AES密钥和IV。
    4. 使用AES密钥和步骤3中的IV解密剩余的解码数据。
    5. 验证并删除结果中的PKCS#7填充。