Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WinForms

Implementing Protected Configuration With Windows Apps

4.70/5 (53 votes)
29 Aug 200610 min read 1   5.4K  
How to use the ProtectedConfiguration API to protect sensitive information in your application’s configuration file.

Introduction

It all happened when I came across a need to encrypt sensitive information in my Windows Forms application’s configuration file. I decided to use the new Protected Configuration feature of Microsoft .NET 2.0 for encrypting it.

I started searching the web but was unable to find any practical application of Protected Configuration for Windows Forms applications. Almost all of the online resources tell you to do that with ASP.NET. In most of the articles, encryption is done via the aspnet_regiis tool, and aspnet_regiis does not support encryption of Windows Forms application configuration files, so virtually one is left with no option.

Maybe I am not completely correct in saying this; few resources on the web do mention that you can use the System.Configuration.SectionInformation.ProtectSection method to encrypt a Windows Forms application configuration file as well. But none gives an example to use in practical desktop scenarios.

When it comes to a real life implementation of the ProtectSection method, there are the following problems:

  1. The ProtectSection method is not a command line tool like apnet_regiis, one has to call it at runtime from the application’s code. By using this method, a particular configuration section of the application configuration file can be encrypted. So probably, using code such as the following in the application’s Main method will work out.
    C#
    Configuration config = 
      ConfigurationManager.OpenExeConfiguration(
      ConfigurationUserLevel.None);
    ConfigurationSection section = 
      config.GetSection("connectionStrings");
    
    if (!section.SectionInformation.IsProtected)
    {
        section.SectionInformation.ProtectSection(
           "MyUserDataProtectionConfigurationProvider");
    }
    section.SectionInformation.ForceSave =true;
    config.Save(ConfigurationSaveMode.Modified);

    Here, the IsProtected property of System.Configuration.SectionInformation determines whether the configuration section is already encrypted.

    But there is a problem, the Main method will be called when the application is run. So all the sensitive information will lie naked in the config file until and unless a user runs the application for the first time.

  2. Even if you manage to encrypt the configuration section via making some stand-alone application to do this, there are again two problems in the approach:
    1. None of the built in ProtectedConfigurationProviders, i.e., RsaProtectedConfigurationProvider and DpapiProtectedConfigurationProvider, are very well suited to such a scenario because, encryption done from one machine cannot always be decrypted on another one.
    2. This one is interesting. The actual file encrypted will be Exe_Name.exe.config, not the app.config itself. And as we know, by default, Exe_Name.exe.config is overwritten each time we build our project.

    To add a little more to the annoyance, while debugging, one wouldn’t even notice the change in the Exe_Name.exe.config file if the Visual Studio Hosting Process in enabled (which is enabled by default). If so, Exe_Name.vshost.exe.config will be encrypted instead. So all this will make the process of porting the encrypted version of the configuration file from production to deployment a headache.

As you may have realized by now, the Protected Configuration is not a fancy option with Windows applications.

As the ProtectSection method is our only way out for Windows application configuration files, we need to determine a way to use the ProtectSection method in the following manner:

  • Even before the application is first run
  • Only once
  • On the user's machine
  • On the right configuration file

There is a very simple solution for all the problems mentioned above. Use the System.Configuration.SectionInformation.ProtectSection method in an installer class. An MSI setup of your application can call this installer class. So, the configuration information will be encrypted at the time of installation on the user’s machine. Then, .NET takes care of the decryption at runtime.

Background

For those of you who are not familiar with the new Protected Configuration feature of .NET 2.0, it enables you to encrypt application configuration information and configure the application to automatically decrypt it at runtime. This is implemented by using different Protected Configuration Providers, which can be configured in App.config files. Each provider has its own method of performing the encryption. For details, take a look at the MSDN article: Encrypting Configuration Information Using Protected Configuration.

Using the Code

Among the two built-in Protected Configuration Providers, i.e., DpapiProtectedConfigurationProvider and RSAProtectedConfigurationProvider, I shall make use of DpapiProtectedConfigurationProvider, because in my opinion, it is more suited for Windows apps. It uses the Windows built-in cryptographic services, and can be configured for either machine-specific or user-account-specific protection.

