Why do all the variants of SHA256 appear as SHA256Managed?
That's because you are always calling the same static method, SHA256.Create. SHA256 is an abstract class and its descendants do not provide an alternate method. In fact, Resharper will give you a warning that you are accessing a static member from a derived type.
In fact, calling SHA256.Create is the same as calling HashAlgorithm.Create. Both classes call the same implementation internally and simply cast the result to different types.
The SHA256.Create method will create the default implementation that is specified in machine.config and can be overriden in your app.config
If you want to use a specific provider, use SHA256.Create(string) passing the name of the provider you want to use.
Examples are:
SHA256.Create("System.Security.Cryptography.SHA256Cng");
HashAlgorithm.Create("System.Security.Cryptography.SHA256Cng");
SHA256.Create("System.Security.Cryptography.SHA256CryptoServiceProvider");
EDIT
The documentation of HashAlgorithm.Create specifies a list of valid algorithm names. The MSDN article Mapping Algorithm Names to Cryptography Classes describes how you can map algorithm names to other providers (your own, third-party, hardware-accelerated or whatever) and use them instead of the default algorithms.
EDIT 2
It is also possible to change the mappings programmatically. So, to map "Dog" to the SHA512CryptoServiceProvider, you just need to write:
CryptoConfig.AddAlgorithm(
typeof(System.Security.Cryptography.SHA512CryptoServiceProvider),
"Dog");
var t4 = HashAlgorithm.Create("Dog");
Related videos on Youtube
Electric Coffee
Software Engineer at Valhal Connect My Fields of interest are programming in Java, Scala, F#, Haskell, and Objective-C, FLOSS, POSIX, digital design, and making stuff.
Updated on June 17, 2022Comments
-
Electric Coffee almost 2 years
I'm writing an extension method that simplifies the creation of hashes by removing a ton of boilerplate, my problem is however that whenever I step through the code, I can see that it always picks
SHA256Managed
, regardless of whether or not I callSHA256.Create()
,SHA256Cng.Create()
,SHA256Managed.Create()
orSHA256CryptoServiceProvider.Create()
It's the same story when I pick a different hashing algorithm like MD5, but in the case of MD5 it always picks
MD5CryptoServiceProvider
regardless of class that I actually use...Why is that?
Here's my code:
using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; namespace Utility.Methods { public enum HashType { MD5, SHA512, SHA256, SHA384, SHA1 } public enum HashSubType {Normal, Cng, Managed, CryptoServiceProvider} public static class TextHasher { public static string Hash(this string input, HashType hash, HashSubType subType = HashSubType.Normal) { Func<HashAlgorithm, string> hashFunction = alg => HashingHelper(input, alg); switch (subType) { case HashSubType.Normal: return hashFunction(NormalHashes(hash)); case HashSubType.Cng: return hashFunction(CngHashes(hash)); case HashSubType.Managed: return hashFunction(ManagedHashes(hash)); case HashSubType.CryptoServiceProvider: return hashFunction(CSPHashes(hash)); default: return "error"; // unreachable } } private static string HashingHelper(string text, HashAlgorithm algorithm) { Func<string, byte[]> getHash = input => algorithm.ComputeHash(Encoding.UTF8.GetBytes(input)); var sb = new StringBuilder(); Array.ForEach(getHash(text), b => sb.Append(b.ToString("X"))); return sb.ToString(); } private static HashAlgorithm NormalHashes(HashType hash) { switch (hash) { case HashType.MD5: return MD5.Create(); case HashType.SHA1: return SHA1.Create(); case HashType.SHA256: return SHA256.Create(); case HashType.SHA384: return SHA384.Create(); case HashType.SHA512: return SHA512.Create(); default: return null; // unreachable } } private static HashAlgorithm CngHashes(HashType hash) { switch (hash) { case HashType.MD5: return MD5Cng.Create(); case HashType.SHA1: return SHA1Cng.Create(); case HashType.SHA256: return SHA256Cng.Create(); case HashType.SHA384: return SHA384Cng.Create(); case HashType.SHA512: return SHA512Cng.Create(); default: return null; // unreachable } } private static HashAlgorithm ManagedHashes(HashType hash) { switch (hash) { case HashType.SHA1: return SHA1Managed.Create(); case HashType.SHA256: return SHA256Managed.Create(); case HashType.SHA384: return SHA384Managed.Create(); case HashType.SHA512: return SHA512Managed.Create(); default: return null; // unreachable } } private static HashAlgorithm CSPHashes(HashType hash) { switch (hash) { case HashType.MD5: return MD5CryptoServiceProvider.Create(); case HashType.SHA1: return SHA1CryptoServiceProvider.Create(); case HashType.SHA256: return SHA256CryptoServiceProvider.Create(); case HashType.SHA384: return SHA384CryptoServiceProvider.Create(); case HashType.SHA512: return SHA512CryptoServiceProvider.Create(); default: return null; // unreachable } } } }
So, any help?
-
Damien_The_Unbeliever over 10 years1) You can directly construct other versions of the class if that's what you want to obtain, 2) You can use the overload of
Create
that accepts a string to choose a non-default, and 3) Which class to construct if you use this overload is configured at the machine level and not hard coded. -
Electric Coffee over 10 yearsthat's not exactly helpful if the doc doesn't specify what strings are legal to use... I could essentially do
SHA256.Create("Dog");
-
-
Electric Coffee over 10 yearsbut I don't use sha256.create every time... I use sha256Managed.create and sha256Cng.create for the others, and it still gives me the same result...
-
Damien_The_Unbeliever over 10 years@ElectricCoffee - there is no
sha256Managed.Create
method - butsha256Managed
inherits fromSha256
and so the call can be compiled. -
Panagiotis Kanavos over 10 yearsThe point of what? You are calling a static method the wrong way. If you want to create different implementations, just use Create(string) with the name of the provider
-
Electric Coffee over 10 yearsyeah thanks, it'd help if I knew what the string should contain, because the documentation doesn't tell me this... You know what? I'm gonna make a
SHA256.Create("Dog");
-
Panagiotis Kanavos over 10 yearsJust use the type names. I added some examples
-
Electric Coffee over 10 yearsI seriously don't understand why microsoft didn't just have the class names go there instead of strings
-
Panagiotis Kanavos over 10 yearsThat's what they did. These are the class names. You can also define more entries, install third-party providers that will have to be identified in a transparent way
-
Panagiotis Kanavos over 10 yearsThen how would you use third-party providers or new OS implementations without recompiling?
-
Electric Coffee over 10 yearsmake it easy to extend the class?