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); } }
关键修改点说明
- 字节级拼接:使用
Buffer.BlockCopy和Encoding.UTF8.GetBytes直接合并字节数组,完全复刻PHP的$digest . $salted行为。 - 修正循环次数:你的原C#代码循环条件是
i < 1(只执行0次循环),改为i < 5000后,会执行4999次循环,和PHP逻辑完全匹配。 - 优化哈希函数:重载哈希函数直接接收字节数组,避免不必要的字符串转换;同时使用
using语句确保SHA512实例被正确释放,符合C#的内存管理规范。
内容的提问来源于stack exchange,提问作者Grimm
相关产品推荐
相关产品推荐

