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

PHP转C#:PBKDF2密码哈希验证失败求助

PHP PBKDF2迁移至C#.NET的密码验证问题

我正在将PHP代码迁移至C#.NET,其中一项任务是实现密码哈希功能。PHP使用的是defuse.ca提供的PBKDF2 For PHP实现,我已编写了C#版本的哈希代码,但无法验证现有密码,希望排查问题所在。

PHP代码

function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
{
    $algorithm = strtolower($algorithm);
    if(!in_array($algorithm, hash_algos(), true))
        trigger_error('PBKDF2 ERROR: Invalid hash algorithm.', E_USER_ERROR);
    if($count <= 0 || $key_length <= 0)
        trigger_error('PBKDF2 ERROR: Invalid parameters.', E_USER_ERROR);

    if (function_exists("hash_pbkdf2")) {
        // The output length is in NIBBLES (4-bits) if $raw_output is false!
        if (!$raw_output) {
            $key_length = $key_length * 2;
        }
        return hash_pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output);
    }

    $hash_length = strlen(hash($algorithm, "", true));
    $block_count = ceil($key_length / $hash_length);

    $output = "";
    for($i = 1; $i <= $block_count; $i++) {
        // $i encoded as 4 bytes, big endian.
        $last = $salt . pack("N", $i);
        // first iteration
        $last = $xorsum = hash_hmac($algorithm, $last, $password, true);
        // perform the other $count - 1 iterations
        for ($j = 1; $j < $count; $j++) {
            $xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
        }
        $output .= $xorsum;
    }

    if($raw_output)
        return substr($output, 0, $key_length);
    else
        return bin2hex(substr($output, 0, $key_length));
}

C#实现代码(第一种)

public static string ComputePBKDF2(string algorithm, string password, byte[] salt, int count, int keyLength, bool rawOutput = false)
{
    algorithm = algorithm.ToLower();

    if (count <= 0 || keyLength <= 0)
        throw new ArgumentException("Invalid parameters.");

    if (CryptoConfig.AllowOnlyFipsAlgorithms && !algorithm.StartsWith("hmac", StringComparison.OrdinalIgnoreCase))
        algorithm = "hmacsha256"; // Default to HMAC-SHA-256 for FIPS compliance

    using (Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(password, salt, count))
    {
        byte[] derivedKey = pbkdf2.GetBytes(keyLength);

        if (rawOutput)
        {
            return Convert.ToBase64String(derivedKey);
        }
        else
        {
            return BitConverter.ToString(derivedKey).Replace("-", "").ToLower();
        }
    }
}

C#实现代码(第二种)

public static byte[] ComputePBKDF2(string algorithm, string password, byte[] salt, int count, int keyLength)
{
    using (SHA256 hmac = SHA256.Create(algorithm))
    {
        int hashLength = (hmac.HashSize + 7) / 8; // Length of the hash in bytes
        int blockCount = (int)Math.Ceiling((double)keyLength / hashLength);

        byte[] output = new byte[keyLength];
        byte[] last = salt;

        for (int i = 0; i < blockCount; i++)
        {
            byte[] iter = BitConverter.GetBytes(i + 1); // $i encoded as 4 bytes, big endian
            Array.Reverse(iter); // Convert to big-endian

            byte[] xorSum = hmac.ComputeHash(last);
            last = xorSum;

            for (int j = 1; j < count; j++)
            {
                byte[] iterHmac = hmac.ComputeHash(last);
                last = iterHmac;

                for (int k = 0; k < xorSum.Length; k++)
                {
                    xorSum[k] ^= iterHmac[k];
                }
            }

            Array.Copy(xorSum, 0, output, i * hashLength, Math.Min(hashLength, keyLength - i * hashLength));
        }

        return output;
    }
}

验证代码

调用示例

VerifyPassword("Nouman@2023!", "sha256:1000:DlrSWdE5PFiP7MiMPUD98rwYobnDp56+:dDh1pxHduY9iw5uGFowNWncNfhPXWGDB")

验证方法

public static bool VerifyPassword(string password, string correctHash)
{
    int HASH_SECTIONS = 4;
    int HASH_ALGORITHM_INDEX = 0;
    int HASH_ITERATION_INDEX = 1;
    int HASH_SALT_INDEX = 2;
    int HASH_PBKDF2_INDEX = 3;
    string[] hassSplit = correctHash.Split(':');

    if (hassSplit.Length < HASH_SECTIONS)
        return false;

    byte[] pbkdf2 = Convert.FromBase64String(hassSplit[HASH_PBKDF2_INDEX]);
    byte[] salt = new byte[24];
    salt = Convert.FromBase64String(hassSplit[HASH_SALT_INDEX]);

    string result = ComputePBKDF2(hassSplit[HASH_ALGORITHM_INDEX], password, salt, int.Parse(hassSplit[HASH_ITERATION_INDEX]), pbkdf2.Length, true);
    Console.WriteLine(result);
    byte[] computedHash = Convert.FromBase64String(result);
    
    return slowEquals(pbkdf2, computedHash);
    
}

private static bool slowEquals(byte[] a, byte[] b)
{
    uint diff = (uint)a.Length ^ (uint)b.Length;
    for (int i = 0; i < a.Length && i < b.Length; i++)
    {
        diff |= (uint)(a[i] ^ b[i]);
    }
    return diff == 0;
}

两种C#实现均无法完成密码验证,恳请协助排查问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 10:24:53