Create RSA Key Container and Encrypt/Decrypt Config in C# - CodeProject

:

: 4

Introduction

Securing connection strings and other sensitive data in .NET application can be achieved by aspnet_regiis.exe located at %systemroot%\Microsoft.NET\Framework\ in your local system (You can read more at https://msdn.microsoft.com/en-us/library/ms178372%28v=vs.140%29.aspx). The encrypted connection string or any other encrypted section can be easily read by .NET application same as non-encrypted sections. This is really nice if you want to secure any section in your App or Web Config.

Usually, there is more than one QA, UAT and Prod servers in companies and the same application is replicated in all servers with the same config file to achieve load balancing. In order to secure and read encrypted sections on each QA or Prod servers, it is good idea to create RSA Key Container. So you can create RSA Key Container on one server and export it as XML. On other servers, you only need to import that XML key and encrypted config sections would start working on that server. So the server that will have XML key would only be able to decrypt encrypted sections which is a more secure approach. You can also specify the key size when creating a new RSA Key Container, 4096 is the recommended size. Default RsaProtectedConfigurationProvider provider is 1024 in size. To read more about RSA Key Container, please see https://msdn.microsoft.com/en-us/library/yxw286t2%28v=vs.140%29.aspx.

You can create RSA Key Container, Encrypt/Decrypt using aspnet_regiis.exe commands but in this post, I will explain how to do it in C# Windows Application.

Create RSA Key Container

In order to create RSA Key Container, there might be three input parameters; Key_Name, Key_Size and Export_Key_Path.

Following is the code snippet to create a new RSA Key Container, for simplicity purposes, export XML key name is the same as Key Container Name:

var cp = new CspParameters
                {
                    KeyContainerName = Key_Name,
                    Flags = CspProviderFlags.NoPrompt | CspProviderFlags.UseArchivableKey
                   | CspProviderFlags.UseMachineKeyStore,
                    KeyNumber = 1
                };
                using (var rsa = new RSACryptoServiceProvider(Key_Size, cp))
                {
                    using (
                        var fs = new FileStream(
                            String.Concat(Export_Key_Path, "\\", Key_Name, ".xml"), FileMode.Create))
                    {
                        using (StreamWriter sw = new StreamWriter(fs))
                        {
                            rsa.PersistKeyInCsp = true;
                            sw.WriteLine(rsa.ToXmlString(true));
                        }
                    }
                }

Encrypt/Decrypt AppSettings Section

For this example, I am encrypting AppSettings section of Web or App Config, but you can encrypt any section like Connection String. Input parameters for this function are Config_File_Path, Section_Name, PROVIDER_NAME and IS_Encrypt flag. The provider name can be any meaningful string.

The following code snippet will encrypt AppSetting section, if it is already encrypted, it will decrypt the specified section:

var configMap = new ExeConfigurationFileMap { ExeConfigFilename = Config_File_Path};
var configuration = ConfigurationManager.OpenMappedExeConfiguration
				(configMap, ConfigurationUserLevel.None);

var configSection = configuration.GetSection(Section_Name) as AppSettingsSection;

if (configSection != null && ((!(configSection.ElementInformation.IsLocked)) 
	&& (!(configSection.SectionInformation.IsLocked))))
{
 if (!configSection.SectionInformation.IsProtected && IS_Encrypt)
 {
  CreateProtectedDataConfig(configuration);
  configSection.SectionInformation.ProtectSection(PROVIDER_NAME);
}
else
{
 configSection.SectionInformation.UnprotectSection();
}
 configSection.SectionInformation.ForceSave = true;
 configuration.Save();
}

Embed Encrypted AppSettings in Web or App Config

Once you are done with the second step Encrypt/Decrypt AppSettings Section, you can see two sections in encrypted config:

  1. configProtectedData: This section will have custom Provider Name given in the second step.
  2. appSettings: Custom Provider Name with encrypted data.

Go to your application config file where this encrypted appSettings are needed to place, remove the existing appSettings section and paste above given two sections (configProtectedData and encrypted appSettings).

So these steps are enough for a single server, you don't need to make any coding changing in .NET application, ConfigurationManager.AppSetting will still read your encrypted appSetting.

Import Existing Key Container

If you want to use the same encrypted appSettings on other servers, all you need is exported RSA Key Container XML file generated in the first step. XML file name is kept as RSA Key Container name.

Following is the code snippet to import XML Key Container, input parameter is Key_Container_Name and Import_File_Path.

var prm = new CspParameters
{
  KeyContainerName = Key_Container_Name,
  Flags = CspProviderFlags.UseMachineKeyStore
};

using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(prm))
{
  using (FileStream fs = new FileStream(Import_File_Path, FileMode.Open))
  {
   using (StreamReader sr = new StreamReader(fs))
    {
     rsa.FromXmlString(sr.ReadToEnd());
     txtImportKeyContainer.Text = rsa.CspKeyContainerInfo.KeyContainerName;
    }
  }
}

Check Existing RSA Key Container

Before creating any RSA Key Container, you can check if your given RSA Key Container name does exist already, following is the code snippet, input parameter is Key_Container_Name:

var cspParams = new CspParameters
{
Flags = CspProviderFlags.UseExistingKey,
KeyContainerName = Key_Container_Name 
};

try
{
  new RSACryptoServiceProvider(cspParams);
}
catch (Exception)
{
  return false;
}
return true;

Delete RSA Key Container

The following code snippet helps to delete existing RSA Key Container, input parameter is Key_Container_Name:

var cp = new CspParameters { KeyContainerName = Key_Container_Name };

// Create a new instance of RSACryptoServiceProvider that accesses
// the key container.
var rsa = new RSACryptoServiceProvider(cp) { PersistKeyInCsp = false };

// Delete the key entry in the container.

// Call Clear to release resources and delete the key from the container.
rsa.Clear();

History