Note: The purpose of this article is not to demonstrate the best possible encryption mechanism, but to demonstrate how Protected Configuration can be used with Windows Forms apps.

Feel free to implement your own provider, which may use a custom algorithm. See Implementing a Protected Configuration Provider for more details.

Recreating the Demo Project

To recreate the demo project, follow the steps mentioned below.

Creating the Windows Application Project

Open Visual Studio 2005, and create a new C# Windows Application project. Name it DemoWinApp.

Image 1

Open the Settings file, and add a setting named SecretMessage as shown below:

Image 2

Open Form1’s designer, and add a Label control on it, naming it lblSecretMessage as shown below:

Image 3

Add the following code in Form1’s Load method.

C#
lblSecretMessage.Text = DemoWinApp.Properties.Settings.Default.SecretMessage;

Specifying the Protected Configuration Provider

Open the App.Config file, and add the following code as the child node of the Configuration section.

XML
<configProtectedData>
    <providers>
      <add useMachineProtection="true" name="DPAPIProtection"
           type="System.Configuration.DpapiProtectedConfigurationProvider,
                 System.Configuration, Version=2.0.0.0, Culture=neutral, 
                 PublicKeyToken=b03f5f7f11d50a3a" />
    </providers>
</configProtectedData>

The above code is necessary to configure a Protected Configuration provider, which will be used for encrypting and decrypting the configuration section which contains sensitive information. Whenever you want to specify your own provider with custom settings, you can declare a new provider instance using the add element of the providers element under ConfigProtectedData, which in turn is a child element of the Configuration section.

The DpapiProtectedConfigurationProvider uses the Windows built-in cryptographic services, and can be configured for either machine-specific or user-account-specific protection. Machine-specific protection is useful for anonymous services, but provides less security. User-account-specific protection can be used with services that run with a specific user identity.

Notice the attribute useMachineProtection=true in the above listing. This configures the provider to use machine specific protection. So, any user can successfully use the application on that machine. Making its value false will configure the provider to use user-account-specific protection. Here, using the application means, the .NET runtime will not be able to decrypt the configuration information encrypted earlier. As, all Windows applications, by default, run under the currently logged in user accounts and we plan to encrypt the configuration information during installation. So, if we use user-account-specific protection, only the user who will install the application will be able to use the application.

For this article, we shall use the machine specific protection.

The attribute name="DPAPIProtection" will be used to encrypt the configuration section during the installation process.

Other attributes like type, Version, Culture, and PublicKeyToken identify the DpapiProtectedConfigurationProvider assembly installed in the Global Assembly Cache by default.

Here is how the app.config file looks like:

XML
<?xml version="1.0" encoding="utf-8" ?>
<configuration>

    <configSections>
        <sectionGroup name="applicationSettings" 
              type="System.Configuration.ApplicationSettingsGroup, 
                    System, Version=2.0.0.0, Culture=neutral, 
                    PublicKeyToken=b77a5c561934e089" >
            <section name="DemoWinApp.Properties.Settings" 
                type="System.Configuration.ClientSettingsSection, 
                      System, Version=2.0.0.0, Culture=neutral, 
                      PublicKeyToken=b77a5c561934e089" 
                requirePermission="false" />
        </sectionGroup>
    </configSections>
    <applicationSettings>
        <DemoWinApp.Properties.Settings>
            <setting name="SecretMessage" serializeAs="String">
                <value>This is the secret message.</value>
            </setting>
        </DemoWinApp.Properties.Settings>
    </applicationSettings>

  <configProtectedData>
    <providers>
      <add useMachineProtection="true" name="DPAPIProtection"
           type="System.Configuration.DpapiProtectedConfigurationProvider, 
                 System.Configuration, Version=2.0.0.0, 
                 Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    </providers>
  </configProtectedData>

</configuration>

Adding an Installer Class

As mentioned earlier, we shall use the ProtectSection method of the System.Configuration.SectionInformation class in the installer class in order to encrypt sensitive configuration information at the time of installation.

