# VBForums CodeBank > CodeBank - Visual Basic .NET >  [.NET 2.0+] Protected Configuration (Encrypting Config Files)

## jmcilhinney

The config file is the preferred location for application configuration data these days.  .NET apps will use it themselves to store data in various situations.  One such situation that many people may have encountered is when you create a Data Source the wizard offers to store the connection string in the config file.  This is so that you can simply edit the config file when the app is installed to customise the connection for that system.  One issue here is, what if the connection string contains a password?  The config file is just plain text so its visible to the world.  The answer is encryption and it's already built into the .NET configuration mechanism.

Try running the attached project and then opening the config file from the bin\Debug folder in VS.  Notice that there's a <connectionStrings> section and it contains an item named PrimaryConnectionString.  Now, select Tools -> Options from the menu and see that the components of that connection string are displayed as individual fields.  Try editing those fields and then clicking OK.  You don't actually have to have SQL Server installed to do this but if you want to use the drop-down lists to select a server and database you will need it.  Go back to VS and you should be prompted to reload the config file.  Do so and note that the values you entered now appear in the stored connection string.

Next, select Tools -> Encrypt Connection Strings from the menu.  Go back to VS and reload the config file again and observe the changes.  Note that your actual connection string is nowhere to be seen.  Now, if you select Tools -> Options again at this point an exception will be thrown.  I'm not sure exactly why and i'm not sure how to fix it, but that isn't really a problem anyway.  This error only occurs when you start the app with the <connectionStrings> section unencrypted, then encrypt it, then try to read a connection string via My.Settings.  This should never occur so the error should never appear.

So, close the app and then run it again.  Select Tools -> Options from the menu and observe that the components of the connection string are displayed again, even though they cannot be seen in the config file.  There was no extra code needed to accomplish this.  The user code is exactly the same to read the connection string whether the config file is encrypted or not.  the decryption is handled on-the-fly by the Framework.

Now, edit the connection properties again and click OK.  Go back to VS and reload the config file again and observe that the long strings of gibberish have changed.  Those strings contain your data in encrypted format.  Now, select Tools -> Decrypt Connection Strings from the menu and go back to VS and reload the config file again.  Note that your connection string is now visible again and the changes you made are reflected.  Go back to the app and select Tools -> Options again and observer that, using the same code again, the connection properties have been read from the unencrypted config file.  Tada!

*N.B.* - I've removed the original attachment, which was a VS 2008 project, and attached a VS 2005 version in its place.

----------


## jmcilhinney

To continue, that all demonstrates encrypting the <connectionStrings> section.  You can encrypt other sections too.  In the code for the OptionsDialogue in the project find the Load event handler, which looks like this:
vb.net Code:
Private Sub OptionsDialogue_Load(ByVal sender As Object, _                                 ByVal e As EventArgs) Handles MyBase.Load    Me.LoadConnectionString()    'Me.LoadAppSettings()End Sub
and change it to this:
vb.net Code:
Private Sub OptionsDialogue_Load(ByVal sender As Object, _                                 ByVal e As EventArgs) Handles MyBase.Load    'Me.LoadConnectionString()    Me.LoadAppSettings()End Sub
Likewise find the okButton.Click event handler and change this part:
vb.net Code:
configSaved = Me.SaveConnectionString'configSaved = Me.SaveAppSettings
to this:
vb.net Code:
'configSaved = Me.SaveConnectionStringconfigSaved = Me.SaveAppSettings
You can now perform the same steps as before but note that the connection properties are being retrieved from, and stored to, individual elements within the <appSettings> section.  As such, use the Encrypt App Settings and Decrypt App Settings items from the Tools menu to encrypt and decrypt the config file.

Note that in this case you can still read the config file successfully even if encryption was applied after opening the app.  Like I said though, this situation should never arise in the real world.

