Chapter 1: About This Manual
AKM SDK for .NET
The AKM SDK for .NET includes a .NET assembly which provides an API for .NET applications to access the encryption keys on the AKM server for key retrieval or remote encryption. Key caching is included as a feature of key retrieval. .NET sample code for key retrieval and remote encryption is included to demonstrate both local encryption in your application and remote encryption on the AKM server.
NOTE: If your .NET client application will run in Azure Cloud Services, see the AKM for Microsoft Azure Quick Start Guide for information on configuring AKM certificates for use with Azure Cloud Services. Also note that running the client application in Azure App Service Web App is not supported.
SQL Server UDF
An additional SQL Server UDF assembly provides the same functionality for all editions of SQL Server. If you would like to use this assembly, see the AKM SQL Server UDF Guide in addition to this guide. The AKM SQL Server UDF Guide provides information on UDFs for key retrieval, key caching, and remote encryption and also describes using views and triggers to implement automatic encryption of a table.
NOTE: If you have SQL Server Enterprise edition or higher, you can use AKM Key Connection for SQL Server, a ready to use client application which utilizes EKM and TDE (Transparent Data Encryption) to provide automatic key retrieval without any changes to your application. See the AKM Key Connection for SQL Server User Guide for more information.
Who is this for?
This guide is designed to help Windows .NET application developers and project managers implement key retrieval or remote encryption in their business applications using the AKM SDK for .NET. It is also a starting point for users of SQL Server who wish to implement the SQL Server UDF or sample code, who will follow the steps for installation of the SDK and installation of certificates and private keys to the Windows Certificate store, and then use the AKM SQL Server UDF Guide for information on the SQL Server UDF.
Limitations
The AKM SDK for .NET has the following limitations:
AKM version
The SDK requires AKM version 4.0 or later. This version of the SDK only supports TLS version 1.2.
.NET Framework version
The SDK requires Microsoft .NET Framework 4.5.
Windows platform
-
The SDK is only supported on Windows Server OS, and is not supported on Windows desktop versions.
-
The SDK is not supported on Windows Server 2003.
Other resources
The following documents provide additional information on the installation and use of Alliance Key Manager:
Notices
This product and documentation is covered by U.S. and International copyright law. This product may incorporate software licensed under one or more open source license agreements. Government users please note that this product is provided under restricted government use license controls. Please refer to the AKM End User License Agreement for more information.
Change log
The following table provides information on the changes to this documentation:
Version | Date | Description |
---|---|---|
0.01 | 1/6/2009 | Initial draft |
0.02 | 1/21/2009 | Add additional notes on Windows Certificates |
1.00 | 9/12/2011 | Add new notes about limitations and Hot Fix requirements. |
1.01 | 11/5/2011 | Add step-by-step instructions and examples of using the Tester.exe sample key retrieval application. |
3.0.0.001 | 3/19/2014 | Update for AKM 3.0.0. Name change from AKM QuickStart for Windows. |
3.0.0.002 | 4/23/2014 | Minor updates. |
3.0.0.003 | 10/10/2014 | Update for AKM Client Library version 1.1. Name change from “AKM Guide for Windows Developers” to “AKM Guide for Windows .NET Developers”. |
3.0.3.001 | 12/16/2014 | Update for AKM 3.0.3 and the ready to use version of AKM for VMware. |
3.0.3.002 | 10/13/2015 | Update configuration examples. |
4.0.0.001 | 2/17/2016 | Update for AKM 4.0 and version 2.0 of the AKM SDK for .NET. Rename library to “AKM SDK for .NET”. Update limitations section. |
4.0.0.002 | 5/24/2016 | Update installation information, limitations, and preparation chapter for AKM 4.0 HSM release. |
4.0.0.003 | 7/12/2016 | Update for AKM 4.0 Azure release. |
4.5.0.001 | 9/29/2016 | AKM 4.5 release. RSA key support. |
4.6.1.001 | 11/8/2019 | Updated links and references to technical information. |
Chapter 2: Introduction
This chapter introduces concepts related to using the AKM SDK for .NET, including the use of certificates and private keys, configuration of the client application, encryption key names vs. key instances, key retrieval and caching, and remote encryption. It also summarizes the SDK components and capabilities.
Certificates and private keys
The client and AKM server use certificates and private keys to establish a secure TLS connection and perform authentication. Certificates must be installed in the Windows certificate store. See subsequent chapters for more information on locating and installing the required certificates.
Client configuration
You will need to configure your client application to authenticate with the AKM server. Configuration includes certificate and private key information, server information, and other properties. You can set the configuration directly in the code of your application or in an application configuration file. See Chapter 6: Configure the Client Application for more information.
AKM Key Service
The AKM SDK for .NET includes functionality for key retrieval for local encryption in your application. Key caching is also included as a feature of the AKM Key Service. Key caching stores the encryption keys securely in memory for a configurable timespan. An RSA key in the Windows key store called the “key-caching key” encrypts the keys. See Chapter 9: Key Caching for more information. Sample code included with the AKM SDK for .NET demonstrates key retrieval and key caching.
AKM Encryption Service
The AKMSDK for .NET includes functionality for remote encryption and decryption on the AKM server with AES CBC or ECB encryption so the encryption keys never leave the server. Sample code included with the SDK demonstrates CBC encryption with a random IV (initialization vector). ECB mode is also supported, but is only recommended for backwards compatibility with applications previously using ECB mode encryption, or for applications needing deterministic encryption.
Key names and key instances
Every encryption key created by AKM is given a key name and a unique instance (version) name. When the key is rolled, a new key is created with the same key name and a new instance name. This maintains the relationship of each instance to the original key, and means that you can roll the key without having to re-encrypt data that was protected with an older instance of the key. A rolled key is technically a new key, but since the key name does not change, it is considered a new instance of the same key. Every time the key is rolled and a new instance is created, this becomes the “current” instance of the key (sometimes known as the “default” instance). All older instances of the key are retained until you explicitly delete them.
When you send a key retrieval or encryption request, you must specify a key name and you can specify a key instance to request a particular instance of a key. If you do not specify a key instance, AKM will use the current instance of the key. You can store the instance name so that the correct instance of the key will be used on decryption.
AKM SDK for .NET
The AKM SDK for .NET includes the following components:
-
TownsendSecurity.KeyClient.dll
: A .NET assembly for key retrieval and remote encryption. -
TownsendSecurity.EncryptDecryptUdf.dll
: A SQL Server CLR assembly for key retrieval and remote encryption. -
Tester
: A tester application to test connectivity to the AKM server and key retrieval. -
EncryptFile
: A sample application demonstrating local and remote encryption and decryption of a file. -
Sample code:
-
EncryptFile
: Sample code for theEncryptFile
application demonstrating local and remote encryption of a file. -
EncryptString
: Sample code demonstrating local and remote encryption and decryption of a string. -
SQL Server UDF
: Sample code for the SQL Server CLR assembly demonstrating local and remote encryption and decryption.
-
TownsendSecurity.KeyClient.dll
The Key Client assembly is a .NET assembly which provides an API for your .NET applications to access the keys stored on the AKM server. The KeyService
object provides functionality for key retrieval with the option to securely cache the encryption keys. The EncryptionService
object allows you to send data for remote encryption and decryption on the AKM server. The samples EncryptFile
and EncryptString
perform local and remote encryption and decryption of a file and a string, respectively.
TownsendSecurity.EncryptDecryptUdf.dll
The SQL Server UDF is a companion assembly of the Key Client assembly, providing UDFs (user-defined functions) for key retrieval or remote encryption with SQL Server. Remote encryption uses CBC encryption with a random IV (initialization vector). The Local.Encrypt
and Local.Decrypt
methods provide key retrieval and key caching, and Remote.Encrypt
and Remote.Decrypt
methods provide remote encryption on the AKM server. These functions are interchangeable: you can encrypt locally, and decrypt the result remotely, for example. The SQL Server UDF samples demonstrate local and remote encryption and decryption. See the AKM SQL Server UDF Guide for more information on using this assembly.
Tester
This is a GUI application that provides an easy way to test that your certificates are valid and correctly installed, your client configuration is working properly, you have network connectivity to the AKM server, that AKM is responding, you can retrieve keys and perform key caching. You can also use it to become familiar with the available .NET tracing.
EncryptFile
The EncryptFile
application is a console application performing local or remote encryption and decryption of a file using AES CBC encryption with random IV and with HMAC. Local encryption retrieves the encryption key and uses Microsoft AES crypto libraries to locally encrypt/decrypt the file. Remote encryption uses AES CBC encryption on the AKM server. Both local and remote encryption use the Microsoft CryptoStream class and show how to run the encryption through a stream. The HMAC is SHA-256 and uses a second symmetric key. For local encryption, the encryption key and the HMAC key are retrieved. For remote encryption, the HMAC key is retrieved and the encryption key remains on the AKM server. Source code for the EncryptFile
application is available in the Sample Code
directory.
Sample code
Sample code is included with the installation in the Sample Code
directory, and you may modify it to suit your needs. See the file Disclaimer.txt
in the Sample Code
directory for information on use of the sample code.
EncryptFile
Source code for the EncryptFile
application.
EncryptString
EncryptString
performs local and remote encryption and decryption of a string. Local encryption retrieves the encryption key and uses Microsoft’s ICryptoTransform interface to locally encrypt and decrypt the string, and demonstration of the use of key caching is included. Remote encryption uses AES CBC encryption on the AKM server. The string sample does not add a MAC.
SQL Server UDF
Source code for the TownsendSecurity.EncryptDecryptUdf.dll
assembly demonstrates key retrieval and local AES CBC encryption using Microsoft crypto libraries and remote encryption using AES CBC encryption on the AKM server. The output returned by the encrypt functions packs the key name, instance, IV, and ciphertext into a varbinary output string which is unpacked for decryption. See the AKM SQL Server UDF Guide for more information on the assembly and sample code.
Chapter 3: Preparation
You will need to complete the following steps before continuing:
-
Install and set up the primary AKM server and any secondary mirror servers (instructions are located in platform specific deployment guides)
-
Create encryption keys (available as an option during AKM server setup, or, through the AKM Administrative Console application)
-
Download certificates from the AKM server
-
Know the IP address(es) of the AKM server(s) and port numbers for the desired services (key retrieval or remote encryption)
-
Install Microsoft .NET Framework version 4.5
See below for more information.
Licensing
A temporary or permanent license is required to use or evaluate AKM. All deployments of AKM create a 30-day license automatically during setup and initialization, except for the Amazon Web Services fee-based deployment, which generates a permanent license.
A temporary license will enable a fully functional AKM server that may be run in your environment for evaluation or testing. If the temporary license expires, a permanent license may be purchased from Townsend Security or your software vendor. See your AKM platform specific deployment guide for information on installing a permanent license.
Certificates
The client and AKM server use certificate and private keys to establish a secure TLS connection and perform authentication. You will need to install the following certificates and private keys on the client in the Windows certificate store in order to authenticate your client application with the AKM server:
-
The primary AKM’s certificate authority (CA) certificate in
.pem
format -
The secondary mirror AKM’s CA certificate in
.pem
format (needed if setting up mirroring) -
Client certificate/private key, installed as one file in PKCS #12 format (
.p12
or.pfx
), and associated password -
Intermediate CA certificate in
.pem
format (optional)
These certificates are generated on initialization and stored on the AKM server. See your platform specific AKM deployment guide for instructions on downloading key client certificates.
NOTE: If you use AKM-generated certificates and private keys, you will not need to use an intermediate CA certificate.
NOTE: The standard approach to client/server authentication as described in this document is to install AKM’s CA certificate and a client certificate/private key on the client. See Appendix B: Certificate Pinning for a discussion of using AKM server certificates on the client for additional security.
SECURITY ALERT: Private key files must be protected during creation, distribution, and storage to prevent loss. The loss of these files will compromise the security of the AKM server. Depending on the file format, the private key files may be bundled with a certificate or they may be separate files. Transfer the private key files by sharing them over a secure network, placing them in a password-protected zip file, sending them using SFTP, or another secure method. Use the same level of care you would employ to protect encryption keys, including encryption. In the event the private keys are compromised or lost, you should immediately replace the certificate authority on the AKM server and all client certificates in that chain of trust. See the AKM Certificate Manager Guide for more information.
Server information
You will need the following server information before continuing:
-
The IP address or DNS name of the primary AKM server and any secondary AKM servers
-
The port number that AKM has been configured to use for key retrieval (the default is 6000) and/or encryption (the default is 6003)
Encryption keys
To set up client key retrieval or remote encryption, you must have the name(s) of the encryption key(s) on AKM you would like to use.
AKM setup and initialization includes the option to generate an initial set of encryption keys. See your platform-specific AKM deployment guide for more information on encryption keys available for use, if that option was selected.
If needed, encryption keys can be created using the AKM Administrative Console application. See the AKM Administrative Console Guide for more information.
Microsoft .NET Framework
The AKM SDK for .NET requires Microsoft .NET Framework version 4.5. To install the Microsoft .NET Framework, visit https://www.microsoft.com and download an installer from Microsoft.
Checklist
Before continuing, you will need the following items:
-
The CA certificate of each AKM server in
.pem
format -
A client certificate/private key in in PKCS #12 format (
.p12
or.pfx
) -
The IP address or DNS name of the AKM server and the port number it will use for key retrieval (for both the primary and secondary AKM servers if using a failover server) or remote encryption
-
The name of one or more encryption keys on the AKM server
-
Microsoft .NET Framework version 4.5
Next steps
Subsequent chapters will guide you through installation of the AKM SDK for .NET, installation of certificates and private keys to the Windows certificate store, client configuration, samples for key retrieval and key caching, samples for remote encryption, and error reporting.
Chapter 4: Install the AKM SDK for .NET
The install file for the SDK is located in the AKM Windows Dev Kit
Double-click AKM_SDK_for_.NET_[version].msi
to start the installation process.
AKM SDK for .NET components
After the installation is complete, you will find a set of files at this path:
C:\Program Files\Townsend Security\AKM Client Library
The files in the bin
directory are:
-
TownsendSecurity.KeyClient.dll
(Key Client .NET assembly) -
TownsendSecurity.EncryptDecryptUdf.dll
(SQL Server UDF assembly) -
EncryptFile
(Console application for local or remote encryption of a file) -
EncryptFile.exe.config
(An XML configuration file forEncryptFile
) -
Tester
(Tester application to test connectivity to the AKM server and key retrieval) -
Tester.exe.config
(An XML configuration file forTester
)
The files in the Sample Code
directory are:
-
EncryptFile\EncryptFile
(Sample code for theEncryptFile
application) -
EncryptString\EncryptString
(Sample code performing local and remote encryption/decryption of a string) -
SQL Server UDF\
-
Local
(Sample code for the SQL Server UDF performing local encryption/decryption) -
Packing
(Sample code which packs the key name, instance, IV, and ciphertext into the resulting binary string, and that unpack them for decryption) -
Remote
(Sample code performing remote encryption/decryption on the AKM server)
-
Chapter 5: Install Certificates
This chapter describes installing certificates into the Windows certificate store.
Overview
Certificates must be installed in the Windows certificate store for Current User or Local Computer. Install the certificates to the store for Current User if the client application will be run under the Current User. If your client application will run as another user, install the certificates in the Local Computer certificate store where they will be available to all users. You will then grant the user running the client application read permissions to the client private key.
SECURITY ALERT: It is common for SQL Server or other applications to be run under a service account (e.g. Network Service) that may not be exclusively used by SQL Server. Your private key must be accessible to the user account that SQL Server uses, but if the account is shared with other applications, this exposes your private key to those applications. Malicious or accidental exposure may result, yielding access to encryption keys on your AKM server.
Therefore, we strongly recommend your application run under a dedicated service account. This is generally a good security practice, and specifically protects access to your encryption keys. If you cannot change the user that your application runs under, then you must grant access to the private key to that user. Be aware, however, of the risk that this creates.
NOTE: If your .NET client application will run in Azure Cloud Services, see the AKM for Microsoft Azure Quick Start Guide for information on configuring AKM certificates for use with Azure Cloud Services. Also note that running the client application in Azure App Service Web App is not supported.
Install locations for certificates are listed below:
-
Client certificate and private key - Personal store
-
The primary AKM server’s root CA certificate - Trusted Root Certification Authorities store
-
The secondary AKM server’s root CA certificate - Trusted Root Certification Authorities store
-
Intermediate CA certificate (optional) - Intermediate Certification Authorities store
The configuration for the AKM SDK for .NET uses the thumbprint attributes of the certificates. See below for a detailed guide to installing certificates.
Start Windows Certificate Manager
Client application running under Current User
If installation, configuration, and the client application will all be run under the Current User, you can start the Microsoft Management Console (MMC) with the Certificate Manager snap-in for the Current User:
Click Start, Run, and enter “certmgr.msc”. The following panel is displayed:
You can now install certificates to the “Current User” certificate stores. See the section Install the client certificate/private key below.
Client application running under another user
If your client application will run as another user, you will need to install the certificates in the “Local computer” store and grant the client application user private key access.
Click Start, Run, and enter “mmc”. The following panel is displayed:
Select File, Add/Remove Snap-in. The following panel is displayed:
Select the Certificates snap-in and click Add.
The following panel is displayed:
NOTE: SQL Server might be installed to run under a Windows Service account. However, if you are using SQL Server it is not necessary to select the Service account option shown, as you can follow the same steps to grant user permissions to the client private key as described elsewhere in this document.
Select Computer account and click Next. The following panel is displayed:
Select Local computer store and click Finish. In the Add or Remove Snap-ins dialog, click OK.
You can now import certificates to the “Local computer” certificate stores. Certificates installed in the “Local Computer” store will be available to all users. However, whoever installs the private keys will need to grant explicit user access to private keys. See below for more information.
You can add the Certificates snap-in twice (once for “Current User” and once for “Local computer”) if you so choose.
Install the client certificate/private key
Open Windows Certificate Manager. Right-click on the Personal store. Hover over All tasks. Select Import. The Certificate Import Wizard will open. Click Next. The following panel is displayed:
Click Browse to select the .p12
or .pfx
client certificate/private key. You will need to select the “Personal Information Exchange” file format in the file chooser. Click Next. The following panel is displayed:
If there is a password associated with the file, enter it now. The password used when creating the PKCS#12 file is used only in this step; Unless you choose otherwise, once imported, the certificate and private key are unlocked when you log into Windows. If you enter the wrong password, the wizard will not let you proceed.
NOTE: If you want to require the user to enter the password whenever accessing the client private key, check the box to Enable strong private key protection. You will be prompted to enter a password every time the key is used by an application. Do not select this option if you are using the Key Client assembly from a non-interactive program such as a server.
Click Next. The following panel is displayed:
Select Place all certificates in the following store and select “Personal”.
Click Next, then click Finish.
Grant user access to the client private key
If your application is run under a different user and you have installed certificates and private keys to Local Computer, you will need to grant read access to the client private key to the user running the client application. To share the client private key with another user, right-click the certificate and hover over All Tasks. Select Manage Private Keys:
In the permissions dialog, select the users or groups to which you would like to grant read access to the client private key.
Install the CA certificates
You will need to install both the primary AKM server’s root CA certificate and the secondary AKM server’s root CA certificate. The secondary AKM’s root CA certificate is only required when setting up mirroring.
The process for installing the CA certificates is the same as installing the client certificate/private key with some differences:
-
The CA certificates are installed in the Trusted Root Certification Authorities store.
-
If using an intermediate CA certificate, this will be installed in the Intermediate Certification Authorities store.
-
There will not be a password, as certificates are not password protected.
The first time you import the certificate, you will be warned about trusting the certificate. If the certificate is trusted, click Yes to advance through the warning.
Verify certificate installation
Go to the Action menu and click Refresh. That will refresh the certificate lists, and you should find the newly imported certificates. The client certificate should be in the Personal store, the root CA certificate should be in the Trusted Root Certification Authorities store, and any Intermediate CA certificates should be in the Intermediate Certification Authorities store.
Verify connection to the AKM server
You can use the Tester
application to verify the connection to the AKM server and test key retrieval and key caching. This will ensure that the network and the certificates just installed are configured properly. See Appendix A: Verify the Connection with Tester for more information.
Find certificate thumbprints
The configuration options for the AKM SDK for .NET identify certificates by thumbprint. You will need to look up the thumbprints of your certificates in order to configure these certificates in your application. To find a certificate’s thumbprint, double-click on the certificate in the Windows Certificate Manager. Click the Details tab and scroll to the bottom of the pane:
Select the Thumbprint field. The thumbprint will populate in the field below and you can copy it.
Chapter 6: Configure the Client Application
Overview
After you have installed the required certificates and private keys to the Windows certificate store, you can configure your application to connect with the Key Client assembly for key retrieval or remote encryption.
KeyService and EncryptionService
There are two primary object classes in the Key Client assembly: KeyService
and EncryptionService
. A KeyService
object is used to retrieve encryption keys from the AKM server, and an EncryptionService
object is used to encrypt or decrypt data remotely on the AKM server. Before using a KeyService
or EncryptionService
object, they need to be configured to connect to the server.
Configuration
The client and AKM server use certificates and private keys to perform mutual authentication over TLS. In addition, the AKM Client Library for Windows requires a pinned certificate in the client configuration. Any one of the certificates in the server certificate chain must be identified as the “server certificate”. This could be the root CA certificate, an intermediate CA certificate, or the AKM server certificate(s).
The pinned certificate must be installed in the appropriate Windows certificate store as described elsewhere in this document. A standard approach is to use the root CA certificate and this will be used in the examples below. See Appendix B: Certificate Pinning for a discussion of using AKM server certificates in your configuration as pinned certificates for additional security.
You will need to provide the following information in the configuration:
-
IP addresses of the primary AKM server and any additional secondary servers
-
Ports on which those AKM servers are configured to perform key retrieval (default: 6000) or remote encryption (default: 6003)
-
Thumbprint of the client certificate
-
Thumbprint of each AKM server’s root CA certificate
Configuration objects
The configuration consists of a ClientConfiguration
object which identifies a client certificate and one or more server configurations as ServerConfiguration
objects. The ClientConfiguration
has some fields that are set to default values, and other fields which must be set.
These objects classes are defined as:
public class ClientConfiguration
{
public string Name { get; set; }
public string ClientCertificateThumbprint { get; set; }
public ServerConfiguration[] ServerConfigurations { get; set; }
}
The Name
field is only informative. If you load the client configuration from the application configuration file, the name will be set from the configuration. Otherwise, this field is initially set to null and you can use it however you like.
The ClientCertificateThumbprint
identifies a client certificate, used to authenticate this client to the AKM server over TLS.
NOTE: This is the thumbprint of the client certificate you imported to the Windows certificate store in an earlier chapter. The client certificate must be in the Personal certificate store of either Current User or Local Computer and the Windows user ID (i.e. security principal) in effect at the time of the connection needs read permission to the private key. For information on how to grant user access to private keys, see the section Grant user access to the client private key in the previous chapter.
ClientConfiguration
contains an array of ServerConfiguration
:
public class ServerConfiguration
{
public bool AllowCertificateNameMismatch { get; set; }
public bool CheckCertificateRevocation { get; set; }
public int CryptoOfficerPort { get; set; }
public int EncryptionPort { get; set; }
public string Hostname { get; set; }
public int KeyRetrievalPort { get; set; }
public int KmipPort { get; set; }
public string ServerCertificateThumbprint { get; set; }
public string ServerConnectionTimeout { get; set; }
}
One ServerConfiguration
object is required, and you will set additional ServerConfiguration
objects for any secondary (failover) AKM servers. The first in the array is the primary, and any others are secondary.
NOTE: If there is a failure to connect to the AKM server, an attempt is made to connect to the next AKM server in the array, and so on to the end of the array. (However, only a connection failure invokes this behavior. A request failure, such as a key-not-found error, for example, will not cause the next server configuration to be tried.)
The ServerCertificateThumbprint
identifies one of the certificates of the server certificate chain, such as the root CA certificate. This is the “pinned” certificate.
NOTE: The certificate you are identifying by thumbprint must be in the appropriate certificate store of either Current User or Local Computer.
AllowCertificateNameMismatch
defaults to false
. If you are using AKM-generated certificates, be sure to set this to true
as these certificates do not contain the server DNS name.
You can either configure the client directly in code or in an application configuration file. The following sections describe these methods for .NET applications. The code snippets here are C# unless otherwise noted. To configure your client application for use with the SQL Server UDF, see the SQL Server UDF Guide.
Configure the client in code
You can set the client configuration in code and then pass it to the KeyService
or EncryptionService
constructor:
ServerConfiguration serverConfiguration = new ServerConfiguration()
{
AllowCertificateNameMismatch = true,
Hostname = "192.168.1.80",
ServerCertificateThumbprint =
"ee fd 06 98 cc ee 2c 0e af d3 42 f3 6d 8a c5 46 46 f0 03 f8",
ServerConnectionTimeout = 30
};
ServerConfiguration failoverConfiguration = new ServerConfiguration()
{
AllowCertificateNameMismatch = true,
Hostname = "192.168.1.81",
ServerCertificateThumbprint =
"69 92 5b 93 62 d8 12 e6 0f e7 9c 98 5d f3 ee 5d ee 79 11 12"
};
ClientConfiguration clientConfiguration = new ClientConfiguration()
{
ClientCertificateThumbprint =
"e8 8b 7e 7a 33 7f d9 8e c2 cc 60 26 39 f9 79 59 83 bd 64 fd",
ServerConfigurations =
new ServerConfiguration[]
{ serverConfiguration, failoverConfiguration }
};
var encryptionService = new EncryptionService(clientConfiguration);
NOTE: You can also create a
KeyService
orEncryptionService
object and then fill in the fields. See theEncryptString
sample for an example of using this method.
In each ServerConfiguration
object, supply the hostname/IP address for the AKM server for the Hostname
value. For the ServerCertificateThumbprint
value, supply the thumbprint of the root CA certificate of that server.
For the ClientCertificateThumbprint
value, supply the thumbprint of the client certificate.
Configure the client in a .NET application configuration file
You can configure the object using the application configuration file (This will be the configuration file ending in .config
, for example yourapp.exe.config
).
This configuration uses the custom section TownsendSecurity.KeyClient.ConfigurationSection
and supports the configuration of multiple key clients.
Here is an example of configuring the client in a .NET configuration file:
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="MyConfig" type="TownsendSecurity.KeyClient.ConfigurationSection, TownsendSecurity.KeyClient" requirePermission="false"/>
</configSections>
<MyConfig>
<keyClients>
<add name="PERLEBERG" clientCertificateThumbprint="e8 8b 7e 7a 33 7f d9 8e c2 cc 60 26 39 f9 79 59 83 bd 64 fd" keyServer="192.168.1.80" failoverKeyServer="192.168.1.81"/>
<add name="DRESDEN" clientCertificateThumbprint="e8 8b 7e 7a 33 7f d9 8e c2 cc 60 26 39 f9 79 59 83 bd 64 fd" keyServer="192.168.1.82"/>
</keyClients>
<keyServers>
<add hostname="192.168.1.80" keyRetrievalPort="6000" encryptionPort="6003" serverCertificateThumbprint="ee fd 06 98 cc ee 2c 0e af d3 42 f3 6d 8a c5 46 46 f0 03 f8" allowCertificateNameMismatch="true" checkCertificateRevocation="false" serverConnectionTimeout="5"/>
<add hostname="192.168.1.81" keyRetrievalPort="6000" encryptionPort="6003" serverCertificateThumbprint="ee fd 06 98 cc ee 2c 0e af d3 42 f3 6d 8a c5 46 46 f0 03 f8" allowCertificateNameMismatch="true" serverConnectionTimeout="5"/>
<add hostname="192.168.1.82" keyRetrievalPort="6000" encryptionPort="6003" serverCertificateThumbprint="ee fd 06 98 cc ee 2c 0e af d3 42 f3 6d 8a c5 46 46 f0 03 f8" allowCertificateNameMismatch="true" serverConnectionTimeout="5"/>
</keyServers>
</MyConfig>
</configuration>
For the section name
value, supply a name for the configuration (Example: MyConfig
).
In the <keyClients>
section, supply a name
for each client (optional), the ClientCertificateThumbprint
of the client certificate, the keyServer
IP address, and the failoverKeyServer
IP address if applicable. You can configure as many clients as you wish.
In the <keyServers>
section, for each server, supply the IP address, the keyRetrievalPort
and/or encryptionPort
, the thumbprint of the root CA certificate of that server, and the allowCertificateNameMismatch
flag, which must be true
if using AKM-generated certificates. The first server must also have checkCertificateRevocation="false"
. You can add additional secondary servers as in the example above, each with its own attributes.
In the example above, clients PERLEBERG
and DRESDEN
have been configured, and two secondary AKM servers have been configured.
The following example passes the configuration section (“MyConfig
”) to the KeyService
constructor as a string parameter. An optional second parameter to the constructor selects the client by name (“PERLEBERG
”), or defaults to the first client listed if the second parameter is not given:
var keyService = new KeyService("MyConfig", "PERLEBERG");
The following example passes the configuration section (“MyConfig
”) to the EncryptionService
constructor:
var encryptionService = new EncryptionService("MyConfig", "PERLEBERG");
Next steps
Your client application has now been configured to communicate with the Key Client assembly. See subsequent chapters and the EncryptFile
and EncryptString
sample code for information on implementing key retrieval or remote encryption.
Chapter 7: Retrieve Symmetric AES Keys
Overview
This chapter outlines how to retrieve encryption keys using the KeyService
class to encrypt and decrypt a string. Code snippets below are in C# and are excerpted from a full sample which you can find later in the chapter. The sample code EncryptString
included with the SDK also shows remote encryption of the string.
First you will create a KeyService
object and configure the object, then you will use the GetSymmetricKey
method to retrieve AES keys. The KeyService
object will also perform in-memory caching of AES keys with a configurable timespan, so that GetSymmetricKey
will first check the memory cache before going to AKM Server. See Chapter 9: Key Caching for more information on caching retrieved encryption keys.
Create the KeyService object
This example uses a using
statement to create the KeyService
object. Note that class KeyService
implements the IDisposable
interface, and the using
statement will call Dispose
on the object when it goes out of scope.
static void EncryptLocal(string keyName, string data)
{
using (var keyService = new KeyService())
{
}
}
Configure the KeyService object
The KeyService
object has a ClientConfiguration
field. The ClientConfiguration
has some fields that are set to default values, and other fields which must be set. Here, the ClientConfiguration
is passed to a pair of static methods to set required fields.
AllowCertificateNameMismatch
defaults to false
. If you are using AKM-generated certificates, be sure to set this field to true
as these certificates do not contain the server DNS name.
private static void EncryptLocal(string keyName, string data)
{
using (var keyService = new KeyService())
{
SetClientConfiguration(keyService.ClientConfiguration);
}
}
private static void SetClientConfiguration(ClientConfiguration clientConfiguration)
{
clientConfiguration.ClientCertificateThumbprint =
"e8 8b 7e 7a 33 7f d9 8e c2 cc 60 26 39 f9 79 59 83 bd 64 fd";
clientConfiguration.ServerConfigurations = new ServerConfiguration[] { new ServerConfiguration() };
SetServerConfiguration(clientConfiguration.ServerConfigurations[0]);
}
private static void SetServerConfiguration(ServerConfiguration serverConfiguration)
{
serverConfiguration.ServerCertificateThumbprint =
"ee fd 06 98 cc ee 2c 0e af d3 42 f3 6d 8a c5 46 46 f0 03 f8";
serverConfiguration.AllowCertificateNameMismatch = true;
serverConfiguration.Hostname = "192.168.1.80";
}
Retrieve the encryption key
Once the KeyService
object is configured, the GetSymmetricKey
method is called to retrieve an encryption key from the AKM server. You can retrieve a key by key name, key instance, or both.
Specifying the key name retrieves the current instance of the key. You can either supply the key name alone or supply the key name and set the instance name to blanks (null). For example:
var symmetricKey1 = keyService.GetSymmetricKey("AES128");
var symmetricKey2 = keyService.GetSymmetricKey("AES128", null);
Specifying the instance name alone or the key name and instance name retrieves a particular instance of a key:
var symmetricKey3 = keyService.GetSymmetricKey(null, "xerYqb76hVaI7OCEvCZx0w==");
var symmetricKey4 = keyService.GetSymmetricKey("AES128", "xerYqb76hVaI7OCEvCZx0w==");
This example retrieves the encryption key by name to get the current instance:
private static void EncryptLocal(string keyName, string data)
{
using (var keyService = new KeyService())
{
SetClientConfiguration(keyService.ClientConfiguration);
var key = keyService.GetSymmetricKey(keyName);
instance = key.Instance;
}
}
The key instance will be stored with the ciphertext so that later, for decryption, the key can be retrieved by instance.
Enable key caching
The following sample code retrieves the key twice. You enable caching of AES keys in the KeyService
object by setting a non-zero timespan on the KeyCacheTimeSpan
property. The first retrieval will retrieve the key from the AKM server. A second retrieval within 30 seconds of the first will just get the cached copy of the key, avoiding a second connection to the AKM server on the second retrieval. Since the retrievals occur back-to-back, setting a timespan of 30 seconds will be adequate. See Chapter 9: Key Caching for more information.
private static void EncryptLocal(string keyName, string data)
{
using (var keyService = new KeyService())
{
// Turn on caching with a 30-second timespan. The key will
// be cached on the first retrieval and so we won't go back
// to the server on the second retrieval. We'll just get the
// cached copy.
keyService.KeyCacheTimeSpan = new TimeSpan(0, 0, 30);
SetClientConfiguration(keyService.ClientConfiguration);
var key = keyService.GetSymmetricKey(keyName);
instance = key.Instance;
}
}
The SymmetricKey object
The GetSymmetricKey
method returns an object of class SymmetricKey
. This object has properties of the key such as Name
, Instance
, KeySize
, and Expiration
. The actual key value is held encrypted in memory. To access the key value, you can call the method KeyBytes
. Here, the key value is accessed to set the Key field of the algorithm object.
algorithm.Key = key.KeyBytes();
The key bytes are encrypted by an RSA key pair created in the Windows key store. See Chapter 9: Key Caching for more information.
Encrypt using Microsoft Crypto
Here, the Microsoft RijndaelManaged
class is used to encrypt an array of bytes. In this simplest example, the TransformFinalBlock
method of the encryptor object is called directly. In the more involved EncryptFile
example, the Microsoft CryptoStream
class is used.
The new RijndaelManaged
object has a random IV (initialization vector) already set. This is saved along with the ciphertext to be used later in the decryption:
using (var algorithm = new RijndaelManaged())
{
initializationVector = algorithm.IV;
algorithm.Key = key.KeyBytes();
using (var encryptor = algorithm.CreateEncryptor())
{
ciphertext = encryptor.TransformFinalBlock(plaintext, 0, plaintext.Length);
}
}
Encrypting strings vs. bytes
Strings need to be converted to byte arrays before encryption, and back to strings after decryption. Here, the UTF-8 encoding is used to convert the input string to an array of plaintext bytes:
static void EncryptLocal(string keyName, string data)
{
byte[] plaintext;
plaintext = Encoding.UTF8.GetBytes(data);
}
Full example
Here all of the elements are shown together to locally encrypt the string, and immediately decrypt the string. The EncryptString
sample code included with the AKM SDK for .NET also shows remote encryption of the string.
using System;
using System.Text;
namespace EncryptDecryptString
{
using System.Security.Cryptography;
using TownsendSecurity.KeyClient;
class Program
{
static void SetServerConfiguration(ServerConfiguration serverConfiguration)
{
serverConfiguration.ServerCertificateThumbprint =
"ee fd 06 98 cc ee 2c 0e af d3 42 f3 6d 8a c5 46 46 f0 03 f8";
serverConfiguration.AllowCertificateNameMismatch = true;
serverConfiguration.Hostname = "192.168.1.80";
}
static void SetClientConfiguration(ClientConfiguration clientConfiguration)
{
clientConfiguration.ClientCertificateThumbprint =
"e8 8b 7e 7a 33 7f d9 8e c2 cc 60 26 39 f9 79 59 83 bd 64 fd";
SetServerConfiguration(clientConfiguration.ServerConfigurations[0]);
}
static void EncryptLocal(string keyName, string data)
{
string instance;
byte[] plaintext;
byte[] initializationVector;
byte[] ciphertext;
byte[] roundtrip;
plaintext = Encoding.UTF8.GetBytes(data);
using (var keyService = new KeyService())
{
// Turn on caching with a 30-second timespan. The key will
// be cached on the first retrieval and so we won't go back
// to the server on the second retrieval. We'll just get the
// cached copy.
keyService.KeyCacheTimeSpan = new TimeSpan(0, 0, 30);
SetClientConfiguration(keyService.ClientConfiguration);
var key = keyService.GetSymmetricKey("keyName");
instance = key.Instance;
using (var algorithm = new RijndaelManaged())
{
initializationVector = algorithm.IV;
algorithm.Key = key.KeyBytes();
using (var encryptor = algorithm.CreateEncryptor())
{
ciphertext = encryptor.TransformFinalBlock(plaintext, 0, plaintext.Length);
}
}
key = keyService.GetSymmetricKey(keyName, instance);
using (var algorithm = new RijndaelManaged())
{
algorithm.Key = key.KeyBytes();
algorithm.IV = initializationVector;
using (var decryptor = algorithm.CreateDecryptor())
{
roundtrip = decryptor.TransformFinalBlock(ciphertext, 0, ciphertext.Length);
}
}
var result = Encoding.UTF8.GetString(roundtrip);
Console.WriteLine("data: " + data);
Console.WriteLine("plaintext: " + BitConverter.ToString(plaintext));
Console.WriteLine("keyName: " + keyName);
Console.WriteLine("instance: " + instance);
Console.WriteLine("initializationVector: " + BitConverter.ToString(initializationVector));
Console.WriteLine("ciphertext: " + BitConverter.ToString(ciphertext));
Console.WriteLine("roundtrip: " + BitConverter.ToString(roundtrip));
Console.WriteLine("result: " + result);
}
}
static void Main(string[] args)
{
try
{
EncryptLocal("AES256", "Hello World");
}
catch (Exception e)
{
Console.WriteLine("Exception caught: " + e.Message);
}
EncryptLocal("AES256", "Hello World");
Console.ReadLine();
}
}
}
Chapter 8: RSA Keys
Overview
RSA keys are handled in similar and different ways than AES keys. You still use the KeyService
object to retrieve keys, but rather than a customized object like the SymmetricKey
object, you get an RSACryptoServiceProvider
object from the Microsoft library System.Security.Cryptography
. RSA keys are present and usable as long as the RSACryptoServiceProvider
object remains in scope but, as a Microsoft object, do not utilize Townsend’s caching mechanism of the AES keys.
Key service
The KeyService
object is created the same as for AES keys. The same key service can be used to retrieve both AES and RSA keys. See Chapter 6: Configure the Client Application for more details.
Key retrieval
Once the KeyService
is configured, the GetPublicKey
and GetPrivateKey
functions will be available. You can request a key by name, instance, or both. RSA keys do not roll over, therefore there is no current instance as with AES keys. There is no advantage to using the instance for RSA keys, so Townsend Security recommends simply using the key name. All possibilities are shown for completeness.
var publicKey1 = keyService.GetPublicKey(“RSA2048”);
var publicKey2 = keyService.GetPublicKey(“RSA2048”, null);
var privateKey1 = keyService.GetPrivateKey(“RSA2048”);
var privateKey2 = keyService.GetPrivateKey(“RSA2048, null);
var publicKey3 = keyService.GetPublicKey(null, “5HR57aWWDtwhn9XZEbByrg==”);
var privateKey3 = keyService.GetPrivateKey(“RSA2048”, “O2Zoql7rcYJJTF75xMAUjg==”);
The RSACryptoServiceProvider object
The GetPublicKey
and GetPrivateKey
methods return RSACryptoServiceProvider
objects. This class is provided by the Microsoft library System.Security.Cryptography
. More information about using this object for cryptographic operations can be found here.
Encryption Service
RSA keys can be used for encryption or decryption on AKM. See Chapter 10: Perform Remote Encryption.
Chapter 9: Key Caching
Overview
Key caching is a feature of the KeyService
object and is used when retrieving encryption keys. When the key caching feature is activated, retrieved encryption keys are held in memory for a configurable period of time. To activate key caching, you will set a timespan in the ClientConfiguration
object. Retrieved encryption keys will be encrypted by an RSA key and held in memory for this timespan or until the cache is cleared. This “key-caching key” is an RSA key created in the Windows key store, and it can be periodically rolled as described below.
Note that key caching applies to AES keys only; RSA keys are not cached.
Setting the timespan
Retrieved keys are cached by the KeyService
object when its KeyCacheTimeSpan
property is set to a non-zero interval. For example, when the timespan is set to two hours, then once a key is retrieved from AKM Server, a copy is kept for two hours. During the two hours, regardless of what happens to the server or to the key (e.g. it could have been deleted or revoked) the key can be retrieved locally again and again from the KeyService
cache. After the timespan expires, the next time the same key is retrieved, KeyService
will go back to AKM server for a fresh copy.
You can set the timespan to whatever length of time you wish, but 4 to 6 hours might be an adequate balance between improved performance and maintaining the current state of the key.
Here is an example of setting the KeyCacheTimeSpan
property to two hours in the client configuration of the KeyService
object:
<add key="KeyCacheTimeSpan" value="02:00:00"/>
Or by setting the KeyCacheTimeSpan
property:
keyService.KeyCacheTimeSpan = new TimeSpan(2, 0, 0);
The EncryptString
sample code makes use of key caching.
Clearing the cache
The cache can be cleared by setting the KeyCacheTimeSpan
property to a zero timespan, or by calling the keyService.ClearKeyCache()
method.
Key-caching key
Cached encryption keys are held in memory by SymmetricKey
objects and the key value is encrypted by a “key-caching key”. The key-caching key is an RSA key created by the KeyService
object specifically for key caching. One key-caching key is shared by all KeyService
objects, per Windows userid. If the key is rolled, there will be two key-caching keys - the previous and the current. Key caching keys are located in the Windows key store under the Windows signon of the current user. There can only be up to two key-caching keys created per user. The key-caching keys are manually managed by the user and can be deleted at any time.
Rolling the key-caching key
Rolling the key-caching key creates a second RSA key in the Windows key store. Subsequent rolls will replace the first of the two keys and create another new key, such that there are always two keys per user: the previous and the current.
When the key-caching key is rolled, existing SymmetricKey
objects in the cache can still be used since the previous key still exists. But if the key is rolled twice in succession, any existing SymmetricKey
objects become invalid; their key value is lost and they will need to be retrieved again from the AKM server.
The key-caching key can be rolled by calling the keyService.RollKeyCachingKey()
method.
Locating the key-caching key
The keyService.KeyCachingKeyFilenames()
method returns an array of strings listing the filenames used to hold key-caching keys for the current Windows user. If you know the directory in which the keys are stored, you can locate the RSA key containers used to hold the key-caching key(s). The following website can help you locate the directory where the key-caching key files are stored:
Chapter 10: Perform Remote Encryption
Overview
This chapter outlines how to use the EncryptFile
sample code included with the SDK to perform remote encryption and decryption of a file on the AKM server. The sample code also shows key retrieval/local encryption of a file. Code snippets below are in C# and are excerpted from the full sample.
Create the EncryptionService object
Here, the using
statement is used to automatically clean up the EncryptionService
object once you are done.
The EncryptionService
constructor is passed the name of a section in the .NET application configuration file, where it will read its configuration from.
private const string AppConfigSectionName = "EncryptDecryptFile";
static void EncryptRemote()
{
using (var keyService = new EncryptionService(AppConfigSectionName))
{
}
}
Create the Encryptor Object
The CreateEncryptor
method of the EncryptionService
object creates the encryptor
object, which implements Microsoft’s ICryptoTransform interface. Here we create the encryptor
to use AES CBC mode.
private const string AppConfigSectionName = "EncryptDecryptFile";
static void EncryptRemote()
{
using (var encryptionService = new EncryptionService(AppConfigSectionName))
{
using (var encryptor = encryptionService.CreateEncryptor(CipherMode.CBC))
{
}
}
}
Set the key name
The KeyName
property is set on the encryptor
object to choose an encryption key on the AKM server by key name. You can also choose the encryption key by key name and instance.
static void EncryptRemote()
{
using (var encryptionService = new EncryptionService(AppConfigSectionName))
{
using (var encryptor = encryptionService.CreateEncryptor(CipherMode.CBC))
{
encryptor.KeyName = this.keyName;
}
}
}
Store the initialization vector and key instance
The new encryptor
object has a fresh, random IV (initialization vector) which you can use. You will want to keep a copy of this to use later for the decryption.
The encryptor
object also has an Instance
property, but this is not set until after the encryption has started. Here, the instance name is stored after encryption has completed. (The EncryptContent
method is performing the encryption, which is described below.)
static void EncryptRemote()
{
using (var encryptionService = new EncryptionService(AppConfigSectionName))
{
using (var encryptor = encryptionService.CreateEncryptor(CipherMode.CBC))
{
encryptor.KeyName = this.keyName;
// The brand new object comes with a new, random IV.
// We will record this, later, in the output.
this.initializationVector = encryptor.IV;
this.EncryptContent(encryptor);
// The instance is revealed after encrypting something.
// We will record this, too, in the output.
this.keyInstance = encryptor.Instance;
}
}
}
Encrypting a stream
Here we use Microsoft’s CryptoStream
class to run the encryption. The input and output files are opened as streams, and then the CryptoStream is inserted in between the two as the input stream is copied to the output stream.
The CryptoStream
class will use Microsoft’s ICryptoTransform interface, which the encryptor implements.
Before copying the input to the output, through the CryptoStream, the output stream is moved ahead to make room at the beginning of the output file. Later you will return and write the key instance and initialization vector here after you have encrypted the data.
private void EncryptContent(ICryptoTransform transform)
{
using (var inputStream = this.OpenFile(this.inputPath, OpenParam.Read))
using (var outputStream = this.OpenFile(this.outputPath, OpenParam.Create))
{
// Move the output stream ahead to make room to later write
// info at the start of the output ahead of the ciphertext.
outputStream.Position = InstanceSize + InitializationVectorSize;
this.TransformStream(inputStream, outputStream, transform);
}
}
private void TransformStream(Stream inputStream, Stream outputStream, ICryptoTransform transform)
{
using (var cryptoStream = new CryptoStream(outputStream, transform, CryptoStreamMode.Write))
{
this.CopyStream(inputStream, cryptoStream);
}
}
The CopyStream
method is writing large chunks of the input stream at a time through the CryptoStream
, which optimizes throughput of the AKM Client Library over the network connection to the AKM server.
private const int CopyStreamBufferSize = 128 * 1024;
private void CopyStream(Stream inputStream, Stream cryptoStream)
{
// The buffer size is arbitrary, however a large buffer size will
// optimize throughput when using remote encryption.
var buffer = new byte[CopyStreamBufferSize];
int count;
while ((count = inputStream.Read(buffer, 0, buffer.Length)) > 0)
{
cryptoStream.Write(buffer, 0, count);
}
}
Write the initialization vector and key instance to the output file
After the encryption has completed, the output stream is closed. Here, you re-open the output file to store the key instance and initialization vector in the space left at the beginning of the file. Later, when you decrypt the file, you will need those two pieces of information.
private void WriteInfo()
{
using (var outputStream = this.OpenFile(this.outputPath, OpenParam.Modify))
{
this.WriteInstance(outputStream, this.keyInstance);
this.WriteBytes(outputStream, this.initializationVector);
}
}
Here is the OpenFile
method, for reference, showing the mode and access used.
private enum OpenParam
{
Create,
Modify,
Read
}
private FileStream OpenFile(string path, OpenParam param)
{
FileMode mode;
FileAccess access;
switch (param)
{
case OpenParam.Create:
mode = FileMode.Create;
access = FileAccess.Write;
break;
case OpenParam.Modify:
mode = FileMode.Open;
access = FileAccess.ReadWrite;
break;
default:
case OpenParam.Read:
mode = FileMode.Open;
access = FileAccess.Read;
break;
}
return new FileStream(path, mode, access);
}
Sample code
The sample code for EncryptFile
builds on this, and includes local encryption as an alternative to remote encryption. The sample code also includes adding HMAC authentication to the encrypted output file.
Encrypting remotely on AKM using an RSA key
For RSA keys, an ICryptoTransform object is created with the key name as the parameter to the EncryptionService method, CreateRsaTransform.
Limits of RSA encryption and the solution: envelope encryption
Note that there are very strict limits to how much data can be encrypted with RSA keys. The limits for these operations are:
Encrypt with RSA public key:
- 1024-bit key: 86 bytes
- 2048-bit key: 214 bytes
- 3072-bit key: 342 bytes
- 4096-bit key: 470 bytes
For any larger data, RSA keys are best suited for encrypting an AES key which is itself used to encrypt the data. This is sometimes called “envelope encryption.” The encrypted AES key can be sent with the data to the recipient. The AES key is decrypted by the recipient system (or on AKM via a request from the recipient system) with the RSA private key, and the data subsequently decrypted with the decrypted AES key.
Perhaps the best known implementation of this architecture is in how PGP protects email. This image from the PGP Wikipedia page is a pretty good picture of that mechanism.
Sample code
static void EncryptRemote()
{
using (var encryptionService = new EncryptionService(AppConfigSectionName))
{
using(var encryptor = encryptionService.CreateRsaTransform(“RSA2048”)
/// RSA2048 is the key name
{
ciphertext1 = encryptor.Encrypt(plaintextBytes, True);
/// True means use OAEP padding, which is recommended
decryptedPlaintext = encryptor.Decrypt(ciphertext1, True);
signature = encryptor.PrivateEncrypt(dataHashBytes, True);
/// PrivateEncrypt is useful for generating signatures of data
verify = encryptor.PublicDecrypt(signature, True);
/// hash your data and compare to ‘verify’ to confirm authenticity
}
}
}
Chapter 11: Problem Determination
Error reporting
The AKM libraries report errors by throwing exceptions. The exceptions are either of Microsoft exception classes, such as ArgumentException
or InvalidOperationException
, or of exception classes specific to the client library, which derive from the KeyClientException
class.
When the exception represents an error encountered on the server then the server error code is reported in the exception in the field ServerErrorCode
. These are errors the server has returned in response to a key retrieval or encryption request. The exception’s ServerErrorCode
will match the error code logged in the AKM server error log. However, the message text of the exception may not match the error text that appears in the AKM server error log. View the akmerror.log
file on the AKM server for more information. See the AKM Server Management Guide for information on viewing the akmerror.log
file.
The exception classes are defined as follows:
Exception Class | Description |
---|---|
KeyClientException |
This is the base class for the client library exception classes listed here. |
ConfigurationException |
This exception class is used for a number of configuration errors, for example, the client certificate is not found, or the associated private key is missing. |
ConnectAuthenticationException |
This exception class is used for errors with the TLS certificates, or other connection problems, other than TCP socket errors (which are reported as NetworkException – cf. below.) |
KeyAccessDeniedException |
For the specific case of being denied access to a key. For example, the key may be set to Group Access, and the client certificate does not have the correct Group. |
KeyExpiredException |
For the specific case of attempting to retrieve an expired key. |
KeyNotFoundException |
For the specific case of the specified key (or instance) not found on the server. |
KeyPreActiveException |
For the specific case of attempting to retrieve a key that has not yet been activated. |
KeyRevokedException |
For the specific case of attempting to retrieve a revoked key. |
NetworkException |
Wraps a TCP SocketException adding more detail to the exception message. |
ServerException |
When a server request fails in a general, but expected way. For example, you are attempting to retrieve a key but connecting with an admin client (Crypto Officer) certificate. |
ServerFailureException |
When a server request fails in a completely unexpected way. For example, the request is rejected by the server because it is malformed. This could indicate a bug in the server or in the client library, and should be reported. |
In some cases, the thrown exception carries (wraps) an inner exception pertaining to the problem encountered. For example, a failure to connect to the server due to a TCP networking error will cause a NetworkException
to be thrown, which wraps an inner exception which is the actual TCP exception thrown by the Microsoft TCP API.
Microsoft exception classes
In addition, the following Microsoft exception classes are included:
-
ArgumentException
-
ArgumentNullException
-
ArgumentOutOfRangeException
-
CryptographicException
-
InvalidOperationException
-
RankException
Error handling
Here is a simplified example from the EncryptString
sample code of catching an exception:
static void Main(string[] args)
{
try
{
EncryptLocal("AES256", "Hello World");
EncryptRemote("AES256", "Hello World");
}
catch (Exception e)
{
Console.WriteLine("Exception caught: " + e.Message);
}
Console.ReadLine();
}
You could refine your exception catching, for example:
static void Main(string[] args)
{
try
{
EncryptLocal("AES256", "Hello World");
EncryptRemote("AES256", "Hello World");
}
catch (KeyClientException e)
{
Console.WriteLine("Key client error, " + e.GetType().Name + ": " + e.Message);
}
catch (Exception e)
{
Console.WriteLine("Exception caught: " + e.Message);
}
Console.ReadLine();
}
There are many other resources available which cover exception handling in more detail.
.NET tracing
The AKM SDK for .NET uses .NET tracing to help diagnose problems. You can configure .NET tracing in an application configuration file (see below).
In some cases, details of the error encountered are included in the trace message text. For example, a failure to connect to the server may be due to a TCP networking error. In this case, the trace message will include details about the TCP networking error. For server-reported errors, the ServerErrorCode
field is set to the error code returned in the server response.
Tracing points
This section describes the tracing points in the AKM SDK for .NET.
Errors traced
Errors traced | Description |
---|---|
Failed to connect to server (no retry) | Occurs when the client library fails to make a connection to the server, and there are no more failover servers to try. |
Key retrieval failed | Occurs when the client library sends a request to retrieve a key, and the server sends back an error response. |
Encrypt or decrypt request failed | Occurs when the client library sends a request to remotely encrypt or decrypt data, and the server sends back an error response. |
Failed to decrypt key value | Occurs when the client library has retrieved a key, but then fails to decrypt the key value when the client application calls the SymmetricKey.KeyBytes method, for example. |
Warnings traced
Warnings traced | Description |
---|---|
Failed to connect to server (retrying) | Occurs when the client library fails to make a connection to the server, and there is a failover server left to try, then only a warning is traced. The client library will then attempt to connect to the next failover server that is configured. |
Information-level traced
Information-level traced | Description |
---|---|
Connected to server | Occurs when the client library has successfully connected to the server. |
Key retrieved | Occurs when the client library has retrieved a key (for the KeyService.GetSymmetricKey method), whether from the server, or from the KeyService key cache. |
Remote encrypt or decrypt succeeded | Occurs when the client library has successfully remotely encrypted or decrypted data in response to the ICryptoTransform.TransformBlock or ICryptTransform.TransformFinalBlock methods of the encryptor or decryptor objects provided by the EncryptionService class. |
Key-caching key rolled | Occurs when the key-caching key, which is used to protect the key value bytes for SymmetricKey objects, has been rolled. |
Verbose-level traced
Verbose-level traced | Description |
---|---|
Client certificate | Indicates the client certificate used to connect to the server. |
Server certificate | Indicates the server certificate received from the server. |
Server chain certificates | Indicates additional chain certificates for the server, either received from the server or found in the local certificate stores. These would be any intermediate CA certificates, and the final, root CA certificate. |
SSL policy error | Indicates any TLS errors for the server certificate chain. For example, it is an error if the server certificate does not contain the server’s DNS name. However, this particular error may be ignored if the client is configured to ignore the error of the server’s DNS name not appearing in the server certificate (ServerConfiguration.AllowCertificateNameMismatch ). |
Server chain error | Indicates any TLS errors found in the server certificate chain. For example, a given certificate in the chain may be expired. Another example is if the server certificate is untrusted (if there is no root CA certificate installed in the local certificate stores that establishes trust for the server certificate). This particular TLS error, of an untrusted server certificate, is ignored by the client library and the connection is allowed if a copy of the server certificate is installed in the Trusted People certificate store, and if the server certificate itself is identified by thumbprint in the client configuration (ServerConfiguration.ServerCertificateThumbprint ). This allows the client library to trust the server certificate without requiring that the server’s root CA certificate be installed on the client. See Appendix B: Certificate Pinning for more information. |
Encryption API call | Each call to the ICryptoTransform.TransformBlock and ICryptoTransform.TransformFinalBlock methods the encryptor and decryptor objects of the EncryptionService are traced. |
Configure tracing
You can configure tracing to a text file in the application configuration file. The trace source is named TownsendSecurity.KeyClient
. You can configure the following levels of tracing: Error
, Info
, Off
, Verbose
, and Warning
. See Microsoft documentation for more information. You can specify a full path and file name for the trace file, or you can specify only a file name and the file will be placed in the application configuration file directory. You must have write permissions for this directory for this method to work.
The following lines in an application configuration file add logging to a text file named Trace.txt
with Verbose
level of tracing:
<configuration>
<system.diagnostics>
<trace autoflush="true" />
<sources>
<source name="TownsendSecurity.KeyClient">
<listeners>
<add initializeData="Trace.txt" traceOutputOptions="DateTime" type="System.Diagnostics.TextWriterTraceListener" name="AnyNameHere" />
</listeners>
</source>
</sources>
<switches>
<add name="TownsendSecurity.KeyClient" value="Verbose" />
</switches>
</system.diagnostics>
</configuration>
Chapter 12: Support
Technical support for customers with permanent licenses is available via the website at https://townsendsecurity.com/support/ticket. All others should contact your sales representative.
Please see the Townsend Security Maintenance Policy you received with your purchase for information on fees, online technical support, documentation, license transferability and upgrades, software maintenance, hardware maintenance, customer responsibilities, limitations, disclaimers, lapsed maintenance, enhanced maintenance services, and other topics.
Enhanced maintenance services
Townsend Security offers an Enhanced Annual Maintenance contract that includes priority telephone support, 24/7 (24 hours a day, 7 days a week) support, and other benefits for an additional charge.
Appendix A: Verify the Connection with Tester
The sample application Tester
can be used to verify connection to the AKM server and the proper operation of key retrieval. This application is located in your Program Files\Townsend Security\AKM Client Library\bin
folder after the installation of the AKM SDK for .NET.
Obtain a test encryption key
Before continuing, you will need to obtain the name of an encryption key on the AKM server from your Crypto Officer.
SECURITY ALERT: It is strongly recommended that you use a test encryption key for this exercise to avoid accidental disclosure of a production key.
Certificates
If you have already installed certificates to the Windows certificate store, you do not need to install them with Tester and you can skip the “Install the certificate files” section below. Note that the method of installing certificates below installs certificates to the certificates stores for “Current User”.
Server information
You will need the IP address of the AKM server and the port number for key retrieval (the default is 6000).
Install the certificate files
Browse to the directory that contains the client certificate/private key .p12
file:
Double click the client certificate/private key file.
Windows will launch the Certificate Import Wizard:
Select Current User and click the Next button to start the import process.
The following dialog is displayed with the full path to the certificate file:
Click the Next button to continue.
The password dialog is displayed:
Enter the password for the client private key.
Leave the Enable strong private key protection box unchecked. Leave the box for Include all extended properties unchecked.
Click the Next button to continue.
The following dialog is displayed:
Select the option to Automatically select the certificate store based on the type of certificate.
Click the Next button to continue.
The completion dialog is displayed:
Click the Finish button to continue.
The following warning dialog is displayed:
Click Yes to install the certificate. Click OK on the completion dialog to complete the certificate import.
Run the Tester application
When running the Tester
application, you must know the IP address and port number for key retrieval of the AKM server, the name of the CA certificate and client certificates/private key, and the name of the encryption key you want to retrieve.
IMPORTANT: If using AKM-generated certificates, be sure to select the option to Allow server certificate name mismatch. If this box is not checked, the connection to the server may fail.
Locate the Tester application and launch it by double-clicking the file:
The application will start and display the following dialog:
Server(s): Enter the server address and port number separated by a colon (:
). For example, “10.0.1.29: 6000”. 6000 is the default key retrieval port.
Client certificate thumbprint: Click the Select button. This displays a list of certificate thumbprints:
Select the client certificate/private key. Click the OK button to populate the “Client certificate thumbprint” field:
Server certificate thumbprint: Click the Select button. A list of certificate authority certificates is displayed:
Select the CA certificate. Click the OK button to populate the “Server certificate thumbprint” field:
IMPORTANT: Check the box to Allow server certificate name mismatch.
NOTE: You can tell Tester to use the XML configuration file by checking the “Use named section in application configuration file” box.
Key name: Enter a name for the encryption key you want to retrieve. In this example, the encryption key is named “Key01-128”.
To test key caching, enter a timespan. You can also clear the cache, roll the key-caching key, and retrieve key-caching key filenames for the current Windows user.
Click the Retrieve button to retrieve the encryption key from the AKM server.
If the key retrieval is successful, the following dialog is displayed:
Click the OK button to continue. You may also test the retrieval of other keys.
Appendix B: Certificate Pinning
The client and AKM server use certificates and private keys to perform mutual authentication over TLS. In addition, the AKM SDK for .NET requires a pinned certificate. Any one of the certificates in the server certificate chain must be identified as the “server certificate” in the client configuration. It can be the CA certificate, an intermediate CA certificate, or the AKM server certificate itself. The pinned certificate must be installed in the appropriate Windows certificate store as described elsewhere in this document.
Standard approach
The standard approach as described in this document is to install the root CA certificate onto the client in addition to the client certificate/private key. With the AKM SDK for .NET, you can use the alternate method of installing AKM’s server certificates on the client instead of the root CA certificate. This creates a situation where the server certificates are essentially “whitelisted” above and beyond simple trust of the root CA certificate, and you avoid having the root CA certificate installed on the client.
Using AKM server certificates as pinned certificates
If you have multiple AKM servers in your high availability configuration, you will need to install the server certificate of each server on the client and add the thumbprint for each AKM server certificate to the client application configuration.
If you only have one AKM server, you will only need to install one certificate and reference the thumbprint of that certificate in the client application configuration.
Install server certificates in .pem
format in the “Trusted People” store of Current User or Local Computer.