Blayd Software
blayd software
Site Map
Google
 
  • Blayd Home
    • Terms of Use
    • Privacy Statement
  • Products
    • Configuration Protector
    • Collection Generator
    • Collection Generator Lite
    • CodeDOM Helper
    • Product Prices
  • Downloads
    • Configuration Protector Trial
    • Collection Generator Trial
    • Articles
    • Products
    • Sample Code
    • Browse All
  • Articles
    • .Net Memory-Mapped Files
    • Generating .Net Source Code
    • Sorting .Net Collections
    • User Application Settings
    • How To
    • Technology
    • Browse All
  • Licensing
    • License Agreement
    • Configuration Protector
    • Collection Generator
    • CodeDOM Helper
  • Code Generator
    • Hints and Tips
    • CollectionBase
    • DictionaryBase
    • Collection(T)
    • BindingList(T)
    • Examples
  • Support
    • FAQs
    • Installation and Setup
    • Product Support

Article Options

Email the article.

Article

Email

Download the article

Article

Download

Protected Configuration

(by John Roberts for Blayd Software)

Contents

  • Introduction
  • Provider Model
  • Protected Configuration Providers
  • RSA Protected Configuration Provider
  • DPAPI Protected Configuration Provider
  • Custom Protected Configuration Provider
  • Encrypting and Decrypting Configuration Data
  • Encrypting and Decrypting Configuration Data From Your Own Code
  • Conclusion
Expand AllExpand All

Note: this article relates to the .Net Framework version 2.0 and later (3.0, 3.5, 4.0 and 4.5), some of the classes and class members referenced in this article were not available in earlier framework versions.

Introduction

A significant number of the applications that we develop use variable data values to set their initial state e.g. Window location, font-size, colour, etc. or to specify the values of a resource required at runtime e.g. path, file name, database name, etc. Even if the number of possible values for a particular settings is limited, hard coding them into an application has never been an ideal solution as it limits the flexibility of the application and requires a re-compile to update an existing value or to add a new value. Before the arrival of the .Net Framework we could use initialization (*.ini) files and/or the registry to store configuration settings and the Windows API to load them or we had to implement our own configuration system. We can, of course, still use any of these options, however the .Net Framework includes a built-in, XML based, configuration system that is the recommended solution for configuring .Net Framework applications.

The .Net Framework configuration system is extensive and extensible and includes functionality that developers can use to configure their applications and functionality that system administrators can use to configure assemblies and the .Net Framework itself. The classes or types relating to application configuration are contained in the System.Configuration namespace and there are additional types, relating to ASP.Net configuration, contained in the System.Web.Configuration namespace.

Dynamically configuring applications that target the .Net Framework is really easy and in most cases just requires a configuration file, in the application's working directory, with an appSettings section containing the required values, each one identified by a unique key. Each individual configuration setting can then be accessed in the application's code by using the ConfigurationManager.AppSettings property and the relevant unique key.

Microsoft extended the .Net Framework configuration system in version 2.0 of the framework to include functionality to protect or encrypt individual configuration sections in a configuration file. Configuration files often have to be used to store sensitive data, for example, you may have to store user names, passwords, database connection strings and many other types of sensitive data in a configuration file for a Windows Forms or an ASP.Net Web Application. Protected configuration can be used to improve the security of your application by making it difficult for an attacker to gain access to the data even if they manage to gain access to the configuration file.

Provider Model

Protected configuration is implemented in the .Net Framework (version 2.0 onward) using the Provider Model. The Provider Model is a factory like design pattern that allows a developer to define a concrete provider class, derived from a known provider (abstract) base class, in a configuration file. The .Net Framework uses the configuration file definition to create an instance of the relevant provider class at runtime. The provider instance is then called upon to provide the relevant service, in the case of protected configuration, to encrypt and decrypt a configuration file section. It is beyond the scope of this article to delve too deeply into the Provider Model but we recommend that you familiarize yourself with this design pattern as it is used a lot in the .Net Framework and may be of use in your own applications or systems.

The following two articles are our recommended starting point.

  • Provider Model Design Pattern and Specification
  • ASP.NET 2.0 Provider Model: Introduction to the Provider Model

Protected Configuration Providers

