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

PHP二进制与字符串拼接转C#:密码哈希实现问题求助

解决PHP到C#密码哈希转换的二进制拼接问题

我明白你遇到的问题了——PHP里hash函数返回的二进制$digest和字符串$salted拼接是字节层面的直接拼接,但你在C#里把二进制转成UTF8字符串再拼接,这会因为二进制哈希结果可能包含UTF8无法正确解析的字节(比如不可打印字符、无效UTF8序列),导致转换后的字符串和原始字节序列不一致,最终哈希结果和PHP完全对不上。

问题核心对比

  • PHP中:$digest . $salted是将$digest的二进制字节序列,直接与$salted的字节序列(PHP字符串本质是字节流)拼接,完全不涉及编码转换。
  • 你的C#代码中:System.Text.Encoding.UTF8.GetString(digest)会尝试将二进制哈希结果解析为UTF8字符串,遇到无效字节时会替换成�,这直接修改了原始数据,导致后续哈希错误。

正确的C#实现代码

要解决这个问题,我们需要直接操作字节数组,跳过字符串转换步骤,完全复刻PHP的字节级拼接逻辑:

void Main() 
{
    string password = "abc";
    string salt = "def";
    string salted = string.Format("{0}{{{1}}}", password, salt);
    
    // 第一次哈希:将salted字符串转字节数组后哈希
    byte[] digest = Hash(Encoding.UTF8.GetBytes(salted));
    
    // 循环4999次(和PHP的for ($i=1; $i<5000; $i++) 次数一致)
    for(int i = 1; i < 5000; i++) 
    {
        // 拼接:上一次的哈希字节数组 + salted的UTF8字节数组
        byte[] combined = new byte[digest.Length + Encoding.UTF8.GetByteCount(salted)];
        Buffer.BlockCopy(digest, 0, combined, 0, digest.Length);
        Encoding.UTF8.GetBytes(salted, 0, salted.Length, combined, digest.Length);
        
        // 哈希拼接后的字节数组
        digest = Hash(combined);
    }
    
    var encodedPassword = Convert.ToBase64String(digest);
    // 此时encodedPassword会和PHP生成的结果完全一致
}

static byte[] Hash(byte[] inputBytes) 
{
    using (SHA512 sha512 = SHA512.Create())
    {
        return sha512.ComputeHash(inputBytes);
    }
}

关键修改点说明

  1. 字节级拼接:使用Buffer.BlockCopy和Encoding.UTF8.GetBytes直接合并字节数组,完全复刻PHP的$digest . $salted行为。
  2. 修正循环次数:你的原C#代码循环条件是i < 1(只执行0次循环),改为i < 5000后,会执行4999次循环,和PHP逻辑完全匹配。
  3. 优化哈希函数:重载哈希函数直接接收字节数组,避免不必要的字符串转换;同时使用using语句确保SHA512实例被正确释放,符合C#的内存管理规范。

内容的提问来源于stack exchange,提问作者Grimm

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:43:04