In the previous installments of this article series, I built a number of tools to establish an encryption key hierarchy: the Create Master Key (CRTMSTK) command, the Create Key Encrypting Key (CRTKEK) command, and the Create Data Encryption Key (CRTDTAK) command. In this installment, I put together all the pieces that I've provided so far and use these encryption key commands and a set of new functions to encrypt and decrypt sensitive data.
To perform this demonstration, I've written two sample commands, the Add Customer Record (ADDCUSRCD) and the Change Customer Record (CHGCUSRCD) command. The ADDCUSRCD command prompt has the following layout:
Add Customer Record (ADDCUSRCD)
Type choices, press Enter.
Customer name . . . . . . . . . ____________________
Address . . . . . . . . . . . . ____________________
City . . . . . . . . . . . . . . ____________________
State . . . . . . . . . . . . . __
Zip code . . . . . . . . . . . . _____
Phone number . . . . . . . . . . __________
A successful execution of the ADDCUSRCD command returns a completion message specifying the assigned customer number:
Customer number 1 added.
The ADDCUSRCD CPP encrypts and stores the sensitive customer data in the CBX1502F data file.
Creating a customer record lets you also change that record. The CHGCUSRCD command initially looks like this:
Change Customer Record (CHGCUSRCD)
Type choices, press Enter.
Customer number . . . . . . . . ________
|
If you enter an existing customer number and have the required usage authorization (which I discuss momentarily), a prompt override program retrieves and decrypts the customer data for that customer. The customer data is then presented in the full command prompt:
Change Customer Record (CHGCUSRCD)
Type choices, press Enter.
Customer number . . . . . . . . > 1
Customer name . . . . . . . . . 'George Best '
Address . . . . . . . . . . . . 'E. Washington St. 7 '
City . . . . . . . . . . . . . . 'Phoenix '
State . . . . . . . . . . . . . 'AZ'
Zip code . . . . . . . . . . . . '85077'
Phone number . . . . . . . . . . '6029328070'
|
Changing any of the customer data and pressing Enter causes all data to be encrypted and written to the customer record.
To run the preceding commands, a user must have usage authorization to the CBX_CRYPTO_KEY_USAGE user function, which was installed earlier during creation of command objects. The command WRKFCNUSG FCNID(CBX_CRYPTO_KEY_USAGE) shows you exactly which user profiles are authorized and also lets you add or remove user profiles.
Apart from this requirement, here's a quick setup guide to prepare the test:
Create a master key using the CRTMSTK command: CRTMSTK
Create a key-encrypting key using the CRTKEK command: CRTKEK KEYLABEL(CBX_KEK_0001)
Create a data encryption key using the CRTDTAK command: CRTDTAK KEYLABEL(CBX_DTAK_0001) KEKLABEL(CBX_KEK_0001)
Use Data File Utility (DFU) or some other such utility to update the CBX1501F control file. Specify the data key label (in the preceding example, CBX_DTAK_0001) in the KEYLBL field. Specify whatever number you want to be the initial customer number in the field LSTCUS.
Run the ADDCUSRCD command to create a customer record.
Run the RUNQRY *N CBX1502F command to verify that the record has been added and the customer data encrypted.
Run the CHGCUSRCD command, specifying the customer number returned in step 5. You should now be able to see in cleartext the data previously entered. Try to change the data and repeat this step to verify the change.
Run the command WRKFCNUSG FCNID(CBX_CRYPTO_KEY_USAGE) and remove your function usage authorization: Option 2, specify USER(
The interfaces between the CPPs and the key store and cryptographic functions in the two previously published service programs, CBX146 and CBX147, are located in a new CBX150 service program, making the following functions available to the commands:
GetDtaAlg() -- Get data encryption algorithm context GetDtaKeyLb() -- Get customer data key label GetNxtCusNo() -- Get next customer number VfyCusDta() -- Verify customer data GetCusDta() -- Get customer data AddCusDta() -- Add customer data ChgCusDta() -- Change customer data
During the research, development, and testing that I performed while writing these articles, I encountered a variety of concerns and topics related to the practical use of the Cryptographic Services APIS. One is related to the Advanced Encryption Algorithm's (AES's) use of padding, and it has an important impact on the space required to store the encrypted data.
As I've mentioned, the AES algorithm produces a cipher string length that is a multiple of the specified block length (which is 16 bytes in this article series). It does, however, also always apply padding to the cleartext string before encrypting it. This means that if you have a cleartext string length that is an exact multiple of the block length, AES adds a full block length of padding to the cleartext string.
In my example, the customer data field occupies 80 bytes in the customer file. This is because the actual customer data takes up 77 bytes, thus leaving 3 bytes for the padding. Having the Encrypt Data API encrypt the full 80-byte string, which is an exact multiple of 16, would cause the API to add another full block length of 16 bytes of pad characters, producing a cipher string of 96 bytes.
You must therefore pass only the 77 bytes of customer data to the Encrypt Data API, to ensure that it doesn't return a cipher string longer than the storage available in the file to hold it. I achieve this by trimming the blank pad field when passing the cleartext data to the Encrypt Data API.
A fairly comprehensive and detailed discussion of the concept of padding in cryptography is in "Using padding in Encryption":
http://www.di-mgt.com.au/cryptopad.html
Another cryptographic API implementation concern emerged while I was testing the commands that I present in this article. This concern was the context token behavior that requires the key and algorithm context tokens used in the process of generating a new key context token to remain valid in order for the new key context token to also be valid in a subsequent cryptographic process.
Let me explain that in a bit more detail: When I generate a data encryption key context token, I specify the key-encrypting key (KEK) context token and a key management algorithm context token as input to the Create Key Context API. This is necessary because, as you remember, this is how the data encryption key value is stored: Encrypted under a KEK. So to avoid having to decrypt the data encryption key before creating a data encryption key context, I simply pass the KEK context as well as the KEK algorithm context token to the Create Key Context API. This way the KEK itself is never exposed.
The result of this process is a data encryption key context token. This data encryption key context token, however, is deemed valid only by, for example the Encrypt Data API, if the key encryption key and algorithm context tokens used to produce the data encryption key context are also still valid (i.e., have not been destroyed or invalidated in the meantime).
So using key context tokens requires you to manage all involved context tokens for the full period of usage and perform the necessary housekeeping when they are no longer needed. Different methods are available to perform such housekeeping and should be carefully evaluated to minimize the risk of exposure in each individual application or context.
Reader Matt Haas brought yet another concern to my attenion during the course of this article series. Matt pointed out the challenge of having to exchange encrypted data between different systems and different code pages and character sets. Because modern cryptographic methods always operate at the bit level, as opposed to the character level, it is of highest importance to take into consideration when and where data conversion is going to take place, if such a requirement is involved in your set up. Although it's beyond the scope of the cryptographic API example that I present here, you might want to read the very interesting and detailed discussion of this complex topic in "Encryption with International Character Sets":
http://www.di-mgt.com.au/cryptoInternational.html
And if you're hungry for even more cryptography reading, look up "An Overview of Cryptography," by Gary C. Kessler, which provides a comprehensive overview with many relevant links to even more detailed and specific information:
http://www.garykessler.net/library/crypto.html
As for the key management concern, please note that V5R4 has added a set of Key Management APIs. Check out the Cryptographic Services API manual for further details and new information about the subject:
http://publib.boulder.ibm.com/infocenter/iseries/v5r4/topic/apis/catcrypt.htm
I've provided the following cryptographic and key management functions with this and previous articles in this series:
GenAesKey() -- Generate AES cipher key GenInzVct() -- Generate initialization vector GetAlgCtx() -- Get algorithm context GetMgtAlg() -- Get key management algorithm context GetKeyCtx() -- Get key context RmvAlgCtx() -- Remove algorithm context RmvKeyCtx() -- Remove key context EncDtaStr() -- Encrypt data string using context tokens DecCphStr() -- Decrypt cipher string using context tokens AddKeyEnt() -- Add key entry to key store ChgKeyEnt() -- Change key store entry ChkSubKey() -- Check sub key existence FndNxtKeyE() -- Find next key entry FndTopKeyE() -- Find top key entry GetKeyAtr() -- Get key attribute GetKeySto() -- Get key store GetMstKeyLb() -- Get master key label RmvKeyEnt() -- Remove key store entry VfyKeyEnt() -- Verify key store entry GetFcnUsg() -- Get function usage GetMstKeyTk() -- Get master key context token GetKekTkn() -- Get key encryption key context token GetDtaKeyTk() -- Get data key context token RmvParCtxTk() -- Remove parent context tokens
NOTE: I recommend reading all parts of this article, and taking into account all recommendations and warnings stated in each part of this article, before using any or part of the tools provided in this article series in a production environment.
You can find part one of this article here:
http://www.iseriesnetwork.com/article.cfm?id=51236
Part two here:
http://www.iseriesnetwork.com/article.cfm?id=51786
Part three here:
http://www.iseriesnetwork.com/article.cfm?id=51863
Part four here:
http://www.iseriesnetwork.com/article.cfm?id=51962
Part five here:
http://www.iseriesnetwork.com/article.cfm?id=52017
This APIs by Example includes the following source members:
CBX147 -- Cryptographic key management service program CBX147B -- Service program binder source
These sources are both revised versions of previously published sources, which have been updated to support the new functions that this article introduces. Please replace these sources in your utility library's source files. The CBX150M program ensures that the service program gets correctly recompiled.
The following new sources deliver the ADDCUSRCD and CHGCUSRCD commands and related services:
CBX150 -- Customer data management - service program CBX150B -- Service program binder source CBX1501 -- Add Customer Record - command processor CBX1501H -- Add Customer Record - help CBX1501V -- Add Customer Record - validity checker CBX1501X -- Add Customer Record - command CBX1502 -- Change Customer Record - command processor CBX1502H -- Change Customer Record - help CBX1502V -- Change Customer Record - validity checker CBX1502O -- Change Customer Record - prompt override program CBX1502X -- Change Customer Record - command
I have included a program that performs all necessary command and object creation:
CBX150M -- Command objects creation
Compilation instructions are also in the source headers, as usual.
This article demonstrates the following APIs:
Add Validation List Entry (QsyAddValidationLstEntry) API:
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/apis/qsyavle.htm
Change Validation List Entry (QsyChangeValidationLstEntry) API:
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/apis/QSYCVLE.htm
Find First Validation List Entry (QsyFindFirstValidationLstEntry) API:
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/apis/QSYFFVLE.htm
Find Next Validation List Entry (QsyFindNextValidationLstEntry) API:
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/apis/QSYFNVLE.htm
Find Validation List Entry (QsyFindValidationLstEntry) API:
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/apis/QSYFIVLE.htm
Remove Validation List Entry (QsyRemoveValidationLstEntry) API:
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/apis/QSYRVLE.htm
Encrypt data (Qc3EncryptData) API:
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/apis/qc3encdt.htm
Decrypt data (Qc3DecryptData) API:
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/apis/qc3decdt.htm
Generate Symmetric Key (Qc3GenSymmetricKey) API:
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/apis/qc3gensk.htm
Generate Pseudorandom Numbers (Qc3GenPRNs) API:
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/apis/qc3genprns.htm
Create Algorithm Context (Qc3CreateAlgorithmContext) API:
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/apis/qc3crtax.htm
Create Key Context (Qc3CreateKeyContext) API:
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/apis/qc3crtkx.htm
Destroy Algorithm Context (Qc3DestroyAlgorithmContext) API:
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/apis/qc3desax.htm
Destroy Key Context (Qc3DestroyKeyContext) API:
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/apis/qc3deskx.htm
Send Program Message (QMHSNDPM) API:
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/apis/QMHSNDPM.htm
Move Program Messages (QMHMOVPM) API:
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/apis/qmhmovpm.htm
Resend Escape Message (QMHRSNEM) API:
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/apis/QMHRSNEM.htm
You can retrieve the source code for this API example from the following link:
http://www.pentontech.com/IBMContent/Documents/article/52119_58_CryptoServices6.zip