A protected configuration provider is a class that derives from the System.Configuration.ProtectedConfigurationProvider class. This is an abstract base class that derives from the System.Configuration.Provider.ProviderBase class and therefore inherits the (very) basic functionality of a provider. The .Net Framework (version 2.0 onward), includes two, ready to run, protected configuration providers that can be used to encrypt and decrypt configuration settings and you can also develop your own, custom, provider by extending the ProtectedConfigurationProvider class.

The protected configuration provider classes included in the .Net Framework are as follows.

RsaProtectedConfigurationProvider
This protected configuration provider uses the RSA algorithm to encrypt and decrypt configuration settings. Typically, this provider is specified as the default protected configuration provider.
DpapiProtectedConfigurationProvider
This protected configuration provider uses the Windows Data Protection API (DPAPI) to encrypt and decrypt configuration settings.

As noted, in the Provider Model section above, the .Net Framework runtime uses the data specified in a configuration file to identify and initialize the required instance of a protected configuration provider. A protected configuration provider instance can be specified in the machine.config, app.config or web.config file. In a typical .Net Framework installation the attributes or properties for instances of the RsaProtectedConfigurationProvider and DpapiProtectedConfigurationProvider classes are specified in the machine.config file. Therefore, by default, they can both be used to encrypt and decrypt your configuration settings without requiring further definition in your application's configuration file, providing you are happy to use the provider's machine.config specified attributes. If you want to use different attribute or property values for either of these two protected configuration providers, for example, you may want to specify a different key container for the RSA provider or specify a key entropy for the DPAPI provider, you will have to override the machine.config file settings in your application's configuration file by adding your own protected configuration provider instance settings.

Specifying the attributes of a protected configuration provider in the machine.config file or in an app.config or web.config file can be thought of as defining an instance of the provider. You can, for example, have several definitions or instances of the RsaProtectedConfigurationProvider, each with its own set of, unique, attributes. Protected configuration providers are identified by a unique friendly name that is specified in the name attribute value. The .Net Framework uses the provider's friendly name to identify, create and initialize an instance of the provider at runtime.

A provider's friendly name is not necessarily its class or type name, it can be any value. It is interesting or perhaps confusing to note that the RsaProtectedConfigurationProvider instance defined in the machine.config file is named "RsaProtectedConfigurationProvider", while the DpapiProtectedConfigurationProvider instance defined in the machine.config file is named "DataProtectionConfigurationProvider". The important thing to remember is that if you define your own protected configuration provider instance you should give it a name that is meaningful and relevant to the provider's use.

RSA Protected Configuration Provider

The machine.config definition of an RsaProtectedConfigurationProvider protected configuration provider instance is, typically, as follows.

ExpandRSA protected configuration provider attributes.
<configProtectedData defaultProvider="RsaProtectedConfigurationProvider">
   <providers>
      <add name="RsaProtectedConfigurationProvider"
      type="System.Configuration.RsaProtectedConfigurationProvider,
           System.Configuration, Version=4.0.0.0, Culture=neutral,
           PublicKeyToken=b03f5f7f11d50a3a"
      description="Uses RsaCryptoServiceProvider to encrypt and decrypt"
      keyContainerName="NetFrameworkConfigurationKey"
      cspProviderName=""
      useMachineContainer="true"
      useOAEP="false" />
   </providers>
</configProtectedData>

Note

The sample configuration settings above are referencing the .Net Framework 4.0 version of the RsaProtectedConfigurationProvider class, however, you can change the version number to reference an earlier version of the framework. If you need to confirm the name of a provider class in order to create a declaration similar to the example above, you can retrieve the fully qualified name of a type using code similar to the following example.

Retrieving the fully qualified name of a type.

string qualifiedName = typeof(RsaProtectedConfigurationProvider).AssemblyQualifiedName;

There is only one configProtectedData section element and in a typical installation the "RsaProtectedConfigurationProvider" is specified as the default protected configuration provider. You should note that the value of the defaultProvider and name attributes refer to the friendly name of the provider not its class or type name. All of the protected configuration provider instance definitions are grouped within a single providers element.

The attributes for an RSA protected configuration provider definition are as follows.

