由于某些奇怪的原因,Node的内置Cipher
和Decipher
类无法正常工作。 documentation表示cipher.update
“返回加密的内容,并且在流式传输时可以使用新数据多次调用。”
docs也声明cipher.final
“返回任何剩余的加密内容。”
但是,在我的测试中,你必须调用cipher.final
来获取所有数据,从而使Cipher对象变得毫无价值,并处理下一个块,你必须创建一个新的密码对象
var secret = crypto.randomBytes(16)
, source = crypto.randomBytes(8)
, cipher = crypto.createCipher("aes128", secret)
, decipher = crypto.createDecipher("aes128", secret);
var step = cipher.update(source);
var end = decipher.update(step);
assert.strictEqual(source.toString('binary'), end); // should not fail, but does
请注意,使用crypto.createCipher
或crypto.createCipheriv
时会发生这种情况,并将秘密作为初始化向量。修复是用以下代码替换第6行和第7行:
var step = cipher.update(source) + cipher.final();
var end = decipher.update(step) + decipher.final();
但是,如前所述,这会使cipher
和decipher
变得毫无价值。
这就是我期望Node的内置加密工作的方式,但显然不是这样。这是我如何使用它或Node中的错误的问题?或者我期待错误的事情?我可以直接实施AES,但这将是耗时且烦人的。我是否应该在每次需要加密或解密时创建一个新的Cipher
或Decipher
对象?如果我作为流的一部分这样做,这似乎很昂贵。
答案 0 :(得分:3)
我遇到了两个问题:首先是我错误地假设一个块的大小是64位,或者是8个字节,这就是我用来创建“明文”的问题。实际上,AES的内部将128位明文分成两个64位块,并从那里开始。
第二个问题是,尽管在应用上述更改后使用了正确的块大小,crypto
模块正在应用自动填充,并且禁用自动填充解决了第二个问题。因此,工作示例如下:
var secret = crypto.randomBytes(16)
, source = crypto.randomBytes(16)
, cipher = crypto.createCipheriv("aes128", secret, secret); // or createCipher
, decipher = crypto.createDecipheriv("aes128", secret, secret);
cipher.setAutoPadding(false);
decipher.setAutoPadding(false);
var step = cipher.update(source);
var end = decipher.update(step);
assert.strictEqual(source.toString('binary'), end); // does not fail
答案 1 :(得分:2)
AES使用16字节的块大小(不是您建议的两倍8)。此外,如果填充已启用,则应始终填充。原因是否则unpadding算法无法区分填充和明文的最后一个字节。
大多数情况下,您不应期望密文与纯文本的大小相同。确保始终调用doFinal()
。如果要实现自己的加密方案,则只应使用此方式进行加密/解密。
答案 2 :(得分:0)
连续多次调用更新a node.js issue。我想它已在下一个版本中得到解决和反映。