ANSI TR-31 key block operations for symmetric transport keys
In a secure environment such as banking, it is important that each symmetric key has a specific set of attributes attached to it, specifying such things as the cryptographic operations for which that key can be used. Different cryptographic architectures implement these attributes in different ways and as a result, the normal approach when exchanging keys with different vendors was to strip the attributes and send just the key material. ANSI TR-31 provides a standardized way to securely exchange key material and its attributes between differing cryptographic systems.
- The key is protected in a way that meets the "key bundling" requirements of various standards that state that the individual 8-byte pieces of a double-length or triple-length triple DES key must be bound in such a way that they cannot be individually manipulated. In TR-31, this result is accomplished mainly by computation of a MAC across the entire structure.
- The key usage attributes, which define how the key can be used, are securely bound to the key itself. Thus, when a key is sent from one party to another, the attributes are also transferred and cannot be modified to suit the needs of an attacker.
In addition to the encoding defined in ANSI TR-31, the TR-31 key block can have a number of optional data blocks where each has a two character string key and a variable length string value. Any optional data blocks that are included in a TR-31 key block are securely bound to the key in the same way as the TR-31 defined usage attributes are bound to it.
The TR-31 key block can be used to export keys for encrypting and decrypting data, and transport keys (key encrypting keys). Only DES and triple DES keys can be transported in TR-31 key blocks. There is no support for transporting AES keys in TR-31 key blocks.
The keys that are used to protect a TR-31 key block are transport keys. For information about transport keys, see Symmetric transport keys (key encrypting keys) .
Exporting (wrapping) a key in a TR-31 Key Block
tdesDataKey
, used for encrypting and decrypting data, is
wrapped by using an EXPORTER transport key named
tdesExporterKey
.// obtain a cipher with the "DESedeTR31KeyWrap" cipher algorithm
//
Cipher wrapCipher = Cipher.getInstance("DESedeTR31KeyWrap", "IBMJCECCA");
// initialize the cipher, specifying WRAP_MODE and the transport key
//
wrapCipher.init(Cipher.WRAP_MODE, tdesExporterKey);
// create the TR-31 key block
//
byte[] keyBlock = wrapCipher.wrap(tdesDataKey);
tdesImporterKey2Wrap
, by using an EXPORTER transport key
named
tdesExporterKey
.// obtain a cipher with the "DESedeTR31KeyWrap" cipher algorithm
//
Cipher wrapCipher = Cipher.getInstance("DESedeTR31KeyWrap", "IBMJCECCA");
// because the key being exported is a transport key, it is necessary
// to create a parameterSpec object to specify its usage
//
CCAAlgorithmParameterSpec ccaParmSpec = new CCAAlgorithmParameterSpec();
ccaParmSpec.setKeyUsage(KeyUsage.OP_IMPORTER);
// initialize the cipher by specifying WRAP_MODE, the transport key,
// and the parameterSpec
//
wrapCipher.init(Cipher.WRAP_MODE, tdesExporterKey, ccaParmSpec);
// create the TR-31 key block
//
byte[] keyBlock = wrapCipher.wrap(tdesImporterKey2Wrap);
tdesExporterKey2Wrap
using an EXPORTER transport key named
tdesExporterKey
.// obtain a cipher with the "DESedeTR31KeyWrap" cipher algorithm
//
Cipher wrapCipher = Cipher.getInstance("DESedeTR31KeyWrap", "IBMJCECCA");
// because the key being exported is a transport key, it is necessary
// to create a parameterSpec object to specify its usage
//
CCAAlgorithmParameterSpec ccaParmSpec = new CCAAlgorithmParameterSpec();
ccaParmSpec.setKeyUsage(KeyUsage.OP_EXPORTER);
// initialize the cipher by specifying WRAP_MODE, the transport key,
// and the parameterSpec
//
wrapCipher.init(Cipher.WRAP_MODE, tdesExporterKey, ccaParmSpec);
// create the TR-31 key block
//
byte[] keyBlock = wrapCipher.wrap(tdesExporterKey2Wrap);
// define some data for the optional data blocks
//
String optData_ID1 = "AB";
String optData_1 = "Some data required by the receiving system";
String optData_ID2 = "CD";
String optData_2 = "Some information to make this block self-documenting";
// create an array of optional data blocks
//
TR31OptionalDataBlock[] optDatablocks = new TR31OptionalDataBlock[2];
optDataBlocks[0] = new TR31OptionalDataBlock(optData_ID1, optData_1);
optDataBlocks[1] = new TR31OptionalDataBlock(optData_ID2, optData_2);
// Store the optional data blocks in a ParameterSpec
//
// (If the key being exported were a transport key it would also
// be necessary to call ccaParmSpec.setKeyUsage() as shown in
// the previous samples.)
//
CCAAlgorithmParameterSpec ccaParmSpec = new CCAAlgorithmParameterSpec();
ccaParmSpec.setTR31OptionalDataBlocks(optDatBlocks);
// obtain a cipher with the "DESedeTR31KeyWrap" cipher algorithm
//
Cipher wrapCipher = Cipher.getInstance("DESedeTR31KeyWrap", "IBMJCECCA");
// initialize the cipher, specifying WRAP_MODE, the transport key,
// and the ParameterSpec
//
wrapCipher.init(Cipher.WRAP_MODE, tdesExporterKey, ccaParmSpec);
// create the TR-31 key block
//
byte[] keyBlock = wrapCipher.wrap(tdesDataKey);
Importing (unwrapping) a key from a TR-31 key block
desDataKey
, used for encrypting and decrypting data, is unwrapped
from a TR-31 key block, tr31KeyBlock
, by using an IMPORTER transport key named
tdesImporterKey
, and is stored in the CCA key storage
area.// obtain a cipher with the "DESedeTR31KeyWrap" cipher algorithm
//
Cipher unwrapCipher = Cipher.getInstance("DESedeTR31KeyWrap", "IBMJCECCA");
// initialize the cipher, specifying UNWRAP_MODE and the transport key
//
unwrapCipher.init(Cipher.UNWRAP_MODE, tdesImporterKey);
// extract the key from the TR-31 key block
//
DESKey desDataKey = unwrapCipher.unwrap(tr31KeyBlock, "DES", Cipher.SECRETKEY);
tdesDataKey
,
used for encrypting and decrypting data from a TR-31 key block tr31KeyBlock
, by
using an IMPORTER transport key named tdesImporterKey
. The resulting key is encoded
by using the host primary key.
// obtain a cipher with the "DESedeTR31KeyWrap" cipher algorithm
//
Cipher unwrapCipher = Cipher.getInstance("DESedeTR31KeyWrap", "IBMJCECCA");
// specify that the unwrapped key is to be enciphered under the local primary key
//
CCAAlgorithmParameterSpec ccaParmSpec = new CCAAlgorithmParameterSpec(CCAAlgorithmParameterSpec.SECURE_INTERNAL_TOKEN);
// initialize the cipher, specifying UNWRAP_MODE, the transport key, and the parameterSpec
//
unwrapCipher.init(Cipher.UNWRAP_MODE, tdesImporterKey, ccaParmSpec);
// extract the key from the TR-31 key block
//
DESedeKey tdesDataKey = unwrapCipher.unwrap(tr31KeyBlock, "DESede", Cipher.SECRETKEY);
The following sample illustrates importing a triple DES IMPORTER transport key named
tdesImporterKey2Import
from a TR-31 key block tr31KeyBlock
by
using an IMPORTER transport key named tdesImporterKey
. The resulting key is encoded
by using the host primary key.
// obtain a cipher with the "DESedeTR31KeyWrap" cipher algorithm
//
Cipher unwrapCipher = Cipher.getInstance("DESedeTR31KeyWrap", "IBMJCECCA");
// specify that the unwrapped key is to be enciphered under the local primary key
//
CCAAlgorithmParameterSpec ccaParmSpec = new CCAAlgorithmParameterSpec(CCAAlgorithmParameterSpec.SECURE_INTERNAL_TOKEN);
// specify that the key being imported is an IMPORTER transport key
//
ccaParmSpec.setKeyUsage( KeyUsage.OP_IMPORTER );
// initialize the cipher, specifying UNWRAP_MODE, the transport key, and the parameterSpec
//
unwrapCipher.init(Cipher.UNWRAP_MODE, tdesImporterKey, ccaParmSpec);
// extract the key from the TR-31 key block
//
DESedeKey tdesImporterKey2Import = unwrapCipher.unwrap(tr31KeyBlock, "DESede", Cipher.SECRETKEY);
Extracting non-key data from a TR-31 Key Block
A TR-31 key block is a byte array and as such, it is not easily parsed. So, a convenience class,
TR31KeyBlock
, is provided for extracting the non-key information from a TR-31 key
block. The toString()
method formats the data for printing. When possible, fields
in the TR-31 header are displayed with their encoded value and a string that interprets them. In
addition, methods are provided to enable extracting data programmatically.
//
// a TR-31 key block is a byte[]
// For this illustration we assume that tr31Block is a TR-31 key block created using
// one of the previous examples.
//
// Get an instance of the TR31KeyBlock convenience class, passing the
// actual TR-31 key block to the constructor.
//
TR31KeyBlock kblk = new TR31KeyBlock( tr31Block );
// call toString()
//
System.out.println( kblk.toString() );
TR31KeyBlock:
keyBlockVersion: A
keyBlockLength: 128
keyUsage: D0 ( DataEncryptionKey )
keyAlgorithm: T ( Triple-DES )
keyMode: B ( EncryptDecrypt )
keyVersion: 00
keyExportablility: S ( Exportable under any key )
numOptDataBlocks: 2
TR31OptionalDataBlock:
OptDataID: 01
OptData: Now is the time for all good men
TR31OptionalDataBlock:
OptDataID: PB
OptData:
TR31KeyBlock:
keyBlockVersion: A
keyBlockLength: 88
keyUsage: K0 ( KeyEcryptingKey )
keyAlgorithm: T ( Triple-DES )
keyMode: E ( Exporter )
keyVersion: 00
keyExportablility: S ( Exportable under any key )
numOptDataBlocks: 0
//
// a TR-31 key block is a byte[]
// For this illustration we assume that tr31Block is a TR-31 key block created using
// one of the previous examples.
//
// Get an instance of the TR31KeyBlock convenience class, passing the
// actual TR-31 key block to the constructor.
//
TR31KeyBlock kblk = new TR31KeyBlock( tr31Block );
// Extract the data as stored in the TR-31 key block
//
String keyBlkVersion = kblk.getKeyBlockVersion();
int keyBlkLength = kblk.getKeyBlockLength();
String keyUsage = kblk.getKeyUsage();
String keyAlgorithm = kblk.getKeyAlgorithm();
String keyMode = kblk.getKeyMode();
String keyVersion = kblk.getKeyVersion();
String keyExportability = kblk.getKeyExportability();
int numOptionalBlocks = kblk.getNumOptDataBlocks();
// Get descriptions of the data stored in the TR-31 key block
//
String keyUsageDescript = kblk.getKeyUsageAsString();
String keyAlgorithmDescript = kblk.getKeyAlgorithmAsString();
String keyModeDescript = kblk.getKeyModeAsString();
String keyExportabilityDescript = kblk.getKeyExportabilityAsString();
// Extract the contents of the optional data blocks,
// if any
//
TR31OptionalDataBlock[] optblks = kblk.getOptDataBlocks();
String[] optionalDataIDs = new String[numOptionalBlocks];
String[] optionalData = new String[numOptionalBlocks];
for( int idx=0; idx < numOptionalBlocks; idx++ ) {
optionalDataIDs[idx] = optblks[idx].getOptDataID();
optionalData[idx] = optblks[idx].getOptData();
} // end for