How To use ASPNET_SetReg to store encrypted data in the registry and then decrypt the data for use in your app

1) You may find it a bit unsecure storing usernames and passwords inside your web.config.  As an alternative to doing this, Microsoft has established a
standard way to store that type of info in the registry of your server instead. 

Yes, you can encrypt portions of the web.config using aspnet_regiis, but it can become quite a hassle if you need to make changes to some of your appSettings keys or change the account password over a number of different applications.   (http://msdn.microsoft.com/en-us/library/dtkwfdky.aspx)

2) You can use a simple command line tool called aspnet_setreg.exe to create your registry entries.

    You can find the tool here:
             http://support.microsoft.com/kb/329290

    The tool will use CryptProtectData to encrypt the values you put in the registry.

The example in the article uses the following example:
Run the following command to add the registry entry:
c:\Tools>aspnet_setreg.exe -k:SOFTWARE\MY_SECURE_APP\identity -u:"yourdomainname\username" -p:"password"

Then in web.config:
<identity impersonate="true"
userName="registry:HKLM\SOFTWARE\MY_SECURE_APP\identity\ASPNET_SETREG,userName"
password="registry:HKLM\SOFTWARE\MY_SECURE_APP\identity\ASPNET_SETREG,password" />

Note that on 64 bit systems, the registry setting will be placed in the HKLM\Software\WOW6432Node. 

So, if you are on a 64 bit system (as most are these days), you can use regedit to find where the key is and use that path.

Finally, you will need to set the permissions in the registry key to make sure that the application pool identity for the web application has read permissions to the registery key for ASPNET_SETREG.  I believe the permissions are reset everytime you run the ASPNET_SETREG tool, so make sure you do set the permissions if you run the aspnet_setreg tool again.


3) However, if you'd like to do this for appkeys or connection strings, you'll need a function to parse the text, read the registry, and decrypt the value before you can use this method.

