A C# class to easily create an md5, sha1, sha256, or sha512 hash

I started making a class to make hashing easier in C#. I found someone who had done this already here: http://techlicity.com/blog/dotnet-hash-algorithms

That was a good start. I just needed to:

  1. Add unit tests
  2. Remove the duplicate code (condense the class)
  3. Add a default values, such as a default Encoding and to use sha256 by default.
  4. Add easier salt handling.

I condensed the code (by more than half the lines by the way) and now have this much easier to read and test class:

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

namespace WcfSimpleTokenExample.Business
{
    public class Hash
    {
        public static Encoding DefaultEncoding = Encoding.UTF8;
        public const HashType DefaultHashType = HashType.SHA256;

        public enum HashType
        {
            MD5,
            SHA1,
            SHA256,
            SHA512
        }

        public static string Get(string text, HashType hashType = DefaultHashType, Encoding encoding = null)
        {
            switch (hashType)
            {
                case HashType.MD5:
                    return Get(text, new MD5CryptoServiceProvider(), encoding);
                case HashType.SHA1:
                    return Get(text, new SHA1Managed(), encoding);
                case HashType.SHA256:
                    return Get(text, new SHA256Managed(), encoding);
                case HashType.SHA512:
                    return Get(text, new SHA512Managed(), encoding);
                default:
                    throw new CryptographicException("Invalid hash alrgorithm.");
            }
        }

        public static string Get(string text, string salt, HashType hashType = DefaultHashType, Encoding encoding = null)
        {
            return Get(text + salt, hashType, encoding);
        }

        public static string Get(string text, HashAlgorithm algorithm, Encoding encoding = null)
        {
            byte[] message = (encoding == null) ? DefaultEncoding.GetBytes(text) : encoding.GetBytes(text);
            byte[] hashValue = algorithm.ComputeHash(message);
            return hashValue.Aggregate(string.Empty, (current, x) => current + string.Format("{0:x2}", x));
        }

        public static bool Compare(string original, string hashString, HashType hashType = DefaultHashType, Encoding encoding = null)
        {
            string originalHash = Get(original, hashType, encoding);
            return (originalHash == hashString);
        }

        public static bool Compare(string original, string salt, string hashString, HashType hashType = DefaultHashType, Encoding encoding = null)
        {
            return Compare(original + salt, hashString, hashType, encoding);
        }
    }
}

Here are some unit tests using MSTest.

using System;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using WcfSimpleTokenExample.Business;

namespace WcfSimpleTokenExample.Tests
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void MD5Test()
        {
            // Arrange
            const string tobehashed = "1";
            // Got comparison hash from here: http://www.xorbin.com/tools/md5-hash-calculator
            // Also verified with md5sums.exe
            const string expectedHash = "c4ca4238a0b923820dcc509a6f75849b";

            // Act
            string actualHash = Hash.Get(tobehashed, Hash.HashType.MD5);

            // Assert
            Assert.AreEqual(expectedHash, actualHash);
        }

        [TestMethod]
        public void Sha1Test()
        {
            // Arrange
            const string tobehashed = "1";
            // Got comparison hash from here: http://www.xorbin.com/tools/sha1-hash-calculator
            // Also verified with sha1sums.exe
            const string expectedHash = "356a192b7913b04c54574d18c28d46e6395428ab";

            // Act
            string actualHash = Hash.Get(tobehashed, Hash.HashType.SHA1);

            // Assert
            Assert.AreEqual(expectedHash, actualHash);
        }

        [TestMethod]
        public void Sha256Test()
        {
            // Arrange
            const string tobehashed = "1";
            // Got comparison hash from here: http://www.xorbin.com/tools/sha256-hash-calculator
            // Also verified with sha1sums.exe
            const string expectedHash = "6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b";

            // Act
            string actualHash = Hash.Get(tobehashed, Hash.HashType.SHA256);

            // Assert
            Assert.AreEqual(expectedHash, actualHash);
        }

        [TestMethod]
        public void Sha512Test()
        {
            // Arrange
            const string tobehashed = "1";
            // Got comparison hash from here:  http://www.miniwebtool.com/sha512-hash-generator/
            const string expectedHash = "4dff4ea340f0a823f15d3f4f01ab62eae0e5da579ccb851f8db9dfe84c58b2b37b89903a740e1ee172da793a6e79d560e5f7f9bd058a12a280433ed6fa46510a";

            // Act
            string actualHash = Hash.Get(tobehashed, Hash.HashType.SHA512);

            // Assert
            Assert.AreEqual(expectedHash, actualHash);
        }
    }
}

Leave a Reply

How to post code in comments?