SHA1: different results for PHP and C# - c#

I have a code to generate hash in C#:
string hash = GetHash("Ю-41241624.05.1991");
public static string GetHash(string str)
{
Encoding eu = Encoding.UTF8;
byte[] data = eu.GetBytes(str);
SHA1 sha = new SHA1CryptoServiceProvider();
return Convert.ToBase64String(sha.ComputeHash(data));
}
The result is:
G7xY+gb35Lw4HlDnTZP89FU3Khk=
And I try to get the same result in PHP:
$str = mb_convert_encoding("Ю-41241624.05.1991","UTF-8");
$hash = sha1($str,true);
$base64 = base64_encode($hash);
echo $base64;
But the result is:
Dg+x7F8lsC/r9O8PNskgJ/MwNgU=

Just get rid of mb_convert_encoding(), if the string is already UTF-8 it will mess things up.
When I run the code without that function I get the correct result: https://eval.in/620412

Hi your problem is in "YU" character. Your c# code looks fine. When you debug the code only with this character, you will get byte array with values 208 174 which is really Ю character in UTF8. So c# code should works fine and sha1 from c# should be good.
Can you get byte numbers from php only for char Ю? It should be also 208 and 174.
If you remove this character your hash string should be equal.

Related

Hash algorithm returning abnormal string length

I am hashing a string 3C970E3BF535 using the below method:
internal static string Hash(string content)
{
System.Security.Cryptography.KeyedHashAlgorithm ha = System.Security.Cryptography.KeyedHashAlgorithm.Create();
string asmKey = "Some key";
byte[] hashkey = System.Text.Encoding.ASCII.GetBytes(asmKey);
byte[] data1 = System.Text.Encoding.ASCII.GetBytes(content);
byte[] data2 = System.Text.Encoding.ASCII.GetBytes(content.ToLower());
System.Security.Cryptography.HMACSHA512 hmac = new System.Security.Cryptography.HMACSHA512(hashkey);
byte[] hashmac1 = hmac.ComputeHash(data1);
byte[] hashmac2 = hmac.ComputeHash(data2);
string hashmacencoded1 = System.Text.Encoding.ASCII.GetString(hashmac1);
string hashmacencoded2 = System.Text.Encoding.ASCII.GetString(hashmac2);
return string.Format("{0:X}", hashmacencoded1.GetHashCode());
}
The output I get is 2BED23B1. The length is 8.
If I reverse the string, using this method:
private static string Reverse(string s)
{
char[] charArray = s.ToCharArray();
Array.Reverse(charArray);
return new string(charArray);
}
And then re-hash it, I get 7 characters - 707D653 instead of 8 characters of the non-reversed hash, though the fact that it's reversed or non-reversed shouldn't matter at all, since hashing should return same length despite the input.
I have switched out the key that we actually use, so if you use the code above it would not reproduce the issue. The issue would ONLY pop up if we use our key. What is going on?
You can't use System.Text.Encoding.ASCII.GetString to represent the hash because the hash is just a (pseudo) random assortment of bytes, not a binary representation of an ASCII string.
Instead you could represent it as a base64 string.
Convert.ToBase64String(hashmac1); // ABCDEF123== for example
You also should not be testing the GetHashCode() of the result - this is a different code that is used internally in the .NET framework for key-based data structures such as Dictionary, HashSet, etc. Just output the variable, not the hash code of the variable - the variable is the hash code.
The result of string.GetHashCode is always a 32bit signed integer.
In this case, your result just happened to have a leading zero, which gets lopped off when you do string.Format("{0:X}", ... )
There are all sorts of other problems with this (why are you getting the hash code of the hash?) but that's the answer to the problem you actually asked about.

Replicate C# MD5 hash to PHP

I have to replicate C# hash from the code below into PHP. I have been searching but didn't find a solution so far.
From this article on creating an md5 hash string:
using System;
using System.Text;
using System.Security.Cryptography;
// Create an md5 sum string of this string
static public string GetMd5Sum(string str)
{
// First we need to convert the string into bytes, which
// means using a text encoder.
Encoder enc = System.Text.Encoding.Unicode.GetEncoder();
// Create a buffer large enough to hold the string
byte[] unicodeText = new byte[str.Length * 2];
enc.GetBytes(str.ToCharArray(), 0, str.Length, unicodeText, 0, true);
// Now that we have a byte array we can ask the CSP to hash it
MD5 md5 = new MD5CryptoServiceProvider();
byte[] result = md5.ComputeHash(unicodeText);
// Build the final string by converting each byte
// into hex and appending it to a StringBuilder
StringBuilder sb = new StringBuilder();
for (int i=0;i<result.Length;i++)
{
sb.Append(result[i].ToString("X2"));
}
// And return it
return sb.ToString();
}
For input = "123", the above code gives me "5FA285E1BEBE0A6623E33AFC04A1FBD5"
I have tried the following PHP code but it does not give the same output.
From the SO question PHP MD5 not matching C# MD5:
$str = "123";
$strUtf32 = mb_convert_encoding($str, "UTF-32LE");
echo md5($strUtf32);
This code has the result = "a0d5c8a4d386f15284ec25fe1eeeb426". By the way, changing UTF-32LE to utf-8 or utf-16 still does not give me the same result.
Can anyone help?
Yep, as CodesInChaos suggests, you got the encodings wrong.
On php side try this:
$str = "123";
$strUtf32 = mb_convert_encoding($str, "UTF-16LE");
echo md5($strUtf32);
This will give you 5FA285E1BEBE0A6623E33AFC04A1FBD5. This will match System.Text.Encoding.Unicode on the c# side.
Otherwise change System.Text.Encoding.Unicode to System.Text.Encoding.UTF32 on the c# side. This will give you A0D5C8A4D386F15284EC25FE1EEEB426.
Uhh, the C# code creates a MD5 hash and the PHP mb_convert_encoding function just encodes the string...
Plus, this is NOT THE FULL CODE from the link you gave. You are missing the important MD5 function:
$str = "123";
$strUtf32 = mb_convert_encoding($str, "UTF-16");
echo md5($strUtf32); <=====
If that code matches there should be NO REASON why that shouldn't work, as the MD5 algorithm is still the same and does not vary from language to language.

