Migrate Cryptographic Support for system cross-domain key files

If you have worked with cryptography before on your server, you may have cryptographic cross-domain files from Cryptographic Support (5769-CR1). You can migrate existing cross-domain keys to your new Cryptographic Coprocessor.

The Cryptographic Support for OS/400® product (5769-CR1 or 5722-CR1) encrypts its cross-domain keys under the host master key and stores them in a file. Common Cryptographic Architecture (CCA) cannot use them in this form, but you can migrate them from the Cryptographic Support product for the CCA to use with your Coprocessor. You must consider a number of things before completing this task:
  • Encryption of cross-domain keys by cross-domain keys: Cryptographic Support supports importing clear key values for cross-domain keys and encrypting data keys under cross-domain keys. However, it does not support encrypting cross-domain keys under cross-domain keys, nor does it support returning the clear key value of any cross-domain key. Because of this, migrating cross-domain keys is considerably more involved than just performing an export and import operation.
  • Single-length keys versus double-length keys: All keys in Cryptographic Support are single-length keys. In CCA, all key-encrypting keys and PIN keys are double-length keys. Although the key lengths are different, you can build a double-length key from a single-length key and have that double-length key behave like the single-length key. If both halves of a double-length key are the same, the result of any encryption operation will be the same as if a single-length key was used. Therefore, when you migrate keys from Cryptographic Support to CCA, you will need to copy the key value of the cross-domain key into both halves of the key value for a CCA key.
  • CCA control vectors versus master key variants: In CCA, when a key is said to be encrypted under a key-encrypting key, it is really encrypted under a key that is formed by an exclusive OR operation of the key-encrypting key and a control vector. For Cryptographic Support, cross-domain keys are encrypted under one of three different master key variants. A master key variant is the result of the exclusive OR operation of the host master key with either 8 bytes of hexadecimal 22, 44, or 88. Both control vectors and master key variants provide key separation and thereby restrict keys to their intended use. In CCA, the value of the control vector determines its use. In Cryptographic Support how a key is used determines which master key variant will be used to decrypt it. In both cases, any attempt to use the key for other than its intended use will result in an error. Although control vectors and master key variants may work similarly, the values used to form master key variants are not the same as control vectors.
  • Asymmetry of CCA control vectors for double-length keys: Double-length keys behave like single-length keys only when both halves of the double-length key are identical. Control vectors for double-length keys are asymmetric. Any double-length key that is exclusive ORed with a control vector will not result in a key with identical halves. This double-length key will not behave like a single length key.
You can choose one of two methods for migrating the keys.

You can choose one of two methods for migrating the keys.

Method 1 (recommended)

This method provides some solutions to the considerations listed above and is the recommended method to use.

To migrate the cross-domain keys from Cryptographic Support to CCA, you will need to use a key-encrypting key that is common to both. You can use the Cryptographic Support host master key as the common key between Cryptographic Support and CCA (in CCA, the host master key is known as the master key). Import the Cryptographic Support host master key clear value into CCA as an IMPORTER key-encrypting key. Because you enter the host master key in two separate parts, you should consider importing it into CCA as two parts using the Key_Part_Import (CSNBKPI) CCA API. If you had dual responsibility for the Cryptographic Support host master key, you should maintain this dual responsibility for this key-encrypting key. Alternatively, if you know both parts of the host master key, you could also perform an exclusive OR of the two parts and import the key in just one part. The program example uses this method of importing the host master key. You may want to consider importing the host master key in a completely separate process instead of combining it with the migration of all cross-domain keys like the program example does.

There are three types of cross-domain keys:
  • Receiving cross-domain keys
  • Sending cross-domain keys
  • PIN cross-domain keys

The CCA equivalent of receiving cross-domain keys are IMPORTER key-encrypting keys. Both are used for receiving or importing an encrypted key.

Sending-cross-domain keys are used for both a) encrypting data keys, which can then be sent to another system, and b) translating encrypted personal identification numbers (PIN). CCA has stricter key separation than the Cryptographic Support product, so you cannot generate or import a key that provides both functions. If the key is used as both an EXPORTER key-encrypting key and an OPINENC (outbound PIN encrypting) key, you need to import sending-cross-domain keys twice into two different keys with two different key types.

You may use PIN-cross-domain keys for generating PINs and verifying PINs. CCA separates these two usage's into PINGEN (PIN generation) and PINVER (PIN verification) keys. If the key is used for both generating and verifying PINs, you need to import PIN-cross-domain keys twice, as well.