So, speaking of the real world, how would you use this?  Well, normally if you want to encrypt the config file then you'd want it encrypted all the time.  As such you would use a Setup project to install your app and then you'd include the encryption code in a Custom Action, so the config file is encrypted when the app's installed.  because you don't need to make any code changes to read and write an encrypted config file, you can read and write the unencrypted config file while you're developing and then read and write the encrypted config file when the app's deployed without having to care which is which.

Note that what I've shown is for WinForms apps.  ASP.NET apps are very similar except that you don't perform the encryption and decryption in code.  You encrypt a web.config file using the aspnet_regiis utility at the commandline.  That's basically because web apps get installed once only, and it's not going to be the end user who installs it.

How To: Encrypt Configuration Sections in ASP.NET 2.0 Using DPAPI
How To: Encrypt Configuration Sections in ASP.NET 2.0 Using RSA

Please play with the code and feel free to ask questions *BUT* please make sure you have read the code THOROUGHLY first.

----------


## jlbantang

great! i always hope the best from jm  :Big Grin:

----------


## jlbantang

hcan you please provide, is there available version for 2005?  im receiving this error "the selected file is a solution file, but was created by newer version of this application or cannot be opened."

tnx

----------


## jmcilhinney

> hcan you please provide, is there available version for 2005?  im receiving this error "the selected file is a solution file, but was created by newer version of this application or cannot be opened."
> 
> tnx


Go back and read the edit I added to the end of the first post.

----------


## jlbantang

thnx. 

i tried to work around by chance to remove the blue squirky lines particular in the *Dim config As System.Configuration.Configuration*

what i did is import configuration related namespace to make sure i wont miss a thing

vb Code:
Imports System.ConfigurationImports System.Configuration.ApplicationScopedSettingAttributeImports System.Configuration.ApplicationSettingsBaseImports System.Configuration.AssembliesImports System.Configuration.DefaultSettingValueAttributeImports System.Configuration.NoSettingsVersionUpgradeAttributeImports System.Configuration.SettingAttributeImports System.Configuration.SettingsAttributeDictionaryImports System.Configuration.SettingsDescriptionAttributeImports System.Configuration.SettingsGroupDescriptionAttributeImports System.Configuration.SettingsGroupNameAttributeImports System.Configuration.SettingsLoadedEventArgsImports System.Configuration.SettingsManageabilityAttributeImports System.Configuration.SettingsPropertyWrongTypeExceptionImports System.Configuration.SettingsProviderAttributeImports System.Configuration.SettingsSerializeAsAttributeImports System.Configuration.SpecialSettingAttributeImports System.Configuration.UserScopedSettingAttribute

but still i received the same error.

----------


## jmcilhinney

There's no use importing the namespace a class is a member of if you haven't referenced the assembly it's declared in.

----------


## jlbantang

everything's clear except this line


vb Code:
Private Sub LoadConnectionString()        'Load the current connection string.        Dim builder As New SqlConnectionStringBuilder(My.Settings.PrimaryConnectionString)...end sub

i dont understand the line and its produce an error. i change the argument to 



```
        Dim builder As New SqlConnectionStringBuilder("Data Source=ConnectionStringsServer;Initial Catalog=ConnectionStringsDatabase;User ID=ConnectionStringsUserName;Password=ConnectionStringsPassword")
```





the program run but i was not able to encrypt/decrypt app.config

----------


## jmcilhinney

It's not clear what you mean when you say it's not clear. Do you mean you don't understand it or that it's not working?

----------


## jlbantang

hi jm. the prog runs but the app.config were not encrypted/decrypted. your code which i replace might have something to do w/ this.

your code:

vb Code:
Dim builder As New SqlConnectionStringBuilder(My.Settings.PrimaryConnectionString)

what was this line for anyway?

replaced with this:

vb Code:
Dim builder As New SqlConnectionStringBuilder("Data Source=ConnectionStringsServer;Initial Catalog=ConnectionStringsDatabase;User ID=ConnectionStringsUserName;Password=ConnectionStringsPassword")

----------


## jmcilhinney

