Question

So, I found a question just like this with an accepted answer, so I hopped off and tried to implement the necessary changes. For some reason though, I am still getting two different strings, and I don't know what it is I'm doing wrong. I tried to comment on the accepted answer to find help, but I lack the reputation to do so. So, I figured I'd ask the question again (that question was 2 years old, too).

Let me explain what I'm doing.

In php...

$intermediatesalt = md5(uniqid(rand(), true));
$salt = substr($intermediatesalt, 0, 8);
$hashpassword = base64_encode(
hash('sha256', $salt . hash('sha256', $password), true)
);

The line that says $hashpassword was taken from the accepted answer from this question. I didn't write any of this php, my friend did. I only know enough about programming to alter the code, but I couldn't create anything in php, let alone HTML.

After the hash has been created, both the hash and the salt are stored on a database.

The C# method I'm using is also from the answer I found here.

    public static string ComputeHash(string plainText, string salt)
    {
        // Convert plain text into a byte array.
        byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
        byte[] saltBytes = Encoding.UTF8.GetBytes(salt);

        SHA256Managed hash = new SHA256Managed();

        // Compute hash value of salt.
        byte[] plainHash = hash.ComputeHash(plainTextBytes);

        byte[] concat = new byte[plainHash.Length + saltBytes.Length];

        System.Buffer.BlockCopy(saltBytes, 0, concat, 0, saltBytes.Length);
        System.Buffer.BlockCopy(plainHash, 0, concat, saltBytes.Length, plainHash.Length);

        byte[] tHashBytes = hash.ComputeHash(concat);

        // Convert result into a base64-encoded string.
        string hashValue = Convert.ToBase64String(tHashBytes);

        // Return the result.
        return hashValue;
    }

But for some bizarre reason, even though the person who asked the question got what s/he wanted, I am still getting an undesired result.

This is the block of code that loads player data then compares the the php generated hashed password with the c# generated hashed password.

        // load the player based on the given email
        PlayerStructure.Player newPlayer = MySQL.loadPlayer(email);

        // compute a hash based on the given password and the retrieved salt
        // then, compare it to the hashed password on the database
        string hPassword = Program.ComputeHash(password, newPlayer.salt);

        if (newPlayer.password != hPassword)
        {
            sendStatusMsg(index, "Invalid password.");
            sendStatusMsg(index, "1: " + hPassword);
            sendStatusMsg(index, "2: " + newPlayer.password);

            return;
        }

MySQL.loadPlayer loads the hash string and the salt string from the database, and I had to use those sendStatusMessage methods to print strings as this is for a server application that takes up to 15 minutes to load data from the database in debug mode. So I run the debug exe instead, ergo no Console.WriteLine calls. newPlayer.password is the hashed password stored on the database (the password created with php). hPassword is the computed hash using the C# method I borrowed.

The salt is e0071fa9 and the plain-text password is 'test'.

This is the result I get with the sendStatusMsg methods:

Invalid password.
1: 3QQyVEfmBN4kJJHsRQ307TCDYxNMpc4k3r3udBaVz8Y=
2: moHRVv9C0JvpdTk28xGm3uvPPuhatK2rAHXd5he4ZJI=

Any ideas as to what I might be doing incorrectly? As I've stated before, I literally just used the answer on here (borrowing the code almost verbatim) and I'm still not getting my desired result. This is the question I referenced: Why isn't my PHP SHA256 hash equivalent to C# SHA256Managed hash

Was it helpful?

Solution

Because as the answer to question you are linking to says, hash returns a hex-encoded string instead of raw bytes by default. You are passing true as the third parameter to override this behavior for the outer call to hash, but you are not doing the same for the inner call.

In fact why are there two hashes in the first place? The inner hash doesn't seem to serve any purpose at all.

OTHER TIPS

As Jon stated earlier, the php was slightly flawed. If anyone else is attempting to do something like this, know that

$hashpassword = base64_encode(
hash('sha256', $salt . hash('sha256', $password), true)
);

as opposed to

$hashpassword = base64_encode(
hash('sha256', $salt . hash('sha256', $password, true), true)
);

makes a HUGE difference. The second line of php is what did the trick.

I hope this helps!

Please on PHP avoid using your own hashing mechanism, unless you are a security / crypto expert and (more important, know what you are doing).

Have a good look on how password_hash works in PHP (and if using a PHP version that doesn't support it - please upgrade it), you can always use Anthony Ferrara compatibility library for good effect:

https://github.com/ircmaxell/password_compat

If you follow his blog, you will get some hints about the issues at stake:

http://blog.ircmaxell.com/search/label/Security

:)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top