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
相关产品推荐
相关产品推荐

