You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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'));

错误点分析

  1. SHA256哈希大小写不一致:C#中GenerateSHA256String返回大写十六进制字符串(ToString("X2")),但Node.js代码返回小写,导致后续加密的明文字节流不一致。
  2. PBKDF2输入错误:C#中直接传入SHA256哈希后的密码字节数组,而Node.js代码传入的是SHA256哈希的小写字符串,而非原始字节。
  3. PBKDF2输出长度冗余:C#中仅需32字节密钥+16字节IV共48字节,Node.js却请求100字节,多余字节无意义且可能导致截取错误。
  4. 加密编码处理差异: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 11:10:34