在Python中实现OpenSSL AES加密

Piz*_*her 2 python openssl aes m2crypto pycrypto

我正在尝试在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,我宁愿避免.

Squ*_*ree 6

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

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

唯一的非标准(也是最困难的)部分是从密码中推导出IV和密钥.OpenSSL通过自己的EVP_BytesToKey函数完成它,本手册中对此进行了描述.

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]
Run Code Online (Sandbox Code Playgroud)

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

OpenSSL在加密的有效负载的前8个字节中放入并期望salt.

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

因此,加密步骤如下:

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

解密的步骤是相反的:

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