Generating an exportable / movable RSA key and encrypting using your custom key
- Generate an RSA Key container
aspnet_regiis -pc "SampleKeys" –exp - Tie the RSA key container to your web.config (<configProtectedData> is a top-level key, like connectionStrings or appSettings) - note that this should be identical to the config for RsaProtectedConfigurationProvider in your machine.config, with a different value for the defaultProvider, name and keyContainerName attributes.
<configProtectedData defaultProvider="SampleProvider">
<providers>
<add name="SampleProvider" type="System.Configuration.RsaProtectedConfigurationProvider,System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" description="Uses RsaCryptoServiceProvider to encrypt and decrypt" keyContainerName="SampleKeys" cspProviderName="" useMachineContainer="true" useOAEP="false"/>
</providers>
</configProtectedData> - Grant access to the key container to the user your process runs as
aspnet_regiis -pa "SampleKeys" "ASPNET"- This sets up permissions for the "default" RsaProtectedConfigurationProvider. I had to set this up for the ASPNET user along with permissions for my own container above.
aspnet_regiis -pa "NetFrameworkConfigurationKey" "ASPNET" - If the user your process is running as doesn't have permission to use the provider, you'll get an error "Failed to decrypt using provider 'RsaProtectedConfigurationProvider'."
- I recently ran into a server that didn't have the "NetFrameworkConfigurationKey" - I think this is part of the normal .NET Framework setup so I don't know why it might have been missing. Generating the key fixed the problem:
aspnet_regiis -pc "NetFrameworkConfigurationKey"
- This sets up permissions for the "default" RsaProtectedConfigurationProvider. I had to set this up for the ASPNET user along with permissions for my own container above.
- Encrypting strings - if you're not using the default site you'll need the site identifier (shown in IIS manager window under "Web Sites"?)
aspnet_regiis -pe "connectionStrings" -site 1 -app "/SampleApplication" -prov "SampleProvider" - Other Useful Commands
- Decrypting strings (in case you need to change something)
aspnet_regiis -pd "connectionStrings" -app "/SampleApplication" - Export the public and private keys for import on another machine
aspnet_regiis -px "SampleKeys" keys.xml -pri - Importing the keys
aspnet_regiis -pi "SampleKeys" keys.xml - Removing access to a no longer needed key
aspnet_regiis -pr "SampleKeys" "ASPNET" - Deleting a no longer needed key container
aspnet_regiis -pz "SampleKeys"
- Decrypting strings (in case you need to change something)
Using encrypted strings in code
Most of the canned demo code on the internet shows you opening, testing for the strings to be encrypted, decrypting them, then saving the config file back. I don't think I want to save the unencrypted strings, as this would seem to defeat the purpose of encrypting them in the first place. I may be misunderstanding the code samples, but this is what I came up with and it makes more sense to me.
static string GetProtectedConnectionString(string name)
{
// Open the Web.config file.
Configuration config = WebConfigurationManager.
OpenWebConfiguration("~");
// Get the connectionStrings section.
ConnectionStringsSection section =
config.GetSection("connectionStrings")
as ConnectionStringsSection;
// Toggle encryption.
if (section.SectionInformation.IsProtected)
{
section.SectionInformation.UnprotectSection();
ConnectionStringSettings s = section.ConnectionStrings[name];
return s.ConnectionString;
}
else
{
throw new ConfigurationException("Warning: connection strings are not encrypted");
}
}
This code probably needs a bit more cleanup. The point is, you don't save the unprotected section, but you decrypt the section long enough to get the string from the config file that you were looking for. Note that you could easily modify this to just return the connection string whether or not it was encrypted but I decided I'd rather be notified if the config ends up unprotected for some reason. Which brings up a valuable point: when you re-publish your site, you will need to re-encrypt your strings! Add this as a post-build step!
Useful links
Securing Connection Strings
http://msdn.microsoft.com/en-us/library/89211k9b(VS.80).aspx
Encrypting Configuration Information Using Protected Configuration
http://msdn.microsoft.com/en-us/library/53tyfkaw(VS.80).aspx
Importing and Exporting Protected Configuration RSA Key Containers
http://msdn.microsoft.com/en-us/library/yxw286t2(VS.80).aspx
Walkthrough of encrypting connection strings and accessing them from ASPx
http://msdn.microsoft.com/en-us/library/dtkwfdky(VS.80).aspx
How To: Encrypt with ASP.NET 2.0 using RSA
http://msdn.microsoft.com/en-us/library/ms998283.aspx