While the host master key encrypts data keys, different master key variants encrypt cross-domain keys.
  • Master key variant 1 encrypts sending cross-domain keys. Variant 1 is the result of an exclusive-OR operation of the host master key with 8 bytes of hexadecimal 88.
  • Master key variant 2 encrypts receiving cross-domain keys. Variant 2 is the result of an exclusive-OR operation of the host master key and 8 bytes of hexadecimal 22.
  • Master key variant 3 encrypts PIN cross-domain keys. Variant 3 is the result of an exclusive-OR operation of the host master key and 8 bytes of hexadecimal 44.
Note: If you only import the clear key value of the host master key into CCA, you will not be able to migrate any keys. You need to factor in which master key variant encrypts the key in order to migrate it.

The 8 byte values for creating master key variants are analogous to control vectors. The process of migrating keys can be thought of as changing control vectors on a key. The IBM® PCI Cryptographic Coprocessor CCA Basic Services Reference and GuideLink
outside Information Center describes a method for this process. The method is the pre-exclusive-OR technique. If the clear key value of a key-encrypting key (the host master key, in this case) is 'exclusive-ORed' with control vector information before importing the key, you can effectively change the control vector for any key that this key-encrypting key imports.

The "pre-exclusive-OR" technique works well if you are working with single-length keys. For double-length keys, the technique must be changed because the control vector for the right half of a CCA key is different than the control vector for the left half. To overcome this difference, import the key twice, as follows:

  1. Create a 16 byte value such that each 8 byte half is identical to the left half of the control vector of the key you want to import. Use this 16 byte value in the pre-exclusive-OR technique to create an importer key-encrypting key that you can refer to as the "left-importer." Only the left half of keys that are imported using this key-encrypting key will be valid.
  2. Create another 16 byte value such that each 8 byte half is identical to the right half of the control vector of the key you want to import. Use this 16 byte value in the pre-exclusive-OR technique to create an importer key-encrypting key. Using this importer key-encrypting key, only the right half of the keys that are imported will be valid
  3. Import the cross-domain key, twice:
    1. First use the key-encrypting key created in step 1 and save the left half of the result.
    2. Then use the key-encrypting key created in step 2 and save the right half of the result.
  4. In the final step, concatenate the left half of the result from step A with the right half of the result from step B. Place the combined results in a new key token.

You now have a CCA double-length key that behaves like the cross-domain key from the Cryptographic Support product. See [Using IMPORTER key-encrypting keys] for a summary of all the importer key-encrypting keys that are needed to import all of the cross-domain keys, as well as the steps required to create the importer key-encrypting keys.

Method 2

You should only use this method if you feel comfortable with the security of your system and environment. This method is easier than the recommended method, but it presents a greater security risk for your cross-domain key files, since the cross-domain keys will be in clear form in application storage.
  1. Import the host master key into CCA as a data key by using the Clear_Key_Import (CSNBCKI) CCA API. Remember to perform an exclusive OR operation on the key with the values needed to produce data keys equivalent to the master key variants as follows:
    1. Master key variant 1 encrypts sending cross-domain keys. Variant 1 is the result of an exclusive-OR operation of the host master key with 8 bytes of hexadecimal 88.
    2. Master key variant 2 encrypts receiving cross-domain keys. Variant 2 is the result of an exclusive-OR operation of the host master key and 8 bytes of hexadecimal 22.
    3. Master key variant 3 encrypts PIN cross-domain keys. Variant 3 is the result of an exclusive-OR operation of the host master key and 8 bytes of hexadecimal 44.
    You will have 3 different data keys after this step.
  2. Use the Decrypt (CSNBDEC) CCA API to decrypt the cross-domain keys to return the clear key values. Use the correct data key to decrypt it.
  3. Use the Key_Part_Import (CSNBKPI) CCA API to import the clear key into CCA.

You should not consider this method to be secure. All of the keys will have been in clear form in application storage at some time during this method.

Congratulations! You are now qualified to write a program to migrate cross-domain keys, or you can change the following program example to suit your needs for migrating Cryptographic Support cross-domain key files to your Cryptographic Coprocessor.

