0

I'm new to this so please bear with me. I'm trying to encrypt/decrypt a .config section using RsaProtectedConfigurationProvider

Please correct me if I'm wrong but from what i've been reading I need to do the following:

  1. Get a certificate and a public key from that certificate

    X509Certificate2 cert = new X509Certificate2(pathToCert, "password");
    RSACryptoServiceProvider rsa = cert.PrivateKey as RSACryptoServiceProvider;
    
  2. Load this info to Container: Not sure how to do it as the sample below does not account for certificates

http://msdn.microsoft.com/en-us/library/tswxhw92(en-us,VS.80).aspx

    // Create the CspParameters object and set the key container 
    // name used to store the RSA key pair.
    CspParameters cp = new CspParameters();
    cp.KeyContainerName = "MySuperAwesomeKeyContainer";

    // Create a new instance of RSACryptoServiceProvider that accesses
    // the key container MyKeyContainerName.
    RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cp);
  1. Then have the same Container name specified in my App.Config:
<configProtectedData>
<providers>
 <clear/>
  <add name="MyProvider"
  type="System.Configuration.RsaProtectedConfigurationProvider"
  keyContainerName="MySuperAwesomeKeyContainer"
  useMachineContainer="true" />
</providers>
</configProtectedData>
  1. Then just run this code that will use that KeyContainer and encrypt/decrypt it:
....
string provider = "MyProvider";
// Protect the section.
connStrings.SectionInformation.ProtectSection(provider);

Is this correct?. If so, how would I do it?? Not sure how to get those keys from certificate and load them in a KeyContainer.

thanks

ShaneKm
  • 20,823
  • 43
  • 167
  • 296

2 Answers2

1

I did it like this:

Provider Implementation:

public class X509ProtectedConfigProvider : ProtectedConfigurationProvider
{
    #region Fields

    private X509Certificate2 cert;

    #endregion

    // Performs provider initialization. 
    #region Public Methods and Operators

    public override XmlNode Decrypt(XmlNode encryptedNode)
    {
        // Load config section to encrypt into xmlDocument instance
        XmlDocument doc = encryptedNode.OwnerDocument;
        EncryptedXml eXml = new EncryptedXml(doc);

        eXml.DecryptDocument();
        return doc.DocumentElement;
    }

    public override XmlNode Encrypt(XmlNode node)
    {
        // Load config section to encrypt into xmlDocument instance
        XmlDocument doc = new XmlDocument { PreserveWhitespace = true };
        doc.LoadXml(node.OuterXml);

        // Encrypt it
        EncryptedXml eXml = new EncryptedXml();
        EncryptedData eData = eXml.Encrypt(doc.DocumentElement, this.cert);
        return eData.GetXml();
    }

    public override void Initialize(string name, NameValueCollection config)
    {
        base.Initialize(name, config);

        string certSubjectDistName = config["CertSubjectDistinguishedName"];
        string certStoreName = config["CertStoreName"];

        X509Store certStore = !string.IsNullOrEmpty(certStoreName) ? new X509Store(certStoreName, StoreLocation.LocalMachine) : new X509Store(StoreLocation.LocalMachine);

        try
        {
            certStore.Open(OpenFlags.ReadOnly);
            X509Certificate2Collection certs = certStore.Certificates.Find(
                X509FindType.FindBySubjectName, certSubjectDistName, true);

            this.cert = certs.Count > 0 ? certs[0] : null;
        }
        finally
        {
            certStore.Close();
        }
    }

    #endregion
}

Helper class:

public static class Crypto
    {
        // Protect the connectionStrings section. 
        #region Public Methods and Operators

        public static bool ProtectConfiguration(string path)
        {
            string provider = "X509ProtectedConfigProvider";

            // Get the application configuration file.
            Configuration config = ConfigurationManager.OpenExeConfiguration(path);

            // Get the section to protect.
            ConfigurationSection connStrings = config.ConnectionStrings;

            if (connStrings != null)
            {
                if (!connStrings.SectionInformation.IsProtected)
                {
                    if (!connStrings.ElementInformation.IsLocked)
                    {
                        // Protect the section.
                        connStrings.SectionInformation.ProtectSection(provider);

                        connStrings.SectionInformation.ForceSave = true;
                        config.Save(ConfigurationSaveMode.Full);

                        return true;
                    }

                    return false;
                }

                return true;
            }

            return false;
        }

        // Unprotect the connectionStrings section. 
        public static void UnProtectConfiguration(string path)
        {
            // Get the application configuration file.
            Configuration config = ConfigurationManager.OpenExeConfiguration(path);

            // Get the section to unprotect.
            ConfigurationSection connStrings = config.ConnectionStrings;

            if (connStrings != null)
            {
                if (connStrings.SectionInformation.IsProtected)
                {
                    if (!connStrings.ElementInformation.IsLocked)
                    {
                        // Unprotect the section.
                        connStrings.SectionInformation.UnprotectSection();

                        connStrings.SectionInformation.ForceSave = true;
                        config.Save(ConfigurationSaveMode.Full);
                    }
                }
            }
        }

        #endregion
    }
}

App.Config (note configProtectedData):

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog"/>
  </configSections>
  <connectionStrings>
    <add name="MyDbConnStr" providerName="System.Data.SqlClient" connectionString="Data Source=localhost;Initial Catalog=MyDb;Integrated Security=True;"/>
  </connectionStrings>
  <appSettings>
    <add key="SiteName" value="MyAwesomeSite"/>
  </appSettings> 
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup>
    <configProtectedData>
        <providers>
            <add CertSubjectDistinguishedName="localhost" CertStoreName="MyCertKeyStore" name="X509ProtectedConfigProvider" type="ProtectedConfigProvider.X509ProtectedConfigProvider, X509ProtectedConfigProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=098027505e2ed139" />
        </providers>
    </configProtectedData>
</configuration>

Program (Usage):

...

ProtectConfiguration("mysuperawesomeapp.exe);

DatabaseFactory.SetDatabaseProviderFactory(new DatabaseProviderFactory());
Database db = DatabaseFactory.CreateDatabase("MyDbConnStr");

Reading from db works fine with encrypted app config "connectionStrings" section. :)

ShaneKm
  • 20,823
  • 43
  • 167
  • 296
0

You'll find the steps here: Walkthrough: Creating and Exporting an RSA Key Container. You don't need a certificate, you can generate the key container directly.

If you're encrypting a custom configuration section, there's a trick to make it work: You'll have to remove the declaration of the configSection. I've blogged the details here: How to encrypt a custom configuration section in ASP.NET.

klings
  • 963
  • 6
  • 12