GemStone/S 64 Bit Supplemental Documentation

Data Encryption using Azure Key Vault

Overview

GemStone supports key management using Microsoft Azure Key Vault, on Linux on Intel.

Azure Key Vault is a cloud service for securely storing and accessing secrets, such as encryption keys. GemStone classes allow you to use Azure Key Vault to hold keys for data encryption.

To use this feature, you must have an account with Azure, have created an Azure Key Vault, and obtained the client secret string. You must also have created one or more keys in that Key Vault. Consult the Azure documentation for more information.

The Azure SDK for C++ (see https://github.com/Azure/azure-sdk-for-cpp) is an open-source project that provides a C++ interface to Azure services. The GemStone distribution includes shared libraries based on the Azure toolkit. These libraries are included in the Linux/x86 distribution.

Version 3.7 of GemStone includes Azure SDK for C++ v1.4.0.

Azure Key Management

The following classes support this feature:

AzureCredentials - encapsulates the key information needed for authentication to the Azure Key Vault.

AzureDataKey - holds a local encryption key that can be used to encrypt and decrypt Strings and ByteArrays. This requires the Azure Key Vault URL and keyname, as well as the AzureCredentials needed to authenticate.

AzureError - signalled when errors occur in Azure API classes.

GemStone’s API allows you to authenticate a key name in a Key Vault, and use the resulting key instance to encrypt a String or ByteArray, which can be decrypted using that same key.

A key is created using code such as:

cred := AzureCredentials
newWithClientId: '1234567890'
clientSecret: 'abcdefghij'
tenantId: '1a2b3c4d5e6f7g8h'.
key := AzureDataKey
createKeyUsingAzureCredentials: cred
keyVaultUrl: 'https://keyvaultname.vault.azure.net/'
keyName: 'keyname'.

This instance of AzureDataKey should be persisted in the database for ongoing use for encryption and decryption. If the key instance is lost, any data that was encrypted with that key cannot be decrypted, and is permanently inaccessible, even if the credentials.

AzureCredentials can be recreated as needed. Since a persisted instance of AzureDataKey is locked in newly logged in sessions, the same or a recreated instance of AzureCredentials will be needed to unlock a persisted instance of AzureDataKey.

Locking

An AzureDataKey may be in a locked or unlocked state. A newly created key is unlocked. The key can be explicitly locked, and is automatically locked when the creating session logs out. When it is saved to disk, it is saved in the locked state.

If a key is locked, it cannot be used to encrypt or decrypt data. Before it can be used, it must be unlocked using an instance of AzureCredentials that is valid to authenticate the AzureDataKey.

The following methods are available:

AzureDataKey >> lock
AzureDataKey >> unlockWithAzureCredentials: anAzureCredentials
AzureDataKey >> isLocked
AzureDataKey >> isUnlocked

Encryption/decryption using the Key

Encryption and decryption done by sending a request to the (unlocked) AzureDataKey.

Encryption is performed using the AES-OCB authenticated encryption, which ensures data that has been successfully decrypted has not been modified in any way.

AzureDataKey >> encrypt: srcByteObj into: destByteObj
Uses the receiver to encrypt srcByteObj and stores the resulting encrypted bytes into destByteObj as a Base64 string. srcByteObj must be a non-empty byte object. destByteObj must be a mutable byte object; any contents will be overwritten.

AzureDataKey >> encryptAndErase: srcByteObj into: destByteObj
Encrypt srcByteObj, erasing all data in srcByteObj, and store the resulting encrypted bytes into destByteObj as a Base64 string. srcByteObj must be a non-empty byte object. destByteObj must be a mutable byte object; any contents will be overwritten.

AzureDataKey >> decrypt: srcByteObj into: destByteObj
Uses the receiver to decrypt srcByteObj and stores the resulting decrypted bytes into destByteObj. srcByteObj must be a non-empty byte object containing Base64 encrypted text. destByteObj must be an mutable byte object.; any contents will be overwritten.

For example:

| key credentials data encryptedData |
credentials := AzureCredentials
newWithClientId: '1234567890'
clientSecret: 'abcdefghij'
tenantId: '1a2b3c4d5e6f7g8h'.
key := AzureDataKey
createKeyUsingAzureCredentials: credentials
keyVaultUrl: 'https://keyvaultname.vault.azure.net/'
keyName: 'keyname'.
data := 'Please excuse my dear aunt Sally'.
encrStr := String new.
decrStr := String new.
key encrypt: data into: encryptedData.
key decrypt: encryptedData into: decryptedData.

Managing Keys

Key rotation

Azure Key Vault provides the ability to do key rotation for improved security. You may update an instance of AzureDataKey to be associated with a new keyName, vault, and credentials, using the following method. To ensure that the change will be committed if successful, this method write locks the receiver and commits the session, so this requires that there are no uncommitted changes.

AzureDataKey >> changeKeyNameTo: newName inKeyVault: theVault usingCredentials: theCreds
Atomically update the receiver to use the key name newName, in the vault theVault, which is accessed with theCreds in a single operation, and commit. The receiver must be unlocked, the session must not have uncommitted changes, and the session must be able to write lock the receiver.

The key newName must already exist in the given vault. You may use the existing vault and credentials to rotate the key within the same vault, or use different parameters.

For example:

| key credentials data encryptedData decryptedData |
credentials := AzureCredentials
newWithClientId: '1234567890'
clientSecret: 'abcdefghij'
tenantId: '1a2b3c4d5e6f7g8h'.
key := AzureDataKey
createKeyUsingAzureCredentials: credentials
keyVaultUrl: 'https://keyvaultname.vault.azure.net/'
keyName: 'keyname'.
data := 'Please excuse my dear aunt Sally'.
encryptedData := String new.
decryptedData := String new.
key encrypt: data into: encryptedData.
key
changeKeyNameTo: 'key2' 
inKeyVault: 'https://keyvaultname.vault.azure.net/' 
usingCredentials: cred.
key decrypt: encryptedData into: decryptedData.
data = decryptedData

Making a copy of a key

An AzureDataKey can be copied. The copy of an AzureDataKey has the same locked state as the original, and can be unlocked using the same credentials.

AzureDataKey >> copy
Answer a new object which is a deep copy of the receiver. The lock state of the receiver is preserved when copied, i.e.: if the receiver is unlocked the resulting copy will also be unlocked.

Key equality

AzureDataKey objects are considered equal (=) if they have the same vault, key name, and the same encrypted key string. Lock state does not affect equality.

Debugging

Tracing Azure calls

The following environment variables can be defined in the client environment to print trace information on Azure calls. These GemStone environment variables set Azure environments variables to perform the debugging; note that the numeric values are defined by Azure, rather than conforming with GemStone’s other debugging environment variables.

GS_AZURE_LOG_DIR
A directory in which to create the azure log file

GS_AZURE_LOG_LEVEL
The level of logging. Valid values are 1, 2, 3, 4. The meanings of these values are:

1 – Verbose: Logging level for detailed troubleshooting scenarios

2 – Informational: Logging level when a function operates normally.

3 – Warning: Logging level when a function fails to perform its intended task.

4 – Error: Logging level for failures that the application is unlikely to recover from.

If both these environment variables are set to valid values, Azure creates a log file named

azure_sdk_YY-MM-DD-HH-mm-ss.log

where YY-MM-DD-HH-mm-ss are timestamp values, in the directory specifed by$GS_AZURE_LOG_DIR.