How To Encrypt The .NET Config File
Both website applications and client applications allow the application to store sensitive information in an XML configuration file. This sensitive information could be database connection strings or user credentials. The .NET framework allows us to encrypt configuration sections with tags <appSettings>, <connectionStrings>, <identity>, and <sessionState>. In most deployment environments, these configuration files can remain safely hidden and inaccessible. However, it is possible to encrypt these files for added protection. We will use the DPAPI (Data Protection Application Programming Interface) provided by the .NET framework. You can also use RSA as the encryption algorithm, but we won’t be demonstrating using RSA encryption. As an added wrinkle, the encrypted config file may not reside in the project that contains your presentation logic. So in this example, we will create a two project solution with a Windows Forms presentation project and a Data Access project. The Data Access project config file will contain a database connection string with possibly a username and password which we desire to encrypt.
There are a number of tricky issues that come up during the implementation. The first tricky issue is the timing of when we encrypt the config file. During development, we want the information to remain available and unencrypted in Visual Studio. During build-time, we want to encrypt the config file and place it in the appropriate deployment directory. BUT, we need to encrypt the config file by running .NET code, which implies that we can’t do it at build-time (unless you are more clever than I am). The easiest solution to this conundrum, is to run our application once after compiling. We can then safely deploy it with the config files encrypted. Our code will have the logic necessary to detect if the config file is not encrypted, and to then encrypt it. After that, the application deliverables should only include the encrypted config file. There is only one problem with this scenario. The encryption algorithm uses the machine key. That means that we can’t ship encrypted config files from the development machine to the deployment machines and expect the deployment machines to be able to decrypt the encrypted config files.So….. we will have to deploy the unencrypted config files to the deployment machines. Once the application runs, the config files will be encrypted. Whether this is an acceptable solution depends on your deployment scenario. RSA encryption has similar problems.

The first thing we need to do is create two projects in Visual Studio. The first project will be a Windows Forms project that I named ‘EncryptConfig’. The other project will be a class library named ‘DataAccess’. Now we can create an application scoped setting in Visual Studio. We can do this by right-clicking on the ‘DataAccess’ project node in Solution Explorer and clicking on Properties. On the ‘Settings’ tab, we can add our connection string. I am going to side-step the problem that the connection string that is used in development may be different from that required on the deployment machine. For this blog, we will assume they are the same. This setting will be saved in XML format in the app.config file in the DataAccess project. By the way, the ‘Copy To Ouput Directory’ property for this file should be left in ‘Do not Copy’ state. Below is an example of the XML formatted app.config file.
<?xml version=“1.0“ encoding=“utf-8“ ?>
<configuration>
<configSections>
</configSections>
<connectionStrings>
<clear />
<add name=“MyConnStr“ connectionString=“Data Source=.;Initial Catalog=library;Integrated Security=true;“ />
<add name=“DataAccess.Properties.Settings.MyConnStr“ connectionString=“Data Source=.;Initial Catalog=library;Integrated Security=true;“ />
</connectionStrings>
</configuration>
|
|
We can now create a reusable static class for encrypting our connection string. Below is the code for this class. The code is a bit tricky, because the config file we need to encrypt is not the app.config file that is located in our DataAccess project. Neither is it the DataAccess.dll.config file in the /bin/debug directory of the ‘DataAccess’ project. Instead it will be the EncryptConfig.EXE.config file in the /bin/debug or /bin/release directory of the ‘EncryptConfig’ project.

This static class ‘EncryptConnectString’ has only a single static method in it ‘ProtectConnectionString()’. This method will examine the EncryptConfig.EXE.config file and determine if it is encrypted. If it is encrypted, it returns otherwise it will encrypt the file. We use the ExecutablePath property of the static object System.Windows.Forms.Application to get the filepath to where the EncryptConfig.EXE.config file resides at runtime. The ‘ConfigurationManager’
class provides the ‘OpenExeConfiguration()’ method which takes a filepath string to retrieve the contents of the XML file and expose it through an instance of the ‘Configuration’ class. This class allows us to programmatically work with the configuration file without using one of the .NET XML classes like XmlDocument or XDocument.
Assuming the Configuration object was created successfully, we have to find the correct section of the config file and cast it as a ConnectionStringsSection object. The section name we need is ‘connectionStrings’ in this case. Next we need to verify that the section information we have is available for editing by examining the ‘IsLocked’ property of the ConnectionStringsSection object. Finally, we need to check if the section is encrypted by using the ‘IsProtected’ property.
If it is protected (encrypted), then we are done. If it isn’t encrypted, then we simply invoke the ‘ProtectSection()’ method of the SectionInformation object, pass it the ‘DataProtectionConfigurationProvider’ string as a parameter and all the magic of encrypting the connection strings (there may be several) is done for us by the .NET provided classes. Now that the config section has been encrypted, we need to save the changes. To do that we should set the ‘ForceSave’ property of the SectionInformation object to true and then invoke the ‘Save()’ method of the Configuration object.

Since the config file only needs to be encrypted once, we could put the ‘EncryptConnectString.ProtectConnectionString()’ method call in a some static constructor. In the code to the right, we placed the method call in the DataAccess constructor. We can now access the user setting like it was not encrypted at all. The .NET framework does all the work of decrypting the connection string for us behind the scenes.
If you examine the config file after it is encrypted, it should appear like what is shown below. The XML has been modified into another form with the connection string encrypted as a base64 string in the <CipherValue> tag. If you bring the config file into a code editor window, it will display errors on some of the tags. You can safely ignore those editor error messages.
|
|
<?xml version=“1.0“ encoding=“utf-8“?>
<configuration>
<connectionStrings configProtectionProvider=“DataProtectionConfigurationProvider“>
<EncryptedData>
<CipherData>
<CipherValue>
AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAq09FHZA6nkuWLZ8pSjO7OAQAAAACAAAAAAAQZgAAAAEAACAA
AAAz3ZR+wIzLWdJNZUkoduMp3CPaUgaJvda2R9V/QtcmRQAAAAAOgAAAAAIAACAAAAD0jbN4Nb98FLzq5m
yiEt/VYnwCim5oPzdKqr7mvBwJYTAAAABwDXZrOKQtwUq7gKDoR4dnzK55IDANT7HWAuQZNnkhmPH8b+GC
VczCSUgdv9RNyctAAAAAya/c+Djo1v1B7gK7/FQWw9hull+EPs81JPdy6uJxkgcTUF0RfDBskq5g2si87k4US2Iz
/4E3+dK/yfWIyEpAcw==</CipherValue>
</CipherData>
</EncryptedData>
</connectionStrings>
</configuration>
|
|
If you compile and run this application a few times, you may receive the dreaded exception message listed below.
Failed to decrypt using provider
‘DataProtectionConfigurationProvider’.
Error message
from the provider: Key not valid for use in specified state.
(Exception from HRESULT: 0x8009000B)
Sometimes, the copied config files in the ‘EncryptConfig’ project get out of synch with the original config files in the DataAccess project. You will notice that the DataAccess.dll.config file in the ‘DataAccess’ project was copied to the EncryptConfig.EXE.config file as well as to the EncryptConfig.vshost.exe.config file in the ‘EncryptConfig’ project (if you are using the debugger). To fix this error, you can manually copy the unencrypted DataAccess.dll.config file in the DataAccess project to the EncryptConfig.EXE.config and EncryptConfig.vshost.exe.config files in the ‘EncryptConfig’ project.
The solution is now ready for deployment. You will want to make sure that the config files are UNENCRYPTED for deployment (due to the machine key problem discussed at the top of this blog).