Add a new installer class in your project, and name it DemoWinAppInstaller.cs.

Image 4

For those of you who are not familiar with using installers, installers are components that help install applications on a computer. A custom class is derived from the base Installer class, and any or all of the Install, Commit, Rollback, and Uninstall methods can be overridden in the custom class. From the Visual Studio setup projects, these methods are configured to be called at various stages of the installation process. As you should have guessed, these stages are Install, Commit, Rollback, and Uninstall.

Here is the code listing of the custom installer class:

C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Configuration;

namespace DemoWinApp
{
    [RunInstaller(true)]
    public partial class DemoWinAppInstaller : Installer
    {
        public DemoWinAppInstaller()
        {
            InitializeComponent();
        }

        public override void Install(System.Collections.IDictionary stateSaver)
        {
            base.Install(stateSaver);

            //get Configuration section 
            //name from custom action parameter
            string sectionName = this.Context.Parameters["sectionName"];
            
            //get Protected Configuration Provider 
            //name from custom action parameter
            string provName = this.Context.Parameters["provName"];

            // get the exe path from the default context parameters
            string exeFilePath = this.Context.Parameters["assemblypath"];

            //encrypt the configuration section
            ProtectSection(sectionName, provName, exeFilePath);


        }

        private void ProtectSection(string sectionName, 
                     string provName, string exeFilePath)
        {
            Configuration config = 
              ConfigurationManager.OpenExeConfiguration(exeFilePath);
            ConfigurationSection section = config.GetSection(sectionName);

            if (!section.SectionInformation.IsProtected)
            {
                //Protecting the specified section with the specified provider
                section.SectionInformation.ProtectSection(provName);
            }
            section.SectionInformation.ForceSave = true;
            config.Save(ConfigurationSaveMode.Modified);

        }
    }
}

Notice that only the Install method has been overridden in the custom installer, and this contains the code for encrypting the Configuration section. The Install method retrieves the parameters, i.e., sectionName (configuration section to be encrypted) and provName (provider name as defined in the configuration file, which will be used to encrypt the configuration section) passed to the installer (not the Install method). We shall see how the parameters are passed to an installer, in a moment.

Also notice that, you don’t have to pass the assemblypath parameter; it is present in the Installer’s Context, by default.

The Install method then calls a private method, ProtectSection, in order to encrypt the specified configuration section. This method will encrypt the configuration section using the actual System.Configuration.SectionInformation.ProtectSection method and saves the changes to the configuration file.

The OpenExeConfiguration method of the System.Configuration.ConfigurationManager class requires an EXE path to be passed to it, and it finds the configuration file of the specified EXE itself.

The ProtectSection method of the System.Configuration.SectionInformation class needs the provider name, which will be used to encrypt the configuration section.

The DemoWinApp application is complete. Don’t forget to build the project.

Creating the Visual Studio Setup Project

Now, let's see how a Visual Studio Setup project can be created, which will make use of the installer class presented above to encrypt the sensitive configuration information upon installation.

Add a new setup project to the solution, and name it DemoWinAppSetup.

Image 5

From the File System Editor, add the primary output of the DemoWinApp project to the setup project.

Image 6

The key to using an installer class with a Visual Studio Setup project is Custom Actions.

Open the Custom Action Editor, and add the primary output of the DemoWinApp project under the Install folder.

Image 7

Open the Properties window of the newly added custom action, and add custom action parameters and their values in the CustomActionData property.

Image 8

Notice the format of specifying the parameters. Each parameter takes the form /[Parameter Name]="[Value]". Individual parameters are delimited by spaces. Make sure there are no spaces between the parameter name, equal sign, and the parameter value.

To encrypt the whole Settings section, the sectionName parameter has been provided the value applicationSettings/DemoWinApp.Properties.Settings, which is the path of the Settings node in the App.Config file.

Note that adding a value in the Settings.settings file automatically creates the Settings node in the App.Config, as shown below.

