1

出于某种奇怪的原因,Node 的内置CipherDecipher类没有按预期工作。该文件指出cipher.update

“返回加密的内容,并且可以在流式传输时使用新数据多次调用。”

文档还指出cipher.final

“返回任何剩余的加密内容。”

但是,在我的测试中,您必须调用cipher.final以获取所有数据,从而使 Cipher 对象变得毫无价值,并且要处理下一个块,您必须创建一个新的 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.createCipheror时会发生这种情况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如果我将其作为流的一部分这样做,那似乎很昂贵。

4

3 回答 3

4

我遇到了两个问题:第一个是我错误地假设一个块的大小是 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
于 2012-08-22T06:01:51.047 回答
2

AES 使用 16 字节的块大小(不是您建议的 8 的两倍)。此外,如果启用了填充,它应该总是填充。这样做的原因是,否则 unpadding 算法无法区分填充和明文的最后一个字节。

大多数时候,您不应该期望密文与纯文本大小相同。确保doFinal()始终调用它。如果您正在实施自己的加密方案,则应仅以这种方式使用 update 进行加密/解密。

于 2012-08-22T07:28:58.563 回答
0

连续多次调用更新存在node.js 问题。我想它已经解决并反映在下一个版本中。

于 2012-08-23T08:01:10.923 回答