C# Code Snippet: Creating an md5 hash string.
While writing some code to cache objects from the web (actually items in an RSS channel) in a local database, I ran into the problem of uniquely identifying items in the database. RSS 0.91 defines an optional “guid” element that uniquely identifies an item, but many sites don’t provide it. There was no “key” that I could use to see if the data was already in the database, so I wanted to generate one using a hashing algorithm.
The .NET framework has GetHashCode() which seems promising, and which every object must support, but it returns an int, and considering the database could potentially have hundreds of thousands of entries in it, multiple objects generating the same hash code would eventually happen. Duplication wouldn’t be a catastrophic problem, but if it happened frequently, it would make the caching less useful.
The framework can generate an MD5 hash of an arbitrary piece of data, which is just what I want – a unique enough hash that it’s very unlikely that two arbitrary pieces of information would generate the same hash. The MD5 algorithm takes as input a message of arbitrary length and produces as output a 128-bit “fingerprint” of the input. The .NET framework glue for taking the 128-bit binary data and turn it into a hex string was a bit of a pain to figure out, so I’m presenting what I wrote here both to provide an example to anyone else with a similar need, and to ask if there’s a better way.
A full description of the MD5 algorithm is available in rfc1321.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 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();
}
Thanks to Johannes Hiemer for pointing out a bug in my initial version.
March 13th, 2006 at 5:13 am
Great. that rocks, and its hell fast too: 1000 iterations in under 1/2 a second on my laptop…
May 4th, 2006 at 8:37 pm
Instead of using a StringBuilder, use Convert.ToBase64String(result). That will do 6 bits per character instead of 4 (so the output string will be shorter).
You should also use MD5CryptoServiceProvider.Create() rather than ‘new’ because it is faster. Or just MD5.Create() for short.
byte[] input = Encoding.UTF8.GetBytes(inputString);
byte[] output = MD5.Create().ComputeHash(input);
return Convert.ToBase64String(output);
Something like this would be sufficient (and faster). If you want to support Unicode, just type Unicode instead of UTF8.
If you want even faster, keep the MD5 in a static variable so that it only has to be created once.
August 25th, 2006 at 1:54 am
You really should’nt use Convert.ToBase64String() because that returns a non-hex decimal value.
A true hex is Base16.
If, like in my case, you want to have a Windows App working in conjunction with a WebApp this would’nt work.
In ASP.NET you use:
System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(string,”MD5″)
which returns a correct MD5 hash with Base16 hex.
But that function is not available in a Windows App.
This function gets a little closer, but still has some flaws:
public string GenPwdHash(string src)
{
string str = “”;
byte[] btySrc = ASCIIEncoding.ASCII.GetBytes(src);
MD5CryptoServiceProvider objMD5 = new MD5CryptoServiceProvider();
byte[] btyRes = objMD5.ComputeHash(btySrc);
int intTot = (btyRes.Length * 2 + (btyRes.Length / 8));
StringBuilder strRes = new StringBuilder(intTot);
int intI;
for (int intI = 0; intI
September 10th, 2006 at 7:27 pm
The original code is very useful in that it matches output from MySQL’s MD5 call. If you’re switching from MySQL to C#, or still using MySQL with C# then this original poster’s code is the way to go. However, Nick’s code may be faster; I have not tested it.
September 15th, 2006 at 8:58 am
i had database which had password coded to MD5 using PHP but now i had to compare that string for login with C# .how can i do that .above method give different MD5 value in C# from PHP MD5 encoded password .
please give me solution .
November 1st, 2006 at 5:38 am
Hi,
It is very use ful for me. but how can reform the hashed password.
December 5th, 2006 at 1:24 pm
If you were going to declare the MD5 instance as static would’t you need to use some thread sync? Something easy like:
lock (_staticMD5)
{
_staticMD5.Clear();
result = _staticMD5.ComputeHash(rawText);
}
where:
private static MD5 _staticMD5 = MD5.Create();
Is the call to .Clear() even necessary?
I am using this for a screen scrape app to sense changes in external web-pages and unfortunately they put in a date/time, which I have to strip out. I get the data as UTF8. I’m not sure of the benefit of padding for Unicode in my case (although as a general case I can see this is the only option).
All my ‘Crypto’ code is localized in a class called CryptoServices which is not a static class. This is the only static method. As this is on a web-site I am concerned about threading issues, but the ONLY shared data is the _staticMD5 variable. However, I believe this lock would make it OK…
Comments?
Thanks,
Damon
December 21st, 2006 at 4:57 pm
Encryption is used for scrambling text for later decryption. Hashing is one way, you can’t get the original value out of a hash. For passwords, when you set the password, you hash the password, and store the hash. When a user logs in, hash the typed password, and compare it to the stored hash.
June 22nd, 2007 at 12:50 pm
http://msdn2.microsoft.com/en-us/library/system.security.cryptography.md5(vs.80).aspx
There was a bug in the initial version?
October 2nd, 2007 at 4:20 pm
[...] here. I’ve had a scenario in the past when I needed to compute a MD5 hash of a string. I also found this blog post on the subject and decided I can now use extension methods to add this functionality to every [...]
November 20th, 2008 at 4:03 am
Thanks for the snippet, worked instantly and greatly helped me out!
January 15th, 2009 at 2:09 pm
Thanks for sharing the snippet!
March 27th, 2009 at 9:49 am
Can also use,
byte[] toEncodeAsBytes
= System.Text.ASCIIEncoding.ASCII.GetBytes((str);
instead of
Encoder enc = System.Text.Encoding.Unicode.GetEncoder();
byte[] unicodeText = new byte[str.Length * 2];
enc.GetBytes(str.ToCharArray(), 0, str.Length, unicodeText, 0, true);
Good work thanks for sharing!
May 4th, 2009 at 3:40 am
I think the refactored version would be something like this:
private static readonly MD5 Md5 = MD5.Create();
public static string GetMd5Sum(string inputString)
{
byte[] input = Encoding.UTF8.GetBytes(inputString);
byte[] result = Md5.ComputeHash(input);
return Convert.ToBase64String(result);
}
May 4th, 2009 at 10:51 am
Following article will be helpful:
http://www.etechplanet.com/post/2009/03/29/Generate-MD5-Hash-code-from-a-string-using-C.aspx
July 13th, 2009 at 8:57 am
The need to generate DOS compatible MD5 hash codes in a .NET application should be close to zero. Please everyone, stop using Encoding.ASCII. That’s a 7 bit encoding. There’s no need whatsoever to use this ever in a .NET application. If you want ANSI, use Encoding.Default.
August 17th, 2009 at 9:07 am
Convert.ToBase64String() seems more than 10 times faster than iterating over the hashed byte array appending it to a stringbuilder.
So if you don’t want to be fully compatible (using the hashes in a closed system internally), I’d go with Convert.
September 15th, 2009 at 8:47 am
Okej. Here’s a question:
I need some method that can convert then MD5 back to text. Is that possible?
I used this method to convert the string into md5:
private static readonly MD5 Md5 = MD5.Create();
public static string GetMd5Sum(string inputString)
{
byte[] input = Encoding.UTF8.GetBytes(inputString);
byte[] result = Md5.ComputeHash(input);
return Convert.ToBase64String(result);
}
Now how can i convert it back?
September 23rd, 2009 at 4:34 am
Esben, Is not possible you can only generate 2 fingerprint of 2 strings and compare them.
MD5 is an hash.
September 23rd, 2009 at 11:34 am
Esben,
MD5 hashing is a one way function.
You can create a hash for your data, but you cannot convert it back.
Hashes are usually used to check if some data has been altered.
If you want to make sure someone does not read your data, use encryption like aes.
If you want to make it smaller, use compression like ZIP.
If you want to make it small and make sure it can not be read by someone, use both ;)
Good luck with your project.
September 29th, 2009 at 4:05 am
@Esben:
No, that’s not possible. That’s exactly the purpose of an MD5 hash (it’s a one-way encryption). It’s only possible to check if two strings create the same MD5 hash.
As it’s very unlikely to create the same MD5 hash from two different strings, strings which create the same MD5 hash can be considered as equal (for example in a password check).
September 29th, 2009 at 12:58 pm
Esben, you can’t. That’s the whole point of hashing, that it creates an as-good-as-unique character code to represent your code, but it is not reversible. Instead, you take back the original string, re-hash it and compare it to the stored hash. The same original string will always create the same hash.
So in the case of passwords, you just store the hash of their password in your database. Then when they log back in you take the password they’ve just supplied in the log-in box, recompute the hash and compare that with the stored hash of their original password. If the two hashes are identical, you know they got it right. If they aren’t, all you can say is that they are different. You can’t restore the original if it’s been forgotten.
October 12th, 2009 at 12:31 am
About uniqueness of HashCode, Microsoft says: http://msdn2.microsoft.com/en-us/library/system.object.gethashcode.aspx
The default implementation of the GetHashCode method does not guarantee unique return values for different objects. Furthermore, the .NET Framework does not guarantee the default implementation of the GetHashCode method, and the value it returns will be the same between different versions of the .NET Framework. Consequently, the default implementation of this method must not be used as a unique object identifier for hashing purposes.
I tried to find out, why Microsoft says this:
Making Hash Code unique for Different objects / strings is almost impossible, the one of the reason is the size of the Hash (int) which is 32 bits only, this means that the contents of the string and the size of any object much be squeezed into those bits, which means a lot of data is lost. For any given string bigger than the size of the hash, total uniqueness cannot be guaranteed and that’s why MSDN is also not giving guarantee on this
Read more on http://ashishkhandelwal.arkutil.com/?p=85
October 12th, 2009 at 12:32 am
Also read about string.GetHashCode() and HashTable calls GetHashCode() Differ?
http://ashishkhandelwal.arkutil.com/?p=98
November 21st, 2009 at 6:29 am
This is not compatible with mysql or php md5.
this is:
http://www.spiration.co.uk/post/1203/MD5%20in%20C%23%20-%20works%20like%20php%20md5%28%29%20example
public static string GetMd5Sum(string password)
{
byte[] textBytes = System.Text.Encoding.Default.GetBytes(password);
try
{
System.Security.Cryptography.MD5CryptoServiceProvider cryptHandler;
cryptHandler = new System.Security.Cryptography.MD5CryptoServiceProvider();
byte[] hash = cryptHandler.ComputeHash(textBytes);
string ret = “”;
foreach (byte a in hash)
{
if (a < 16)
ret += "0" + a.ToString("x");
else
ret += a.ToString("x");
}
return ret;
}
catch
{
throw;
}
}
December 10th, 2009 at 2:31 am
This is not compatible with php md5.
Thanks,
February 5th, 2010 at 5:40 am
Rubbish code!! I wrote the below and I get over 100,000+ /sec. Supports both string and bin() inputs, salt is optional:
Public Shared Function CreateMD5(ByVal input() As Byte) As String
Dim output() As Byte = Cryptography.MD5.Create.ComputeHash(input)
Dim sHash As String = “”
For Each bit As Byte In output
If bit < 16 Then sHash += "0"
sHash += Hex(bit)
Next
Return sHash.ToLower
End Function
Public Shared Function CreateMD5(ByVal input As String, Optional ByVal salt As String = "") As String
Dim bin() As Byte = Encoding.Default.GetBytes(salt + input)
Return CreateMD5(bin)
End Function
February 11th, 2010 at 1:45 pm
Hi Friends,
I am trying to display the hashed string to UI in web page. The same will be used by user to copy the hashed string generated and displayed on web page and store the same in database. But the hashed string displayed on web page always have some loss of special characters. I am using same base64 string method of convert.
i.e. in my case the hashed output has “new line” character and when I display the hashed string on web page it does not show the same and the user who copies the data does not get the exact hashed string.
How can I display all the hashed string without loss of characters?
Appreciate your help.
February 20th, 2010 at 5:15 am
Hi guys,
I’m using this online md5 encoder to hash string.
It encrypts right away, quite useful!
David
March 2nd, 2010 at 4:26 pm
this produces a wrong md5 hash…. lars’s function will work (you can use ‘X2′ formatting instead of the padded 0 stuff, but either way works)
July 26th, 2010 at 8:28 am
You can use BitConverter.ToString() instead of String.ToString(“X2″)
July 26th, 2010 at 8:36 am
Example:
string hexValues = System.BitConverter.ToString(hash).Replace(“-”, null);
July 14th, 2011 at 7:30 am
return string.Join(“”,
new MD5CryptoServiceProvider().ComputeHash(
new MemoryStream(Encoding.UTF8.GetBytes(content))).Select(x => x.ToString(“X2″)));