name
The friendly name of the provider. This is the value that you would specify as the protectionProvider parameter value if you are explicitly using the provider to encrypt or decrypt a configuration section in your own code.
type
The assembly qualified type name of the protected configuration provider. The .Net Framework must be able to locate the provider in order to automatically decrypt an encrypted configuration section when it is loaded into memory.
description
The protected configuration provider description.
keyContainerName
The name of the RSA key container to be used when encrypting and decrypting configuration section data. The "NetFrameworkConfigurationKey" RSA key container is created when the .Net Framework is installed. Although all machines containing an installation of the .Net Framework will, typically, have an RSA key container named "NetFrameworkConfigurationKey" each will have a different, generated, key pair. Therefore you cannot encrypt on one machine using the "NetFrameworkConfigurationKey" key container and decrypt on another machine using the "NetFrameworkConfigurationKey" key container, as the keys will, typically, be different.
cspProviderName
The name of the Windows cryptography API (crypto API) cryptographic service provider (CSP).
useMachineContainer
true if using a machine-level RSA key container, false if using a user-level RSA key container. If you are intending to encrypt the configuration data on one machine and have it decrypted on another or several other machines you should use a machine-level RSA key container.
useOAEP
true if using Optimal Asymmetric Encryption Padding (OAEP) when encrypting and decrypting, otherwise false.

The RSA protected configuration provider can be used to encrypt configuration section data on one machine and decrypt it on another machine and is therefore an ideal candidate for protecting web.config file sections in, for example, a web farm installation. To use an instance of the RSA protected configuration protector to encrypt on one machine and decrypt on another or several other machines you will have to take the following steps.

  • Create a machine-level RSA key container on the encrypting machine.
  • Define the attributes of an instance of the RSA protected configuration provider, that uses the RSA key container created in the previous step, in the web.config file.
  • Encrypt the relevant web.config section(s) using the RSA protected configuration provider instance defined in the previous step.
  • Export both the public and private keys from the RSA key container created in step 1. The public key is used to encrypt configuration data and the private key is required to decrypt it.
  • On the decrypting machine or machines, import both the public and private keys, exported in the previous step, into an RSA key container with the same name as the container on the encrypting machine.
  • On the decrypting machine or machines, grant read access to the newly create RSA key container to the Windows identity of the relevant web application.

You can find the Windows or process identity under which your web application is running, assuming that you are using anonymous authentication, by temporarily adding the following code to a page load event and outputting the result to the response stream.

System.Security.Principal.WindowsIdentity.GetCurrent().Name

The value of this property is the account name under which your web application is running. This account needs read access to the relevant RSA key container in order for the .Net Framework to use the relevant protected configuration provider to automatically decrypt configuration section data as it is loaded.

DPAPI Protected Configuration Provider

The machine.config definition of a DpapiProtectedConfigurationProvider protected configuration provider instance is, typically, as follows.

ExpandDPAPI protected configuration provider attributes.
<configProtectedData defaultProvider="RsaProtectedConfigurationProvider">
   <providers>
      <add name="DataProtectionConfigurationProvider"
      type="System.Configuration.DpapiProtectedConfigurationProvider,
           System.Configuration, Version=4.0.0.0, Culture=neutral,
           PublicKeyToken=b03f5f7f11d50a3a"
      description="Uses CryptProtectData and CryptUnProtectData
                  Windows APIs to encrypt and decrypt"
      useMachineProtection="true"
      keyEntropy="" />
   </providers>
</configProtectedData>

There is only one configProtectedData section element and in a typical installation the "RsaProtectedConfigurationProvider" is specified as the default protected configuration provider. You should note that the value of the name attribute refers to the friendly name of the provider not its class or type name. All of the protected configuration provider instance definitions are grouped within a single providers element.

The attributes for an DPAPI protected configuration provider definition are as follows.

name
The friendly name of the provider. This is the value that you would specify as the protectionProvider parameter value if you are explicitly using the provider to encrypt or decrypt a configuration section in your own code.
type
The assembly qualified type name of the protected configuration provider. The .Net Framework must be able to locate the provider in order to automatically decrypt an encrypted configuration section when it is loaded into memory.
description
The protected configuration provider description.
useMachineProtection
true to use machine-level DPAPI protection, false to use user-level DPAPI protection.
keyEntropy
Only relevant when using machine-level protection. An application specific value, that can be thought of as a password, to use with the encryption key to protect against other applications on the same machine decrypting information.

