Crypt your config files with PowerShell

ASP.Net 2.0 comes with a convenient native support for configuration file encryption. Yet, things are still not that easy for WinForms, Console applications or Windows Services since the aspnet_regiis.exe utility only supports Web Configuration files.

My own μISV has its share of distributed applications which involve securing a few connection strings over several machines. Securing the connection strings through encryption is not an ultimate defense (if the attacker gains executions rights on the local machine, connection strings will get disclosed anyway), but it can still save you a lot of trouble such as involuntary disclosure.

I have found a practical way to solve the issue through PowerShell, namely two functions crypt-config and decrypt-config. The source code comes as single PSH script contains the function definitions.

To get started, extract the PS1 file from the snippet below, then

PS docs:\> . ($directory + "\crypt-config.ps1") ;
PS docs:\> crypt-config 'MyConsole.exe' 'section';
PS docs:\> decrypt-config 'MyConsole.exe' 'section';  

Typically, section will be replaced by connectionStrings. Note that you do not need to add the .config at the end of the configuration file path.

crypt-config.ps1

# Crypt-Config -- Decrypt-Config
# By Joannes Vermorel, 2007
# 
# Utility to secure configuration files (based on DpapiProtectedConfigurationProvider)
# 
# Usage: 	Crypt-Config 'MyApp.exe' 'connectionStrings'
# 		Decrypt-Config 'MyApp.exe' 'connectionStrings'

[System.Reflection.Assembly]::LoadWithPartialName("System.Configuration");

function Crypt-Config {

param( [string] $configPath = $(throw "Missing: Indicate the path of the configuration file."), 
	[string] $sectionName = $(throw "Missing: Indicate the section to be encrypted.") ) ;

begin {
}

process {
  $config = [System.Configuration.ConfigurationManager]::OpenExeConfiguration( (Convert-Path $configPath) );
  $section = $config.GetSection( $sectionName );

  if(-not $section.SectionInformation.IsProtected) {
    if(-not $section.SectionInformation.IsLocked) {
      $section.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
      $section.SectionInformation.ForceSave = $true;
      $config.Save( [System.Configuration.ConfigurationSaveMode]::Modified );
    }
  }
}

end {
}

}


function Decrypt-Config {

param( [string] $configPath = $(throw "Missing: Indicate the path of the configuration file."), 
	[string] $sectionName = $(throw "Missing: Indicate the section to be encrypted.") ) ;

begin {
}

process {
  $config = [System.Configuration.ConfigurationManager]::OpenExeConfiguration( (Convert-Path $configPath) );
  $section = $config.GetSection( $sectionName );

  if($section.SectionInformation.IsProtected) {
    if(-not $section.SectionInformation.IsLocked) {
      $section.SectionInformation.UnprotectSection();
      $section.SectionInformation.ForceSave = $true;
      $config.Save( [System.Configuration.ConfigurationSaveMode]::Modified );
    }
  }
}

end {
}

}