Base 64 编码和解码可以通过标准base64
模块轻松处理。
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]
其中key_len
是 32,iv_len
对于 AES-256 是 16。该函数返回可用于解密有效负载的密钥和 IV。
OpenSSL 将盐放在加密负载的前 8 个字节中。
最后,CBC 模式下的 AES 只能处理与 16 字节边界对齐的数据。使用的默认填充是 PKCS#7。
因此,加密的步骤是:
- 生成 8 字节的随机数据作为盐。
- 使用步骤 1 中的盐从密码中派生 AES 密钥和 IV。
- 使用 PKCS#7 填充输入数据。
- 使用 CBC 模式下的 AES-256 加密填充,使用步骤 2 中的密钥和 IV。
- 在 Base64 中编码并输出步骤 1 中的盐。
- 在 Base64 中编码并输出步骤 4 中的加密数据。
解密的步骤是相反的:
- 将 Base64 中的输入数据解码为二进制字符串。
- 将解码数据的前 8 个字节视为盐。
- 使用步骤 1 中的盐从密码中派生 AES 密钥和 IV。
- 使用步骤 3 中的 AES 密钥和 IV 解密剩余的解码数据。
- 验证并从结果中删除 PKCS#7 填充。