将C# SSO哈希逻辑迁移至PHP的技术验证问询
Great question—let's walk through your PHP code step by step and cross-reference it with how a typical C# PBKDF2-based SSO authentication flow would work. There are a few key details to validate here, since mismatches in encoding or parameter handling are the most common causes of hash inconsistencies between languages.
Key Points to Validate & Potential Fixes
Let’s break down each part of your code and compare it to standard C# practices:
1. Salt Extraction & Handling
Your code extracts the salt with:
$salt = base64_decode(substr($token, 0, -1));
- Check: Make sure the C# system actually appends an extra character to the salt's Base64 string when generating the token. If not,
substr($token, 0, -1)will truncate one valid byte from the salt, which will break the hash entirely. - Critical Note: In your original code, you convert the decoded salt bytes to UTF-16LE with
mb_convert_encoding($salt, 'UTF-16LE'). Unless the C# code explicitly takes the salt string, converts it to UTF-16LE bytes, and then uses that as the PBKDF2 salt, this step is unnecessary (and incorrect).
In most C# implementations, the salt is passed directly as a raw byte array (from Base64 decoding), so you should use the decoded bytes directly without encoding conversion.
2. ID + SSO Key Encoding
You combine the ID and key with:
$idAndKey = $id . $ssokey;
- Check: How does the C# code convert this combined string to bytes? This is the most frequent source of mismatch:
- If C# uses
Encoding.UTF8.GetBytes(id + ssokey), your PHP code is fine (since PHP strings default to UTF-8 in most environments). - If C# uses
Encoding.Unicode.GetBytes(id + ssokey)(which is UTF-16LE), you need to convert the combined string in PHP to UTF-16LE bytes before passing it tohash_pbkdf2:$idAndKeyBytes = mb_convert_encoding($id . $ssokey, 'UTF-16LE');
- If C# uses
3. PBKDF2 Parameter Matching
Your hash_pbkdf2 call uses:
- Algorithm:
sha256→ Matches C#'sRfc2898DeriveByteswithHashAlgorithmName.SHA256(available in .NET Core 2.0+ / .NET Framework 4.7.2+). - Iterations:
1000→ Ensure this matches the iteration count used in the C# code exactly. - Output length:
24→ Matches C#'spbkdf2.GetBytes(24). - Raw output (
false) → Correct, since you're Base64 encoding the result afterward (matches C#'sConvert.ToBase64String(hashedBytes)).
Corrected PHP Implementation Examples
Scenario 1: C# Uses UTF-8 for ID+Key & Raw Salt Bytes
This is the most common setup:
$token = "MqsXexqpYRUNAHR_lHkPRic1g1BYhH6bFNVPagEkuaL8Mf80l_tOirhThQYIbfWYErgu4bDwl-7brVhXTWnJNQ2"; $id = "bob@company.com"; $ssokey = "7MpszrQpO95p7H"; // Combine ID and key (UTF-8 matching C#'s Encoding.UTF8) $idAndKey = $id . $ssokey; // Extract salt (remove trailing char only if C# adds it) $salt = base64_decode(substr($token, 0, -1)); // Run PBKDF2 with correct parameters $hashed = hash_pbkdf2("sha256", $idAndKey, $salt, 1000, 24, false); $data = base64_encode($hashed);
Scenario 2: C# Uses UTF-16LE for ID+Key
If C# uses Encoding.Unicode for the combined string:
$token = "MqsXexqpYRUNAHR_lHkPRic1g1BYhH6bFNVPagEkuaL8Mf80l_tOirhThQYIbfWYErgu4bDwl-7brVhXTWnJNQ2"; $id = "bob@company.com"; $ssokey = "7MpszrQpO95p7H"; // Combine and convert to UTF-16LE (matches C#'s Encoding.Unicode) $idAndKeyBytes = mb_convert_encoding($id . $ssokey, 'UTF-16LE'); // Extract salt $salt = base64_decode(substr($token, 0, -1)); // Run PBKDF2 $hashed = hash_pbkdf2("sha256", $idAndKeyBytes, $salt, 1000, 24, false); $data = base64_encode($hashed);
How to Verify for Certain
The best way to confirm correctness is to run a test with known values:
- Pick a fixed ID, SSOKey, and salt (use a short, test salt instead of extracting from the token).
- Generate the hash in C# using the exact logic from your SSO system.
- Run the corresponding PHP code with the same inputs and compare the Base64-encoded results.
If they match, your implementation is correct.
内容的提问来源于stack exchange,提问作者jacobdubail