> hi jm. the prog runs but the app.config were not encrypted/decrypted. your code which i replace might have something to do w/ this.
> 
> your code:
> 
> vb Code:
> Dim builder As New SqlConnectionStringBuilder(My.Settings.PrimaryConnectionString)
> 
> what was this line for anyway?
> 
> ...


That line is to load the stored connection string via My.Settings.  Likely you have to actually add the connection string to the settings first.  Just impoting the config file is probably not enough.  Go to the Settings tab of your project properties and check if there's a connection string listed there.  If there isn't then you'll need to add one, so you'll need to delete the existing one from the config file first.

----------


## MechEng

> N.B. - This solution was created in VS 2008, so you will not be able to open it in VS 2005, even though it targets .NET 2.0 and all the code will work. If you're using VS 2005 then you have two choices:
> 
> 1. Edit the SLN and VBPROJ files so they become compatible with VS 2005. Do NOT try this if you don't absolutely know what you're doing.
> 2. Create a new VS 2005 solution and use Add Existing Item to import the items from my solution. I think you should be able to import everything but, if not, only a small amount of hand-editing will be required.


Thanks jmc.  This is seams to be a well done post, but I was wondering if anyone actually been able successfully import the code into VB2005?  I have been working on this for hours and I obviously do not have enough VB-brain power to correct all the import issues.       :Frown:

----------


## jmcilhinney

I've removed the original attachment and attached a VS 2005 version of the project in its place.

----------


## MechEng

Thanks jmc.  This works great and is an excellent example of encrypt/decrypt of and access to the config file.     :Thumb:   :Thumb:   :Thumb:  

Thanks very much.

----------


## Xancholy

> Go to the Settings tab of your project properties and check if there's a connection string listed there.


Thanks for this terrific info. I don't understand a few things and request clarification.

After one adds the connection string to the Settings tab of your project properties and the encryption takes place though your solution...

If I want to use your data access examples to pull data to a form...

How would I now open & close connections ?

----------


## jmcilhinney

> Thanks for this terrific info. I don't understand a few things and request clarification.
> 
> After one adds the connection string to the Settings tab of your project properties and the encryption takes place though your solution...
> 
> If I want to use your data access examples to pull data to a form...
> 
> How would I now open & close connections ?



vb.net Code:
Dim connection As New SqlConnection(My.Settings.MyConnectionString)
That's it, whether the config file is encrypted or not.  The decryption is handled seamlessly.

----------


## Xancholy

That's beautiful - thanks !

----------


## thermo_ll

can you post also the vb2008 version of this code ! thanks

----------


## jmcilhinney

> can you post also the vb2008 version of this code ! thanks


The code is exactly the same.  I only attached a VS 2005 project because VS 2005 users couldn't open a VS 2008 project.  The converse is not the case so you can simply open the attached project as you normally would and say yes when VS offers to upgrade it to VS 2008 format.

----------


## illskills

many thanks im going to bookmark this and read it in the morning ;0)

----------


## jsun9

Do we know what encryption this is, exactly? AES? 128bit?

----------


## jmcilhinney

> Do we know what encryption this is, exactly? AES? 128bit?


Check out the links in post #2.  You can use the DPAPI and not care or user RSA and provide your own key.

----------


## Bladewing51

Hi Jmc,
       Recently found your example and found it fascinating, I wanted to see if I could use certain principles found in your example in a vb.net 4.0, WPF application in order to learn but I seem to be stuck and wondered if you could help me. Now although I am able to save custom connection strings to the YOUR_APP.exe.config file, I am not able to retrieve the saved connection string in the same way you do in your example, instead the default ConnectionStringsPassword etc... values show up instead.

This is the example which I was trying to figure out (Works perfect)


