C# MD5 hash function return weird result? - c#

I just tried to create a MD5 hash program in C#. My friend give me a sample code about this but when I try to run a test with "123456", instead of returning the correct hash result
e10adc3949ba59abbe56e057f20f883e
it returns the result
ce0bfd15059b68d67688884d7a3d3e8c
I tried to read the main code but still cannot get anything!
string value = textBox1.Text;
byte[] valueBytes = new byte[value.Length * 2];
Encoder encoder = Encoding.Unicode.GetEncoder();
encoder.GetBytes(value.ToCharArray(), 0, value.Length, valueBytes, 0, true);
MD5 md5 = new MD5CryptoServiceProvider();
byte[] hashBytes = md5.ComputeHash(valueBytes);
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < hashBytes.Length; i++)
{
stringBuilder.Append(hashBytes[i].ToString("x2"));
}
textBox2.Text = stringBuilder.ToString();

Looks like your friend used Encoding.Default instead of Encoding.Unicode
Strings in .NET are UTF16. Hashing works on bytes though, not strings. The string has to be converted to bytes. To do that, a specific encoding has to be used .
If the .NET native encoding is use, ie UTF16, the original byte buffer will be 12 bytes long and the hex representation of the hash will be ce0bfd15059b68d67688884d7a3d3e8c :
var valueBytes=Encoding.Unicode.GetBytes("123456");
Debug.Assert(valueBytes.Length==12);
var md5=System.Security.Cryptography.MD5.Create();
byte[] hashBytes = md5.ComputeHash(valueBytes);
var hexText=String.Join("",hashBytes.Select(c=>c.ToString("x2")));
If the 7-bit US-ASCII encoding is used though, the array will be 6 bytes long and the hex representation will be e10adc3949ba59abbe56e057f20f883e :
var valueBytes=Encoding.ASCII.GetBytes("123456");
Debug.Assert(valueBytes.Length==6);
var md5=System.Security.Cryptography.MD5.Create();
byte[] hashBytes = md5.ComputeHash(valueBytes);
var hexText=String.Join("",hashBytes.Select(c=>c.ToString("x2")));
The fist 127 bytes of most codepages match the 7-bit US-ASCII characters, so most encodings, including UTF8, would return e10adc3949ba59abbe56e057f20f883e. The following encodings would return the same hash string : Encoding.GetEncoding(1251) (Cyrillic), Encoding.GetEncoding(20000) (Chinese Traditiona) would result in the same hash.
The Encoding.Default value returns the encoding that corresponds to the computer's system locale. It's the encoding used by non-Unicode applications like C++ applications compiled with ANSI string types.
Encoding.GetEncoding(20273) though would return a different value - that's an IBM EBCDIC that used different bytes even for the english alphabet and digits. This will return : 73e00d17ee63efb9ae91d274baae2459

You're expecting to have UTF8 string, so why do you use Unicode encoding? Use UTF8 and you'll get the result that you expect:
string value = "123456";
byte[] valueBytes = new byte[value.Length]; // <-- don't multiply by 2!
Encoder encoder = Encoding.UTF8.GetEncoder(); // <-- UTF8 here
encoder.GetBytes(value.ToCharArray(), 0, value.Length, valueBytes, 0, true);
MD5 md5 = new MD5CryptoServiceProvider();
byte[] hashBytes = md5.ComputeHash(valueBytes);
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < hashBytes.Length; i++)
{
stringBuilder.Append(hashBytes[i].ToString("x2"));
}
Console.WriteLine(stringBuilder.ToString()); // "e10adc3949ba59abbe56e057f20f883e"

Related

C# equivalent to parse cryptojs

