如何在Node.js中加密?

How to encrypt in Node.js?

我正在尝试使用 'des-cbc' 算法在 Node.js 7.5.0 中执行加密。根据RFC 1423,该算法需要一个 64 位加密密钥和一个 64 位初始化向量。

我正在尝试使用由 8 个 Latin-1 字符组成的密钥和 iv;然而,Node 说,"Error: Invalid IV length"。下面是一些示例代码:

let crypto = require('crypto');

let key = '\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8',
     iv = '\xb8\xb7\xb6\xb5\xb4\xb3\xb2\xb1';

let cipher = crypto.createCipheriv('des-cbc', Buffer.from(key), Buffer.from(iv));

如果我将 iv 更改为 8 个 ASCII 字符,那么 Node 会说,"Error: Invalid key length":

let crypto = require('crypto');

let key = '\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8',
     iv = 'abcdefgh';

let cipher = crypto.createCipheriv('des-cbc', Buffer.from(key), Buffer.from(iv));

但是如果key和iv都是8个ASCII字符,就可以了:

let crypto = require('crypto');

let key = 'hgfedcba',
     iv = 'abcdefgh';

let cipher = crypto.createCipheriv('des-cbc', Buffer.from(key), Buffer.from(iv));

为什么 key 和 iv 不能使用 Latin-1 字符?

解决方案

您应该使用

Buffer.from('\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8', 'binary')

甚至如 Maarten Bodewes 指出的那样更清洁

Buffer.from([0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8'])

您的 IV 也是如此。

原因

Buffer.from('\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8').length 结果为 16,这不是 DES 密钥的有效长度。 DES 期望 exactly 64 位或 8 字节作为密钥。这也是 DES 非常不安全的原因。密钥尺寸太小了。

上述缓冲区大小为 16 字节而不是 8 字节的原因是默认编码为 UTF-8。如果代码点大于 127(十进制)或 0x7F(十六进制),它将编码为至少两个字节而不是一个字节。密钥的每个代码点(字符)都大于 0x7F。因此,它们中的每一个都被编码为两个字节。

需要考虑的事情

现在不用DES了。它只提供56位的安全性。 AES 会好得多,因为它使用 128 位的最小密钥大小更安全。 DES 的最大密文大小也有实际限制。参见 Security comparison of 3DES and AES

IV 必须是不可预测的(读作:随机)。不要使用静态 IV,因为这会使密码具有确定性,因此在语义上不安全。观察密文的攻击者可以确定之前发送相同消息前缀的时间。 IV 不是秘密的,因此您可以将它与密文一起发送。通常,它只是简单地添加到密文中并在解密之前被切掉。

密钥应该与随机噪声无法区分。最好只是随机生成它并以编码形式在您的代码中使用它。

最好对您的密文进行身份验证,以便像 padding oracle attack are not possible. This can be done with authenticated modes like GCM or EAX, or with an encrypt-then-MAC 方案一样进行攻击。