The ICSF function CSNBKGN2 allows you to generate keys for encrypting data (such as data sets) where you can
- specify the hex data for the key value
- have ICSF generate the key value securely so that the key value is never exposed as clear text.
Once a key has been created the key value will either be encrypted with the hardware key of the cryptographic hardware the program is running on, or is encrypted with Key Encryption Key, so it can be securely sent to a remote system.
You can generate a key in two modes:
- For use on the local system. This is known as the OP mode, because the cipher key is OPerational immediately. You can use it immediately to encrypt data, or you can use another ICSF function to write the key data to the CKDS. Once it has been written to the CKDS, you can refer to and use it by its label. At a later date you can extract the key and encrypt with another key for sending to a remote system.
- Encrypted under a transport key, called a Key Encrypting Key (KEK) an EXporter or IMporter key). You can write the created key to a file, send the file to a remote system, and then use an ICSF function(CSNDSYI2) to (decrypt it and re-encrypt it with the hardware key) and then write it to that systems CKDS. This is mode EX or IM.
The documentation for CSNBKGN2 has information about all of the options, but it is not very clear on how to use it!
I found it easier to understand the concepts, and to use, if I used two steps; generate a cipher key and then export it from the CKDS using a KEK, rather than trying to generate a cipher key for local use and encrypt it with a KEK in a single API call (point 3. below).
The CSNBKGN2 function has several modes:
- Generate a cipher key which you can use to encrypt data. This is known as the OP mode, because the cipher key is OPerational immediately.
- Generate a cipher key which is encrypted with a Key Encrypting Key. This is mode EX or IM.
- Generate a key you can use to encrypt data – both in OP mode, and generate the same key encrypted with a KEK, so you can send it somewhere. This is a combination of 1. and 2. in one API request (You specify mode = OPEX or mode = OPIM).
- Generate an exporter/importer pair of keys for encrypting other keys.
- One of the pair is (usually) created so it can be used immediately, or written to the CKDS. This is known as the OP mode.
- The other is encrypted with an existing Key Exporting Key. This is mode EX or IM.
- The combined mode is OPEX or OPIM.
CSNBKGN2 provides some defaults which are suitable for some keys, but not suitable for AES CIPHER keys used to encrypt data sets.
You can create a skeleton key using CSNBKTB2, to specify non default parameters, and get CSNBKGN2 to use the skeleton. If you want to restrict what a key can do, you will need to use the skeleton. For example you can say this exporter/importer key pair can be used to encrypt AES keys, but not DES keys. For more information see the documentation. You tell CSNBKGN2 to use a skeleton by using the TOKEN keyword instead of CIPHER, EXPORTER, or IMPORTER.
Guidance on using CSNBKGN2
Lengths of data
When using some values such as KEKs, you can specify a key name in the CKDS of length 64 bytes. You can also read the key token from CKDS yourself (or get the key token from somewhere else). In this case the length you specify of the KEK may be ignored and the length of the data in the key token is used.
If an ICSF function provides you a key token, it will check your buffer is big enough, and return the length it used.
The function complains if you give a length field more than the maximum value. So when the documentation says generated_key_identifier_2_length is the maximum value is
900 bytes. You must provide an area of the specified size, because it will complain if a different size is used.
Terms
The documentation uses the term generator key identifier. I think of this as the skeleton input.
My basic use of CSNBKGN2
Because of many parameters, I’ll give an example of my “standard” usage. The documentation gives the syntax
CALL CSNBKGN2(
return_code,
reason_code,
exit_data_length,
exit_data,
rule_array_count,
rule_array,
clear_key_bit_length,
key_type_1,
key_type_2,
key_name_1_length,
key_name_1,
key_name_2_length,
key_name_2,
user_associated_data_1_length,
user_associated_data_1,
user_associated_data_2_length,
user_associated_data_2,
key_encrypting_key_identifier_1_length,
key_encrypting_key_identifier_1,
key_encrypting_key_identifier_2_length,
key_encrypting_key_identifier_2,
generated_key_identifier_1_length,
generated_key_identifier_1,
generated_key_identifier_2_length,
generated_key_identifier_2 )f
Some constants I frequently use.
int rule_count = 2;
char * pKeyType1 = "EXPORTER";
char * pKeyType2 = "IMPORTER";
int lKey1 = 64;
int lKey2 = 64;
char KeyName1[64] ...
char KeyName2[64] ...
int lKekName = 64;
char KekName[64] ....
int lData1 = 900;
char data1[lData1];
char * pData1 = &data1[0];
int lData2 = 900;
char data2[lData2];
char * pData2 = &data2[0];
I used the parameters to CSNBKGN2 to define an Exporter/Importer
- Return code &rc,
- Reason code &rs,
- exit data length 0
- exit data array 0. This is not used because the previous field gives the length as 0.
- &rule_count, this had the value 2 because pRule below pointed to two parameters.
- pRule this pointed to {AES, OPEX}. AES is the type of cipher; OPEX says generate the first one so it can be written to the local CKDS, EX says use the second Key Exporting Key – which has a type of EXPORTER.
- &keyBitLength keyBitLength has the value 256. This specifies how secure to make the cipher.
- pKeyType1 where KeyType1 was EXPORTER.
- pKeyType2 where KeyType2 was IMPORTER.
- &lKey1 value 64. This is the length of the string following – the value of the key name stored in the first key. Set this to zero if you do not want a name stored in the first generated key.
- &KeyName1[0], the address of the 64 char name to be stored in the first key. You can specify 0 if the length value is 0. This name becomes part of the key data. It needs to be unique within the CKDS.
- &lKey2 value 64. This is the length of the string following – the value of the key name stored in the second key. Set this to zero if you do not want a name stored in the second generated key
- &KeyName2[0], the address of 64 char name to be stored in the second key. You can specify 0 if the length value is 0.
- 0, user associated data length for the first key.
- 0 not used if the length is zero.
- 0, user associated data length for the second key.
- 0 not used if the length is zero.
- 0,
- – length of the KEK for the first key. Because the rule was OPEX – the first key is to be stored in the local CKDS and so does not have a KEK.
- 0 this KEK is not used.
- &lKekName lKekName has the value 64.
- &KEK[0] this is the address of the first character of the Key Encrypting Key. It must be padded with blanks to 64 characters.
- &lData1 the value 900 which is the length of the storage pointed to by pData1 for the first generated key. This storage is 900 characters long. If a smaller value is used, I got rc 8 rs 11000 Invalid length for a key token, key, or text field even though the returned data was less than 120 bytes long.
- pData1 pointer to the first skeleton, which is also the area where the first key is returned. This storage is 900 characters long.
- &lData2 the value 900, which is the length of the storage pointed to by pData2 for the second generated key. This storage is 900 characters long. The length of the data is returned here. If a smaller value is used, I got rc 8 rs 11000 Invalid length for a key token, key, or text field even though the returned data was less than 120 bytes long.
- pData2 pointer to the second skeleton, which is also the area area where the second key is returned. This storage is 900 characters long.
Generate a CIPHER key using Key Generate 2 (CSNBKGN2) directly
I used the following parameters in CSNBKGN2. (See below for all of the typical parameters I specify.) The character values have been formatted for display, they are 8 byte characters, padded on the left with blanks.
- rule = {“AES”,”OP” }
- KeyType1 = “CIPHER”
- keyBitLength 256
- kek lengths = 0; no KEK is used (because it will be used/stored on this system)
This created a key, but I could not use it because it defaults to Key Usage CBC, when ANY_MODE is required for data set encryption.
Generate a CIPHER key using a skeleton and Key Generate 2
You need to use Key Token Build CSNBKTB2 if you want to use any of the non default options. For example
Key Token Build CSNBKTB2 parameters
- rule_count = 5;
- rule = {“EXTERNAL”,”AES “,”CIPHER “, “XPRTCPAC”,”ANY-MODE” }
The “XPRTCPAC”,”ANY-MODE” parameters are required if data set encryption is used
CSNBKTB2 returns an internal format key, which can be used by CSNBKGN2.
CSNBKGN2 parameters
- rule_count = 2;
- rule = {“AES “,”OP “};
- keyType1 = “TOKEN”. This says use the skeleton value in the generated_key_identifier_1 field.
- kek lengths = 0; no KEK is used (because it will be used/stored on this system).
- generated_key_identifier_1_length 900 (in this case).
- generated_key_identifier_1 address of my skeleton data.
- generated_key_identifier_2_length 0 – we are not generating a second parameter.
- generated_key_identifier_2 0 – this value is ignored.
Generation two CIPHERs one for local, one for remote.
To generate the skeletons
- Rule_count = 5;
- Rule1 = {“INTERNAL”,”AES “,”CIPHER “, “XPRTCPAC”,”ANY-MODE” }
- Rule2 = {“EXTERNAL”,”AES “,”CIPHER “, “XPRTCPAC”,”ANY-MODE” }
CSNBKGN2 parameters
- pOPRule = {“AES”,”OPIM “};
- keyType1 = “TOKEN”. This says use the skeleton value in generated_key_identifier_1. Skeleton 1 was defined with CIPHER.
- keyType2 = “TOKEN”. This says use the skeleton value in generated_key_identifier_2. Skeleton 2 was defined with CIPHER.
- kek length1 = 0; no KEK is used (because it will be used/stored on this system).
- kek length2 = 64 ; A KEK is used. The name of an IMPORTER KEK.
- generated_key_identifier_1_length 900
- generated_key_identifier_1 address of my skeleton data, and where the data is returned.
- generated_key_identifier_2_length 900.
- generated_key_identifier_2 address of my skeleton data, and where the data is returned.
I created one OPerational copy which I wrote to the local PKDS, and an encrypted copy which I wrote to a data set using fwrite(). On the remote system I used fread() toread the file, and used the IMPORTER key to import it into the PKDS. This is the OPIM in the rules.
Generating an importer/exporter pair
In the examples above they just generated a CIPHER for the local system. You can use CSNBKGN2 to generate a key an IMPORTER/EXPORTER pair.
It creates one of the keys in a form that can be added directly to the CKDS, and creates the opposite key, encrypted by a KEK. This means you can write it to a dataset, send the data set to the remote system, and import it using the KEK’s importer key.
To generate the skeletons
- Rule_count = 3;
- Rule1 = {“INTERNAL”,”AES “,”IMPORTER” }
- Rule2 = {“EXTERNAL”,”AES “,”EXPORTER” }
CSNBKGN2 parameters
- pOPRule = {“AES”,”OPEX”};
- keyType1 = “TOKEN”. This says use the skeleton value. Skeleton 1 was defined with EXPORTER.
- keyType2 = “TOKEN”. This says use the skeleton value. Skeleton 2 was defined with IMPORTER
- kek length1 = 0; no KEK is used (because it will be used/stored on this system).
- kek length2 = 64 ; A KEK is used. The name of an EXPORTER KEK.
- generated_key_identifier_1_length 900
- generated_key_identifier_1 address of my skeleton data, and where the data is returned.
- generated_key_identifier_2_length 900.
- generated_key_identifier_2 address of my skeleton data, and where the data is returned.
I used the ICSF function CSNBKRC2 to write the first generated key to the CKDS.
I wrote the second generated key to a file using fwrite() . I could send this file to a remote site, then use CSNDSYI2 with the IMPORTER version of the KEK to process the data into a key for local use, then write it to the CKDS using CSNBKRC2.
Which options produce what output?
- With EX in the rule OPEX, and an EXPORTER Key Exporting Key it worked.
- With IM in the rule OPIM, and an EXPORTER key, I got Key not found, because it was searching for keyname of type IMPORTER, when only key name with type EXPORTER was present.
- With IM in the rule OPIM, and an IMPORTER key, I got reason code 10040 Key identifiers contain a version number.
- You can use OPIM for CIPHER keys, but not IMPORTER or EXPORTER. See the list of valid combinations.