I'm trying to create C# that does this in CryptoJS
var hash = CryptoJS.HmacSHA512(msg, key);
var crypt = CryptoJS.enc.Utf8.parse(hash.toString());
var base64 = CryptoJS.enc.Base64.stringify(crypt);
My question is in the second statement where hash variable is put into a string then parsed.
Is there an equivalent in C#? Once parsed how do you encode the result into Utf8.
Thanks
I'm not 100% if I understand exactly which piece you are looking for here. But there is no such thing as a UTF8 System.String in C#. However when you write a string to a stream you can choose the encoding of the bytes in the stream to be UTF8
For example by passing that encoding as an option to a StreamWriter.
using (StreamWriter writer = new StreamWriter(stream, Encoding.UTF8)) {
writer.Write(text);
}
My boss find the answer to this. The difference is that before you return the base64 string using C# you have to change the bytes into hexadecimal.
var encoder = new UTF8Encoding();
byte[] keyBytes = encoder.GetBytes(key);
var newlinemsg = action + "\n" + msg;
byte[] messageBytes = encoder.GetBytes(newlinemsg);
byte[] hashBytes = new HMACSHA512(keyBytes).ComputeHash(messageBytes);
var hexString = ToHexString(hashBytes);
var base64 = Convert.ToBase64String(encoder.GetBytes(hexString));

C# code php equivalent md5 hash

I have this C# code:
public static string Encript(string strData)
{
string hashValue = HashData(strData);
string hexHashData = ConvertStringToHex(hashValue);
return hexHashData;
}
public static string HashData(string textToBeEncripted)
{
//Convert the string to a byte array
Byte[] byteDataToHash = System.Text.Encoding.Unicode.GetBytes(textToBeEncripted);
//Compute the MD5 hash algorithm
Byte[] byteHashValue = new System.Security.Cryptography.MD5CryptoServiceProvider().ComputeHash(byteDataToHash);
return System.Text.Encoding.Unicode.GetString(byteHashValue);
}
public static string ConvertStringToHex(string asciiString)
{
string hex = "";
foreach (char c in asciiString)
{
int tmp = c;
hex += String.Format("{0:x2}", (uint) System.Convert.ToUInt32(tmp.ToString()));
}
return hex;
}
Here you can see an online version.As you can see for the string "test" I get the output "5c82e9e41c7599f790ef1d774b7e6bf"
And this is what I tried on php side
$a = "test";
$a = mb_convert_encoding($a, "UTF-16LE");
$a = md5($a);
echo $a;
But the value of the php code is "c8059e2ec7419f590e79d7f1b774bfe6".Why is not working?
Edit:Looks like the C# code is incorrect and needs to be replaced
The correct MD5 hash for 'test' is '098f6bcd4621d373cade4e832627b4f6' in PHP.
I tested it with this code in C#
public static string CreateMD5(string input)
{
// Use input string to calculate MD5 hash
using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
{
byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
byte[] hashBytes = md5.ComputeHash(inputBytes);
// Convert the byte array to hexadecimal string
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hashBytes.Length; i++)
{
sb.Append(hashBytes[i].ToString("X2"));
}
return sb.ToString();
}
}
It will generate the same hash as PHP will, without the 'convert encoding' method you are using.
I believe converting the encoding is what is giving you a different answer, try it without
$a = mb_convert_encoding($a, "UTF-16LE");
The problem is that you are converting the result incorrectly in your C# code. If you put a breakpoint in the code after you call ComputeHash, and examine the value of byteHashValue, you'll see that it's c8059e2e....
Or, just add this code to your ComputeHash method:
Console.WriteLine(BitConverter.ToString(byteHashValue));
I would suggest rewriting your code to be:
public static string Encript(string strData)
{
string hashValue = HashData(strData);
return hashValue;
}
public static string HashData(string textToBeEncripted)
{
//Convert the string to a byte array
Byte[] byteDataToHash = System.Text.Encoding.Unicode.GetBytes(textToBeEncripted);
//Compute the MD5 hash algorithm
Byte[] byteHashValue = new System.Security.Cryptography.MD5CryptoServiceProvider().ComputeHash(byteDataToHash);
return BitConverter.ToString(byteHashValue).Replace("-", "");
}
Oh, and a side note: the word is "Encrypt," not "Encript."
The problem in your case is not the encoding, but your conversion to string on the C# side. As long as you use the same encoding everywhere, it should work as expected. But note, that most of the online hashers use ASCII encoding, whereas you use System.Text.Encoding.Unicode which is UTF-16, thus the results will differ from the online encoders.
The code below will give the same result as your PHP snippet (ie c8059e2ec7419f590e79d7f1b774bfe6)
public static void Main(string[] args)
{
string a = "test";
string en = HashData(a);
Console.WriteLine(en);
}
public static string HashData(string textToBeEncripted)
{
Byte[] byteDataToHash = System.Text.Encoding.Unicode.GetBytes(textToBeEncripted);
Byte[] byteHashValue = new System.Security.Cryptography.MD5CryptoServiceProvider().ComputeHash(byteDataToHash);
System.Text.StringBuilder s = new System.Text.StringBuilder();
foreach (var b in byteHashValue)
s.Append(b.ToString("x2"));
return s.ToString();
}
If you use System.Text.Encoding.ASCII instead, you will get 098f6bcd4621d373cade4e832627b4f6 as suggested in other answers. But then you'll have to use ASCII encoding in your PHP code as well.
This is because with UTF16 every character is represented by two bytes, and not only by one. Thus the byteDataToHash will have twice the size ([116, 0, 101, 0, 115, 0, 116, 0] vs [116, 101, 115, 116] in your case). And a different bytevector of course leads to a different hashvalue. But as said above, as long as all included components use the same encoding, it does not really matter which one you use.

