Page 1 of 1

PHP MD5 to .NET C#

Posted: Sun Nov 29, 2009 6:53 am
by belcherman
Hi all,


I am in a project where I need to create a MD5 login that works like the PHP MD5 function. I have set this up and it seems to work but the results are not coming out the same. What I mean is the same login using the "PHP MD5" hashed password does not match the .NET hashed password. Both are taking a salt and the password and then creating the hash but the results are different for the same entered password.




Simple PHP CODE:

Code: Select all

 
function encryptString($string) {
    return  md5($string . PASSWORD_SALT);
}
 
PASSWORD_SALT is a defined constant with the value (without the quotes) = 'TheSalt'
$string is what is entered in the password field.






.NET CODE:
[csharp]     protected void Login_Click(object sender, EventArgs e)    {        string SaltValue = "thesalt"; //Salt value         string HashAlgorithm = "MD5"; //MD5        string PasswordtoHash = "hello123"; //Password typed in password textbox         // Convert SaltValue string to a UTF-8 encoded byte[] - PHP MD5 encodes in a different way?        byte[] SaltValueBytes = Encoding.UTF8.GetBytes(SaltValue);         Session["HashedPassword"] = ComputeHash(PasswordtoHash, HashAlgorithm, SaltValueBytes);         complete();     }     /// <summary>    /// Generates a hash for the given plain text value and returns a    /// base64-encoded result. This salt is stored at    /// the end of the hash value, so it can be used later for hash    /// verification.    /// </summary>    /// <param name="plainText">    /// Plaintext value to be hashed. The function does not check whether    /// this parameter is null.    /// </param>    /// <param name="hashAlgorithm">    /// Name of the hash algorithm. Allowed values are: "MD5", "SHA1",    /// "SHA256", "SHA384", and "SHA512" (if any other value is specified    /// MD5 hashing algorithm will be used). This value is case-insensitive.    /// </param>    /// <param name="saltBytes">    /// Salt bytes. This parameter can be null, in which case a random salt    /// value will be generated.    /// </param>    /// <returns>    /// Hash value formatted as a base64-encoded string.    /// </returns>    public static string ComputeHash(string plainText,                                     string hashAlgorithm,                                     byte[] saltBytes)    {         // Convert plain text into a byte array. Once again UTF8, is this the same encoding as PHP MD5?        byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);         // Allocate array, which will hold plain text and salt.        byte[] plainTextWithSaltBytes =                new byte[plainTextBytes.Length + saltBytes.Length];         // Copy plain text bytes into resulting array.        for (int i = 0; i < plainTextBytes.Length; i++)            plainTextWithSaltBytes = plainTextBytes;         // Append salt bytes to the resulting array.        for (int i = 0; i < saltBytes.Length; i++)            plainTextWithSaltBytes[plainTextBytes.Length + i] = saltBytes;         // Because we support multiple hashing algorithms, we must define        // hash object as a common (abstract) base class. We will specify the        // actual hashing algorithm class later during object creation.        HashAlgorithm hash;         // Make sure hashing algorithm name is specified.        if (hashAlgorithm == null)            hashAlgorithm = "";         // Initialize appropriate hashing algorithm class.        switch (hashAlgorithm.ToUpper())        {            case "SHA1":                hash = new SHA1Managed();                break;             case "SHA256":                hash = new SHA256Managed();                break;             case "SHA384":                hash = new SHA384Managed();                break;             case "SHA512":                hash = new SHA512Managed();                break;             default:                hash = new MD5CryptoServiceProvider();                break;        }         // Compute hash value of our plain text with appended salt.        byte[] hashBytes = hash.ComputeHash(plainTextWithSaltBytes);         // Create array which will hold hash and original salt bytes.        byte[] hashWithSaltBytes = new byte[hashBytes.Length +                                            saltBytes.Length];         // Copy hash bytes into resulting array.        for (int i = 0; i < hashBytes.Length; i++)            hashWithSaltBytes = hashBytes;         // Append salt bytes to the result.        for (int i = 0; i < saltBytes.Length; i++)            hashWithSaltBytes[hashBytes.Length + i] = saltBytes;         // Convert result into a base64-encoded string.        string hashValue = Convert.ToBase64String(hashWithSaltBytes);         // Return the result.        return hashValue;    }  [/csharp]






THE RESULTS:


XXXXXXXX TEXT VALUES TYPED IN FORM XXXXXXXX
Username typed in form = : example
Password typed in form = : hello123

XXXXXXXX SALT VALUE XXXXXXXX
Salt = : thesalt

XXXXXXXX PHP MD5 VALUES XXXXXXXX
Results after MD5 and salt are hashed via PHP
"5b1980b160ae19131ae1a68c76685d1b"

XXXXXXXX .NET MD5 VALUES XXXXXXXX
Results after MD5 and salt are hashed via .NET C#:
"WxmAsWCuGRMa4aaMdmhdG0EyZGluZ00yU0dTYWwydG9QYTJzd29yZHNNYWtlc29uZXdheUVuY3J5cHRlZEhhc2hlc01vcmVTZWN1cmU="



As you can see the password and salt are identical but the results do not match. The .NET result is about 3 times longer than the PHP result. I am not sure why this is happening.

I also read this post dated April 2008 that in order to get .NET to match an MD5 with the PHP md5 function you need to use a UTF7 encoding.
See http://ok-cool.com/posts/read/125-php-m ... s-net-md5/ for more details. Some on that post say UT7 isn't the best way to go and some say it is. Other sites say it has nothing to do with encoding at all; this gets confusing.

I am not sure if this is a encoding issue or not. But the results are way off; not even close.


Any Help or advice is appreciated




Thanks,


Mike

Re: PHP MD5 to .NET C#

Posted: Sun Nov 29, 2009 9:49 am
by Apollo
You are first computing the hash, then adding the salt..?

And why would you base64 encode a hash string?

(besides, the result you're getting seems pretty strange to me.. did you base64 decode that? at the end it says "M2SGSal2toPa2swordsMakesonewayEncryptedHashesMoreSecure".... 8O)

Re: PHP MD5 to .NET C#

Posted: Sun Nov 29, 2009 1:41 pm
by Weirdan
There are severe differences between algorithms in your snippets. That ComputeHash function can be roughly translated to php like this:

Code: Select all

 
/**
  @param $plainText string
  @param $saltBytes string
  @return string
**/
function ComputeHash($plainText /*,$hashAlgorithm - skipped for brevity, */, $saltBytes) {
  return base64_encode(md5($plainText . $saltBytes) . $saltBytes);
}
 

Re: PHP MD5 to .NET C#

Posted: Mon Nov 30, 2009 9:00 am
by belcherman
The problem is that the PHP version is with another company and part of their site login.


How what I am designing will work with their site is:



Scenario #1:
People log into their site and the PHP hash routine is run; then the newly created hashed-password is then compared to a hashed-password stored in their database. If they match, the session is granted. At this point the user may click on our button and that posts to our site. This would then pass the username and hashed-password to us at which point my .NET hash routine would check that hashed-password against the one stored in our Database and grant access or deny it.


Scenario #2:
Users would load up our site directly. They would land on the login page, type in their username and password, and then my .NET hash routine would create a hashed_password from the login password. This hashed-password would then be compared against the one stored in the Database and access would be granted or denied.


ANSWERS TO OTHER QUESTIONS:

-------------------------------------------------------------------------------------------------
dwayne:
"TheSalt" and "thesalt" are not equivelant salts. That's the first place I would check.
Dwayne

The reason I put that is just to hide the actual salt from the public :) The two salts are actually identical.
-------------------------------------------------------------------------------------------------


---------------------------------------------------------------------------------------------------
john:
At a guess I would suspect you are comparing apples to oranges. Is the PHP
password and user name plain ASCII or Unicode? Same question for dotnet.

That I am not sure of. I would have to check with the people that run thier website. But in my tests here using the password hello123 VS the hash they sent me representing hello123 via PHP MD5 the results are way off. The .NET hash comes out 3 times as long as the PHP version.
---------------------------------------------------------------------------------------------------


Thanks,


Mike

Re: PHP MD5 to .NET C#

Posted: Tue Dec 01, 2009 8:56 pm
by belcherman
Okay, I changed the way I am doing things a bit more to make it like PHP. Now the length is a lot shorter but the results are still different.


-----------------------------------------------------
function encryptString($string) {

return md5($string . PASSWORD_SALT);

}
-----------------------------------------------------

PHP Result = "5b1980b160ae19131ae1a68c76685d1b"



String Hashpass = "hello123" + "TheSalt";
String HashpassComplete = Convert.ToBase64String(new System.Security.Cryptography.MD5CryptoServiceProvider().ComputeHash(System.Text.Encoding.Default.GetBytes(Hashpass)));
Session["HashpassComplete"] = HashpassComplete;


.NET Result = "WxmAsWCuGRMa4aaMdmhdGw=="


Any Ideas on why this is happening. I am still fooling around with encoding.



Also I am base64 encoding otherwise in C# you will get this error:

Compilation Error
Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.

Compiler Error Message: CS0029: Cannot implicitly convert type 'byte[]' to 'string'

Re: PHP MD5 to .NET C#

Posted: Tue Dec 01, 2009 9:54 pm
by daedalus__
why are you converting to base64?

Re: PHP MD5 to .NET C#

Posted: Tue Dec 01, 2009 10:09 pm
by daedalus__
also from what i read of that website you linked to, one person said something along the lines of making sure that the strings are being hashed in the same or a similar encoding between the languages. hope this helps

Re: PHP MD5 to .NET C#

Posted: Tue Dec 01, 2009 10:23 pm
by belcherman
Hi and thanks for the reply. I am base64 encoding otherwise in C# you will get the following error.

Compilation Error
Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.

Compiler Error Message: CS0029: Cannot implicitly convert type 'byte[]' to 'string'

Re: PHP MD5 to .NET C#

Posted: Tue Dec 01, 2009 10:33 pm
by John Cartwright
belcherman wrote:Hi and thanks for the reply. I am base64 encoding otherwise in C# you will get the following error.

Compilation Error
Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.

Compiler Error Message: CS0029: Cannot implicitly convert type 'byte[]' to 'string'
You can convert the byte[] array to a string by simply doing

byte[] myBytes = new byte[10];

Encoding.ASCII.GetString(myBytes); //returns string

Re: PHP MD5 to .NET C#

Posted: Tue Dec 01, 2009 10:44 pm
by daedalus__
none of the examples i have seen use convert.base64

http://www.geekpedia.com/code3_Encrypti ... rithm.html

try this example. he claims it generates hashes that match php