我正在使用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)
任何想法都是真的。
答案 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字节)。可以在here和here中找到有关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/