Invalid padding error when using AesCryptoServiceProvider in C#

I've written a simple encryp/decrypt method in c# which uses the AES alg. When I try to encrypt and then decrypt a string with certain lengths like 4 or 7 characters, it works fine, with other lengths however It says that the padding is invalid and cannot be removed.
public static string Decrypt(string text)
{
Aes a = System.Security.Cryptography.AesCryptoServiceProvider.Create();
a.Padding = PaddingMode.PKCS7;
a.Key = Convert.FromBase64String("UDlArN63HCk15fHBski/zvaWiMZJi+jR1BADvVgenCU=");
a.IV = Convert.FromBase64String("xZG/eLY8eq0mQhUXvKbUDQ==");
var dc = a.CreateDecryptor();
byte[] encryptedBytes = Encoding.Unicode.GetBytes(text);
byte[] decryptedBytes = dc.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
return Encoding.Unicode.GetString(decryptedBytes);
}
public static string Encrypt(string text)
{
Aes a = System.Security.Cryptography.AesCryptoServiceProvider.Create();
a.Padding = PaddingMode.PKCS7;
a.Key = Convert.FromBase64String("UDlArN63HCk15fHBski/zvaWiMZJi+jR1BADvVgenCU=");
a.IV = Convert.FromBase64String("xZG/eLY8eq0mQhUXvKbUDQ==");
var dc = a.CreateEncryptor();
byte[] decryptedBytes = Encoding.Unicode.GetBytes(text);
byte[] encryptedBytes = dc.TransformFinalBlock(decryptedBytes, 0, decryptedBytes.Length);
return Encoding.Unicode.GetString(encryptedBytes);
}
Ciphertexts are binary data which might contain bytes that are not printable. If try to encode the byte array as a Unicode string, you will lose some bytes. It will be impossible to recover them during decryption.
If you actually want to handle the ciphertext as a string, you need to convert it into a textual representation like Base 64 or Hex.
// encryption
return Convert.ToBase64String(decryptedBytes);
// decryption
byte[] decryptedBytes = Convert.FromBase64String(text);

Ruby sha and hash to c#