Note: Read the Code license and disclaimer information for important legal information.
/*********************************************************************/
/* This program migrates keys stored in the file QACRKTBL in library */
/* QUSRSYS to key storage for Option 35 - CCA Cryptographic Service  */
/* Provider.  The QACRKTBL file contains cross domain keys that are  */
/* used for the Cryptographic Support licensed program, 5722-CR1.    */
/*                                                                   */
/*  COPYRIGHT 5769-SS1 (C) IBM CORP. 1999                            */
/*                                                                   */
/*  This material contains programming source code for your          */
/*  consideration.  These examples have not been thoroughly          */
/*  tested under all conditions.  IBM, therefore, cannot             */
/*  guarantee or imply reliability, serviceability, or function      */
/*  of these program.  All programs contained herein are             */
/*  provided to you "AS IS".  THE IMPLIED WARRANTIES OF              */
/*  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE         */
/*  ARE EXPRESSLY DISCLAIMED.  IBM provides no program services for  */
/*  these programs and files.                                        */
/*                                                                   */
/*                                                                   */
/*                                                                   */
/* The keys are migrated by the following steps:                     */
/*                                                                   */
/* 1 - The master key used for 5722-CR1 passed as a parameter.       */
/* 2 - Build importer keys using the master key, 8 bytes of a mask   */
/*     to create a variant, and a control vector.                    */
/* 3 - The file QACRKTBL is opened for input.                        */
/* 4 - A record is read.                                             */
/* 5 - Import the key using the pre-exclusive OR process.  CCA uses  */
/*     control vectors while non-CCA implementations don't.  5722-CR1*/
/*     creates master key variants similar to what 4700 finance      */
/*     controllers do.  Since the control vector and master key      */
/*     variant material affect how the key is enciphered, the pre-   */
/*     exclusive OR process "fixes" the importer key so that it can  */
/*     correctly import a key.                                       */
/*   - *SND keys are imported twice as an EXPORTER and OPINENC keys. */
/*   - *PIN keys are imported twice as a PINGEN and IPINENC keys.    */
/*   - *RCV keys are imported as a IMPORTER key.                     */
/* 6- A key record is created with a similar name as in QACRKTBL.    */
/*     For key names longer than 8 characters, a '.' will be         */
/*     inserted between the 8th and 9th characters.  Also a 1 byte   */
/*     extension is appended that describes the key type.            */
/*     For example,   MYKEY      *RCV  ---->   MYKEY.R               */
/*                    MYKEK00001 *RCV  ---->   MYKEK000.01.R         */
/*                                                                   */
/*     For *SND and *PIN keys, a second key record is also created.  */
/*     For example,   MYKEY      *SND  ---->   MYKEY.S               */
/*                                             MYKEY.O               */
/*                    MYPINKEY   *PIN  ---->   MYPINKEY.P            */
/*                                             MYPINKEY.I            */
/*                                                                   */
/* 7 - The key is written out to key store.                          */
/*                                                                   */
/* 8 - Steps 4 through 7 are repeated until all keys have been       */
/*     migrated.                                                     */
/*                                                                   */
/*                                                                   */
/*                                                                   */
/* Note: Input format is more fully described in Chapter 2 of        */
/*       IBM  CCA Basic Services Reference and Guide             */
/*       (SC31-8609) publication.                                    */
/*                                                                   */
/* Parameters:                                                       */
/*   nonCCA master key - 8 bytes                                     */
/*                                                                   */
/* Example:                                                          */
/*   CALL PGM(MIGRATECR) PARM(X'1C23456789ABCDEF')                   */
/*                                                                   */
/*                                                                   */
/* Note: This program assumes the device to be used is               */
/*       already identified either by defaulting to the CRP01        */
/*       device or by being explicitly named using the               */
/*       Cryptographic_Resource_Allocate verb. Also this             */
/*       device must be varied on and you must be authorized         */
/*       to use this device description.                             */
/*                                                                   */
/*                                                                   */
/* Use these commands to compile this program on the system:         */
/* ADDLIBLE LIB(QCCA)                                                */
/* CRTCMOD MODULE(MIGRATECR) SRCFILE(SAMPLE)                         */
/* CRTPGM  PGM(MIGRATECR) MODULE(MIGRATECR)                          */
/*         BNDSRVPGM(QCCA/CSNBKIM QCCA/CSNBKPI QCCA/CSNBKRC          */
/*                   QCCA/CSNBDEC QCCA/CSNBKRW)                      */
/*                                                                   */
/* Note: Authority to the CSNBKIM, CSNBKPI, CSNBKRC, and CSNBKRW     */
/*       service programs in library QCCA is assumed.                */
/*                                                                   */
/*                                                                   */
/* The Common Cryptographic Architecture (CCA) verbs used are:       */
/*                                                                   */
/*        Key_Import (CSNBKIM)                                       */
/*        Key_Part_Import (CSNBKPI)                                  */
/*        Key_Record_Create (CSNBKRC)                                */
/*        Key_Record_Write (CSNBKRW)                                 */
/*                                                                   */
/*                                                                   */
/*********************************************************************/


/*********************************************************************/
/* Retrieve various structures/utilities that are used in program.   */
/*********************************************************************/

