I am working on a new PHP project that uses an exist database created for ASP.NET. I can't reach the ASP source code, so I don't know how the passwords are hashed.
All I need is a way to compare users logins from PHP to the stored password in database, so already existing users (and new ASP script registers) don't have to create two passwords for both scripts.
I know they've been hashed in sha1/base64 form, but researches led me to realize that ASP.NET uses either SqlMembershipProvider or membershipprovider that generates SALT, which is my problem I guess.
I need a way to make PHP verify the ASP hashed password.
UPDATE 1:
This is a hashed password from the database, for a test user:
AHmLnE/qf1Jb9ABf6uIHEomuQCN8e0Xt8Bpl8Ty4fzdicsnut6nK/Rv/ZlfJDOK9Pg==
the password is 1234
UPDATE 2:
after trying @DeadSpace 's answer below, I ended up with this (not working):
<?php
include "SymmetricEncryption.php";
$hash = "AHmLnE/qf1Jb9ABf6uIHEomuQCN8e0Xt8Bpl8Ty4fzdicsnut6nK/Rv/ZlfJDOK9Pg=="; // password is : 1234
echo "Hashed: ". $hash . "<br>";
$salt = substr(base64_decode($hash), 0, 16);
//$salt = substr(base64_decode($hash), 1, 16); // C# = Buffer.BlockCopy(src, 1, dst, 0, 16);
$hasher = new SymmetricEncryption();
echo "Class test: ". base64_encode($salt. $hasher->encrypt('', '1234', $salt) ) . "<br>";
/***** another faield approach *****/
//Not working either :(
echo "another way: ". base64_encode($salt. pbkdf2('SHA1', '1234', $salt, 1000, 32, true)) ;
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 = 0; $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));
}
Output:
Hashed: AHmLnE/qf1Jb9ABf6uIHEomuQCN8e0Xt8Bpl8Ty4fzdicsnut6nK/Rv/ZlfJDOK9Pg==
Class test: AHmLnE/qf1Jb9ABf6uIHEmNZcjhUOFMxREhQOGQrTFMzb0VpL2c9PQ==
another way: AHmLnE/qf1Jb9ABf6uIHEp3Abm4NCdtNaQ/iXjxShfVK9SDoAiCfYJ7Pbz0UUnDZ
Well,
None of the pbkdf2 functions around the world work for me, I always get the wrong hash. Rfc2898DeriveBytes results in php are different than asp/c#.
So I thought, "The shortest distance between two points is a straight line".
I ended up creating CLI in c# that accepts arguments and uses VerifyHashedPassword(string, string) function from PasswordHasher Class, then execute it in php with exec("some.exe $thehash $password", $output)
function, and grab the $output.
This way works like a charm, since I'm running php in windows.