3

I'm really new with C# and I'm looking at code that my predecessor generated. Here's the code:

public static string ComputeHash(string plainText,
                                     string hashAlgorithm, byte[] saltBytes)
    {
        if (saltBytes == null)
            saltBytes = CreateSalt(8);

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

    public static bool VerifyHash(string plainText,
                                  string hashAlgorithm,
                                  string hashValue)
    {
        // Convert base64-encoded hash value into a byte array.
        byte[] hashWithSaltBytes = Convert.FromBase64String(hashValue);

        // We must know size of hash (without salt).
        int hashSizeInBits, hashSizeInBytes;

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

        // Size of hash is based on the specified algorithm.
        switch (hashAlgorithm.ToUpper())
        {
            case "SHA1":
                hashSizeInBits = 160;
                break;

            case "SHA256":
                hashSizeInBits = 256;
                break;

            case "SHA384":
                hashSizeInBits = 384;
                break;

            case "SHA512":
                hashSizeInBits = 512;
                break;

            default: // Must be MD5
                hashSizeInBits = 128;
                break;
        }

        // Convert size of hash from bits to bytes.
        hashSizeInBytes = hashSizeInBits / 8;

        // Make sure that the specified hash value is long enough.
        if (hashWithSaltBytes.Length < hashSizeInBytes)
            return false;

        // Allocate array to hold original salt bytes retrieved from hash.
        byte[] saltBytes = new byte[hashWithSaltBytes.Length -
                                    hashSizeInBytes];

        // Copy salt from the end of the hash to the new array.
        for (int i = 0; i < saltBytes.Length; i++)
            saltBytes[i] = hashWithSaltBytes[hashSizeInBytes + i];

        // Compute a new hash string.
        string expectedHashString =
                    ComputeHash(plainText, hashAlgorithm, saltBytes);

        // If the computed hash matches the specified hash,
        // the plain text value must be correct.
        return (hashValue == expectedHashString);
    }

The company has upgraded their security standards and requires secure hashing algorithms such as SHA-1, 3DES (triple DES) or AES MAC. I have no idea where to include them. Would someone please help?

3
  • 3
    3DES is not a hashing algorithm... and AES MAC sounds like a MAC, not a hash. Commented Jan 11, 2012 at 15:40
  • @KerrekSB isn't 3DES the same as Triple DES? I think that is a hashing algorithm. And isn't MAC (message authentication code) based on Poly1305-AES? Correct me if I'm wrong, because I'm really new to all this. Commented Jan 11, 2012 at 15:57
  • 4
    You should definitely keep a very wide berth around crypto topics until you have a very firm understanding of the matter and can answer those questions yourself! (3DES (= Triple DES) is a cipher; and a MAC is a MAC, not a hash -- it is possible to design a MAC using a hash (e.g. HMAC), but that's a separate topic.) Commented Jan 11, 2012 at 16:00

3 Answers 3

2

The company has upgraded their security standards and requires secure hashing algorithms such as SHA-1, 3DES (triple DES) or AES MAC.

First of all, you already have SHA-1, and that hash algorithm, although slightly weaker than SHA-256/512, is still pretty good. Sticking to SHA-512 will keep you very safe, unless you are dealing with villains which are willing to spend 10 years breaking your messages using a supercomputer.

As for the other two algorithms, 3DES is a symmetric cypher and therefore unsuitable for hashing, while MACs are created using hashing algorithms such as SHA-2 (the difference is that you hash you a "secret key" along your message (something like "fixed salt") to ensure its authenticity. AES is also a symmetric cypher, and therefore also unsuitable for hashing.

Tell the guys from your company to check this page and settle for one of these hashing functions (in other words: don't change anything). If you are not experienced with cryptography, chances are you might make the system insecure regardless of your hashing choice.

Sign up to request clarification or add additional context in comments.

Comments

1

I assume by "AES MAC" you are referring to Poly1305-AES. Poly1305-AES isn't a simple hash, it needs a AES key, and a 128 bit nonce, which is used when you communicate between two entities.

3DES (Triple DES) is an encryption cipher, it doesn't ensure authentication or integrity of a message whatsoever. The only function of 3DES is to ensure confidentiality of a message.

In respect to SHA-1, you should no longer use that hash as it has been broken since 2005.

I would suggest you get a formal description of what these new security standards are. 2 of the things you listed aren't even hash algorithms, and the third is a bad choice. Of the hash algorithms listed in your current implementation SHA-256 and above should be fine (aka SHA-2 category). These don't have any published vulnerabilities I am aware of at the moment.

Side note: You probably want to use arraycopy instead of looping over the bytes.

Comments

0

There's an HMAC type in the .NET Framework base class library that would probably be useful for you.

You might also be able to use all or part of my C# password utilities library. But you would need to adapt it to add more hash types. I wrote a series of blog entries that explain why and how this library was constructed.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.