#include <stdio.h>                /* Standard I/O header.            */
#include <stdlib.h>               /* General utilities.              */
#include <stddef.h>               /* Standard definitions.           */
#include <string.h>               /* String handling utilities.      */
#include "miptrnam.h"             /* MI templates for pointer        */
                                  /* resolution instructions.        */
#include "csucincl.h"             /* Header file for security API    */

/*********************************************************************/
/*  Declare function prototype to build tokens to import keys        */
/*********************************************************************/
int buildImporter(char * token,
                  char * clearkey,
                  char * preXORcv,
                  char * variant);

/*********************************************************************/
/*  Declare function prototype to import a non-CCA key and put it    */
/*  into key store.                                                  */
/*********************************************************************/
int importNonCCA(char * label,
                 char * left_importer,
                 char * right_importer,
                 char * cv,
                 char * encrypted_key);

/*********************************************************************/
/* Declares for working with files                                   */
/*********************************************************************/
#include <xxfdbk.h>               /* Feedback area structures.       */
#include <recio.h>                /* Record I/O routines             */
_RFILE           *dbfptr;        /* Pointer to database file.        */
_RIOFB_T         *db_fdbk;       /* I/O Feedback - data base file    */
_XXOPFB_T        *db_opfb;

/*********************************************************************/
/* Define the record for cross domain key file QACRKTBL              */
/*********************************************************************/
struct
      {
       char   label[10];
       char   key_type;
       char   key_value[8];
      } key_rec;

/*********************************************************************/
/* Define the structure for key tokens                               */
/*********************************************************************/
typedef struct
      {
       char   tokenType;
       char   reserved1;
       char   MasterKeyVerifPattern[2];
       char   version;
       char   reserved2;
       char   flagByte1;
       char   flagByte2;
       char   reserved3[8];
       char   leftHalfKey[8];
       char   rightHalfKey[8];
       char   controlVectorBase[8];
       char   rightControlVector[8];
       char   reserved4[12];
       char   tvv[4];
      } key_token_T;

/*************************************************************/
/* Declare control vectors used for building keys            */
/*************************************************************/
char            pingen_cv[16] = { 0x00, 0x22, 0x7E, 0x00,
                                  0x03, 0x41, 0x00, 0x00,
                                  0x00, 0x22, 0x7E, 0x00,
                                  0x03, 0x21, 0x00, 0x00};

char            ipinenc_cv[16] = { 0x00, 0x21, 0x5F, 0x00,
                                   0x03, 0x41, 0x00, 0x00,
                                   0x00, 0x21, 0x5F, 0x00,
                                   0x03, 0x21, 0x00, 0x00};

char            opinenc_cv[16] = { 0x00, 0x24, 0x77, 0x00,
                                   0x03, 0x41, 0x00, 0x00,
                                   0x00, 0x24, 0x77, 0x00,
                                   0x03, 0x21, 0x00, 0x00};

char            importer_cv[16] = { 0x00, 0x42, 0x7D, 0x00,
                                    0x03, 0x41, 0x00, 0x00,
                                    0x00, 0x42, 0x7D, 0x00,
                                    0x03, 0x21, 0x00, 0x00};

char            exporter_cv[16] = { 0x00, 0x41, 0x7D, 0x00,
                                    0x03, 0x41, 0x00, 0x00,
                                    0x00, 0x41, 0x7D, 0x00,
                                    0x03, 0x21, 0x00, 0x00};

char            importer_cv_part[16] = { 0x00, 0x42, 0x7D, 0x00,
                                    0x03, 0x48, 0x00, 0x00,
                                    0x00, 0x42, 0x7D, 0x00,
                                    0x03, 0x28, 0x00, 0x00};

char            exporter_cv_part[16] = { 0x00, 0x41, 0x7D, 0x00,
                                    0x03, 0x48, 0x00, 0x00,
                                    0x00, 0x41, 0x7D, 0x00,
                                    0x03, 0x28, 0x00, 0x00};