4) I had found a VB.Net function  in a blog from the following link:
http://webcache.googleusercontent.com/search?q=cache:http://securitythroughabsurdity.com/2006/04/howto-use-aspnetsetreg-utility-to.html
(Had to get it from google's cache because the blog was no longer there.)

I wrote a C# version of the function below:


using NCrypto.Security.Cryptography;
using System.Text;
using Microsoft.Win32;
using System;


namespace RegistryHelper
{
public enum RegistryHive {HKLM,HKCR,HKCU,HKU,HKCC}

public class RegistryCryptoUtility
{
    private const string COLON_DELIMITER = ":";
    private const string COMMA_DELIMITER  = ",";
    private const string BACKSLASH_DELIMITER  = "\\";
    private const string REGISTRY_PREFIX = "registry:";  
   
    // Receives a string in the format:
    // registry:HKLM\Software\ASP.NET\MyKey\ASPNET_SETREG,sqlConnectionString   
    // and pulls the value from the correct registry hive, and extracts and   
    // decrypts the connection string information   
   
    //
    public static string DecryptRegistryConnectionString(string configConnectionSetting )
    {       
        RegistryKey regKey;   // 
        Byte[] registryBytes;
       
        if (configConnectionSetting.StartsWith(REGISTRY_PREFIX))
        {
            string regKeyPathAndKey = configConnectionSetting.Split(COLON_DELIMITER.ToCharArray())[1];
            string regKeyPath  = regKeyPathAndKey.Split(COMMA_DELIMITER.ToCharArray())[0];
            string keyName  =  regKeyPathAndKey.Split(COMMA_DELIMITER.ToCharArray())[1];
            RegistryKey regkeyHive;// Open the proper Registry Hive
           
            if (regKeyPath.StartsWith( System.Enum.GetName(Type.GetType("RegistryHelper.RegistryHive"), RegistryHive.HKLM)))
            {
                regkeyHive = Registry.LocalMachine;
               
            }
            else if (regKeyPath.StartsWith(System.Enum.GetName(Type.GetType("RegistryHelper.RegistryHive"), RegistryHive.HKCR)))
            { regkeyHive = Registry.ClassesRoot;
            }
            else if (regKeyPath.StartsWith(System.Enum.GetName(Type.GetType("RegistryHelper.RegistryHive"), RegistryHive.HKCU)))
            {
                regkeyHive = Registry.CurrentUser;
            }
            else if (regKeyPath.StartsWith(System.Enum.GetName(Type.GetType("RegistryHelper.RegistryHive"), RegistryHive.HKU)))
            {
                regkeyHive = Registry.Users;
            }
            else if (regKeyPath.StartsWith(System.Enum.GetName(Type.GetType("RegistryHelper.RegistryHive"), RegistryHive.HKCC)))
            {
                regkeyHive = Registry.Users;
            }
            else
            {
                throw new ApplicationException("Unknown Key reference: " + regKeyPath);
            }
          
            int seperatorPosition = regKeyPath.IndexOf(BACKSLASH_DELIMITER, 0) + 1;
            regKeyPath = regKeyPath.Substring( seperatorPosition, regKeyPath.Length - seperatorPosition);
            regKey = regkeyHive.OpenSubKey(regKeyPath);
            registryBytes = (Byte[]) regKey.GetValue(keyName);
            return Encoding.Unicode.GetString(ProtectedData.Unprotect(registryBytes));

           
        }
        else
        {
           // return the Config string, registry not specified          
            return configConnectionSetting;
        }

    }
  }
}


You will need files from the NCrypto source code available on sourceforge at the below link for the crypto portion:
http://ncrypto.sourceforge.net/default.htm

NCrypto Files needed to use the ProtectedData.Unprotect function in your project:
CryptographyPermission.cs
CryptographyPermissionAttribute.cs
ProtectedData.cs
Resource.cs
Utility.cs
Win32Native.cs

Sample usage:
Example 1 Username and password:
aspnet_setreg -k:Software\WebConfigSettings\taskidentity  -u:username -p:[password]

In web.config:
 <appSettings>
    <add key="LDAPAccount" value="registry:HKLM\Software\WebConfigSettings\taskidentity\ASPNET_SETREG,userName" />
 </appSettings>


In Code:
  string LDAPAccount=RegistryCryptoUtility.DecryptRegistryConnectionString(ConfigurationManager.AppSettings["LDAPAccount"]);



Example 2 Connection string:
aspnet_setreg -k:Software\ASP.NET\MyKey -c:"data source=server;userid=user;password=password"


In web.config:
<appSettings>  <add key="ConnectionString" value="registry:HKLM\Software\ASP.NET\MyKey\ASPNET_SETREG,customConnectionString" /></appSettings>


In Code:
 string strConn=RegistryCryptoUtility.DecryptRegistryConnectionString(ConfigurationManager.AppSettings["ConnectionString"]);




Troubleshooting Registry Permissions for ASPNET_SetReg:
    You can wrap the code in a try-catch statement and display the windows identity that the web app is running as to determine which account needs read permissions to the registry, if you are having permissions issues with the registry entry.

        try
        {
            username = RegistryHelper.RegistryCryptoUtility.DecryptRegistryConnectionString(ConfigurationManager.AppSettings["LDAPAccount"]); //ConfigurationManager.AppSettings["LDAPAccount"].ToString();
        }
        catch (Exception ex)
        {
            HttpContext.Current.Response.Write("user: " + username + ", LDAPAccount: "+ ConfigurationManager.AppSettings["LDAPAccount"] + ".<br /> "+ ex.Message +"<br />");

           
                HttpContext.Current.Response.Write("Windows Identity: " + WindowsIdentity.GetCurrent().Name + "<br />" ;


    
            HttpContext.Current.Response.End();


        }

Comments

Popular posts from this blog

Getting Authentication Prompt When Accessing SharePoint Web Services

PowerShell Script to Clean the Windows Installer Directory