python(pycrypto)和nodejs(crypto)之间不匹配的encryption(aes-128-cbc)

我有这个python代码,我需要翻译成nodejs。 python代码使用来自encryption的pycrypto。 在nodejs方面,我正在使用本地encryption模块。 encryption的string似乎不匹配。

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. 节点的自动填充是PKCS填充。 你的python代码使用空字节填充,而不是格式。 节点文档甚至明确提到禁用自动填充以使用空字节填充。

  2. JSON在节点和python之间的格式稍有不同。 JavaScript的JSON.stringify()删除所有不必要的空白,而python留下一些空白(例如在数组/对象中的元素之间)。 最简单的解决scheme可能是更改Python代码以指定明确的separators选项 : json.dumps({ "a": 1, "b": 2 }, separators=(',', ':')) ,因为JavaScript的JSON.stringify()在改变格式时不那么灵活。

下面的节点代码显示,通过匹配JSON输出使用适当的填充,您将得到与python相同的hex输出:

 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'));