使用Node.js AES CTR进行加密,使用PyCrypto进行解密

3

好的,基本上我在使用Python解密方面遇到了问题。

我已经成功地使用Node.js和PyCrypto加密/解密数据 - 使用“aes-128-ctr”,但是当我尝试使用Node.js加密并使用Python解密时,我得到了无效的解密文本。

Node.js代码:

var key = "1234567890123456";
var cipher = crypto.createCipher("aes-128-ctr",key)
var ctext = cipher.update('asasasa','utf8','hex') +  cipher.final('hex')
console.log(ctext) // outputs: "f2cf6ecd8f"

Python代码:

counter = Counter.new(128)
cipher = AES.new("1234567890123456", AES.MODE_CTR, counter=counter)
cipher.decrypt("f2cf6ecd8f") // outputs: weird encoding characters

顺便说一下,我并不关心这种加密的安全级别,我更在意性能。


“asasasa”是要加密的数据,长度为7个字符吗?如果是,在CTR模式下输出应该是7字节,即14个十六进制字节。但实际输出结果是“f2cf6ecd8f”,只有5个字节的十六进制编码。这表明使用中存在错误。另外,请问计数器的初始值是多少? - zaph
1个回答

3

crypto.createCipher接受一个密码,并在内部使用EVP_BytesToKey来派生出密钥和IV。相反,pycrypto直接期望一个密钥和IV。你需要在两边都使用完全相同的过程。

crypto.createCipher永远不应该与CTR模式一起使用,因为密钥和IV生成没有随机化。由于CTR模式是流模式,它将始终产生相同的密钥流,这可能使仅观察用相同密码加密的多个密文的攻击者推断明文。这是由于导致多次使用密码问题。

如果你必须使用CTR模式,则必须使用crypto.createCipheriv。如果你使用相同的密钥,则每次都必须使用不同的IV。这就是为什么实际上称之为CTR模式的一次性数字。对于AES-CTR,96位的一次性数字是安全性和可加密明文大小之间的良好折衷。

var plaintext = 'asasasa'
var key = "1234567890123456" # don't use this one!
var nonce = crypto.randomBytes(12)
var iv = Buffer.concat([nonce, Buffer.alloc(4, 0)])
var cipher = crypto.createCipheriv("aes-128-ctr", key, iv)
var ciphertext = nonce.toString('hex') + cipher.update(plaintext,'utf8','hex') +  cipher.final('hex')
console.log(ciphertext)

示例输出:

5b88aeb265712b6c8bfa8dbd63012d1e52eb42

IV 不是秘密,您必须在解密过程中使用完全相同的 IV。通常,它会被添加到密文前缀中一起发送。然后在解密之前将其切掉:

ct = codecs.decode('5b88aeb265712b6c8bfa8dbd63012d1e52eb42', 'hex') # I'm using Python 3
counter = Counter.new(32, prefix=ct[:12], initial_value=0)
cipher = AES.new("1234567890123456", AES.MODE_CTR, counter=counter)
cipher.decrypt(ct[12:])

输出:

b'asasasa'

请记住,密钥需要随机选择。您可以生成一个随机密钥,并将其以编码形式保存在源代码中(即十六进制)。如果这样做,您必须不向任何您不信任的人提供源代码或字节码。


谢谢Artjom,我很感激你的回答,我已经将其标记为正确答案。 我想问一下counter = Counter.new(32, prefix=ct[:12], initial_value=0),我想了解为什么你会选择这个前缀,以及32位整数如何起作用?关于其他方面,我必须承认,通过查看git和其他资源,还有在SO上,我有了一些理解,但是我没有加密和PyCrypto的熟练掌握来设计出那个计数器,我很乐意更好地理解它的工作原理。再次感谢您的帮助! - Holdsworth
CTR模式的主要要点是,当使用相同的密钥时,绝不能再次使用相同的计数器值。AES块大小为128位,这意味着CTR模式中的计数器必须具有相同的大小。有不同的方法来考虑计数器是什么。通常,我们谈论的是固定的位数x和可变的位数128-x。在开始加密消息时,固定部分通常设置为96个随机位,因为很难出现多个加密的相同前缀... - Artjom B.
1
设置前缀后,剩余的位数(128-96=32)可用于递增每个加密块的计数器。对于AES,这意味着可以加密68 GB的数据,然后需要一个新的前缀(2 ^ 32 * 128 bit)。如果需要在单次传递中加密更多数据,则可以使用88位前缀和40位计数器。您不能任意减少前缀长度,必须考虑要加密多少条消息。例如,如果要加密超过40亿条消息,则64位前缀由于生日问题不足够。 - Artjom B.
感谢您详细的解释。 - Holdsworth
感谢您提供如此精彩的解释和解决方案。我已经寻找了一整天了。 - Neetigya Chahar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接