How to Hash a String - C#

The process of hashing in cryptography is to map any string of any given length, to a string with a fixed length. This smaller, fixed length string is known as a hash.

To create a hash from a string, the string must be passed into a hash function.

What is a hash?

Unlike encryption, where the value can be decrypted, hash functions are a one-way street.

You can easily find the hash value of a string using a hash function, however it is not possible to get the value back from a hash.

Because of this property, hashes are commonly used to identify if a password, or other secure information is correct.

The user can input their password for the first time, and the server can save the hash value. When the user logs in later, the two hash values are compared, and the user is authenticated if they match.

Thanks to hashing, the sensitive data doesn't need to be sent across the internet, and it doesn't need to be stored on a server that could have a data breach later.

Examples of hashes

Here we have a hash of two strings, created using the SHA256 hash function (implemented in C# in the next section):

Input: Hello there!

Output: 89B8B8E486421463D7E0F5CAF60FB9CB35CE169B76E657AB21FC4D1D6B093603
Input: Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime mollitia,
molestiae quas vel sint commodi repudiandae consequuntur voluptatum laborum
numquam blanditiis harum quisquam eius sed odit fugiat iusto fuga praesentium
optio, eaque rerum!

Output: 03655505CC0F70EF1243B60DD994A19950536B4711580E399AEB2BB37CFD4BC4

Since a hash is a fixed value, there are a finite number of hash variations that can be made from an infinite number of string inputs. Therefore, given any particular hash string, there are an infinite number input strings that could have made that hash.

When two or more input values result in the same hash for a hash function, we call this a collision.

Creating a Hash in C#

You can create a hash in C# by using the SHA256Managed class within System.Security.Cryptography:

static string HashString(string text, string salt = "")
{
    if (String.IsNullOrEmpty(text))
    {
        return String.Empty;
    }
    
    // Uses SHA256 to create the hash
    using (var sha = new System.Security.Cryptography.SHA256Managed())
    {
        // Convert the string to a byte array first, to be processed
        byte[] textBytes = System.Text.Encoding.UTF8.GetBytes(text + salt);
        byte[] hashBytes = sha.ComputeHash(textBytes);
        
        // Convert back to a string, removing the '-' that BitConverter adds
        string hash = BitConverter
            .ToString(hashBytes)
            .Replace("-", String.Empty);

        return hash;
    }
}

Note that I've also added a salt parameter.

What is salt?

A salt is a private string that can be reliably retrieved when performing the hash in the future.

By adding a salt, it makes it significantly more difficult to associate a hash with the input value, particularly in the case when a common input string was used.

For example:

Input: 16-05-1986
Output: C551BEEF574D48CA63EDE8FC6B9E7905E5700B5BA8E42A9EC07544538974F2A3

While there are 2^256 combinations of the hashed value, a date in this format only has 365*(Number of years), and it's computationally easy to store all of those hash values in a key-value dictionary, and compare hashes to get the input.

Alternatively, adding "nf8n43nsd9s" as a salt:

Input: 16-05-1986nf8n43nsd9s
Output: F448A55F8429D52AEF06EB35B8D5E247DB89B91A548E2D3755438A07F9BEB26B

It's highly unlikely that this input string is stored in any dictionary anywhere.