我正在将 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# 设置或默认设置不兼容,或者我没有正确配置它们。这就是我需要您的建议的地方。 一些假设
aes-128-cbc
aes-256-cbc
算法的 32 字节/256 位密钥。C# Rijndael 算法默认使用 PKCS7 填充,crypto.createCipheriv
cipher.setAutoPadding(true)nodejs 方法中的 key 和 iv 正在创建与 C# 等效的值
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 个字符不匹配。我更喜欢使用内置的加密包来创建相同的哈希值。是否可以?你能发现我的错误吗?预先感谢。