CipherDB Developer’s Guide – .NET

The Crypteron CipherDB middleware is a patented application layer data security framework that allows your .NET or Java application to quickly be upgraded for strong data encryption even if the underlying database technologies or infrastructure providers are insecure. In fact CipherDB reduces the trust footprint to just your application. This means the database server, database administrators and pretty much anything outside your application instance and its OS does NOT need to be trusted for information assurance.

CipherDB works with SQL Server, Azure SQL, MySQL, Amazon RDS, Oracle or pretty much any SQL other database (sharded or not) and integration is just a couple of lines of code for the entire application. We have client libraries that extend existing ORM APIs like Entity Framework or NHibernate (C# clients) or Hibernate (Java clients) to auto-magically work with the built-in key management servers which can handle billions of keys. Best of all, we preserved the familiar programming model so you and your team are productive within minutes. In fact, here is the before and after programming model:

// Before: Unprotected regular access
using (var db = new DbContext())
{
    // do work
}
// After: Crypteron protected access
using (var secDb = new CipherDBContext())
{
    // do work. Network and database see only strongly encrypted data
    // while only your app sees unencrypted data for ease of development
}

All database access points are automatically upgraded for security in a transparent manner, so no need to check every database call separately. Behind the scenes, the encryption framework takes care of encryption, decryption, key caching, key lifecycle management, tamper detection, SQL row binds, encryption key migrations and rollovers, policy enforcement, decoupling of administrative, security and development roles as well as many other features. The overhead of the entire security pipeline is imperceptible to your end users – under 1ms for your typical record so external factors like network, bandwidth usually dominate any impact of CipherDB. For a detailed article on performance, please read our blog post here.

CipherDB also enables creating isolated security partitions for multi-tenant situations as well as ACLs based policies controlling data access. This is reduced to a simple programming model like

// Crypteron protected access
using (var secDb = new CipherDBContext("MyTenant45", "ReadOnlyRole"))
{
// access to other tenant's security paritions denied
// write access within this partition denied
}

CipherDB helps you focus on the core of your application without being overwhelmed by the security implications of handling sensitive data in a connected environment.

Also take a look at Crypteron’s CipherStor product if your application also needs to protect unstructured data like flat-files (eg: 911 audio recording, crime scene imagery etc) that will be resident on file servers (eg: Amazon S3, Azure Blob Storage or 3rd party filers) rather than database servers. CipherDB and CipherStor use the same underlying key-management system, simplifying the application domain model.

Crypteron’s CipherDB and CipherStor security framework is also available in a FIPS-140-2 certified flavor and is fully compliant with NSA Suite B. It can even be used to protect data classified as military “Top Secret”.

Overview

The overall process is

  1. Classification of data: Plan which fields to encrypt
  2. Column naming: Prefixing the secure columns with Secure_ either directly in SQL (new designs) or via Entity Framework remapping (existing, legacy SQL designs)
  3. Setup your App on the Crypteron Management Dashboard and passing the API AppSecret back to your app via the web.config or app.config
  4. Integrating CipherDB middleware to your .NET app.

We also provide some simple sample applications on GitHub.

Classification of data

This stage is code free in the sense that it’s purely a planning stage. You need to decide which fields in which tables are sensitive for your business. For example, while social security number would be considered a sensitive field in almost every application, perhaps your use case might consider ‘address’ as a secure field too. All such secure columns are marked as such so Crypteron can protect them during their natural data flows. Some illustrative examples are:
1. User profile Table, SocialSecurity column
2. Patient profile Table, First Name column
3. Payments Table, CreditCardNumber column
and so on
Remember, if you aren’t sure about a particular field, it’s probably a good idea to flag it as secure it because attackers can be quite creative how they use leaked data.

NOTE:

  1. Plan for the fact that SQL columns to be secured must be of string or binary type
  2. Keep column lengths to max (e.g. nvarchar(max) for string or varbinary(max) for binary). This is because strong encryption expands the resulting cipher-text size and keeping it ‘max’ gives you full flexibility without any disadvantages. Note that modern databases do not pre-allocate space – so this technique doesn’t wastes space.

Flag columns as ‘Secure’

Depending on whether this is Entity Framework code-first or Entity Framework database-first, there are two paths.

Entity Framework – Code First

Simple add the [Secure] attribute to the entity’s property and you’re done

public class User
{
    ...
    [Secure]
    public string CreditCardNumber { get; set; }
    ...
}

Entity Framework – Database First

Database first regenerates the entity class files, so you can’t add the [Secure] attribute to your class (they’ll get overwritten during auto-generation). You can instead prefix the property name with Secure_. Example: CreditCardNumber becomes Secure_CreditCardNumber.

Directly renaming SQL schema

This can be used in new databases. So if your SQL column is named (for example) Secure_CreditCardNumber, the Entity Framework property will also be Secure_CreditCardNumber. This is a simple and straight forward approach.

Name mapping when SQL schema can’t be changed

To keep the SQL schema unchanged but only add the Secure_ prefix to entity framework properties, you have to edit the SQL schema to Entity Framework mappings. Simply double click the the Entity Framework EDMX file in your Visual Studio solution to open it. Then update the name mapping as shown in the example below:

Entity Framework Database-first remapping

TIP: If you’re renaming existing members and are using a recent version of Visual Studio, it’s best to use Visual Studio’s refactor menu (right click member => refactor => rename) to rename members with the ‘Secure_’ prefix.

Setup your App on the Dashboard

Your CipherDB powered App orchestrates the necessary work with the back-end Key management systems at Crypteron. First you need to setup your App on the Crypteron dashboard. By default we register an App for you when you first create your Crypteron account. Select the App on the dashboard and in App Details you’ll find the App’s Secret Key. This is the API key securing all the key management API between your App and the Crypteron Service.

NOTE: The App Secret is NOT your data encryption key(s) but you should still guard this API key.

Integrating CipherDB middleware

Get the Crypteron Agent via NuGet. You can find them all listed here. Then you want to upgrade your existing generic Entity Framework class(es) to be powered by CipherDB. This step is slightly different depending on whether you are using Entity Framework code-first approach or the database-first approach.

Entity Framework – Database First

Entity framework database first developers follow a workflow in which the Entity Framework automatically generates the Entity Framework class, say, MyAppEntities. Since it’s possible that Entity Framework may auto-generate that class again later, it’s best to leave that class untouched and instead add the integration code in a newer, inherited class, say, CipherDBEntities. This is shown below in the same code:

using Crypteron.CipherCore;
using Crypteron.CipherDB;

public class CipherDBEntities : MyAppEntities
{
    public CipherDBEntities(string securityPartition = null, string asRole = null,)
    {
        // Activate CipherDB, specify security context. That's it!
        Crypteron.CipherDB.Session.Create(this, securityPartition, asRole);
    }
}

Entity Framework – Code First

Entity framework code first developers follow a workflow in which they hand-write and maintain their entity Framework class, say, MyAppEntities. Due to this they can either add the integration code above directly into MyAppEntities or in an inherited class, say, CipherDBEntities. The performance is the same; it’s just a matter of preference.

Now always use the CipherDB powered class (example CipherDBEntities) instead of the generic Entity Framework MyAppEntities class. The runtime usage is identical and CipherDB will manage encryption and all key management behind the scenes.

Stored Procedures and CipherDB

CipherDB works just fine with stored procedures as long as one follows the general entity framework guidelines.

  1. You must import the stored procedures into entity framework
  2. After importing, the database-first approach still requires another step; importing it from the “store” into the “model”.
    1. Double click the EDMX file
    2. Go to Model Browser (if not visible, right click an empty area of the EDMX designer and select “Model Browser”)
    3. Right click the stored procedure and choose “Add Function Import…”
    4. This moves it to the “Function Imports” section as seen below
      CipherDB Stored Procedures
  3. The inputs and outputs to the stored procedure must be “Entities”. For example, to set the output to type “Entity”, double click the stored procedure in “Function Imports” and change to Entities as shown below
    CipherDB Stored Procedures
  4. These entities are basically rows from your secure or non-secure tables.

NOTE: For getting entities that are CipherDB secured your stored procedure must return the entire entity (i.e. must return the entire row). The stored procedure cannot simply return a small subset of fields (a subset of columns) because they wouldn’t “fit” the type of the Entity (and CipherDB will not decrypt it).

Configuration settings

Crypteron settings are configured either by code or by your application’s configuration file. Depending on whether you’re running .NET framework or .NET core, the process can be slightly different.

NOTE: Certain settings (e.g. BindRow or AllowNullsInSecureFields) shouldn’t be changed once useful data has been written as these settings have the same lifetime as the data they protect.

.NET Core

.NET Core allows great flexibility in how settings are stored. We’ll cover only the JSON file configuration provider as a full discussion of various configuration providers is outside the scope of this document (but you can find details here)

You can have an appsettings.json file to which you can add the following Crypteron specific configuration values

{
  "CrypteronConfig": {
    "MyCrypteronAccount": {
      "AppSecret": "Replace_this_with_app_secret_from_https://my.crypteron.com"
    }
  }
}

You then read this file and configure through code as follows

using Microsoft.Extensions.Configuration;
using System.IO;

namespace YourNamespace
{
    class Program
    {
        public static void Main()
        {
            IConfiguration Configuration = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json")
                .Build();

            Crypteron.CrypteronConfig.Config.MyCrypteronAccount.AppSecret = 
                Configuration["CrypteronConfig:MyCrypteronAccount:AppSecret"];
            
            // do work ...
        }
    }
}

.NET Framework

For .NET Framework application, use the web.config file for ASP.NET web applications or the app.config file for standalone .NET application. Following the usual .NET Framework configuration pattern, there is a declaration in the followed by the actual configuration itself inside the <crypteronConfig> section. An illustrative example is shown below:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <!-- Declaration only, no customization -->
    <section name="crypteronConfig" type="Crypteron.CrypteronConfig, CipherCore" requirePermission="false" />
  </configSections>

  <!-- Read docs below for explanations -->
  <crypteronConfig>
    <myCrypteronAccount appSecret="Replace this with App Secret from https://my.crypteron.com" />
    <commonConfig securePrefix="Secure_" allowNullsInSecureFields="false" bindRow="true" />
    <cipherDbConfig migrationPolicy="ReadOld" />
    <debugLogs>
      <debugLogFile logFilename="MyApp-CipherDB.log" filterLevel="Warning"/>
      <debugConsole filterLevel="Information"/>
    </debugLogs>
  </crypteronConfig>
</configuration>

Note that you can also set any configuration option using the code pattern shown below.

CrypteronConfig.Config.MyCrypteronAccount.AppSecret = "Replace_this_with_app_secret_from_https://my.crypteron.com";

Detailed information for various configuration parameters are documented below.

<crypteronConfig>

Within the configuration XML, this is the top-level element within with all other Crypteron specific configuration exists.

<myCrypteronAccount>

To register this app with your MyCrypteron account

Name Example Description
appSecretappSecret=”EiB/xyx123abcdefghijklmnopqrstuvwxyz1234567890abcd==”This is the what you obtain from your MyCrypteron management dashboard

<commonConfig>

All common settings across the various Crypteron agent libraries are captured in this XML configuration element as follows:

NameExampleDescription
securePrefixsecurePrefix=”Secure_”Objects or entities with properties or fields with this prefix (example: “Secure_CreditCard”) will be protected by Crypteron’s security pipeline. Properties or fields without this prefix (example: “ItemIdPK”) will flow in bypass mode outside the Crypteron Security pipeline.Default: “Secure_”
allowNullsInSecureFieldsallowNullsInSecureFields=”false”Setting this to “true” means plaintext as well as ciphertext values of NULL are allowed. Some developers find permitting NULLs to be more flexible or practical (e.g. SQL column NULLs) but this is less secure since an attacker may silently erase data by writing NULLs without raising any alarms. This in turn is because NULLs cannot store any metadata needed to enforce integrity protection. Effectively NULLs are passed through as-is across both the decryption and encryption operations.

Setting this to “false” is more secure since Crypteron will now throw an exception if it find NULLs prior to decryption. We suggest using an empty string or empty byte array instead of NULL when writing. This way when plaintext is empty, it’s ciphertext is non-empty with helpful metadata that can enforce tamper protection checks next time decrypting it.

Default: false
bindRowbindRow=”true”Row binding prevents careful manipulation of encrypted data by an attacker to change it’s meaning. Specifically, row binding applies strong cryptography to bind all the secure fields of a single row/entity together to mitigate a ciphertext replacement attack.

As an example: Imagine a law enforcement scenario where Suspect-A from Case-A simply copies encrypted field “Secure_SuspectName” from Case-B into Case-A. He overwrites his own name with someone else, without ever having to decrypt anything. Without row binding, this silent attack would effectively accuse Suspect-B and exonerate Suspect-A. Enabling this value increases security since an attack with cherry picked replacements will now raise a security exception when a property/field value is discovered that wasn’t part of the object/row at the instant the entire object/row was encrypted or sealed. Binding is performed on writes and verified on reads and adds about 16 bytes to the encrypted data.

Default: true

<cipherDbConfig>

All settings related to CipherDB are captured in this XML configuration element. It has several XML attributes as follows:

NameExampleDescription
migrationPolicymigrationPolicy=”ReadOld”The latest version of a given key is always used when encrypting fresh data. migrationPolicy decides what happens when data encrypted by older versions of the encryption key is encountered.

Default: ReadOld

Options are:

NoOld: Entities encrypted with any older key versions will be rejected i.e. NOT be decrypted. Rare but used in cases where older versions of encryption keys were compromised and data encrypted by those keys cannot be trusted anymore. Such data is encountered, it’s decrypted as NULLs to protect untrusted data from entering the application.

ReadOld: Most common case where data encrypted with older keys will be decrypted. CipherDB will not queue up any writes to migrate data to the latest data encryption key. This default mode allows you to issue new keys periodically, ensuring no single key every protects too much data.

MigrateOnWrite: Like ReadOld but also allows for live migration of entities from older key versions to the latest key version. The following conditions apply within this mode:

  • The application must issue a SaveChanges() within the same database context (e.g.: same using block) that read the older entity
  • MigrationLimit, a separate configuration parameter, is a positive number
  • The older version of the used key is accessible (i.e. the Security Partition ACLs allow access)
Behind the scenes, entities with older encryption keys are queued up for migration to the latest encryption key upon the SaveChanges(). Since this increases the database write times linearly with number of entities migrated and since it can happen in a live environment you use MigrationLimit to control the impact. Due to access patterns inherent in any application the most frequently used entities are migrated first and migration volume tapers off naturally.
migrationLimitmigrationLimit=”20″Valid only for MigrationPolicy = MigrateOnWrite.

This specifies how many database entities using the older encryption keys are tracked by CipherDB (upon read) for subsequent key migration related writes.Example: MigrationLimit is set to 20. Within a using block, the application reads 30 entities from the database out of which 25 are still on an older AES encryption key. CipherDB tracks the first 20. The application then decides to write 2 entities to the database, within the same using block as the read. At the instant of the application triggered write, CipherDB will write 2 (Application originated) + 20 (Application read, CipherDB tracked) = 22 entities into the database.

Default: 20

<cipherStorConfig>

All settings related to just CipherStor are captured in this XML configuration element. The XML attributes are as follows:

NameExampleDescription

reportEventEveryXBytes

reportEventEveryXBytes=”16000″

Determines after how many bytes of processing should CipherStor send an event to the callers to notify it.

Default: “0” (never)

Recent blog posts

Migrating existing live data into Crypteron

You’re already live in production. And you have sensitive in the clear. Read this article to see how Crypteron can help.

Encryption, Entity Framework and Projections

Projections in Entity Framework live outside the entity lifecycle. Read more to learn how your can use Crypteron to secure such data.

PCI DSS and key rotations simplified

PCI compliance requires data encryption keys to be changed frequently. Here is how you can do it easily.

Your data-center is not secure and what you can do about it

There is no secure perimeter anymore. Neither in your corporate network nor in your data center. Fight a winning battle armed with self-protecting data rather than a losing one trying to protecting the infrastructure.

Introducing the Crypteron Startup Innovators Program

Qualifying startups get up to 50% off all plans. Tell us how you’re changing the world and the our Startup Innovators Program will support your journey.

6 encryption mistakes that lead to data breaches

If encryption is so unbreakable, why do businesses and governments keep getting hacked? Six common encryption mistakes that lead to data breaches.

Announcing the new Crypteron Community Edition

Starting today you can now sign up for the Crypteron Community Edition for free with no performance limitations.

Data breach response – One click to save your business

Get breathing room – when you need it the most. Respond to a data breach with a single click.

Why We Need Proper Data-At-Rest Encryption: 191M U.S. Voters’ Data Exposed

Adding security at the application level is a large step forward in protecting data from the constant threat of data breaches

How to encrypt large files

CipherStor is blazingly fast! Here we show how to use it within your data-flow pipeline to maintain high performance when encrypting large files.