C# > Security and Cryptography > Cryptographic Operations > Hashing with SHA256

SHA256 with Salt Example

This example expands on the previous example by demonstrating how to incorporate a salt into the SHA256 hashing process for enhanced security, particularly when dealing with password storage. Using a salt makes rainbow table attacks significantly more difficult.

SHA256 Hashing with Salt

This code defines `SHA256SaltedHasher` class with two methods: `HashStringWithSalt` and `GenerateSalt`. The `HashStringWithSalt` method takes the input string and a salt, concatenates them, and then computes the SHA256 hash of the combined string. The `GenerateSalt` method generates a random salt using `RandomNumberGenerator`. It creates a 16-byte array and populates it with cryptographically secure random bytes, then converts it to a Base64 string for easier storage and handling. When storing a password, you'd store *both* the salt and the hashed password. When verifying the password, you'd retrieve the salt, hash the entered password with the stored salt, and compare the result to the stored hashed password.

using System;
using System.Security.Cryptography;
using System.Text;

public class SHA256SaltedHasher
{
    public static string HashStringWithSalt(string input, string salt)
    {
        // Combine the input and the salt
        string saltedInput = input + salt;

        using (SHA256 sha256Hash = SHA256.Create())
        {
            // ComputeHash - returns byte array
            byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(saltedInput));

            // Convert byte array to a string
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < bytes.Length; i++)
            {
                builder.Append(bytes[i].ToString("x2"));
            }
            return builder.ToString();
        }
    }

    public static string GenerateSalt()
    {
        // Generate a random salt (e.g., 16 bytes)
        byte[] saltBytes = new byte[16];
        using (var rng = RandomNumberGenerator.Create())
        {
            rng.GetBytes(saltBytes);
        }
        return Convert.ToBase64String(saltBytes);
    }

    public static void Main(string[] args)
    {
        string password = "mySecretPassword";
        string salt = GenerateSalt();
        string hashedPassword = HashStringWithSalt(password, salt);

        Console.WriteLine("Original Password: " + password);
        Console.WriteLine("Salt: " + salt);
        Console.WriteLine("Hashed Password: " + hashedPassword);
    }
}

Importance of Cryptographically Secure Random Number Generator

Using `RandomNumberGenerator` is crucial for generating secure salts. `RandomNumberGenerator` produces cryptographically strong random numbers, making it more difficult for attackers to predict the salts and compromise the system. Do not use `Random` class for generating salts. The `Random` class is not cryptographically secure.

Storing the Salt

It is crucial to store the salt along with the hashed password. The salt should be unique for each user. When a user attempts to log in, the system retrieves the salt associated with the user, combines it with the entered password, hashes the result, and compares it to the stored hashed password. The salt should be stored in the same database or storage location as the hashed password, ensuring that they are always available together.

Why Not Just Use a KDF (Key Derivation Function)?

While this example demonstrates salting with SHA256, modern best practices favor using dedicated Key Derivation Functions (KDFs) like PBKDF2, bcrypt, or Argon2 for password hashing. These KDFs incorporate salting, iterative hashing (repeating the hashing process multiple times to slow down attacks), and potentially adaptive parameters to increase security. They are specifically designed to be resistant to brute-force attacks and rainbow table attacks. Therefore, while this example illustrates the concept of salting, for real-world password storage, a KDF is strongly recommended.

FAQ

  • Why is it important to use a cryptographically secure random number generator for generating the salt?

    Using a cryptographically secure random number generator ensures that the salt is unpredictable. If the salt is predictable, attackers can precompute hashes and crack passwords more easily.
  • How long should the salt be?

    A salt should be at least 16 bytes (128 bits) long. This provides sufficient entropy to prevent rainbow table attacks.