Skip to content

Cryptography Overview

Tricklebyte edited this page Jan 31, 2020 · 4 revisions

Configuration Encryption/Decryption

It is sometimes required to encrypt sensitive configuration data like connection strings and authentication secrets based on the sensitivity of the data and the security of the hosting environment.

Option 1 - Transparent Data Encryption (TDE)

The easiest method of encrypting configuration data at rest is to centralize configuration data using a DBMS that supports TDE.
ConfigCore.ApiSource may be used to query settings from an API that uses any DBMS with TDE - like SQL, Oracle, or DB2.
ConfigCore.DbSource may be used to query settings directly from an encrypted SQL Server database.

Option 2 - ConfigCore Cryptography Features

When a centralized configuration source using TDE is not possible, ConfigCore offers cryptography features that allow you to apply encryption on a per-setting basis. You also may combine the two approaches and use ConfigCore to encrypt the locally-stored connection string for the TDE database.

  • ConfigCore utilizes the Microsoft Data Protection API.
  • Settings must first be encrypted using DPAPI, then stored in encrypted form.
  • When the client application loads the configuration, the values will still be in encrypted form.
  • The ConfigCore IConfiguration.Decrypt Extension method is called after the configuration is built to decrypt all encrypted values found in the configuration.
  • ConfigCore.ICryptoHelper provides methods for encrypting and decrypting app settings.
  • A sample interactive console application, CryptoConsole is also provided to encrypt settings prior to saving in the configuration source.

Configuration Settings required for Encryption/Decryption

All encrypting and decrypting clients require Configuration Section ConfigOptions:Cryptography
These settings are used to initialize cryptography services so they must stored in plain text

{
"ConfigOptions": {
    "Cryptography": {
      "ClientScope": "SharedSecretForClientAccess",
      "EncValPrefix": "<(*_*)>",
      "KeyStore": "\\\\localhost\\Share\\temp-keys"
    }
  }
}


ClientScope string
Client-based purpose string that is used to create the Data Protection Provider. The decrypting client must present the same ClientScope string as the encrypting client for the decryption operation to succeed.

EncValPrefix String
This string prefix is automatically added to the encrypted value after encryption, and automatically removed prior to decryption. It is used by the library to identify encrypted values in the configuration during the process of configuration decryption. If the encrypted value does not have the prefix, it will not be decrypted.

KeyStore String
UNC shared folder path for key storage. All encrypting and decrypting clients require folder access. DPAPI automatically manages and protects the keys. This shared UNC folder is required for the examples and unit tests in this project.

Example - Encrypted Connection String

In this example, there is a connection string in appsettings.json of a Web Application that we want to encrypt.

{
  "ConnectionStrings": {
    "DefaultConnection": "Server = (localdb)\\mssqllocaldb;Database=ConfigDb;Trusted_Connection=True;MultipleActiveResultSets=True;"
  }
}


After decrypting the Connection String we are going to simply display it in the Client UI.
In a real application you would use the decrypted connection string to initialize other services, or build a final configuration using a database source.

STEP 1 - Encrypt the value using console application CryptoConsole

Configure CryptoConsole


Configure appsettings.json in the CryptConsole project folder
appsettings.json - CryptoConsole

{
  "ConfigOptions": {
    "Cryptography": {
      "ClientScope": "SharedSecretForClientAccess",
      "EncValPrefix": "<(*_*)>",
      "KeyStore": "\\\\localhost\\Share\\temp-keys"
    }
  }
}

Launch CryptoConsole


image not found

Encrypt Connection String**

  • Enter E to ENCRYPT a value
  • Enter the setting name to encrypt (ConnectionStrings:DefaultConnection)
  • Enter the setting value to encrypt (Server = (localdb)\mssqllocaldb;Database=ConfigDb;Trusted_Connection=True;MultipleActiveResultSets=True;)

Copy the encrypted version of the connection string, including prefix, from the CryptoConsole output window.


image not found

Paste the encrypted connection string, including prefix, back into the appsettings.json file of the WebApp, replacing the plaintext version.



appsettings.json - Web Application

"ConnectionStrings": {
    "DefaultConnection": "<(*_*)>CfDJ8HG0D3XUOidEr4kYVy-7Np5Onl7-zgAsZ29C_Yej8YYXcTzOlMm0qXu8hMfp6hbL4Wy3dUgIkoW1FWwMdZNrAAWC4kC1sYVu0T-yJrMoKDWzKDwF1QofyTNn75XVq0ed4-9QGHcqbo8y8Clp0ZbQJCsjwQqde5UsjytMf97mSbRdEXLf_P3476YOJ0NmQ_50zdAODOgT-FncnC4q5-rM4U3r7rXJ2whrxowzYasA_Wy8"
  }

STEP 2 - Web Application Configuration

Add configuration section ConfigOptions:Cryptography to Web App configuration

The decrypting web application and the encrypting console application must use the same cryptography settings.
appsettings.json - Web Application

{
  "ConfigOptions": {
    "Cryptography": {
      "ClientScope": "SharedSecretForClientAccess",
      "EncValPrefix": "<(*_*)>",
      "KeyStore": "\\\\localhost\\Share\\temp-keys"
    }
  },
"ConnectionStrings": {
    "DefaultConnection": "<(*_*)>CfDJ8HG0D3XUOidEr4kYVy-7Np5Onl7-zgAsZ29C_Yej8YYXcTzOlMm0qXu8hMfp6hbL4Wy3dUgIkoW1FWwMdZNrAAWC4kC1sYVu0T-yJrMoKDWzKDwF1QofyTNn75XVq0ed4-9QGHcqbo8y8Clp0ZbQJCsjwQqde5UsjytMf97mSbRdEXLf_P3476YOJ0NmQ_50zdAODOgT-FncnC4q5-rM4U3r7rXJ2whrxowzYasA_Wy8"
  }
}

STEP 3 - Web Application Startup.cs

Add Data Protection Services to DI

Use the AddDataProtectionServices extension method to create Singletons for Microsoft Data Protection Provider and ICryptoHelper.

Decrypt the Configuration

Use the IConfiguration.Decrypt Extension method to decrypt the configuration loaded by Dependency Injection. The extension method requires an implementation of ICryptoHelper, which we must first retrieve from DI:

public void ConfigureServices(IServiceCollection services)
        {
            
            services.AddDataProtectionServices(Configuration);
           
          // Get the DPAPI Service provider which a dependency of CryptoHelper  
            var serviceProvider = services.BuildServiceProvider();

            //Add ICryptoHelper, with its dependency, to DI
            ICryptoHelper crypto = serviceProvider.GetRequiredService<ICryptoHelper>();
           
            //  DECRYPT the configuration values - Setting values will be decrypted if they begin with the Encrypted Value Prefix (EncValPrefix)
            Configuration.Decrypt(crypto);

            // Use decrypted configuration to initialize other services like data access, authentication, and authorization
            
            // other services...

Results

The decrypted connection string is displayed on the Index page of the client UI.
image not found

Clone this wiki locally