问题描述
最近发现一些node项目使用原生crypto模块加密的数据不能通过python正常解密:
const crypto = require("crypto");
function encrypt(data) {
key = 'mysecretmysecret';
var cipher = crypto.createCipher('aes-128-ecb', key);
var ret = cipher.update(data, "utf8", "base64");
ret += cipher.final("base64");
return ret;
}
console.log(encrypt('testdata'))
// g7qc8vUMyOAmkRj2dwvCGA==
import base64
from Crypto.Cipher import AES
def decrypt(data):
data = base64.b64decode(data)
key = 'mysecretmysecret'
cipher = AES.new(key.encode(), AES.MODE_ECB)
res = cipher.decrypt(data)
return res
print(decrypt('g7qc8vUMyOAmkRj2dwvCGA=='))
# b"!w\xd2\x04Q\x04\x84\xe9\x82\x03\x95?'\xd7\xf6\x8b"
python 解密数据完全不一样
原因分析:
经过Google大法发现,node现在 createCipher 已经被弃用,推荐使用createCipheriv
并且createCipher中使用的secret并不是AES加密所使用的key
真正的key是用openSSL的方法EVP_BytesToKey,通过MD5,并且不需要加盐生成的密匙
解决方案:
知道是什么问题就好解决了,在网上找到了EVP_BytesToKey的python实现:
def EVP_BytesToKey(key_length, iv_length, md, salt, data, count=1):
"""
Usage:
key, iv = EVP_BytesToKey(
32, # 256 bits
Crypto.Cipher.AES.block_size,
hashlib.sha256,
salt,
password.encode('utf-8'),
)
See:
https://github.com/openssl/openssl/blob/6f0ac0e2f27d9240516edb9a23b7863e7ad02898/crypto/evp/evp_key.c#L74
"""
assert data
assert salt == b'' or len(salt) == 8
md_buf = b''
key = b''
iv = b''
# key_length = 32 # type.key_size
# iv_length = type.block_size
addmd = 0
while key_length > len(key) or iv_length > len(iv):
c = md()
if addmd:
c.update(md_buf)
addmd += 1
c.update(data)
c.update(salt)
md_buf = c.digest()
for i in range(1, count):
md_buf = md(md_buf)
md_buf2 = md_buf
if key_length > len(key):
key, md_buf2 = key + md_buf2[:key_length - len(key)], md_buf2[key_length - len(key):]
if iv_length > len(iv):
iv, md_buf2 = iv + md_buf2[:iv_length - len(iv)], md_buf2[iv_length - len(iv):]
return key, iv
使用方式:
secret = 'mysecretmysecret'
key, iv = EVP_BytesToKey(16, 16, hashlib.md5, b'', secret, 1)
这里的key才是AES所需要的真正的key
以上