使用 crypto 模块将旧版 C# Rijndael 加密算法移植到 Nodejs

问题描述 投票:0回答:0

我正在将 C# .NET 4.8 Framework 代码库迁移到云。新架构使用nodejs firebase功能。这些函数只允许使用nodejs代码。

以下代码用于使用数据库中存储的哈希值验证输入文本密码。该应用程序正在迁移到 SSO 解决方案,但将允许用户通过验证其先前的凭据来从其旧帐户中获取数据。

以下代码使用 RFC2898(现在称为 PBKDF2)生成密钥和初始化向量,并将它们提供给 Rijndael 对象以设置加密。

此方法出于某种原因将密码与盐结合在一起,大概是为了增加密码的长度。盐始终为 36 个字符。然后,它会在通常放盐的地方使用胡椒粉。最后,加密值以 Base64 字符串的形式输出。

using System.Security.Cryptography;
using System.Text;

var password = "password123";
var salt = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
var pepper = "yyyyyyyy";

var enc = new UTF8Encoding();
var keyGen = new Rfc2898DeriveBytes(password + salt, enc.GetBytes(pepper));

var key = keyGen.GetBytes(32);
var iv = keyGen.GetBytes(16);

var cipher = new RijndaelManaged
{
  Key = key,
  IV = iv
};

Console.WriteLine("Key: " + Convert.ToBase64String(key));
Console.WriteLine("IV: " + Convert.ToBase64String(iv));

var plainText = enc.GetBytes(password + salt);
using var encryptor = cipher.CreateEncryptor();
using var ms = new MemoryStream();
using var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write);

cs.Write(plainText, 0, plainText.Length);
cs.FlushFinalBlock();

Console.WriteLine("Hash: " + Convert.ToBase64String(ms.ToArray()));

使用nodejs 18和crypto包,我可以使用以下代码创建与上面的C#代码相同的密钥和iv。

const generatePbkdf2Values = (password, pepper) => {
  const pepperBytes = Buffer.from(pepper, 'utf8');

  const iterations = 1000;
  const length = 32 + 16;
  const digest = 'sha1';
  const keyPlusIv = crypto.pbkdf2Sync(
    password,
    pepperBytes,
    iterations,
    length,
    digest
  );

  return {
    key: keyPlusIv.subarray(0, 32),
    iv: keyPlusIv.subarray(32, length),
  };
};

我读到 Rijndael 是具有固定块大小的 AES 变体。因此,我希望能够使用 crypto 的包 createCipheriv 方法来加密文本,但我很难做到这一点。我担心 C# 设置或默认设置不兼容,或者我没有正确配置它们。这就是我需要您的建议的地方。 一些假设

IV 是 16 字节/128 位密钥,需要
    aes-128-cbc
  1. 算法。但 128 算法会引发密钥长度错误,因此它必须基于需要
    aes-256-cbc
    算法的 32 字节/256 位密钥。
    C# Rijndael 算法默认使用 PKCS7 填充,
  2. crypto.createCipheriv
  3. 通过
    cipher.setAutoPadding(true)
    nodejs 方法中的 key 和 iv 正在创建与 C# 等效的值
  4. 以下是我用来散列文本的nodejs。
key

iv
password
salt
来自上面的片段。
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);

const passwordAndSalt = Buffer.from(password + salt, 'utf8');
const encoding = 'hex';
const inputEncoding = encoding;
const outputEncoding = encoding

let result = cipher.update(passwordAndSalt, inputEncoding, outputEncoding);
result += cipher.final(outputEncoding);

console.log(result.toString('base64'));

这提供了一个比 C# 解决方案多 32 个字符的字符串,并且不共享任何模式。

具有上述值的正确哈希是

DC07eaMXkaeK26KTIt3ldtzTdISTH5j9cmrg3OzFF16MvfKkEi9ihEkI8VDLzNvU

作为 B 计划,我尝试使用 

rinjndael-js

npm 包。使用上面相同的密钥和 iv,以下代码生成几乎正确的哈希值,但不完全正确。 import Rijndael from 'rijndael-js'; const { key, iv } = createKeyGen(password + salt, pepper); const cipher = new Rijndael(key, 'cbc'); const text = Buffer.from(password + salt, 'utf8'); return Buffer.from(cipher.encrypt(text, 16, iv)).toString('base64')

这会产生一个长度相同且 68% 等价的哈希值。前 43 个字符匹配,后 21 个字符不匹配。我更喜欢使用内置的加密包来创建相同的哈希值。是否可以?你能发现我的错误吗?预先感谢。

c# node.js encryption cryptography rijndael
© www.soinside.com 2019 - 2024. All rights reserved.