The DPAPI protected configuration provider cannot be used to encrypt configuration data on one machine and decrypt it on another machine, the Data Protection API is machine specific. However, if this is not a problem for your implementation, this provider is probably the easiest to use because it has fewer configuration options.

Custom Protected Configuration Provider

The Provider Model Design Pattern used by the .Net Framework protected configuration provider implementation allows developers to define a specific protected configuration provider instance that is to be used by the framework to encrypt and decrypt configuration data. Therefore, if the neither of the two protected configuration providers supplied in the .Net Framework meet your requirements you can develop your own custom provider, specify the attributes for your provider in a configuration file and have the .Net Framework use your provider to encrypt and decrypt configuration section data.

Your custom protected configuration provider class must inherit from the ProtectedConfigurationProvider abstract base class contained in the System.Configuration namespace. The ProtectedConfigurationProvider class inherits from the ProviderBase abstract base class contained in the System.Configuration.Provider namespace, therefore, there are several abstract members that your provider class must implement and several virtual members that your provider class should override. The relevant members are as follows.

Initialize
This is a virtual method of the ProviderBase class and should be overridden to setup your provider. The base class implementation tracks the number of calls to Initialize and only allows a single call, therefore, if you only want a single instance of your provider to exist, your code should call the base class implementation. The provider's friendly name is passed to the Initialize method together with a collection of name value pairs representing the provider's attributes from the configuration file. If your implementation does not call the base class version of Initialize you should capture the friendly name and possibly the provider's description and override the Name and possibly the Description properties.
Encrypt
This is an abstract method of the ProtectedConfigurationProvider class and must be overridden in your provider. The Encrypt method is passed an XmlNode instance representing the configuration data to encrypt. Your code should encrypt the data contained in the node i.e. the OuterXml property value, wrap the encrypted data in an element named "EncryptedData" and return the resulting node.
Decrypt
This is an abstract method of the ProtectedConfigurationProvider class and must be overridden in your provider. The Decrypt method is passed an XmlNode instance representing the data to decrypt. Your code should decrypt the data contained in the node i.e. the InnerText property value and return the resulting node.

It is worth noting that although the two main methods are named Encrypt and Decrypt it is up to you to define exactly what these methods do. The Encrypt method does not have to encrypt the configuration data, it may, for example, store the configuration data in a location that is more secure than the configuration file and then just place an opaque marker in the configuration file indicating, in some way, that the actual configuration data is external. You may be able to come up with other, better, ideas, our point is that you have the freedom to protect your configuration data in whatever way you choose.

The Initialize method is passed a NameValueCollection containing the configuration attributes of the custom provider. Your custom provider must have, at least a name and a type attribute, as these values are required by the .Net Framework to locate and load your provider. In addition to the two required attributes you can add your own attributes to the provider's configuration settings and retrieve the value of these attributes in your provider's Initialize method. You should, note, however, that the provider's attributes are in clear text in the configuration file, so if the file is accessible then so are your provider's attributes.

When you have completed your custom protected configuration provider class you need to ensure that the .Net Framework can find it when it needs to encrypt and decrypt the relevant configuration section data. There are several options available for deploying a custom protected configuration provider and they depend on how you are going to encrypt the configuration data and the type and number of applications that are going to use the provider. Some of the options available are as follows.

Add the provider class to your application's assembly.
If you are intending to encrypt and decrypt configuration section data explicitly from code and your provider is only going to be used by one application this solution should be fine. However, if you are going to use a tool (see the Encrypting and Decrypting Configuration Data section below) to manually encrypt the data and have the .Net Framework automatically decrypt the data as it is loaded, this solution can be problematic. To manually encrypt the data, your application's assembly and the encrypting tool will, typically, have to be in the same directory or you will have to add a codeBase element to the encrypting tool's configuration file pointing to your application's assembly. Automatically decrypting the data should be fine as the .Net Framework will look in your application's assembly for the provider. If you are intending to use the provider from more than one application, this solution is not really suitable.
Place the provider class in its own assembly.
Compile the provider class into its own assembly and place one copy of the assembly in the same directory as the tool used to manually encrypt the configuration data and another copy in your application's directory. Using this solution you will be able to use a tool to manually encrypt the configuration data and have the .Net Framework automatically decrypt the configuration data at runtime. If you are going to use the provider from more than one application then each application will required a copy of the provider's assembly in its directory.
Add the provider class to the Global Assembly Cache.
Compile your custom protected configuration provider into its own assembly with a strong name and place the assembly in the global assembly cache (GAC). This is probably the easiest way to make your provider available to multiple processes on the same machine.