XML
<applicationSettings>
    <DemoWinApp.Properties.Settings>
        <setting name="SecretMessage" serializeAs="String">
            <value>This is the secret message.</value>
        </setting>
    </DemoWinApp.Properties.Settings>
</applicationSettings>

The provName is the provider name as specified in the App.config file earlier.

Now we are ready to go. Build the Setup project to generate the MSI Installer package.

Running the Application

Run the generated installer package to install the application. Go to the installation folder, and open the configuration file. Note the applicationSettings/DemoWinApp.Properties.Settings section.

In my case, it looks like the following:

XML
<applicationSettings>
  <DemoWinApp.Properties.Settings configProtectionProvider="DPAPIProtection">
    <EncryptedData>
      <CipherData>
        <CipherValue>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAJY9eXbg340Gn
                        Ay8Dyzkf4QQAAAACAAAAAAADZgAAqAAAABAAAAAac+j1
                        UbifDAtrOUt9xNUWAAAAAASAAACgAAAAEAAAAKwqPS6A
                        bcFdlDZiS8gBMvCIAQAAgBPMemCdMCcX6juvCaB02kNJ
                        Vb3tyHHLztYWkMyNgs60cIBiqQbNYPUcPkuMg42tbffk
                        0VQ0KEwMu8/mRAc4+LQwni9kRbpSR4GOUPoOzLSrdxcK
                        6D1mjntJ+804dZ7fk9gq793GpPJroV0VfxoaMBDZtHKw
                        uRbAnFvVn+yWfH6ZVN1gQFIM3vhinc/kpiBB+pPLCO/5
                        XbsOfwu3eLSw436LGqfTPsvAj6JY6pax8hd7KnIsCDte
                        EkZVGjHAfJnSj6mB5vI9u7fBLwjTa0V4qhznW+lcb6uP
                        JeR565sRnJq7Od+3c716bJ6fOS/AY91zF+f5rYLN+ebZ
                        ZnKabrilA6+xS70+rSPuLnXueKp6UymP0R4k9oVjfmAm
                        Utd4/PYuZqk+nKbEyJwr8lzc7lkwsy/aYE7IK9/BHlDf
                        rpJfR0B11ZeUBmXbGLD0N0hFQHZO6FHDxnRIzadJx7UX
                        o5VGVoE63tjAnDfRtj/UbudIq8GhM8CHxkh0o/AUuEpo
                        PsobGQ576EDdwo4UAAAAP2wB/QutHyUIYCG6T7n6YNbE
                        4gg=</CipherValue>
      </CipherData>
    </EncryptedData>
  </DemoWinApp.Properties.Settings>
</applicationSettings>

So as you can see, the installation process has encrypted the SecretMessage setting, which was the child node of the applicationSettings/DemoWinApp.Properties.Settings section.

Note that the configProtectionProvider attribute has been automatically added to the DemoWinApp.Properties.Settings section, which tells the .NET runtime that the configuration section is encrypted and which provider to use for decryption.

Now, the responsibility of decrypting the configuration section is on the .NET runtime, not the application programmer.

To recall, in the DemoWinApp application, we did not add any code for decrypting the SecretMessage setting before accessing it.

C#
lblSecretMessage.Text = DemoWinApp.Properties.Settings.Default.SecretMessage;

Now, run the DemWinApp application installed on your PC.

The output should look like the following:

Image 9

Conclusion

The ProtectedConfiguration API is a nice and clean way to protect sensitive information in the application’s configuration file. Unfortunately, the built-in ProtectedConfigurationProviders are not very well suited for many Windows application scenarios, e.g., an advance user can easily develop his own application and decrypt the configuration information for the provider configuration (machine specific DpapiProtectedConfigurationProvider) used in this article. But still, for many scenarios, one can use it neatly with Windows applications as well. As I mentioned earlier, the purpose of this article is not to demonstrate the best possible encryption mechanism, but to demonstrate how Protected Configuration can be used with Windows Forms apps. If you want more control over the actual encryption algorithm, you can easily make a custom ProtectedConfigurationProvider. See Implementing a Protected Configuration Provider, for more details.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here