One option is to use the application's properties to define the default algorithms if that machine.config file does not contain them. One possible scenario, and the one I will use here, is that all of your base crypto files/utils can extend from a base class that uses a static constructor to ensure that either the machine.config values exist OR that they are added to the CryptoConfig configuration from a property file. There are other ways to initialize the CryptoConfig, of course, but this one is easy and works well. However, it is important to note, that if an exception is thrown within the static constructor, that the application will NOT terminate and the class file will be left in an unusable state, so please make sure you code for this. Some might consider this a bad decision (to use this static constructor), but I think it depends on your situation - in my case, if this fails that application can't be used, thus I check for this and fail out gracefully.
Now on to the example. First create a base class from which your others can extend:
public abstract class Cryptography
{
static Cryptography()
{
}
}
Before we fill in the static constructor, let's add a couple methods that we will be using within the constructor. The first method will be the one used to register with CryptoConfig the algorithm defined in the properties file. This will be used when the machine.config file is missing the mapping or when there is a desire to override it (more on this option shortly).
private static void SetAlgorithm(
string name, string cryptoType)
{
CryptoConfig config = new CryptoConfig();
Type type = Type.GetType(cryptoType);
CryptoConfig.AddAlgorithm(type, name);
}
The next method is the main method to check if the value is in the machine.config file, it it is not (the call to CreateFromName will return null), then it will call SetAlgorithm to set the type based on what is in the configuration file. You must ensure there is a value in the configuration file as this class doesn't handle the situation where it is not (or add your own defaults to this class).
private static void SetConfiguration(
string name, string type)
{
object algorithm = CryptoConfig.CreateFromName(type);
if (algorithm == null)
{
SetAlgorithm(name, type);
}
}
Finally, back to the static constructor. In order to allow overrides, we use a property to indicate that we should use the local settings rather than machine.config values. In order to reduce code, I am using an action delegate to define that the method "SetAlgorithm" should be used when the UseLocalSettings property is set to true; thus, when this property is true, even if the algorithm is configured in machine.config, the local setting will be used instead.
static Cryptography()
{
Action action = SetConfiguration;
if(Properties.Settings.Default.UseLocalSettings)
{
action = SetAlgorithm;
}
action("Hash256", Properties.Settings.Default.Hash256);
action("Hash512", Properties.Settings.Default.Hash512);
action("Symmetric", Properties.Settings.Default.Symmetric);
action("Asymmetric", Properties.Settings.Default.Asymmetric);
}
Edit: Thanks to a post from a google+ follower (Chris Eargle) I realized there was one omission (the generics on my Action) and a more elegant way to set the action method (ternary expression).
Action<string, string> action =
Properties.Settings.Default.UseLocalSettings ?
SetAlgorithm : SetConfiguration;
Finally, you just need to set these properties in your app.config file. Each of the hash algorithms are strings and the UseLocalSettings property is a bool. Example settings for the algorithm's values are as follows (for .Net 4.0):
Hash256=System.Security.Cryptography.SHA256CryptoServiceProvider,
System.Core, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
Hash512=System.Security.Cryptography.SHA512CryptoServiceProvider,
System.Core, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
Symmetric=System.Security.Cryptography.AesCryptoServiceProvider,
System.Core, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
Asymmetric=System.Security.Cryptography.RSACryptoServiceProvider,
mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
I hope someone finds this useful... Feel free to comment if you have suggestions on how this can be improved or if you have questions about the content.