Having read around on this issue on these posts (to name but two)...
Encrypting / Decrypting in vb.net does not always return the same value
C# PasswordDeriveBytes Confusion
...I was wondering if anyone knew the method that Microsoft use to key stretch their output?
To integrate with a system written in C# by someone else, I need to generate a large hash in PHP. The code that generates their SHA1 hash generates a 32 byte output, rather than the standard 20 byte SHA1 output. So has anyone cracked how Microsoft fill up the remaining 12 bytes? I've tried lots of combinations of appending the a SHA1 of the salt, password etc. as well as appending on previous iterations, but nothing seems to produce Microsoft's output.
I'm slightly concerned by this comment on https://stackoverflow.com/a/13482133/4346051...
"PasswordDeriveBytes uses an unknown, proprietary, non-deterministic, broken, cryptographically insecure method of key stretching for PasswordDeriveBytes"
Sample code as follows...
The C# code I need to replicate in PHP in order to produce the correct hash for integration with third party software:
string sPassword = "iudF98yfh9aRfhanifakdfn0a4ut-a8J789jasdpasd=";
string sSalt = "lYU7m+MDCvVWVQyuLIX3og==";
int iLength = 256 / 8;
byte[] saltInBytes = Encoding.ASCII.GetBytes(sSalt);
PasswordDeriveBytes password = new PasswordDeriveBytes(sPassword, saltInBytes, "SHA1", 2);
byte[] keyBytes = password.GetBytes(iLength);
Console.WriteLine("\nkeyBytes = \n");
foreach (byte value in keyBytes)
{
Console.WriteLine(value);
}
...which outputs...
0
176
172
127
35
113
212
85
123
19
71
65
23
127
84
165
163
225
80
207
67
125
128
205
188
248
103
52
23
245
111
20
My PHP code for the same functionality is...
$sPassword = "iudF98yfh9aRfhanifakdfn0a4ut-a8J789jasdpasd=";
$sSalt = "lYU7m+MDCvVWVQyuLIX3og==";
$iIterations = 2;
$iLength = 256 / 8;
// combine password with salt
$key = $sPassword.$sSalt;
// perform sha1 how ever many times, using raw binary output instead of hex
for($i = 1; $i <= $iIterations; $i++) {
$key = sha1($key, true);
}
// get the iLength number of chars
$key = substr($key, 0, $iLength);
$aKeyBytes = unpack('C*', $key);
print_r($aKeyBytes);
...and this outputs...
Array
(
[1] => 0
[2] => 176
[3] => 172
[4] => 127
[5] => 35
[6] => 113
[7] => 212
[8] => 85
[9] => 123
[10] => 19
[11] => 71
[12] => 65
[13] => 23
[14] => 127
[15] => 84
[16] => 165
[17] => 163
[18] => 225
[19] => 80
[20] => 207
)
...but as you can see, we're 12 "bytes" short.
Unfortunately, it has to be replicated - I can't amend the C# to use a better method - I have no control over that side - my PHP code has to generate it