C#Rfc2898DeriveBytes到节点

时间:2019-05-09 06:24:12

标签: c# node.js node-crypto

我正在使用Node重写一种加密算法(在C#中实现)。加密使用32字节密钥和16字节IV,并使用Rfc2898DeriveBytes生成密钥和IV。我使用crypto.pbkdf2Sync来生成48个字节的密钥,而不是32个密钥。前32位将是密钥,其余的位将用作IV,如下所示:

const crypto = require( "crypto");

const secret = 'e23d5bb0-2349-289a-d932-abc5a238a873';
const salt = '1bca26a8-49b8-6ad0-b65c-206a96107702';
const algorithm = 'aes-256-xts';
const keyAndIv = crypto.pbkdf2Sync(Buffer.from(secret, "binary"),
  Buffer.from(salt, "binary"),
  1024,
  48,
  'sha1');
const key = keyAndIv.slice(0, 32);
const iv = keyAndIv.slice(32, 48);

const cipher = crypto.createCipheriv(algorithm, key, iv);

let encrypted = cipher.update('test', 'utf8', 'hex');
encrypted += cipher.final('hex');
console.log(encrypted);

这将引发以下错误:

Error: Invalid key length
    at Cipheriv.createCipherBase (internal/crypto/cipher.js:78:18)
    at Cipheriv.createCipherWithIV (internal/crypto/cipher.js:122:20)
    at new Cipheriv (internal/crypto/cipher.js:231:22)
    at Object.createCipheriv (crypto.js:105:10)

任何想法都是真的。

2 个答案:

答案 0 :(得分:1)

观察到的行为的原因是所使用的模式AES-256-XTS。

AES-XTS从传递的密钥中生成两个密钥,可以作为AES-256-XTS和AES-128-XTS使用。 AES-256-XTS期望使用64个字节的密钥并从这两个32字节密钥生成,AES-128-XTS期望使用32字节的密钥并生成两个16字节密钥。

代替填充ciphertext stealing。因此,明文和密文具有相同的长度。另外,明文的大小必须至少为一个块(= 16字节)。可以在herehere中找到有关AES-XTS的更多详细信息。

在C#代码中使用32字节的密钥代表使用AES-128-XTS,而不是AES-256-XTS,为此需要64字节的密钥。如果代码中的算法从AES-256-XTS更改为AES-128-XTS,该错误将不再发生。

例如对于发布的输入数据,纯文本

The quick brown fox jumped over the lazy dog

在以下密文中使用AES-128-XTS加密

b70d9f10ea6c1db513e141290059a73ab7c454e7d0a24fe482c9a6023a783303fe8bcc41bec1734d85af84ba

密钥和IV生成没有问题。

带有pbkdf2Sync的NodeJS方法digest = 'SHA1'是C#方法Rfc2898DeriveBytes的对应方法。两者都用HMACSHA1实现PBKDF2,因此对于相同的输入数据返回相同的结果。例如。输入的输入数据:

secret:          e23d5bb0-2349-289a-d932-abc5a238a873
salt:            1bca26a8-49b8-6ad0-b65c-206a96107702
iteration count: 1024
key size:        48

将生成以下字节序列:

BE00676F6A3D57EE66FF618FDE5BB15C0E1FC9ECDE5CE949BC784D14ACB7963B49FA9319394A69024A1F359BCC23C703

答案 1 :(得分:0)

以下代码适用于大多数密码:

const crypto = require( "crypto");
const base64url = require('base64url');

const secret = 'secret';
const salt = 'add some salt';

const plainText = 'test';
const algorithm = 'aes-256-ctr';

const derivedBytes = crypto.pbkdf2Sync(Buffer.from(secret), Buffer.from(salt), 1024, 48, 'sha1');

const key = derivedBytes.slice(0, 32);
const iv = derivedBytes.slice(32, 48);

const cipher = crypto.createCipheriv(algorithm, key, iv);
const output = Buffer.concat([cipher.update(plainText, 'utf8'), cipher.final()]);

console.log(output.toString('hex'));
console.log(base64url(output));

详细的博客:https://www.devinstincts.com/2019/05/15/rewrite-c-encryption-using-node-crypto/