C#转Node.js:SHA256+PBKDF2+AES-256-CBC加密迁移遇阻求助
C#加密代码迁移至Node.js失败的问题定位与解决
问题描述
需将实现SHA256哈希、PBKDF2密钥派生及AES-256-CBC加密的C#代码迁移至Node.js环境,尝试多种方案、查阅文档后仍未成功,推测编码环节存在问题但无法准确定位。
C#原实现代码
using System; using System.Text; using System.IO; using System.Security.Cryptography; public class HelloWorld { public static void Main(string[] args) { HelloWorld h1 = new HelloWorld(); Console.WriteLine(h1.EncryptText("Vitthal", "Vitthal")); } public string EncryptText(string pInput, string password) { byte[] bytesToBeEncrypted = Encoding.UTF8.GetBytes(GenerateSHA256String(pInput)); byte[] passwordBytes = Encoding.UTF8.GetBytes(password); passwordBytes = SHA256.Create().ComputeHash(passwordBytes); byte[] bytesEncrypted = AES_Encrypt(bytesToBeEncrypted, passwordBytes); string result = Convert.ToBase64String(bytesEncrypted); return result; } public string GenerateSHA256String(string inputString) { StringBuilder stringBuilder = new StringBuilder(); try { SHA256 sha256 = SHA256Managed.Create(); byte[] bytes = Encoding.UTF8.GetBytes(inputString); byte[] hash = sha256.ComputeHash(bytes); for (int i = 0; i <= hash.Length - 1; i++) stringBuilder.Append(hash[i].ToString("X2")); return stringBuilder.ToString(); } catch (Exception ex) { } return stringBuilder.ToString(); } private byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes) { byte[] encryptedBytes = null; byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; using (MemoryStream ms = new MemoryStream()) { using (RijndaelManaged AES = new RijndaelManaged()) { AES.KeySize = 256; AES.BlockSize = 128; var key = new System.Security.Cryptography.Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000); AES.Key = key.GetBytes(AES.KeySize / 8); AES.IV = key.GetBytes(AES.BlockSize / 8); AES.Mode = CipherMode.CBC; using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write)) { cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length); cs.Close(); } encryptedBytes = ms.ToArray(); } } return encryptedBytes; } }
原Node.js尝试代码
const GenerateSHA256String = (object) => { const buff = Buffer.from(object.toString()); const hash = createHash('sha256'); hash.update(buff); const hashed = hash.digest('hex'); return hashed; } const getEncryptedChecksum = (object) => { const payload = GenerateSHA256String(object); console.log(Buffer.from(payload)); const passKey = Buffer.from('Vitthal'); const saltString = [1,2,3,4,5,6,7,8]; const key = pbkdf2Sync(GenerateSHA256String(passKey), Buffer.from(saltString), 1000, 100, 'sha1'); const encKey = key.subarray(0, 32); const encIV = key.subarray(32, 48); const cipher = createCipheriv('aes-256-cbc', encKey, encIV); let encrypted = cipher.update(Buffer.from(payload), 'utf8', 'base64'); encrypted += cipher.final('base64'); return encrypted; } console.log(getEncryptedChecksum('Vitthal'));
错误点分析
- SHA256哈希大小写不一致:C#中
GenerateSHA256String返回大写十六进制字符串(ToString("X2")),但Node.js代码返回小写,导致后续加密的明文字节流不一致。 - PBKDF2输入错误:C#中直接传入SHA256哈希后的密码字节数组,而Node.js代码传入的是SHA256哈希的小写字符串,而非原始字节。
- PBKDF2输出长度冗余:C#中仅需32字节密钥+16字节IV共48字节,Node.js却请求100字节,多余字节无意义且可能导致截取错误。
- 加密编码处理差异:Node.js中
update方法直接指定base64输出,和C#先加密为字节再转Base64的流程不一致,可能引入编码误差。
修正后的Node.js代码
const { createHash, pbkdf2Sync, createCipheriv } = require('crypto'); const GenerateSHA256String = (input) => { const buff = Buffer.from(input.toString(), 'utf8'); const hash = createHash('sha256'); hash.update(buff); // 生成大写十六进制字符串,与C#逻辑对齐 return hash.digest('hex').toUpperCase(); } const getEncryptedChecksum = (input, password) => { const payload = GenerateSHA256String(input); // 对密码做SHA256哈希,直接取字节数组,对齐C#逻辑 const passwordHash = createHash('sha256').update(Buffer.from(password, 'utf8')).digest(); const salt = Buffer.from([1,2,3,4,5,6,7,8]); // PBKDF2生成32字节密钥+16字节IV,共48字节 const keyMaterial = pbkdf2Sync(passwordHash, salt, 1000, 48, 'sha1'); const encKey = keyMaterial.subarray(0, 32); const encIV = keyMaterial.subarray(32, 48); const cipher = createCipheriv('aes-256-cbc', encKey, encIV); // 先加密为字节数组,再统一转Base64,对齐C#流程 let encryptedBytes = cipher.update(Buffer.from(payload, 'utf8')); encryptedBytes = Buffer.concat([encryptedBytes, cipher.final()]); return encryptedBytes.toString('base64'); } // 测试输入与C#一致 console.log(getEncryptedChecksum('Vitthal', 'Vitthal'));
内容的提问来源于stack exchange,提问作者Vitthal Kulkarni
相关产品推荐
相关产品推荐

