AES ECB 模式在使用不同语言时给出不同的结果
AES ECB Mode giving different results when using different languages
我正在尝试使用 ECB 模式将 AES 加密字符串从 python 脚本传递到 nodejs 脚本。使用的代码是:
首先,我使用 pycryptodome 将字符串加密为 AES
from Crypto.Cipher import AES
key = b'ipu9TUv54yv]isFMh5@;t.5w34E2Ry@{'
cipher = AES.new(key, AES.MODE_ECB)
print(cipher.encrypt(b"foobar "))
This gives me the string \xb0\x07\x93\xf3\x02\xd0\x87\xa4\xaek\x1bS\xccg\xa4H
.
但是,当我尝试使用 Javascript 反转效果时:
var crypto = require('crypto')
let key = Buffer.from('ipu9TUv54yv]isFMh5@;t.5w34E2Ry@{');
let decipher = crypto.createDecipheriv("aes-256-ecb", key, '');
let result = decipher.update(Buffer.from('\xb0\x07\x93\xf3\x02\xd0\x87\xa4\xaek\x1bS\xccg\xa4H'));
console.log(result.toString())
It gives me a completely different result from the original text: �k��gR�O
是否有我遗漏的东西正在改变它的解密方式?
有两个核心问题:
在节点端,您将 Python 的输出视为 UTF-8 字符串。 Node 会将其视为 UTF-8 字符串,组成 Buffer 的结果字节将是错误的。把它转储出来,你会看到它是一个 25 字节的缓冲区,而不是你想要的。
一旦你解决了这个问题,你就会发现第二个问题。加密库需要填充字节,即使唯一的块恰好是块大小。要解决此问题,请始终向明文添加填充。
因此,加密更改为:
from Crypto.Cipher import AES
key = b'ipu9TUv54yv]isFMh5@;t.5w34E2Ry@{'
cipher = AES.new(key, AES.MODE_ECB)
# Don't need to ensure the plain text is exactly block-size anymore
data = b'foobar'
# Pad it, regardless of it's size
length = 16 - (len(data) % 16)
data += bytes([length]) * length
# And encode the encrypted text. Using hex here, it's easy, though
# often base64 is used
print(cipher.encrypt(data).hex())
并在 Node 中解码:
var crypto = require('crypto')
let key = Buffer.from('ipu9TUv54yv]isFMh5@;t.5w34E2Ry@{');
let decipher = crypto.createDecipheriv("aes-256-ecb", key, '');
// Using the hex encoding, let Buffer decode it
let result = decipher.update(Buffer.from('bf8242c6046ad5cb47e733dca4d487f1', 'hex'));
// Make sure to give decipher a chance to operate on the final block
result += decipher.final();
console.log(result.toString())
这会按预期输出 foobar
。
我正在尝试使用 ECB 模式将 AES 加密字符串从 python 脚本传递到 nodejs 脚本。使用的代码是:
首先,我使用 pycryptodome 将字符串加密为 AES
from Crypto.Cipher import AES
key = b'ipu9TUv54yv]isFMh5@;t.5w34E2Ry@{'
cipher = AES.new(key, AES.MODE_ECB)
print(cipher.encrypt(b"foobar "))
This gives me the string
\xb0\x07\x93\xf3\x02\xd0\x87\xa4\xaek\x1bS\xccg\xa4H
.
但是,当我尝试使用 Javascript 反转效果时:
var crypto = require('crypto')
let key = Buffer.from('ipu9TUv54yv]isFMh5@;t.5w34E2Ry@{');
let decipher = crypto.createDecipheriv("aes-256-ecb", key, '');
let result = decipher.update(Buffer.from('\xb0\x07\x93\xf3\x02\xd0\x87\xa4\xaek\x1bS\xccg\xa4H'));
console.log(result.toString())
It gives me a completely different result from the original text:
�k��gR�O
是否有我遗漏的东西正在改变它的解密方式?
有两个核心问题:
在节点端,您将 Python 的输出视为 UTF-8 字符串。 Node 会将其视为 UTF-8 字符串,组成 Buffer 的结果字节将是错误的。把它转储出来,你会看到它是一个 25 字节的缓冲区,而不是你想要的。
一旦你解决了这个问题,你就会发现第二个问题。加密库需要填充字节,即使唯一的块恰好是块大小。要解决此问题,请始终向明文添加填充。
因此,加密更改为:
from Crypto.Cipher import AES
key = b'ipu9TUv54yv]isFMh5@;t.5w34E2Ry@{'
cipher = AES.new(key, AES.MODE_ECB)
# Don't need to ensure the plain text is exactly block-size anymore
data = b'foobar'
# Pad it, regardless of it's size
length = 16 - (len(data) % 16)
data += bytes([length]) * length
# And encode the encrypted text. Using hex here, it's easy, though
# often base64 is used
print(cipher.encrypt(data).hex())
并在 Node 中解码:
var crypto = require('crypto')
let key = Buffer.from('ipu9TUv54yv]isFMh5@;t.5w34E2Ry@{');
let decipher = crypto.createDecipheriv("aes-256-ecb", key, '');
// Using the hex encoding, let Buffer decode it
let result = decipher.update(Buffer.from('bf8242c6046ad5cb47e733dca4d487f1', 'hex'));
// Make sure to give decipher a chance to operate on the final block
result += decipher.final();
console.log(result.toString())
这会按预期输出 foobar
。