```
    Private Sub LoadConnectionString()
        'Load the current connection string.
        Dim builder As New SqlConnectionStringBuilder(My.Settings.PrimaryConnectionString)

        'Display individual connection string properties.
        Me.serverCombo.Text = builder.DataSource
        Me.integratedSecurityOption.Checked = builder.IntegratedSecurity
        Me.sqlServerSecurityOption.Checked = Not builder.IntegratedSecurity
        Me.userText.Text = builder.UserID
        Me.passwordText.Text = builder.Password
        Me.databaseCombo.Text = builder.InitialCatalog
    End Sub
```


This is my simplified code that I have built from your example (Which still shows default values that are in the app.config and settings wizard in VS and not the custom values in YOUR_APP.exe.config.)


```
    Private Sub Loadconstr()
        'Load the current connection string
        Dim csb As New SqlConnectionStringBuilder(My.Settings.PrimaryConnectionString)

        'displays individual constr propertys from the app.config.
        Me.start1_Cmbo_InstNam.Text = csb.DataSource
        start1_Userid_Cmbox.Text = csb.UserID
        start1_cmbo_pass.Text = csb.Password

    End Sub
```

----------


## jmcilhinney

I haven't looked at this code for a long time but my first guess would be that you need to reload the settings from the config file.  My.Settings has a Reload method or something like that, so you might try that.

----------


## Bladewing51

ok I'll give that a shot and let you know. Would I put the my.settings.reload in the first line of the loadconstring sub or elsewhere?

----------


## jmcilhinney

> ok I'll give that a shot and let you know. Would I put the my.settings.reload in the first line of the loadconstring sub or elsewhere?


You would put it wherever it's appropriate to reload your settings.  After making changes would be the logical option, so that you know immediately that My.Settings contains the most current data.

----------


## Bladewing51

On second look I found the my.settings.reload under the saveconstr(), I'll post my whole code here, I'd really, really, appreciate it if you could look over it quick and see if anything stands out to you, like I stated before the user inputted connection string values save to YOUR_APP_NAME.exe.config and asks to refresh in VS but the code just wont pull the saved info from YOUR_APP_NAME.exe.config back to the textboxes. It seems to only pull values from app.config or the settings page, under project propertys, it sucks to be this close but yet still so far away.  :Cry: 



```
Imports System.Data
Imports System.Data.Sql
Imports System.Data.SqlClient
Imports System.Configuration


Class Start1

    Private Sub Button6_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles Button6.Click


        Call saveconstr()

    End Sub

    Private Sub Start1_Loaded(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Loaded
        Call Loadconstr()

    End Sub

'THIS IS WHERE I HAVE THE PROBLEM, LOADS ONLY DEFAULT VALUES.
    Private Sub Loadconstr()
        'Load the current connection string
        Dim csb As New SqlConnectionStringBuilder(My.Settings.PrimaryConnectionString)

        Me.start1_Cmbo_InstNam.Text = csb.DataSource
        start1_Userid_Cmbox.Text = csb.UserID
        start1_cmbo_pass.Text = csb.Password

    End Sub

    Private Sub start1_Cmbo_InstNam_DropDownOpened(sender As Object, e As EventArgs) Handles start1_Cmbo_InstNam.DropDownOpened

        Dim Servertable As DataTable = SqlDataSourceEnumerator.Instance.GetDataSources()
        Dim upperbound As Integer = Servertable.Rows.Count - 1
        Dim servernames(upperbound) As String

        For index As Integer = 0 To upperbound
            If Servertable.Rows(index).IsNull("InstanceName") Then
                servernames(index) = CStr(Servertable.Rows(index)("ServerName"))
            Else

                servernames(0) = String.Format("{0}\{1}", _
                                               Servertable.Rows(0)("ServerName"), _
                                               Servertable.Rows(0)("InstanceName"))
            End If
        Next

        Dim currentservername As String = start1_Cmbo_InstNam.Text

        'WPF requires combobox binding to work, hense datacontext and in xaml itemsource.
        With start1_Cmbo_InstNam
            '.Items.Clear()
            .DataContext = servernames
            .SelectedItem = currentservername
            .Text = currentservername

        End With

    End Sub
    Private Function saveconstr() As Boolean
        Dim result As Boolean = False

        'WORKS PERFECT, SAVES TO YOUR_APP_NAME.EXE.CONFIG (PROBABLY DOESNT NEED TO BE A FUNCTION FOR MY APPLICATION BUT LEFT AS IS FOR NOW)
        Dim config As System.Configuration.Configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)

        For Each setting As ConnectionStringSettings In config.ConnectionStrings.ConnectionStrings
            'find the connectionstring
            If setting.Name.Contains("PrimaryConnectionString") Then
                'save the new connection string entered by the user.
                setting.ConnectionString = getconstr()

                'save the changes to the config file
                config.Save(ConfigurationSaveMode.Modified)
                ConfigurationManager.RefreshSection("connectionStrings")

                'force refresh of connectionstring from the config file
                My.Settings.Reload()

                Exit For
            End If
        Next setting
        Return result
    End Function

    Private Function getconstr() As String
        Dim csb As New SqlConnectionStringBuilder()

        'put together a connection string from all user inputs
        csb.DataSource = start1_Cmbo_InstNam.Text
        csb.IntegratedSecurity = False
        csb.UserID = start1_Userid_Cmbox.Text
        csb.Password = start1_cmbo_pass.Text
        csb.InitialCatalog = ""

        Return csb.ConnectionString

    End Function

End Class
```