Encrypting and Decrypting Configuration Data

If you have defined the required protected configuration provider in the machine.config or in your app.config or web.config file, the .Net Framework will automatically decrypt any configuration section data encrypted by the provider at runtime. However, this does mean that you will have to manually encrypt the configuration section data before deploying your application and its configuration file.

The .Net Framework includes a command line tool, named Aspnet_regiis.exe, that can be used to encrypt and decrypt configuration section data and also to manage RSA key containers for the RsaProtectedConfigurationProvider class. The Aspnet_regiis.exe command line tool is located in the following directory:

%windows%\Microsoft.NET\Framework\versionNumber

You can use the Visual Studio command prompt, which has the relevant environment variables setup, to make use of the Aspnet_regiis.exe tool to encrypt your configuration section data. Full details of the various switches and parameters for Aspnet_regiis.exe can be found in the .Net Framework documentation under the ASP.Net Command-Line Tools section.

If you are not a fan of command line applications, Blayd Software supply a developer tool named Configuration Protector that provides a graphical user interface that enables configuration sections to be encrypted and decrypted using a point and click technique that reduces typing and therefore mistakes and speeds up the whole process. In addition to providing a simple and intuitive user interface for encrypting and decrypting configuration file sections the Configuration Protector also provides a graphical user interface for managing RSA key containers and their keys. You can download a free evaluation version of Configuration Protector from the download registration page....

To manually encrypt a configuration section using RSA encryption you will require, at least, read access to the relevant key container. Even if you are using the default .Net Framework key container i.e. the "NetFrameworkConfigurationKey" container you will need to run the command line tool with administrator privileges or from an account with read access to the container.

When using protected configuration to protect your sensitive configuration section data you should note that the configuration data is in encrypted form in the configuration file but it is decrypted as it is loaded into memory, therefore, if an attacker has access to the memory of your application they, potentially, have access to the sensitive configuration data.

To assess the impact that encryption can have on your configuration settings we have encrypted the appSettings section of a configuration file.

ExpandThe, example, configuration file, before encryption is as follows.
<configuration>
   <appSettings>
      <add key="SensitiveKey1" value="SensitiveValue1" />
      <add key="SensitiveKey2" value="SensitiveValue2" />
      <add key="SensitiveKey3" value="SensitiveValue3" />
      <add key="SensitiveKey4" value="SensitiveValue4" />
   </appSettings>
</configuration>
ExpandThe, example, configuration file after encryption using the RSA protected configuration provider is as follows.
<configuration>
   <appSettings configProtectionProvider="RsaProtectedConfigurationProvider">
      <EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element"
            xmlns="http://www.w3.org/2001/04/xmlenc#">
         <EncryptionMethod Algorithm="http://www.w3.org/2001/04/
            xmlenc#tripledes-cbc" />
         <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
            <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
               <EncryptionMethod Algorithm="http://www.w3.org/2001/04/
                  xmlenc#rsa-1_5" />
               <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
                  <KeyName>Rsa Key</KeyName>
               </KeyInfo>
               <CipherData>
                  <CipherValue>
                     QXNNzE1+Nugve6RLaLFUqBhMNPbnJEuomsy
                     OiYo/B7lGi+BaNOrj08VGZqOGyvjucxyG5p
                     WC/ZXgs9C83VZIaH8n/OGyirl59GNZ+HK7K
                     6188nxviNR0ZoljLXGI2Q+MkIDI55g9HpeW
                     KwDNS8y9PlldPRJ0W3VUv9T6TiTNuYw=
                  </CipherValue>
               </CipherData>
            </EncryptedKey>
         </KeyInfo>
         <CipherData>
            <CipherValue>
               oryMqG3Gx0i7R37lLwi6kVYHQRN5Cp80JqWZULe+Q
               D2OfLW9EOPIrWbAyZVUQSzcLOd3+5C45Qr+yUVuAL
               Z8pZraDHECoEGo9vu7GJzVNhynU/9XAvMkEV/msiX
               ckBuqJ25hkVAAp3/Q5Z285UODAAyLyJTt/L6TwMB/
               cZ+5WL/AdLLU8UC7Xbt26aNogr5z9ju3bIpGrxk6j
               scBmuVoUm8JzXvJah9ah3RhypToMyWGOGm9DbxKNA
               5ztMzypRiIFoh2i9Po8rQuOdRzjbQZT0bqf0/yEJp
               gQpbZDjly3lmLlgMGY0wCr0QiVFwYhwaIwMpHLS7M
               uY734AUyIrFw7aGHlHb/QiVIz5PzeffT22M=
            </CipherValue>
         </CipherData>
      </EncryptedData>
   </appSettings>
