127

I have a problem when trying get a hash string in c#.

I already tried a few websites, but most of them are using files to get the hash. Others that are for strings are a bit too complex. I found examples for Windows authentication for web like this:

FormsAuthentication.HashPasswordForStoringInConfigFile(tbxPassword.Text.Trim(), "md5")

I need to use a hash to make a string that contains a filename more secure. How can I do that?

Example:

string file  = "username";
string hash = ??????(username); 

Should I use another hashing algorithm and not "md5"?

Edy Cu
  • 3,262
  • 5
  • 20
  • 19

8 Answers8

243
using System.Security.Cryptography;

public static byte[] GetHash(string inputString)
{
    using (HashAlgorithm algorithm = SHA256.Create())
        return algorithm.ComputeHash(Encoding.UTF8.GetBytes(inputString));
}

public static string GetHashString(string inputString)
{
    StringBuilder sb = new StringBuilder();
    foreach (byte b in GetHash(inputString))
        sb.Append(b.ToString("X2"));

    return sb.ToString();
}

Additional Notes

  • Since MD5 and SHA1 are obsolete and insecure algorithms, this solution uses SHA256. Alternatively, you can use BCrypt or Scrypt as pointed out in comments.
  • Also, consider "salting" your hashes and use proven cryptographic algorithms, as pointed out in comments.
Redwolf
  • 540
  • 4
  • 17
Dmitry Polomoshnov
  • 5,106
  • 2
  • 24
  • 25
  • 57
    **DO NOT USE MD5 OR SHA1**, they are obsolete and insecure algorithms. Use SHA256 at the very least or even better use BCrypt or Scrypt. – Muhammad Rehan Saeed Jan 11 '16 at 14:09
  • 1
    See this example of using SCrypt: https://stackoverflow.com/questions/20042977/example-code-for-scrypt-and-cryptsharp/34739165#34739165 – Muhammad Rehan Saeed Jan 12 '16 at 09:03
  • For the more modern (secure) yet easy and compact hash creation method please look at my answer to this question – andrew.fox Jan 13 '16 at 07:06
  • 14
    @Muh It can easily be used for checksums, because its much faster than SHA512. But indeed to store Passwords, it is not recommended, which is right. – LuckyLikey Apr 20 '17 at 09:21
  • @LuckyLikey Correct! – Muhammad Rehan Saeed Apr 20 '17 at 10:10
  • 11
    What does this `b.ToString("X2")` mean ? – Bilal Fazlani Jun 05 '17 at 18:27
  • 3
    @BilalFazlani see https://stackoverflow.com/questions/20750062/what-is-the-meaning-of-tostringx2 – Hezi Nov 25 '19 at 09:51
  • 21
    FYI It **IS** perfectly legitimate to use MD5 or SHA1 if your **not** using the hash as a **cryptographic** hash, for example as a hash of content for comparison. The advantage there of MD5 (for example) is speed of computation, that fact that they are insecure is then irrelevant. – Liam Mar 18 '21 at 15:44
  • Does it work on your machine? I test it and get compile error that the `algorithm.ComputeHash(...)` requires a stream as parameter, not array of bytes... – Konrad Viltersten Feb 28 '23 at 13:38
  • I have a question regarding hashing user's password: is it better to use this kind of string-to-string hash or simply use C#'s GetHashCode()? Why? – Tom Charles Zhang Mar 19 '23 at 13:36
  • 1
    @TomCharlesZhang `GetHashCode()` was specifically designed for hash tables, hash sets, etc. You should not consider using this method outside of that scope. It is not intended to provide any security characteristics. Its only goal is to provide numbers with random distribution for non equal entries of those hash tables. There is another reason - internal implementation of `GetHashCode()` may change anytime, like with the next .NET update, so you should never store `GetHashCode()` results in db, sent over the wire, etc. – Dmitry Polomoshnov Apr 25 '23 at 08:36
75

The fastest way, to get a hash string for password store purposes, is a following code:

    internal static string GetStringSha256Hash(string text)
    {
        if (String.IsNullOrEmpty(text))
            return String.Empty;

        using (var sha = new System.Security.Cryptography.SHA256Managed())
        {
            byte[] textData = System.Text.Encoding.UTF8.GetBytes(text);
            byte[] hash = sha.ComputeHash(textData);
            return BitConverter.ToString(hash).Replace("-", String.Empty);
        }
    }