Im trying to translate this to c#
f1 = Digest::SHA1.hexdigest(#password)
f2 = nonce + ":" + f1
Digest::MD5.hexdigest(f2)
My Code
private static string GetSHA1HashData(string data)
{
//create new instance of md5
SHA1 sha1 = SHA1.Create();
//convert the input text to array of bytes
byte[] hashData = sha1.ComputeHash(Encoding.Default.GetBytes(data));
//create new instance of StringBuilder to save hashed data
StringBuilder returnValue = new StringBuilder();
//loop for each byte and add it to StringBuilder
for (int i = 0; i < hashData.Length; i++)
{
returnValue.Append(hashData[i].ToString());
}
// return hexadecimal string
return returnValue.ToString();
}
public static string CreateMD5Hash(string input)
{
// Use input string to calculate MD5 hash
MD5 md5 = System.Security.Cryptography.MD5.Create();
byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
byte[] hashBytes = md5.ComputeHash(inputBytes);
// Convert the byte array to hexadecimal string
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hashBytes.Length; i++)
{
sb.Append(hashBytes[i].ToString("X2"));
// To force the hex string to lower-case letters instead of
// upper-case, use he following line instead:
// sb.Append(hashBytes[i].ToString("x2"));
}
return sb.ToString();
}
Call
var nonce = "1386755695841";
var password = "edc123";
var sha = GetSHA1HashData(password);
var md5 = CreateMD5Hash(nonce + ":" + sha);
But i cant get it right, any ideas
The problem is that .NET uses UTF-16 by default whilst Ruby will use something else (normally UTF-8, but it may also respect encoding that has been set by database or web source).
I think you just need to alter one line:
//convert the input text to array of bytes
byte[] hashData = sha1.ComputeHash(Encoding.ASCII.GetBytes(data));
You may need UTF-8 or even some other encoding instead, depending on the range of passwords accepted by the Ruby version. However, the ASCII coding should at least prove correctness of this answer in general from your sample data.

Convert a string's character encoding from windows-1252 to utf-8

I had converted a Word Document(docx) to html, the converted html has windows-1252 as its character encoding. In .Net for this 1252 character encoding all the special characters are being displayed as '�'. This html is being displayed in a Rad Editor which displays correctly if the html is in Utf-8 format.
I had tried the following code but no vein
Encoding wind1252 = Encoding.GetEncoding(1252);
Encoding utf8 = Encoding.UTF8;
byte[] wind1252Bytes = wind1252.GetBytes(strHtml);
byte[] utf8Bytes = Encoding.Convert(wind1252, utf8, wind1252Bytes);
char[] utf8Chars = new char[utf8.GetCharCount(utf8Bytes, 0, utf8Bytes.Length)];
utf8.GetChars(utf8Bytes, 0, utf8Bytes.Length, utf8Chars, 0);
string utf8String = new string(utf8Chars);
Any suggestions on how to convert the html into UTF-8?
This should do it:
Encoding wind1252 = Encoding.GetEncoding(1252);
Encoding utf8 = Encoding.UTF8;
byte[] wind1252Bytes = wind1252.GetBytes(strHtml);
byte[] utf8Bytes = Encoding.Convert(wind1252, utf8, wind1252Bytes);
string utf8String = Encoding.UTF8.GetString(utf8Bytes);
Actually the problem lies here
byte[] wind1252Bytes = wind1252.GetBytes(strHtml);
We should not get the bytes from the html String. I tried the below code and it worked.
Encoding wind1252 = Encoding.GetEncoding(1252);
Encoding utf8 = Encoding.UTF8;
byte[] wind1252Bytes = ReadFile(Server.MapPath(HtmlFile));
byte[] utf8Bytes = Encoding.Convert(wind1252, utf8, wind1252Bytes);
string utf8String = Encoding.UTF8.GetString(utf8Bytes);
public static byte[] ReadFile(string filePath)
{
byte[] buffer;
FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
try
{
int length = (int)fileStream.Length; // get file length
buffer = new byte[length]; // create buffer
int count; // actual number of bytes read
int sum = 0; // total number of bytes read
// read until Read method returns 0 (end of the stream has been reached)
while ((count = fileStream.Read(buffer, sum, length - sum)) > 0)
sum += count; // sum is a buffer offset for next reading
}
finally
{
fileStream.Close();
}
return buffer;
}
How you are planning to use resulting html? The most appropriate way in my opinion to solve your problem would be add meta with encoding specification. Something like:
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
Use Encoding.Convert method. Details are in the Encoding.Convert method MSDN article.

Categories