从 Nodejs 加密时解密 Python 中的 AES-256-CTR 有效负载
Decrypt AES-256-CTR payloads in Python when encrypted from Nodejs
我在 Nodejs 中编写了一个使用 AES-256-CTR 加密用户密码的应用程序:
const crypto = require('crypto')
const masterkey = 'azertyuiopazertyuiopazertyuiopaz'
const cipher = crypto.createCipher('aes-256-ctr', masterkey)
console.log(cipher.update('antoine', 'utf8', 'hex') + cipher.final('hex')) //=> 6415bc70ad76c6
然后它会保存到数据库中,现在我正尝试使用 PyCrypto 从 Python 脚本中破译它,如下所示:
masterkey = 'azertyuiopazertyuiopazertyuiopaz'
password = '6415bc70ad76c6'
from Crypto.Cipher import AES
import os
import binascii
counter = os.urandom(16)
# counter = bytes(16) # does not work
# counter = masterkey[0:16].encode() # does not work
cipher = AES.new(masterkey, AES.MODE_CTR, counter=lambda: counter)
print(cipher.decrypt(binascii.a2b_hex(password)))
但它给了我完全错误的结果。
你知道我错过了什么吗?
编辑
感谢 zaph,我的 Javascript 代码加密数据的方式似乎不安全。我仍然需要弄清楚 Node.js 内部使用的是什么 IV。我试了很多都没有成功
masterkey[0:16].encode()
bytes(16)
根据问题中的新信息进行更新:最好的选择是 Nodejs 使用默认计数器值。
加密和解密必须使用相同的计数器值。但是加密时没有提供计数器值,解密时使用的是随机值,因此它永远无法工作。
使用:crypto.createCipheriv(algorithm, key, iv)
其中 iv
是随机计数器初始值。
有必要在加密时创建一个随机计数器值并保存它,以便在解密时可以使用相同的初始计数器值。一种选择是在加密数据前加上计数器值,它不需要保密。然后在解密时,它可以从加密数据中分离出来并使用。
此外,当使用 CTR 模式时,相同的初始计数器值绝不能再次用于相同的密钥。
PyCrypto documentation CTR mode:
MODE_CBC
Cipher-Block Chaining (CBC). Each of the ciphertext blocks depends on the current and all previous plaintext blocks. An Initialization Vector (IV) is required.
The IV is a data block to be transmitted to the receiver. The IV can be made public, but it must be authenticated by the receiver and it should be picked randomly.)
IV 是初始计数器值。
[Nodejs dociumewnrtation: Class: Cipher:
crypto.createCipheriv(algorithm, key, iv)
algorithm <string>
key <string> | <Buffer> | <TypedArray> | <DataView>
iv <string> | <Buffer> | <TypedArray> | <DataView>
Creates and returns a Cipher object, with the given algorithm, key and initialization vector (iv).
我在 Nodejs 中编写了一个使用 AES-256-CTR 加密用户密码的应用程序:
const crypto = require('crypto')
const masterkey = 'azertyuiopazertyuiopazertyuiopaz'
const cipher = crypto.createCipher('aes-256-ctr', masterkey)
console.log(cipher.update('antoine', 'utf8', 'hex') + cipher.final('hex')) //=> 6415bc70ad76c6
然后它会保存到数据库中,现在我正尝试使用 PyCrypto 从 Python 脚本中破译它,如下所示:
masterkey = 'azertyuiopazertyuiopazertyuiopaz'
password = '6415bc70ad76c6'
from Crypto.Cipher import AES
import os
import binascii
counter = os.urandom(16)
# counter = bytes(16) # does not work
# counter = masterkey[0:16].encode() # does not work
cipher = AES.new(masterkey, AES.MODE_CTR, counter=lambda: counter)
print(cipher.decrypt(binascii.a2b_hex(password)))
但它给了我完全错误的结果。
你知道我错过了什么吗?
编辑
感谢 zaph,我的 Javascript 代码加密数据的方式似乎不安全。我仍然需要弄清楚 Node.js 内部使用的是什么 IV。我试了很多都没有成功
masterkey[0:16].encode()
bytes(16)
根据问题中的新信息进行更新:最好的选择是 Nodejs 使用默认计数器值。
加密和解密必须使用相同的计数器值。但是加密时没有提供计数器值,解密时使用的是随机值,因此它永远无法工作。
使用:crypto.createCipheriv(algorithm, key, iv)
其中 iv
是随机计数器初始值。
有必要在加密时创建一个随机计数器值并保存它,以便在解密时可以使用相同的初始计数器值。一种选择是在加密数据前加上计数器值,它不需要保密。然后在解密时,它可以从加密数据中分离出来并使用。
此外,当使用 CTR 模式时,相同的初始计数器值绝不能再次用于相同的密钥。
PyCrypto documentation CTR mode:
MODE_CBC
Cipher-Block Chaining (CBC). Each of the ciphertext blocks depends on the current and all previous plaintext blocks. An Initialization Vector (IV) is required.The IV is a data block to be transmitted to the receiver. The IV can be made public, but it must be authenticated by the receiver and it should be picked randomly.)
IV 是初始计数器值。
[Nodejs dociumewnrtation: Class: Cipher:
crypto.createCipheriv(algorithm, key, iv)
algorithm <string>
key <string> | <Buffer> | <TypedArray> | <DataView>
iv <string> | <Buffer> | <TypedArray> | <DataView>
Creates and returns a Cipher object, with the given algorithm, key and initialization vector (iv).