加密(aes-128-cbc)在python(pycrypto)和nodejs(加密)

时间:2017-07-21 03:00:22

标签: python node.js aes pycrypto node-crypto

我有这段python代码,我需要将其转换为nodejs。 python代码使用加密的pycrypto。在nodejs方面,我使用的是本机加密模块。加密字符串之间似乎不匹配。

from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex
import json

raw_key = [0x58, 0x86, 0x17, 0x6d, 0x88, 0x7c, 0x9a, 0xa0, 0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x28, 0xa4, 0x5a]
key = str(bytearray(raw_key))

raw_iv =  [0x34, 0x2e, 0x17, 0x99, 0x6d, 0x19, 0x3d, 0x28, 0xdd, 0xb3, 0xa2, 0x69, 0x5a, 0x2e, 0x6f, 0x1b]
iv = str(bytearray(raw_iv))

text = json.dumps({ "a": 1, "b": 2 })

cryptor = AES.new(key, AES.MODE_CBC, iv)
length = 16
count = len(text)
add = length - (count % length)
text = text + ('\0' * add)
encrypted = cryptor.encrypt(text);
print b2a_hex(encrypted)

上面的python代码输出

5c72b1a394654b6dab9ea8fdd90fe56b92141d74cb32ac65ede4d3154801bb57

而下面的nodejs代码

const crypto = require('crypto');

const KEY = Buffer.from([0x58, 0x86, 0x17, 0x6d, 0x88, 0x7c, 0x9a, 0xa0, 0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x28, 0xa4, 0x5a]);
const IV = Buffer.from([0x34, 0x2e, 0x17, 0x99, 0x6d, 0x19, 0x3d, 0x28, 0xdd, 0xb3, 0xa2, 0x69, 0x5a, 0x2e, 0x6f, 0x1b]);

const text = JSON.stringify({ a: 1, b: 2 });

const cipher = crypto.createCipheriv('aes-128-cbc', KEY, IV);
cipher.setAutoPadding(true);
const encrypted = Buffer.concat([cipher.update(text, 'utf-8'), cipher.final()]);
console.log(encrypted.toString('hex'));

输出

d6a0dbc6df2a1038036e4db985f9ca10

为什么他们不匹配?我做错了吗?

1 个答案:

答案 0 :(得分:1)

这里有两个问题:

  1. 节点的自动填充是PKCS填充。您的python代码使用空字节代替填充,这是一种不同的格式。 node documentation甚至明确提到禁用自动填充以使用空字节填充。

  2. JSON在node和python之间的格式略有不同。 Javascript' s JSON.stringify()删除所有不必要的空格,而python则留下一些空格(例如,数组/对象中的元素之间)。对此最简单的解决方案可能是更改python代码以指定显式的separators optionjson.dumps({ "a": 1, "b": 2 }, separators=(',', ':')),因为javascript' JSON.stringify()不具备灵活性以这种方式改变格式。

  3. 下面的节点代码显示,通过使用正确的填充匹配JSON输出,您将获得与python相同的十六进制输出:

    const crypto = require('crypto');
    
    const KEY = Buffer.from([0x58, 0x86, 0x17, 0x6d, 0x88, 0x7c, 0x9a, 0xa0, 0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x28, 0xa4, 0x5a]);
    const IV = Buffer.from([0x34, 0x2e, 0x17, 0x99, 0x6d, 0x19, 0x3d, 0x28, 0xdd, 0xb3, 0xa2, 0x69, 0x5a, 0x2e, 0x6f, 0x1b]);
    
    var text = '{"a": 1, "b": 2}';
    
    const cipher = crypto.createCipheriv('aes-128-cbc', KEY, IV);
    cipher.setAutoPadding(false);
    
    var length = 16;
    var count = Buffer.byteLength(text);
    var add = length - (count % length);
    if (add > 0)
      text += '\0'.repeat(add);
    
    const encrypted = Buffer.concat([cipher.update(text, 'utf-8'), cipher.final()]);
    console.log(encrypted.toString('hex'));