Developing a Key Encryption Plug-In

This is a guide for developers to get started developing a key-encryption plug-in for Link that can be used to encrypt and decrypt the application key, which is again used to encrypt and decrypt secrets in Link. Initially secrets are passwords that are used in different places, but later on other things can be stored as secrets as well. Link uses a symmetric AES 256-bit encryption to protect secrets and usually this key is auto-generated, but options are available to use a specific key. It is this key that is encrypted, either by one of the included modules (No-encryption or RSA assymetric encryption with a certificate) or by a supplied plug-in. When configuring the encryption module, a configuration value can be supplied (key-reference-key) which can be used in any way that suits the encryption module. The included RSA module requires that this value to be the serial number of the certificate to use.

Requirements

The plug-in must be:

  • compiled against Microsoft .NET Framework version 4.5 - to support Microsoft Biztalk Server 2013
  • a separate assembly
  • strong named
  • installed in Global Assembly Cache
  • available at runtime via GAC or other means on all servers where Link components are running

Installation

The plug-in must be made available on all servers where Link components are running, preferably by installing it in the Global Assembly Cache, but it can also be stored in relevant locations on disk. The setup of the plug-in is performed using Link Administration Tool, see this: Administration Tool

The interface

The plug-in must implement the Bizbrains.SecretApi.Contract.IEncryptionKeyPlugin interface which is exposed from the Bizbrains.SecretApi assembly (Bizbrains.SecretApi.dll).

namespace Bizbrains.SecretApi.Contract
{
public interface IEncryptionKeyPlugin
{
string DisplayName { get; }

byte[] DecryptEncryptionKey(string keyReferenceKey, byte[] encryptedKey);
byte[] EncryptEncryptionKey(string keyReferenceKey, byte[] key);
}
}

The DisplayName property returns the name of the plug-in in a user friendly format and is currently only used to represent the plug-in in the configuration screen in the Link Administration tool. It is required to return a descriptive name of the plug-in. The name should not change if the property is read again.

The EncryptEncryptionKey and DecryptEncryptionKey methods both have similar signatures, simply transforming an array of bytes to an encrypted array of bytes and vice versa. The byte arrays returned are not required to have the same length as the bytes arrays that are submitted as input, however, then value returned from the Decrypt method should be the same as the one initially submitted to the Encrypt method - assuming the same key-reference-key and assuming a successful result. The key-reference-key is any string that makes sense to the plug-in in question and is configured during setup in the Link Administration tool.

If either method is unable to return a successful result, they can throw any relevant exception. The exception is logged and the operation is cancelled. It is the responsibility of the plug-in to ensure that sufficient information is available to support the failure scenario.

Creating the plug-in class

The plug-in class can be designed as best to fit the needs, there are two requirements. The first is a default constructor, that is a constructor without arguments and the other is that it implements the IEncryptionKeyPlugin interface. When using the Link Administration tool to setup the plug-in it will load the assembly and list the plug-in classes that are available in the assembly. Only one class can be registered.

There are no lifetime hooks, then class is loaded and instantiated when it is first requested and then the assembly remains in memory for the lifetime of the host, However, the class is instantiated whenever the host requires it. It may also be used for multiple operations.

Sample implementation

This is essentially the source for the No-encryption plug-in that is included with Link. In this case neither method performs any translation of the input, but in stead just returns the unaltered input as output. This show the general structure of an implementation:

using Bizbrains.SecretApi.Contract;

namespace Bizbrains.SecretApi.EncryptionKeyPlugin
{
public class NoEncryptionEncryptionKeyPlugin : IEncryptionKeyPlugin
{
string IEncryptionKeyPlugin.DisplayName
{
get { return "No encryption"; }
}

byte[] IEncryptionKeyPlugin.DecryptEncryptionKey(string keyReferenceKey, byte[] encryptedKey)
{
return encryptedKey;
}

byte[] IEncryptionKeyPlugin.EncryptEncryptionKey(string keyReferenceKey, byte[] key)
{
return key;
}
}
}


Content on this page:

The information on this page is based on Link 2.12