0

I have been going crazy trying to figure this out. Is there a simple way in C# to take a string like "password123" and a salt "vfs5%S]m(_*Y+Tk" and generate a single MD5 Hash. Basically what the website http://free-online-web-tools.com/tool/md5 does but with C#.

  • [MD5 Class](https://msdn.microsoft.com/en-us/library/system.security.cryptography.md5(v=vs.110).aspx) – Ňɏssa Pøngjǣrdenlarp May 30 '15 at 21:41
  • 1
    there is an answer to this question already http://stackoverflow.com/questions/1300890/md5-hash-with-salt-for-keeping-password-in-db-in-c-sharp – Igor Popov May 30 '15 at 21:46
  • 3
    I'm.not sure why you're doing this but it is dated technology for password storage. – Neil Smithline May 31 '15 at 00:41
  • The duplicate link does not provide good answers, MD5 as well as SHA-* are **not** appropriate to hash passwords, because they are way too fast and therefore can be brute-forced too easily. – martinstoeckli Jun 01 '15 at 07:17

1 Answers1

0

The below given function generates a hash for the given plain text value and returns a base64-encoded result. Before the hash is computed, a random salt is generated and appended to the plain text. This salt is stored at the end of the hash value, so it can be used later for hash verification.

Plaintext value to be hashed. The function does not check whether this parameter is null.

Name of the hash algorithm. Allowed values are: "MD5", "SHA1","SHA256", "SHA384", and "SHA512" (if any other value is specified MD5 hashing algorithm will be used). This value is case-insensitive.

In your case set hashAlgorithm to "MD5"

Salt bytes. This parameter can be null, in which case a random salt value will be generated.

Hash value formatted as a base64-encoded string.

public static string ComputeHash(string   plainText,
                                 string   hashAlgorithm,
                                 byte[]   saltBytes)
{
    // If salt is not specified, generate it on the fly.
    if (saltBytes == null)
    {
        // Define min and max salt sizes.
        int minSaltSize = 4;
        int maxSaltSize = 8;

        // Generate a random number for the size of the salt.
        Random  random = new Random();
        int saltSize = random.Next(minSaltSize, maxSaltSize);

        // Allocate a byte array, which will hold the salt.
        saltBytes = new byte[saltSize];

        // Initialize a random number generator.
        RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();

        // Fill the salt with cryptographically strong byte values.
        rng.GetNonZeroBytes(saltBytes); 
    }

    // Convert plain text into a byte array.
    byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);

    // Allocate array, which will hold plain text and salt.
    byte[] plainTextWithSaltBytes = 
            new byte[plainTextBytes.Length + saltBytes.Length];

    // Copy plain text bytes into resulting array.
    for (int i=0; i < plainTextBytes.Length; i++)
        plainTextWithSaltBytes[i] = plainTextBytes[i];

    // Append salt bytes to the resulting array.
    for (int i=0; i < saltBytes.Length; i++)
        plainTextWithSaltBytes[plainTextBytes.Length + i] = saltBytes[i];

    // Because we support multiple hashing algorithms, we must define
    // hash object as a common (abstract) base class. We will specify the
    // actual hashing algorithm class later during object creation.
    HashAlgorithm hash;

    // Make sure hashing algorithm name is specified.
    if (hashAlgorithm == null)
        hashAlgorithm = "";

    // Initialize appropriate hashing algorithm class.
    switch (hashAlgorithm.ToUpper())
    {
        case "SHA1":
            hash = new SHA1Managed();
            break;

        case "SHA256":
            hash = new SHA256Managed();
            break;

        case "SHA384":
            hash = new SHA384Managed();
            break;

        case "SHA512":
            hash = new SHA512Managed();
            break;

        default:
            hash = new MD5CryptoServiceProvider();
            break;
    }

    // Compute hash value of our plain text with appended salt.
    byte[] hashBytes = hash.ComputeHash(plainTextWithSaltBytes);

    // Create array which will hold hash and original salt bytes.
    byte[] hashWithSaltBytes = new byte[hashBytes.Length + 
                                        saltBytes.Length];

    // Copy hash bytes into resulting array.
    for (int i=0; i < hashBytes.Length; i++)
        hashWithSaltBytes[i] = hashBytes[i];

    // Append salt bytes to the result.
    for (int i=0; i < saltBytes.Length; i++)
        hashWithSaltBytes[hashBytes.Length + i] = saltBytes[i];

    // Convert result into a base64-encoded string.
    string hashValue = Convert.ToBase64String(hashWithSaltBytes);

    // Return the result.
    return hashValue;
}

For more details refer here.

user2321465
  • 139
  • 6
  • Why do you support a range of sizes for salt? High entropy in salt increases attack difficulty. I don't think I've ever seen a variable size salt. – Neil Smithline May 31 '15 at 05:40
  • Fast algorithms like MD5 or SHA-* are not appropriate to hash passwords, because they can be brute-forced too easily. Instead one should use a slow hash function with a cost factor like BCrypt or PBKDF2, in this [answer](http://stackoverflow.com/a/14475388/575765) you can find links to examples for CSharp. – martinstoeckli Jun 01 '15 at 07:13