/*********************************************************************/
/* Start of mainline code.                                           */
/*********************************************************************/
int main(int argc, char *argv[])
{
long            i,j,k;                  /* Indexes for loops         */
char            key_label[64];          /* label of new key          */
char            key_label1[64];         /* label of new key          */

/*************************************************************/
/* Declare importer keys - two keys are needed for each type */
/*************************************************************/
char            EXPORTER_importerL[64];
char            EXPORTER_importerR[64];
char            OPINENC_importerL[64];
char            OPINENC_importerR[64];
char            IMPORTER_importerL[64];
char            IMPORTER_importerR[64];
char            PINGEN_importerL[64];
char            PINGEN_importerR[64];
char            IPINENC_importerL[64];
char            IPINENC_importerR[64];


/****************************************************************/
/* Declare variables to hold bit strings to generate master key */
/* variants.                                                    */
/****************************************************************/
char            variant1[16];
char            variant2[16];
char            variant3[16];

/*********************************************************************/
/* Build the key tokens for each of the importer keys using          */
/* Key_Token_Build.  Each key is built by using a variant, a control */
/* vector, and the clear key.  Master key variant 1 is the result of */
/* an exlusive OR of the master key with hex '8888888888888888',     */
/* Master key variant 2 is the result of an exclusive OR of the      */
/* master key with hex '2222222222222222', and Master key varient 3  */
/* is the result of an exclusive OR of the master key with hex       */
/* '4444444444444444'.  During the import operation, the control     */
/* vector is exclusive OR'ed with the importer key.  The effect of   */
/* the control vector is overcome by including the control vector as */
/* key part.  Then when the import operation is done, the exclusive  */
/* OR operation will result in the original key.  For double keys,   */
/* the left and right half of the control vector is not the same and */
/* therefore, XORing with the  control vector will not result in the */
/* original key - only one half of it will be valid.  So two keys are*/
/* needed - one for each half.                                       */
/*********************************************************************/
    memset(variant1, 0x88, 16);
    memset(variant2, 0x22, 16);
    memset(variant3, 0x44, 16);

    if (buildImporter(EXPORTER_importerL, argv[1],
                  exporter_cv, variant1)             ||

        buildImporter(EXPORTER_importerR, argv[1],
                  &exporter_cv[8], variant1)         ||

        buildImporter(IMPORTER_importerL, argv[1],
                  importer_cv, variant2)             ||

        buildImporter(IMPORTER_importerR, argv[1],
                  &importer_cv[8], variant2)         ||

        buildImporter(PINGEN_importerL, argv[1],
                  pingen_cv, variant3)               ||

        buildImporter(PINGEN_importerR, argv[1],
                  &pingen_cv[8], variant3)           ||

        buildImporter(IPINENC_importerL, argv[1],
                  ipinenc_cv, variant3)              ||

        buildImporter(IPINENC_importerR, argv[1],
                  &ipinenc_cv[8], variant3)          ||

        buildImporter(OPINENC_importerL, argv[1],
                  opinenc_cv, variant1)              ||

        buildImporter(OPINENC_importerR, argv[1],
                  &opinenc_cv[8], variant1))

      {
        printf("An error occured creating the importer keys\n");
        return;
      }

/*********************************************************************/
/* Open database file.                                               */
/*********************************************************************/

                                            /* Open the input file.  */
                                            /* If the file pointer,  */
                                            /* dbfptr is not NULL,   */
                                            /* then the file was     */
                                            /* successfully opened.  */
  if (( dbfptr = _Ropen("QUSRSYS/QACRKTBL", "rr riofb=n"))
              != NULL)
   {
     db_opfb = _Ropnfbk( dbfptr );          /* Get pointer to the    */
                                            /* File open feedback    */
                                            /* area.                 */

     j = db_opfb->num_records;              /* Save number of records*/

   /******************************************************************/
   /* Read keys and migrate to key storage.                          */
   /******************************************************************/
     for (i=1; i<=j; i++)                  /* Repeat for each record */
       {                                   /* Read a record          */
        db_fdbk = _Rreadn(dbfptr, &key_rec,
                    sizeof(key_rec), __DFT);



   /******************************************************************/
   /*  Generate a key label for the imported keys.                   */
   /*  The key label will be similar to the label that was used for  */
   /*  the QACRKTBL file.  If the label is longer than 8 characters, */
   /*  then a period '.' will be inserted at position 8 to make it   */
   /*  conform to label naming conventions for CCA.  Also one        */
   /*  one character will be added to the end to indicate what type  */
   /*  of key.  5722-CR1 does not require unique key names across all*/
   /*  key types.  CCA requires unique labels for all keys.          */
   /******************************************************************/
        memset((char *)key_label,' ',64);   /* Initialize key label  */
                                            /* to all blanks.        */

        /* Copy first bytes of label                                 */
        memcpy((char *)key_label,(char *)key_rec.label,8);

        /* If label is longer than 8 characters, add a second element*/
        if (key_rec.label[8] != ' ')
         {
          key_label[8] = '.';
          key_label[9] = key_rec.label[8];
          key_label[10] = key_rec.label[9];
         }

        /* *SND keys and *PIN keys need to be imported twice so      */
        /*  make a second label                                      */
         if (key_rec.key_type != 'R')
          memcpy((char *)key_label1,(char *)key_label,64);

        /* Add keytype to label name.  Search until a space is found */
        /* and if less than 8, add the 1 character keytype.  If it   */
        /* is greater than 8, add a second element with the keytype  */
        /* 'R' is *RCV key, 'S' is *SND key, 'P' is *PIN key,        */
        /* 'I' is an IPINENC key and 'O' is OPINENC key              */
         for (k=1; k<=11; k++)
          {
           if (key_label[k] == ' ')
            {
             if (k != 8)
              {
               key_label[k] = key_rec.key_type;

               /* If this is a *SND or *PIN key, update the keytype  */
               /* in the second label as well                        */
               if (key_rec.key_type != 'R')
                {
                 memcpy((char *)key_label1,(char *)key_label,64);
                 if (key_rec.key_type == 'S')
                   key_label1[k] = 'O';
                 else
                   key_label1[k] = 'I';
                }
              }
             else
              {
               key_label[8] = '.';
               key_label[9] = key_rec.key_type;

               /* If this is a *SND or *PIN key, update the keytype  */
               /* in the second label as well                        */
               if (key_rec.key_type != 'R')
                {
                 memcpy((char *)key_label1,(char *)key_label,64);
                 if (key_rec.key_type == 'S')
                   key_label1[9] = 'O';
                 else
                   key_label1[9] = 'I';
                }
              }
             k = 11;
            }
           }


   /******************************************************************/
   /* Check for the type of key that was in the QACRKTBL file        */
   /*  - S for SENDER key will become two keys - EXPORTER and OPINENC*/
   /*  - R for RECEIVER key will become IMPORTER key                 */
   /*  - P for PIN will become two keys - PINGEN and IPINENC         */
   /*  Set the key id to the key token that contains the key under   */
   /*    which the key in QACRKTBL is enciphered.                    */
   /*  Set the key_type SAPI parameter for the Secure_Key_Import verb*/
   /******************************************************************/
        if (key_rec.key_type == 'S')
          {
           /* Import the exporter key       */
           if(importNonCCA(key_label,
                        EXPORTER_importerL,
                        EXPORTER_importerR,
                        exporter_cv,
                        key_rec.key_value))
             {
              printf("An error occured importing an exporter key\n");
              break;
             }

           /* Import the OPINENC key        */
           if (importNonCCA(key_label1,
                        OPINENC_importerL,
                        OPINENC_importerR,
                        opinenc_cv,
                        key_rec.key_value))
             {
              printf("An error occured importing an opinenc key\n");
              break;
             }
          }
        else
        if (key_rec.key_type == 'R')
          {
            /* Import the importer key       */
            if (importNonCCA(key_label,
                         IMPORTER_importerL,
                         IMPORTER_importerR,
                         importer_cv,
                         key_rec.key_value))
             {
              printf("An error occured importing an importer key\n");
              break;
             }
          }
        else
          {
           /* Import the PINGEN key          */
           if(importNonCCA(key_label,
                        PINGEN_importerL,
                        PINGEN_importerR,
                        pingen_cv,
                        key_rec.key_value))
             {
              printf("An error occured importing a PINGEN key\n");
              break;
             }

           /* Import the IPINENC key          */
           if(importNonCCA(key_label1,
                        IPINENC_importerL,
                        IPINENC_importerR,
                        ipinenc_cv,
                        key_rec.key_value))
             {
              printf("An error occured importing an ipinenc key\n");
              break;
             }
          }


       }                       /* End loop repeating for each record */

/*********************************************************************/
/* Close database file.                                              */
/*********************************************************************/
     if (dbfptr != NULL)                    /* Close the file.       */
       _Rclose(dbfptr);

  }                                         /* End if file open leg  */
  else
    {
      printf("An error occured openning the QACRKTBL file.\n");
    }
 }                                          /* End of main()         */



