schui schui - 3 months ago 28
C# Question

C# Cryptography Generic Method for any Algorithm

At the moment i have 3 different methods for md5, sha1 and sha512. Some small parts are different, like using statement. Is it possible to create a generic method for all of these? I'm a intermediate and some topics are quite new for me.
Below the code (simplified). Ignore the "ConvertHashToString" method.
Thank you!

public string CheckMd5(string filename)
{
using (var stream = File.OpenRead(filename))
{
using (var md5 = MD5.Create())
{
return ConvertHashToString(md5.ComputeHash(stream));
}
}

}

public string CheckSha512(string filename)
{
using (var stream = File.OpenRead(filename))
{
using (var sha = SHA512.Create())
{
return ConvertHashToString(sha.ComputeHash(stream));
}
}
}

Answer

You can simplify it a bit like this:

private string CheckHash(string filename, HashAlgorithm algorithm)
{
    using (var stream = File.OpenRead(filename))
    {
        using (algorithm) 
        {
            return ConvertHashToString(algorithm.ComputeHash(stream));
        }
    }
}

public string CheckMd5(string filename) => CheckHash(filename, MD5.Create());

public string CheckSha512(string filename) => CheckHash(filename, SHA512.Create());

If you want a single method, you need some way of specifying the algorithm. You can also use CryptoConfig.CreateFromName to create a hash instance from a string. Something like this:

public string CheckHash(string filename, string algorithm)
{
    using (var stream = File.OpenRead(filename))
    {
        using (var algorithm = (HashAlgorithm)CryptoConfig.CreateFromName(algorithm)) 
        {
            return ConvertHashToString(algorithm.ComputeHash(stream));
        }
    }
}

You probably want to validate that CryptoConfig.CreateFromName returned a HashAlgorithm before attempting to cast.

Finally, you can use generics, but this doesn't use the factory methods. The factory methods work better in the .NET Core scenario, but it doesn't sound like that's an issue for you since you are using WinForms.

public string Check<THash>(string filename) where THash:HashAlgorithm, new()
{
    using (var stream = File.OpenRead(filename))
    {
        using (var algorithm = new THash()) 
        {
            return ConvertHashToString(algorithm.ComputeHash(stream));
        }
    }
}

Which could be used like this:

CheckHash<SHA512Managed>(file);
Comments