This is from the app.config file


```
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
  </configSections>
  <appSettings>
		<add key="ServerName" value="AppSettingsServer" />
		<add key="DatabaseName" value="AppSettingsDatabase" />
		<add key="OSSecurity" value="False" />
		<add key="UserName" value="AppSettingsUserName" />
		<add key="Password" value="AppSettingsPassword" />
  </appSettings>
  <connectionStrings>
    <add name="Barcodeapp.My.Settings.PrimaryConnectionString" connectionString="Data Source=ConnectionStringsServer; Initial Catalog=ConnectionStringsDatabase;User ID=ConnectionStringsUserName;Password=ConnectionStringsPassword" />
  </connectionStrings>
  <system.diagnostics>
        <sources>
            <!-- This section defines the logging configuration for My.Application.Log -->
            <source name="DefaultSource" switchName="DefaultSwitch">
                <listeners>
                    <add name="FileLog"/>
                    <!-- Uncomment the below section to write to the Application Event Log -->
                    <!--<add name="EventLog"/>-->
                </listeners>
            </source>
        </sources>
        <switches>
            <add name="DefaultSwitch" value="Information" />
        </switches>
        <sharedListeners>
            <add name="FileLog"
                 type="Microsoft.VisualBasic.Logging.FileLogTraceListener, Microsoft.VisualBasic, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"
                 initializeData="FileLogWriter"/>
            <!-- Uncomment the below section and replace APPLICATION_NAME with the name of your application to write to the Application Event Log -->
            <!--<add name="EventLog" type="System.Diagnostics.EventLogTraceListener" initializeData="APPLICATION_NAME"/> -->
        </sharedListeners>
    </system.diagnostics>
</configuration>
```


This is the from the applications .exe.config file that the code saves the values to.


```
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
  </configSections>
  <appSettings>
		<add key="ServerName" value="AppSettingsServer" />
		<add key="DatabaseName" value="AppSettingsDatabase" />
		<add key="OSSecurity" value="False" />
		<add key="UserName" value="AppSettingsUserName" />
		<add key="Password" value="AppSettingsPassword" />
  </appSettings>
  <connectionStrings>
    <add name="Barcodeapp.My.Settings.PrimaryConnectionString" connectionString="Data Source=server1;Initial Catalog=;Integrated Security=False;User ID=user1;Password=pass1" />
  </connectionStrings>
  <system.diagnostics>
        <sources>
            <!-- This section defines the logging configuration for My.Application.Log -->
            <source name="DefaultSource" switchName="DefaultSwitch">
                <listeners>
                    <add name="FileLog"/>
                    <!-- Uncomment the below section to write to the Application Event Log -->
                    <!--<add name="EventLog"/>-->
                </listeners>
            </source>
        </sources>
        <switches>
            <add name="DefaultSwitch" value="Information" />
        </switches>
        <sharedListeners>
            <add name="FileLog"
                 type="Microsoft.VisualBasic.Logging.FileLogTraceListener, Microsoft.VisualBasic, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"
                 initializeData="FileLogWriter"/>
            <!-- Uncomment the below section and replace APPLICATION_NAME with the name of your application to write to the Application Event Log -->
            <!--<add name="EventLog" type="System.Diagnostics.EventLogTraceListener" initializeData="APPLICATION_NAME"/> -->
        </sharedListeners>
    </system.diagnostics>
</configuration>
```