/*********************************************************************/
/*  buildImporter creates an importer token from a clearkey exclusive*/
/*  OR'ed with a variant and a control vector.  The control vector   */
/*  is XOR'ed in order to import non-CCA keys.  The variant is XOR'ed*/
/*  in order to import from implementations that use different       */
/*  master key variants to protect keys as does 5722-CR1.            */
/*********************************************************************/
int buildImporter(char * token,
                  char * clearkey,
                  char * preXORcv,
                  char * variant)
{
/****************************************/
/* Declare variables used by the SAPI's */
/****************************************/
char            rule_array[16];
long            rule_array_count;
long            return_code;
long            reason_code;
long            exit_data_length;
char            exit_data[4];
char            keyvalue[16];
char            keytype[8];
char            ctl_vector[16];
key_token_T     *token_ptr;


/*************************************************/
/* Build an IMPORTER token                       */
/*************************************************/
    memset(token, 0, 64);              /* Initialize token to all 0's */
    token_ptr = (key_token_T *)token;
    token_ptr->tokenType = 0x01;       /* 01 is internal token        */
    token_ptr->version = 0x03;         /* Version 3 token             */
    token_ptr->flagByte1 = 0x40;       /* High order bit is 0 so key  */
                                       /* is not present.  The 40     */
                                       /* bit means that CV is present*/

                                       /* Copy control vector into    */
                                       /* the token.                  */
    memcpy(token_ptr->controlVectorBase, importer_cv_part, 16);
                                       /* Copy TVV into token.  This  */
                                       /* was calculated manually by  */
                                       /* setting all the fields and  */
                                       /* then adding each 4 bytes of */
                                       /* the token (excluding the    */
                                       /* TVV) together.              */
    memcpy(token_ptr->tvv,"\x0A\xF5\x3A\x00", 4);

/*****************************************************************/
/* Import the control vector as a key part using Key_Part_Import */
/*****************************************************************/
    exit_data_length = 0;
    rule_array_count = 1;
    memcpy(ctl_vector, preXORcv, 8);
    memcpy(&ctl_vector[8], preXORcv, 8); /* Need to copy the
                                           control vector into the
                                            second 8 bytes as well*/
    memcpy(rule_array, "FIRST   ", 8);
    CSNBKPI( &return_code, &reason_code, &exit_data_length,
            (char *) exit_data,
            (long *) &rule_array_count,
            (char *) rule_array,
            (char *) ctl_vector,
            (char *) token);

    if (return_code > 4)
     {
      printf("Key_Part_Import failed with return/reason codes \
                  %d/%d \n",return_code, reason_code);
      return 1;
     }

/*****************************************************************/
/* Import the variant as a key part using Key_Part_Import        */
/*****************************************************************/
    memcpy(rule_array, "MIDDLE  ", 8);
    CSNBKPI( &return_code, &reason_code, &exit_data_length,
           (char *) exit_data,
           (long *) &rule_array_count,
           (char *) rule_array,
           (char *) variant,
           (char *) token);

    if (return_code > 4)
     {
      printf("Key_Part_Import failed with return/reason codes \
                   %d/%d \n",return_code, reason_code);
      return 1;
     }

/*****************************************************************/
/* Import the clear key as a key part using Key_Part_Import      */
/*****************************************************************/
    memcpy(keyvalue, clearkey, 8);
    memcpy(&keyvalue[8], clearkey, 8); /* Make key double length*/
    memcpy(rule_array, "LAST    ", 8);
    CSNBKPI( &return_code, &reason_code, &exit_data_length,
            (char *) exit_data,
            (long *) &rule_array_count,
            (char *) rule_array,
            (char *) keyvalue,
            (char *) token);

    if (return_code > 4)
      {
       printf("Key_Part_Import failed with return/reason codes \
                   %d/%d \n",return_code, reason_code);
       return 1;
      }


 return 0;
}