Remarks:

  • if the method is invoked often, the creation of sha variable should be refactored into a class field;
  • output is presented as encoded hex string;
andrew.fox
  • 7,435
  • 5
  • 52
  • 75
  • `SHA1Managed` class is not very costly. it consumes about 130 bytes and initialize them to some static value, but that is all. so there shouldn't be a performance problem in most cases. – Earth Engine Mar 26 '14 at 01:31
  • 1
    Also `SHA1Managed` is `IDisposable` and thus require to wrap its usage into a `using` block. – Earth Engine Mar 26 '14 at 01:34
  • The purpose `Dispose` method is to clear the internal buffer. Failue to do so will be in risk of memory attack. – Earth Engine Mar 26 '14 at 01:38
  • It should be noted that `GetHashCode` is not a cryptographically secure hashing algorithm (As asked for in the question). Use SHA256 at the very least or even better use BCrypt or Scrypt for a secure algorithm. – Muhammad Rehan Saeed Jan 12 '16 at 08:24
  • @EarthEngine In actual fact, you want your cryptographic algorithm to be as costly and slow as possible. This is one of the things that makes it secure! – Muhammad Rehan Saeed Jan 12 '16 at 08:25
  • 3
    @MuhammadRehanSaeed when I said `SHA1Managed` is not costly, I mean its creation is not. Also, a hashing algorithm is not necessary costly. It only have to be (extremely) costly when you want to find a collision. – Earth Engine Jan 13 '16 at 00:42
  • How to decrypt the hashed password ? – King_Fisher Apr 21 '18 at 06:42
  • 1
    @King_Fisher - it's impossible! Hash is a one way function, information is lost. If you need to decrypt, you need to use encryption method not hashing. BTW, encrypting passwords is a bad practice. – andrew.fox Apr 21 '18 at 08:54
  • Jeez, so what am I supposed to do? Am I supposed to copy-paste your function into my program?! For christsake, microsoft. "Copy-paste" is an anti-pattern. For something so common there should be a function in dotnet. – John Henckel Nov 11 '22 at 15:27
  • 1
    @JohnHenckel do you want MS to put all possible usages into the library? It would weigh 1 GB. This method uses "composite" technique to build one of possible solutions. You can change Sha to MD5 or UTF to ASCII. However you like. – andrew.fox Nov 12 '22 at 16:13
11

All the hashing code samples here are outdated. In.NET 5, a new way of hashing data is provided to us which is double fast and does zero memory allocation. ain't that cool? You just need to use the new static HashData(byte[]) on your favorite hashing algorithm class.

byte[] buffer = Encoding.UTF8.GetBytes(input);
byte[] digest = SHA256.HashData(buffer);

Microsoft has a new rule in its analyzer to detect legacy usages and replace them with the new API.

Ehsan Mirsaeedi
  • 6,924
  • 1
  • 41
  • 46
  • The whole *point* of secure hashing, such as for passwords, is that it *needs* to be slow to produce the hash. That's what provides defenses against brute forcing. If you use a hashing algorithm that's fast to compute then it's *that much easier to break it*. – Servy Jan 05 '22 at 01:21
  • 5
    @Servy your point is correct but totally unrelated to my post. – Ehsan Mirsaeedi Jan 05 '22 at 18:17
  • It's not unrelated at all. Suggesting a solution because it's super fast means suggesting a solution that's *necessarily* insecure, since it being slow is a key component of its security. – Servy Jan 05 '22 at 18:19
  • 9
    @Servy The computation time is dependent on the algorithm you choose. The legacy implementation of hashing algorithm is not performant in terms of CPU and memory. It means that under normal circumstances, they put more load on your servers unnecessarily. If you want to be secure, still you need select your algorithm wisely, but it doesn't mean you should select the poorly implemented legacy APIs. – Ehsan Mirsaeedi Jan 05 '22 at 18:29
9

I don't really understand the full scope of your question, but if all you need is a hash of the string, then it's very easy to get that.

Just use the GetHashCode method.

Like this:

string hash = username.GetHashCode();
Cyril Gupta
  • 13,505
  • 11
  • 64
  • 87
  • 1
    Yes, that it what looking for. But it code is big mistake. Show write like int hash = "username".GetHasCode(); – Edy Cu Oct 21 '10 at 05:42
  • 3
    Why have you put username in double quotes? That will get the hash of the word 'username' and now what's in the username variable. – Cyril Gupta Oct 21 '10 at 07:14
  • 22
    don't store values from GetHashCode, it is different for 32x and 64x – Slava Oct 09 '13 at 16:08
  • 19
    This is a bad way of creating a password hash. With GetHashCode() you can't assume that the same number will be generated of different computer. Use Sha1 hash method or something (I'll post an example later) – andrew.fox Jan 10 '14 at 14:59
  • 2
    It should be noted that `GetHashCode` is not a cryptographically secure hashing algorithm. Use SHA256 at the very least or even better use BCrypt or Scrypt for a secure algorithm. – Muhammad Rehan Saeed Jan 11 '16 at 14:11
  • 1
    MSDN documentation: "The hash code itself is not guaranteed to be stable. Hash codes for identical strings can differ across versions of the .NET Framework and across platforms (such as 32-bit and 64-bit) for a single version of the .NET Framework. In some cases, they can even differ by application domain. As a result, hash codes should never be used outside of the application domain in which they were created, they should never be used as key fields in a collection, and they should never be persisted." - https://msdn.microsoft.com/en-us/library/system.string.gethashcode(v=vs.110).aspx – brijber Jul 05 '18 at 09:58
  • This type of hash is not the same across machines or even versions compiled on the same machine - wont work in this context. – MarzSocks Jan 10 '19 at 11:21
  • I also noticed that 'string.GetHashCode()' is not well distributed. I tried to fill a hashtable of 10000 items with test strings and it filled up the first 4600 completely while only sparsingly using the remaining space. So, much time is wasted looking for an empty hashtable bucket => not a good hash function at all! – AndresRohrAtlasInformatik Aug 22 '21 at 12:26
5

I think what you're looking for is not hashing but encryption. With hashing, you will not be able to retrieve the original filename from the "hash" variable. With encryption you can, and it is secure.

See AES in ASP.NET with VB.NET for more information about encryption in .NET.

Community
  • 1
  • 1
Pieter van Ginkel
  • 29,160
  • 8
  • 71
  • 111
3

The shortest and fastest way ever. Only 1 line!

    public static string StringSha256Hash(string text) =>
        string.IsNullOrEmpty(text) ? string.Empty : BitConverter.ToString(new System.Security.Cryptography.SHA256Managed().ComputeHash(System.Text.Encoding.UTF8.GetBytes(text))).Replace("-", string.Empty);
Erçin Dedeoğlu
  • 4,950
  • 4
  • 49
  • 69
  • 1
    Another 1-Line version using StringBuilder & Linq public static string Hash(string value) => string.IsNullOrEmpty(value) ? value : SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(value)).Aggregate(new StringBuilder(), (sb, b) => sb.Append(b.ToString("X2"))).ToString(); – Paul Dec 15 '20 at 12:11
1

If performance is not a major concern, you can also use any of these methods:
(In case you wanted the hash string to be in upper case, replace "x2" with "X2".)

public static string SHA256ToString(string s) 
{
    using (var alg = SHA256.Create())
        return string.Join(null, alg.ComputeHash(Encoding.UTF8.GetBytes(s)).Select(x => x.ToString("x2")));
}

or:

public static string SHA256ToString(string s)
{            
    using (var alg = SHA256.Create())
        return alg.ComputeHash(Encoding.UTF8.GetBytes(s)).Aggregate(new StringBuilder(), (sb, x) => sb.Append(x.ToString("x2"))).ToString();
}
Babak
  • 131
  • 2
0
//Secure & Encrypte Data
    public static string HashSHA1(string value)
    {
        var sha1 = SHA1.Create();
        var inputBytes = Encoding.ASCII.GetBytes(value);
        var hash = sha1.ComputeHash(inputBytes);
        var sb = new StringBuilder();
        for (var i = 0; i < hash.Length; i++)
        {
            sb.Append(hash[i].ToString("X2"));
        }
        return sb.ToString();
    }