</configuration>

As you can see, the structure of the RSA encrypted section is verbose and inflates the size of the configuration section considerably. Encrypting with the DPAPI protected configuration provider is, typically, more efficient in terms of data overhead but it is limited to encrypting and decrypting on the same machine.

Encrypting and Decrypting Configuration Data From Your Own Code

As explained in the previous section the .Net Framework will automatically decrypt configuration section data as it is loaded into memory if the relevant provider details are defined in the machine.config or your app.config or web.config file. You can also explicitly encrypt and decrypt configuration section data in your application code if required. The following code examples demonstrate how to encrypt and decrypt a configuration section in a web.config file. The examples are private helper methods of a web page class and should be called with the name of the section to encrypt or decrypt e.g. "appSettings" and the friendly name of the encrypting protected configuration provider e.g. "RsaProtectedConfigurationProvider". You do not have to specify the friendly name of the protected configuration provider when decrypting a configuration section because the .Net Framework can retrieve the provider name from the encrypted section's configProtectionProvider attribute.

ExpandEncrypting a configuration section from code.
private void ProtectSection(string sectionName, string providerName)
{
   Configuration config =
      WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);

   if (config != null)
   {
      ConfigurationSection section = config.GetSection(sectionName);
      if (section != null)
      {
         SectionInformation sectionInfo = section.SectionInformation;
         if ((!sectionInfo.IsProtected) && (!sectionInfo.IsLocked))
         {
            sectionInfo.ProtectSection(providerName);
            sectionInfo.ForceSave = true;
            config.Save();
         }
      }
   }
}
ExpandDecrypting a configuration section from code.
private void UnProtectSection(string sectionName)
{
   Configuration config =
      WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);

   if (config != null)
   {
      ConfigurationSection section = config.GetSection(sectionName);
      if (section != null)
      {
         SectionInformation sectionInfo = section.SectionInformation;
         if ((sectionInfo.IsProtected) && (!sectionInfo.IsLocked))
         {
            sectionInfo.UnprotectSection();
            sectionInfo.ForceSave = true;
            config.Save();
         }
      }
   }
}

It may at first seem like a tempting proposition to encrypt and decrypt your configuration section data from your own code. However, you should note that in the examples above the Windows identity under which the web application is running requires read access to the RSA key container and write access to the configuration file to perform both the encryption and decryption. It may be possible to grant these permissions in your environment but most web applications will be using anonymous authentication and running in a partial trust environment and will not, typically, have the required permissions.

Conclusion

Encrypting sensitive data in a configuration file will improve the security of your application by making it difficult for an attacker to gain access to the data even if they manage to gain access to the configuration file. The addition of protected configuration providers to the .Net Framework configuration system has made the task of protecting configuration settings a lot easier for developers. The flexibility and extensibility of the system should make it possible to protect configuration data in most applications or systems, although, in some situations you will still have some development work to do.

Copyright ©Blayd Software Limited 2007 - 2013. All rights reserved.
Contact Us bookmark and/or share Link To Us

Copyright ©Blayd Software Limited 2007 - 2013