Try out my new app: MealPlan, a simple weekly meal planning tool for the iPad.

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.

33 Responses to “C# Code Snippet: Creating an md5 hash string.”

  1. Matt Says:

    Great. that rocks, and its hell fast too: 1000 iterations in under 1/2 a second on my laptop…

  2. Nick Says:

    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.

  3. Tomas Says:

    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

  4. Jeremy Says:

    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.

  5. Rosy Says:

    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 .

  6. vijay Says:

    Hi,
    It is very use ful for me. but how can reform the hashed password.

  7. Damon Carr Says:

    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

  8. keith smith Says:

    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.

  9. evyatar ben-shitrit Says:

    http://msdn2.microsoft.com/en-us/library/system.security.cryptography.md5(vs.80).aspx

    There was a bug in the initial version?

  10. ÜberUtils - Part 1 : Cryptography - BradVin's .Net Blog Says:

    [...] 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 [...]

  11. Chris Says:

    Thanks for the snippet, worked instantly and greatly helped me out!

  12. Lars Says:

    Thanks for sharing the snippet!

  13. masic_2000 Says:

    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!

  14. Antharas Says:

    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);
    }

  15. Avi Says:

    Following article will be helpful:

    http://www.etechplanet.com/post/2009/03/29/Generate-MD5-Hash-code-from-a-string-using-C.aspx

  16. Christof Wollenhaupt Says:

    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.

  17. Jorbes Says:

    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.

  18. Esben Says:

    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?

  19. Giovanni Says:

    Esben, Is not possible you can only generate 2 fingerprint of 2 strings and compare them.
    MD5 is an hash.

  20. Richard Says:

    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.

  21. Hubert Says:

    @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).

  22. Steve Says:

    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.

  23. Ashish Khandelwal Says:

    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

  24. Ashish Khandelwal Says:

    Also read about string.GetHashCode() and HashTable calls GetHashCode() Differ?

    http://ashishkhandelwal.arkutil.com/?p=98

  25. lars Says:

    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;
    }
    }

  26. Mahesh Tryambake Says:

    This is not compatible with php md5.

    Thanks,

  27. Ian Bland Says:

    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

  28. Jit Says:

    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.

  29. David Says:

    Hi guys,
    I’m using this online md5 encoder to hash string.
    It encrypts right away, quite useful!
    David

  30. smak Says:

    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)

  31. Carlos Says:

    You can use BitConverter.ToString() instead of String.ToString(“X2″)

  32. Carlos Says:

    Example:
    string hexValues = System.BitConverter.ToString(hash).Replace(“-”, null);

  33. Igor Says:

    return string.Join(“”,
    new MD5CryptoServiceProvider().ComputeHash(
    new MemoryStream(Encoding.UTF8.GetBytes(content))).Select(x => x.ToString(“X2″)));

Leave a Reply