Encrypting configuration files using protected configuration

One of the cool security features in ASP.NET 2.0 is the ability to parts of web.config. Web.config encryption uses XML encryption standards at its core.

Protected configuration uses a class derived from the abstract class ProtectedConfigurationProvider. .NET framework has shipped with two providers RSAProtectedConfigurationProvider which uses TripleDES and RSA encryption and DPAPIProtectedConfigurationProvider which uses Windows Data Protection API (DPAPI)

For more comprehensive information about this topic, please refer to MSDN

Protected configuration in action:

One of the most common uses of the protected configuration is to encrypt connection strings in web.confg (that's one of the reasons for creating a separate tag for connection strings instead of adding it in appSettings tag).

Let's say we have a connection string tag like this

<connectionStrings>

<add name="advWorks" connectionString="Data Source=.\yukon;Initial Catalog=AdventureWorks;User ID=webUser;pwd=my_P@ssw0rd" />

</connectionStrings>

Adding this connection string as plain text is not the best practice for web application security and this might cause serious hacking problems. To encrypt this tag only, you could use the encryption classes in .NET framework or use the handy tool ASPNet_regiis.exe.

Assuming that this application located in https://localhost/testwebCS2, we could use ASPNet_regiis.exe as following

aspnet_regiis -pe connectionStrings -app /testwebcs2

This line will use RSAProtectedConfigurationProvider to encrypt the tag connectionStrings in the application called /testwebCS2.

Then this tag would be as following (I omitted most of the cipher base64 strings to preserve space)

<connectionStrings configProtectionProvider="RsaProtectedConfigurationProvider">

        <EncryptedData Type="https://www.w3.org/2001/04/xmlenc#Element"

            xmlns="https://www.w3.org/2001/04/xmlenc#">

            <EncryptionMethod Algorithm="https://www.w3.org/2001/04/xmlenc#tripledes-cbc" />

            <KeyInfo xmlns="https://www.w3.org/2000/09/xmldsig#">

                <EncryptedKey xmlns="https://www.w3.org/2001/04/xmlenc#">

                    <EncryptionMethod Algorithm="https://www.w3.org/2001/04/xmlenc#rsa-1_5" />

                    <KeyInfo xmlns="https://www.w3.org/2000/09/xmldsig#">

                        <KeyName>Rsa Key</KeyName>

     </KeyInfo>

             <CipherData>

                    <CipherValue>YojkA1KgIR1nnThk=</CipherValue>

                    </CipherData>

                </EncryptedKey>

            </KeyInfo>

            <CipherData>

                <CipherValue>8h+tauv00O52DdGHFKSv =</CipherValue>

     </CipherData>

        </EncryptedData>

    </connectionStrings>

As you can see in the previous XML, the data itself encrypted using the symmetric encryption algorithm called Triple DES. The key used to encrypt the data is embedded but it's also encrypted using RSA.

But where's the key to decrypt that key?

Good question :). The RsaProtectedConfigurationProvider uses the machine account or the user account to encrypt the keys and save them in a file which called "key container". To use the protected configuration with ASP.NET we should not use the user account to encrypt the keys because we need to be logged in with that user to be able to open that key container.

Key container for the machine account usually saved in C:\Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA. And the ASP.NET worker process identity (ASPNET user in XP/2000 or Network Service in case of 2003) should have access to these files to be able to decrypt it or you would get this error message

"Failed to decrypt using provider 'RsaProtectedConfigurationProvider'. Error message from the provider: The RSA key container could not be opened"

Fortunately the ASPNet_regiis tool gives us the option to add users to the ACL of the key containers using the –pa parameter.

For example to give access to the ASPNET user

aspnet_regiis -pa "<key container name>" "ASPNET"

So, how to get the key container name?

By searching in machine.config (usually in C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG) we would find this section

<configProtectedData defaultProvider="RsaProtectedConfigurationProvider">

    <providers>

      <add name="RsaProtectedConfigurationProvider" type="System.Configuration.RsaProtectedConfigurationProvider,System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" description="Uses RsaCryptoServiceProvider to encrypt and decrypt" keyContainerName="NetFrameworkConfigurationKey" cspProviderName="" useMachineContainer="true" useOAEP="false" />

      <add name="DataProtectionConfigurationProvider" type="System.Configuration.DpapiProtectedConfigurationProvider,System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" description="Uses CryptProtectData and CryptUnProtectData Windows APIs to encrypt and decrypt" useMachineProtection="true" keyEntropy="" />

    </providers>

  </configProtectedData>

The keycontainerName of the RsaProtectedConfigurationProvider is "NetFrameworkconfigurationKey" (it's good practice to change it in the production servers). So the aspnet_regiis would be as following

aspnet_regiis -pa "NetFrameworkConfigurationKey" "ASPNET"

What if I'm using a server farm?

In the server farms environment, you can simple use aspnet_regiis to create and export key container to distribute it to the whole server farm.