Batch Cryptography

Updated: August 9, 2017

SmartKey can perform encryption or decryption of multiple requests in a single API call. The requests can use the same or different keys, and any mixture of encryption algorithms and block cipher modes.

Prerequisites

Performing symmetric cryptography requires an SmartKey account, a group with at least one cryptographic key, and an application configured in that group. See the SmartKey Developer’s Guide for more details.

Required Operations

When encrypting, each key used in the batch must have the Encrypt operation enabled. When decrypting, each key used in the batch must have the Decrypt operation enabled.

Authorization and Configuration

You must first authenticate and optionally configure a default API client as described in Configure API Client and Client Authentication. Performing cryptography requires authenticating as an app with an API key or a client certificate. (User accounts cannot perform encryption and decryption). For each key that is used in the batch, the application must be a member of the group that that key belongs to.

Create an EncryptionAndDecryptionApi Client Object

Batch encryption and decryption operations are performed using an EncryptionAndDecryptionApi object.

import com.fortanix.sdkms.v1.api.EncryptionAndDeryptionApi();

EncryptionAndDecryptionApi cryptoApi = new EncryptionAndDecryptionApi();

Batch Encryption

Encryption Requests and Encryption Batches

Individual encryption requests must be created in the same fashion as for single-item encryption. See Public Key Encryption or Symmetric Encryption for more details on how to construct encryption requests.

Each EncryptRequest object in the batch, along with the UUID of the encryption key, must be packaged into a BatchEncryptRequestInner object. The BatchEncryptRequestInner object contains all of the information needed to perform a single encryption request. The BatchEncryptRequestInner objects must then be added to a BatchEncryptRequest object that contains all of the requests in the batch.

Batches may be of any length, but the entire batch is subject to the API request size limit.

For example, to construct a batch for encrypting one piece of data with an RSA key and another piece of data with an AES key using CBC mode:

import com.fortanix.sdkms.v1.model.BatchEncryptRequest;
import com.fortanix.sdkms.v1.model.BatchEncryptRequestInner;
import com.fortanix.sdkms.v1.model.CipherMode;
import com.fortanix.sdkms.v1.model.EncryptRequest;
import com.fortanix.sdkms.v1.model.ObjectType;

BatchEncryptRequest encryptBatch = new BatchEncryptRequest();

EncryptRequest rsaRequest = new EncryptRequest().alg(ObjectType.RSA).plain(<plaintext for RSA as byte[]>);
BatchEncryptRequestInner rsaInner = new BatchEncryptRequestInner().kid(<UUID of RSA key>).request(rsaRequest);
encryptBatch.add(rsaInner);

EncryptRequest aesRequest = new EncryptRequest().alg(ObjectType.AES).plain(<plaintext for AES as byte[]>).mode(CipherMode.CBC);
BatchEncryptRequestInner aesInner = new BatchEncryptRequestInner().kid(<UUID of AES key>).request(aesRequest);
encryptBatch.add(aesInner);

Make the Batch Encrypt Call

The batch is encrypted with the batchEncrypt() method of an EncryptionAndDecryptionApi object. This object returns a BatchEncryptResponse object, which is a list of BatchEncryptResponseInner objects. The BatchEncryptResponseInner objects are in the same order as the corresponding BatchEncryptRequestInner objects in the BatchEncryptRequest. So for the request above, a list will be returned with the first element being a BatchEncryptResponseInner for the RSA encryption request, and the second element will be a BatchEncryptResponseInner for the AES encryption request.

Each BatchEncryptResponseInner object contains the status for that request, the UUID of the encryption key used for the encryption, and an EncryptionResponse object for the corresponding request. Each request may independently succeed or fail, so you must check the return status for each request separately. The return status is an HTTP status code, with 200 indicating success.

import com.fortanix.sdkms.v1.model.BatchEncryptResponse;
import com.fortanix.sdkms.v1.model.BatchEncryptResponseInner;
import com.fortanix.sdkms.v1.model.EncryptResponse;

BatchEncryptResponse batchResponse = cryptoApi.batchEncrypt(encryptBatch);