/********************************************************************/
/* importNonCCA imports a double length key into CCA from the       */
/* non-CCA implementation                                           */
/********************************************************************/
int importNonCCA(char * label,
                 char * left_importer,
                 char * right_importer,
                 char * cv,
                 char * encrypted_key)
{
/******************************************/
/* Declare vaiables used by the SAPIs     */
/******************************************/
long            return_code, reason_code;
char            exit_data[4];
long            exit_data_length;
long            rule_array_count;
char            rule_array[24];
char            keytoken[64];
char            externalkey[64];
char            keyvalue[16];
char            keytype[8];
char            *importer;
char            mkvp[2];
key_token_T     *token_ptr;
int             tvv, tvv_part;
char            *tvv_pos;

/**********************************************/
/* Build an external key token to IMPORT from */
/**********************************************/
    memset((void *)externalkey,'\00',64);
    token_ptr = (key_token_T *)externalkey;
    token_ptr->tokenType = 0x02;           /* 02 is external token    */
    token_ptr->version = 0x00;             /* Version 0 token         */
    token_ptr->flagByte1 = 0xC0;           /* High order bit is 1 so  */
                                           /* key is present.  The    */
                                           /* 40 bit means that CV    */
                                           /* is present              */

    memcpy(token_ptr->controlVectorBase, cv, 16); /* Copy control
                                                   vector into token  */
    memcpy(token_ptr->leftHalfKey,encrypted_key, 8);  /* Copy key
                                                       into left half */
    memcpy(token_ptr->rightHalfKey,encrypted_key, 8); /* Copy key
                                                      into right half */

    /**********************************************/
    /* Calculate the TVV by adding every 4 bytes  */
    /**********************************************/
    tvv_pos = externalkey;
    tvv = 0;
    while (tvv_pos < (externalkey + 60))
      {
        memcpy((void*)&tvv_part,tvv_pos,4);
        tvv += tvv_part;
        tvv_pos += 4;
      }
    memcpy(token_ptr->tvv, (void*)&tvv, 4);


/***********************************************************/
/* Import the left half of the key using Key_Import and    */
/* the importer built with left half of the control vector */
/***********************************************************/
    exit_data_length = 0;
    memcpy(keytype, "TOKEN   ", 8);
    memset((void *)keytoken,'\00',64);
    CSNBKIM( &return_code, &reason_code, &exit_data_length,
           (char *) exit_data,
           (char *) keytype,
           (char *) externalkey,
           (char *) left_importer,
           (char *) keytoken);

    if (return_code > 4)
      {
       printf("Key_Import failed with return/reason codes \
                   %d/%d \n",return_code, reason_code);
       return 1;
      }

/******************************************/
/* Save left half of key out of key token */
/******************************************/
    memcpy(keyvalue, &keytoken[16], 8);


/***********************************************************/
/* Import the right half of the key using Key_Import and   */
/* the importer built with right half of the control vector*/
/***********************************************************/
    memcpy(keytype, "TOKEN   ", 8);
    memset((void *)keytoken,'\00',64);
    CSNBKIM( &return_code, &reason_code, &exit_data_length,
           (char *) exit_data,
           (char *) keytype,
           (char *) externalkey,
           (char *) right_importer,
           (char *) keytoken);

    if (return_code > 4)
     {
       printf("Key_Import failed with return/reason codes \
                   %d/%d \n",return_code, reason_code);
       return 1;
      }


/*******************************************/
/* Save right half of key out of key token */
/*******************************************/
    memcpy(&keyvalue[8], &keytoken[24], 8);

/**********************************************************************/
/* Get master key verification pattern from the last key token built  */
/**********************************************************************/
    mkvp[0] = keytoken[2];
    mkvp[1] = keytoken[3];


/**********************************************************/
/* Build an internal key token using both key halves just */
/* imported and using the master key verification pattern */
/**********************************************************/
    memset((void *)keytoken,'\00',64);
    exit_data_length = 0;
    token_ptr = (key_token_T *)keytoken;
    token_ptr->tokenType = 0x01;           /* 01 is internal token    */
    token_ptr->version = 0x03;             /* Version 3 token         */
    token_ptr->flagByte1 = 0xC0;           /* High order bit is 1 so  */
                                           /* key is present.  The    */
                                           /* 40 bit means that CV is */
                                           /* present                 */

                                           /* Set the first byte of   */
                                           /* Master key verification */
                                           /* pattern.                */
    token_ptr->MasterKeyVerifPattern[0] = mkvp[0];
                                           /* Set the second byte of  */
                                           /* Master key verification */
                                           /* pattern.                */
    token_ptr->MasterKeyVerifPattern[1] = mkvp[1];

                                           /* Copy control vector into*/
                                           /*  token                  */
    memcpy(token_ptr->controlVectorBase, cv, 16);
    memcpy(token_ptr->leftHalfKey, keyvalue, 16); /*Copy key to token */

    /**********************************************/
    /* Calculate the TVV by adding every 4 bytes  */
    /**********************************************/
    tvv_pos = externalkey;
    tvv = 0;
    while (tvv_pos < (externalkey + 60))
      {
        memcpy((void*)&tvv_part,tvv_pos,4);
        tvv += tvv_part;
        tvv_pos += 4;
      }
    memcpy(token_ptr->tvv, (void*)&tvv, 4);


/********************************************/
/* Create a Key Record in Key Store         */
/********************************************/
    exit_data_length = 0;
    CSNBKRC((long *) &return_code,
            (long *) &reason_code,
            (long *) &exit_data_length,
            (char *) exit_data,
            (char *) label);

    if (return_code > 4)
     {
       printf("Key_Record_Create failed with return/reason codes \
                   %d/%d \n",return_code, reason_code);
       return 1;
     }


/********************************************/
/* Write the record out to Key Store        */
/********************************************/
     CSNBKRW((long *) &return_code,
             (long *) &reason_code,
             (long *) &exit_data_length,
             (char *) exit_data,
             (char *) keytoken,
             (char *) label);

     if (return_code > 4)
      {
       printf("Key_Record_Write failed with return/reason codes \
                   %d/%d \n",return_code, reason_code);
       return 1;
      }

    return 0;
}