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:
configProtectedData
: This section will have custom Provider Name given in the second step.
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 };
var rsa = new RSACryptoServiceProvider(cp) { PersistKeyInCsp = false };
rsa.Clear();
History