EncryptResponseInner rsaResponseInner = encryptBatch.get(0);
if (rsaResponseInner.getStatus() == 200) {
        EncryptResponse rsaResponse = rsaResponeInner.getBody();
        rsaCiphertext = rsaResponse.getCipher();
        ...
} else {
        // Error handling...
}

EncryptResponseInner aesResponseInner = encryptBatch.get(1);
if (aesResponseInner.getStatus() == 200) {
        EncryptResponse aesResposne = aesResponeInner.getBody();
        aesCiphertext = aesResponse.getCipher();
        ...
} else {
        // Error handling...
}

Batch Decryption

Decryption Requests and Decryption Batches

Individual decryption requests must be created in the same fashion as for single-item decryption. See Public Key Encryption or Symmetric Encryption for more details on how to construct decryption requests.

Each DecryptRequest object in the batch, along with the UUID of the decryption key, must be packed into a BatchDecryptRequestInner object. The BatchDecryptRequestInner object contains all of the information needed to perform a single decryption request. The BatchDecryptRequestInner objects must then be added to a BatchDecryptRequest object that contains all of the requests in the batch.

Batches may be of any length, but the entire batch is subject to the API request size limit.

For example, to construct a batch for decrypting one piece of data with an RSA key and another piece of data with an AES key using CBC mode:

import com.fortanix.sdkms.v1.model.BatchDecryptRequest;
import com.fortanix.sdkms.v1.model.BatchDecryptRequestInner;
import com.fortanix.sdkms.v1.model.CipherMode;
import com.fortanix.sdkms.v1.model.DecryptRequest;
import com.fortanix.sdkms.v1.model.ObjectType;

BatchDecryptRequest decryptBatch = new BatchDecryptRequest();

DecryptRequest rsaRequest = new DecryptRequest().alg(ObjectType.RSA).plain(<plaintext for RSA as byte[]>);
BatchDecryptRequestInner rsaInner = new BatchDecryptRequestInner().kid(<UUID of RSA key>).request(rsaRequest);
decryptBatch.add(rsaInner);

DecryptRequest aesRequest = new EncryptRequest().alg(ObjectType.AES).plain(<plaintext for AES as byte[]>).mode(CipherMode.CBC);
BatchDecryptRequestInner aesInner = new BatchDecryptRequestInner().kid(<UUID of AES key>).request(aesRequest);
encryptBatch.add(aesInner);

Make the Batch Decrypt Call

The batch is decrypted with the batchDecrypt() method of an EncryptionAndDecryptionApiObject. This object returns a BatchDecryptResponse object, which is a list of BatchDecryptResponseInner objects. The BatchDecryptResponseInner objects are in the same order as the corresponding BatchDecryptRequestInner objects in the BatchDecryptRequest. So for the request above, a list will be returned with the first elment being a BatchDecryptResponseInner for the RSA decryption request, and the second element will be a BatchDecryptResponseInner for the AES decryption request.

Each BatchDecryptResponseInner object contains the status for that request, the UUID of the encryption key used for the decryption, and a DecryptionResponse object for the corresponding request. Each request may independently succeed or fail, so you must check the return status for each request separately. The return status is an HTTP status code, with 200 indicating success.

import com.fortanix.sdkms.v1.model.BatchDecryptResponse;
import com.fortanix.sdkms.v1.model.BatchDecryptResponseInner;
import com.fortanix.sdkms.v1.model.DecryptResponse;

BatchDecryptResponse batchResponse = cryptoApi.batchDecrypt(decryptBatch);

DecryptResponseInner rsaResponseInner = decryptBatch.get(0);
if (rsaResponseInner.getStatus() == 200) {
        DecryptResponse rsaResponse = rsaResponseInner.getBody();
        rsaPlaintext = rsaResponse.getPlain();
        ...
} else {
        // Error handling...
}

DecryptResponseInner aesResponseInner = decryptBatch.get(1);
if (aesResponseInner.getStatus() == 200) {
        DecryptResponse aesResponse = aesResponseInner.getBody();
        aesPlaintext = aesResponse.getPlain();
        ...
} else {
        // Error handling...
}