Data encoding - PHP vs C#

I have something like that written in PHP:
$signature = md5($tosigndata);
Now, I am trying to replicate this in C#:
MD5.Create().ComputeHash(Tools.GetBytes(tosigndata))
But that gives me totally different result. How do I need to change my C# code in order to match PHP hash?
PS. Yeah, I know that .ComputeHash() returns byte[], but that doesn't change anything, i tried decoding it and it's still a different string.
Edit: Tools.GetBytes() returns Encoding.UTF8.GetBytes(tosigndata);
try this in C#:
byte[] asciiBytes = ASCIIEncoding.ASCII.GetBytes(tosigndata); // tosigndata is your string variable
byte[] hashedBytes = MD5CryptoServiceProvider.Create().ComputeHash(asciiBytes);
string hashedString = BitConverter.ToString(hashedBytes).Replace("-", "").ToLower();
// hashString contains your hash data similar to php md5

Hashing text with SHA-256 at Windows Forms

String inputPass = textBox2.Text;
byte[] inputBytes = System.Text.Encoding.UTF8.GetBytes(inputPass);
byte[] inputHashedBytes = Sha256.ComputeHash(inputBytes);
String inputHash = Convert.ToBase64String(inputHashedBytes);
I'm getting some strange output:
Q9nXCEhAn7RkIOVgBbBeOd5LiH7FWFtDFJ22TMLSoH8=
By output hash looks like this:
43d9d70828409fb46420e56005b05e38de4b887ec5585b43149db64cc2d2a07f
// This is where you get the actual binary hash
byte[] inputHashedBytes = Sha256.ComputeHash(inputBytes);
// But you want it in a string format, similar to a variety of Unix tools
string result = BitConverter.ToString(inputHashedBytes)
// This will remove all the dashes in between each two characters
.Replace("-", string.Empty)
// And make it lowercase
.ToLower();
Encoding.UTF8.GetString parses bytes as UTF-8 code points.
The SHA-256 hash is an arbitrary 256-bit number and does not correspond to any Unicode text.
You probably want to show the binary value in hexadecimal, by calling BitConverter.ToString(). You can also call Convert.ToBase64String().

php md5 algorithm that gives same result as c#

i have a hashing algorithm in C#, in a nutshell, it is:
string input = "asd";
System.Security.Cryptography.MD5 alg = System.Security.Cryptography.MD5.Create();
System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding();
byte[] hash = alg.ComputeHash(enc.GetBytes(input));
string output = Convert.ToBase64String(hash);
// outputs: eBVpbsvxyW5olLd5RW0zDg==
Console.WriteLine(output);
Now I need to replicate this behaviour in php,
$input = "asd";
$output = HashSomething($input);
echo $output;
How can I achieve it?
I checked
md5
utf8_decode
utf8_encode
base64_encode
base64_decode
url_decode
but i noted the php md5 doesn't get the == on the end... what am I missing?
NOTE: I cannot change C# behaviour because it's already implemented and passwords saved in my db with this algorithm.
The issue is PHP's md5() function by default returns the hex variation of the hash where C# is returning the raw byte output that must then be made text safe with base64 encoding. If you are running PHP5 you can use base64_encode(md5('asd', true)). Notice the second parameter to md5() is true which makes md5() return the raw bytes instead of the hex.
Did you remember to base64 encode the md5 hash in php?
$result = base64_encode(md5($password, true));
The second parameter makes md5 return raw output, which is the same as the functions you're using in C#
Your C# code takes the UTF8 bytes from the string; calculates md5 and stores as base64 encoded. So you should do the same in php, which should be:
$hashValue = base64_encode(md5(utf8_decode($inputString)))
it should be like as below for php
php -r "echo base64_encode(md5(utf8_encode('asd'),true));"
I had the same issue...using just md5($myvar) it worked. I am getting the same result C# and PHP.
Gavin Kendall posted helped me. I hope this helps others.
http://jachman.wordpress.com/2006/06/06/md5-hash-keys-with-c/
public static string MD5Hash(string text)
{
System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
return System.Text.RegularExpressions.Regex.Replace(BitConverter.ToString(md5.ComputeHash(ASCIIEncoding.Default.GetBytes(text))), “-”, “”);
}

Categories