And finally the settings under the apps project propertys

NAME                                   TYPE                   SCOPE          VALUE
PrimaryConnectionString | (connectionstring) | Application | Data Source=ConnectionStringsServer;Initial Catalog=ConnectionStringsDatabase;User ID=ConnectionStringsUserName;Password=ConnectionStringsPassword

----------


## jmcilhinney

I think I need to make something clear, just to be sure that you're not expecting something to happen that is not meant to happen.  The app.config file is a source file only.  It doesn't exist at run time so the application cannot get anything from it.  When you build your project, any appropriate transformations are performed on app.config file and the result is copied to the output folder along with your EXE and renamed to match the EXE name with a ".config" extension.  Any changes you make at run time are made to that file.  If you close the application, rebuild and then run again, any changes you made will be lost because your config file will have been overwritten with a new copy.  Is that maybe what's happening or are you absolutely sure that the config file contains the correct values when the app apparently reads the wrong ones?

----------


## Bladewing51

Yes were deffinatly on the same page and i posted both the app.config and the Applicationname.exe.config file in the above post to show you that the correct values are indeed being saved to the applicationname.exe.config. In this case server1 for the server instance, user1 for user id and pass1 for password. These values also stay in the applicationname.exe.config file untill new values are entered into the textboxes and the appropriate save subroutine is called.

Also when I use a breakpoint at the end of the loadconstr sub and hover the mouse over the "Primaryconnectionstring" of the line Dim csb As New SqlConnectionStringBuilder(My.Settings.PrimaryConnectionString) it shows the default values, dont know if that helps.

----------


## Bladewing51

Ok so I finally cracked it, and THINK it was just down to 3 things but not exactly sure if it was one or an accumulation off all 3.

#1) It seems visual studio by default hosts your app in its own process which was causing the YOUR_APP.exe.config to be omitted and the YOUR_APP.vshost.exe.config to be used instead with unstable results, which also may or may not be put into your project folder.

#2) I also changed the setting of "PrimaryConnectionString" to just "PCS" to avoid any typos that may occur from a long designation.

#3) Finally I hit synchronize and found that I had a user file somewhere that was deleted and now its working.

NOTE: I started a new app to debug what exactly was going on and found all I needed to do to get the code to work was step #1 although for my own sanity I always implement shorter names as in #2.

 :Smilie:

----------


## jmcilhinney

With regards to point 1, I recall reading some time ago what that VS hosting process was supposed to do for you but I can't remember what that was.  I do recall that it was not required in the majority of cases, so turning it off should not be an issue.  That said, I don't recall having to do that in the demo project I created for this thread.

With regards to point 2, I think that using short names like that that mean nothing to anyone without prior knowledge is a bad idea.  In the case of a connection string, the only time that you have to actually type the name without help from Intellisense is when you create it in the first place, so the chance of a typo is basically null.  It's more important that someone can look at the name and actually know what the thing is from that alone rather than having to divine what some initials might be for.  I'll use initials in cases where a variable exists for a short time and the meaning is obvious, e.g.

```
Using ofd As New OpenFileDialog
```

but PCS would mean nothing to anyone.  You might be able to guess that CS was connection string from usage but the P would be a complete mystery.

----------


## make me rain

what a great contribution it is ,
hats up

----------

