IBM Crypto Education Community - Group home

Rexx Sample: Derive an AES key from a pair of ECC keys

  

/* Rexx */

/* Derive an AES key from a pair of ECC keys                         */
/*-------------------------------------------------------------------*/
/* Description:                                                      */
/*                                                                   */
/* This REXX contains samples for deriving an AES key from two ECC   */
/* key pairs.                                                        */
/*  - Create a skeleton for the AES key token                        */
/*  - Generate a sender ECC key pair                                 */
/*  - Generate a receiver ECC key pair                               */
/*  - Derive the AES key token from the sender and receiver ECC keys */
/*                                                                   */
/* How To Run:                                                       */
/* - Execute this script from TSO                                    */
/*   (e.g. EX 'HLQ.MLD.LLQ(DERIVAES)')                               */
/*-------------------------------------------------------------------*/
signal on novalue;

/* CLEANUP labels in use for this sample */
sender_key_label = left('SAMPLE.SENDER.ECC.KEY',64);
krd_label = sender_key_label;
Call CSNDKRD;
receiver_key_label = left('SAMPLE.RECEIVER.ECC.KEY',64);
krd_label = receiver_key_label;
Call CSNDKRD;

/*********************************************************************/
/* Create a skeleton token for the derived key                       */
/*********************************************************************/

ktb_key_type           = 'DATA    ';
ktb_rule_array_count   = '00000003'x;
ktb_rule_array         = 'AES     ' ||,
                         'INTERNAL' ||,
                         'KEYLN32 ';
ktb_key_value          = '';
ktb_key_token          = copies('00'x,64)
Call CSNBKTB;


/*********************************************************************/
/* Create the "Sender" ECC Public / Private Key Pair                 */
/*********************************************************************/

/* Create a record for the ECC Key Pair in the PKDS */
krc_label        = sender_key_label;
krc_token        = '';
krc_token_length = '00000000'x;
Call CSNDKRC;

/* Build the skeleton token for the Key Pair */
pkb_rule_count                 = '00000002'x;
pkb_rule_array                 = 'ECC-PAIR' ||,
                                 'KEY-MGMT';
pkb_key_value_structure_length = '00000008'x;
pkb_key_value_structure        = '00'x   ||,  /* Prime curve         */
                                 '00'x   ||,  /* reserved            */
                                 '0209'x ||,  /* P-521 curve in bits */
                                 '0000'x ||,  /* length of d in bytes*/
                                 '0000'x;     /* public key q, bytes */
pkb_private_key_name_length    = '00000040'x;
pkb_private_key_name           = sender_key_label;
pkb_key_token_length           = '00000DAC'x;
pkb_key_token                  = copies('00'x,3500);
Call CSNDPKB;

/* Generate the Key Pair from the skeleton. Store in the PKDS. */
pkg_rule_count                     = '00000001'x;
pkg_rule_array                     = 'MASTER  ';
pkg_regeneration_data_length       = '00000000'x;
pkg_regeneration_data              = '';
pkg_skeleton_key_id_length         = pkb_key_token_length;
pkg_skeleton_key_id                = pkb_key_token;
pkg_transport_key_identifier       = copies('00'x,64);
pkg_generated_key_token_length     = '00000040'x;
pkg_generated_key_token            = sender_key_label;
Call CSNDPKG;

/* Read the Key Pair from the PKDS */
krr_label        = sender_key_label;
krr_token_length = '00000DAC'x;
krr_token        = copies('00'x, 3500);
Call CSNDKRR;

sender_ecc_key        = substr(krr_token,1,c2d(krr_token_length));
sender_ecc_key_length = krr_token_length;
say "sender_ecc_key " c2x(sender_ecc_key);
say "sender_ecc_key_length " c2d(sender_ecc_key_length);

/*********************************************************************/
/* Create the "Receiver" ECC Public / Private Key Pair               */
/*********************************************************************/

/* Create a record for the ECC Key Pair in the PKDS */
krc_label        = receiver_key_label;
krc_token        = '';
krc_token_length = '00000000'x;
Call CSNDKRC;

/* Build the skeleton token for the Key Pair */
pkb_rule_count                 = '00000001'x;
pkb_rule_array                 = 'ECC-PAIR' ||,
                                 'KEY-MGMT';
pkb_key_value_structure_length = '00000008'x;
pkb_key_value_structure        = '00'x   ||,  /* Prime curve         */
                                 '00'x   ||,  /* reserved            */
                                 '0209'x ||,  /* P-521 curve in bits */
                                 '0000'x ||,  /* length of d in bytes*/
                                 '0000'x;     /* public key q, bytes */
pkb_private_key_name_length    = '00000040'x;
pkb_private_key_name           = receiver_key_label;
pkb_key_token_length           = '00000DAC'x;
pkb_key_token                  = copies('00'x,3500);
Call CSNDPKB;

/* Generate the Key Pair from the skeleton. Store in the PKDS. */
pkg_rule_count                     = '00000001'x;
pkg_rule_array                     = 'MASTER  ';
pkg_regeneration_data_length       = '00000000'x;
pkg_regeneration_data              = '';
pkg_skeleton_key_id_length         = pkb_key_token_length;
pkg_skeleton_key_id                = pkb_key_token;
pkg_transport_key_identifier       = copies('00'x,64);
pkg_generated_key_token_length     = '00000040'x;
pkg_generated_key_token            = receiver_key_label;
Call CSNDPKG;

/* Read the Key Pair from the PKDS */
krr_label        = receiver_key_label;
krr_token_length = '00000DAC'x;
krr_token        = copies('00'x, 3500);
Call CSNDKRR;

receiver_ecc_key        = substr(krr_token,1,c2d(krr_token_length));
receiver_ecc_key_length = krr_token_length;
say "receiver_ecc_key " c2x(receiver_ecc_key);
say "receiver_ecc_key_length " c2d(receiver_ecc_key_length);


/*********************************************************************/
/* Derive the AES Key                                                */
/*********************************************************************/
edh_rule_array_count      = '00000002'x;
edh_rule_array            = 'DERIV01 ' ||,
                            'KEY-AES ';
edh_private_key_id_length = '00000040'x;
edh_private_key_id        = sender_key_label;
edh_public_key_id_length  = '00000040'x;
edh_public_key_id         = receiver_key_label;
edh_party_id_length       = '0000000E'x;
edh_party_id              = 'transaction-id';
edh_key_bit_length        = '00000100'x;       /* 256-bit AES */
edh_output_key_id_length  = '00000040'x;
edh_output_key_id         = ktb_key_token;
Call CSNDEDH;

say 'derived_key' c2x(edh_output_key_id);
say 'derived_key_length' c2d(edh_output_key_id_length);

say "-----------------------------------------------------------------"
say "End of Sample"
say "-----------------------------------------------------------------"

exit;

/* --------------------------------------------------------------- */
/* CSNBKTB - Key Token Build                                       */
/*                                                                 */
/* Builds a skeleton key token to be used as input for the key     */
/* generate (CSNBKGN) or diversify key generate (CSNBDKG) callable */
/* service.                                                        */
/*                                                                 */
/* See the ICSF Application Programmer's Guide for more details.   */
/* --------------------------------------------------------------- */
CSNBKTB:

KTB_RC = 'FFFFFFFF'x;
KTB_RS = 'FFFFFFFF'x;
KTB_exit_data_length           = '00000000'x;
KTB_exit_data                  = '';
KTB_master_key_version_num     = '00000000'x
KTB_key_register_num           = '00000000'x
KTB_token_data_1               = ''
KTB_control_vector     = '';
KTB_initialization_vector      = ''
KTB_pad_character              = '00000000'x
KTB_cryptographic_period_start = '';
KTB_masterkey_verify_parm      = '';

ADDRESS linkpgm "CSNBKTB",
   'KTB_RC'                      'KTB_RS'               ,
   'KTB_exit_data_length'        'KTB_exit_data'        ,
   'KTB_key_token'               'KTB_key_type'         ,
   'KTB_rule_array_count'        'KTB_rule_array'       ,
   'KTB_key_value'               'KTB_master_key_version_num',
   'KTB_key_register_num'        'KTB_token_data_1'     ,
   'KTB_control_vector'          'KTB_initialization_vector',
   'KTB_pad_character'           'KTB_cryptographic_period_start',
   'KTB_masterkey_verify_parm';

if (KTB_RC /= '00000000'x) Then
  do;
    say 'KTB Failed   (rc=' c2x(KTB_RC)' rs='c2x(KTB_rs)')' ;
    exit;
  end;

Return;

/* --------------------------------------------------------------- */
/* CSNDPKB - PKA Key Token Build                                   */
/*                                                                 */
/* Builds a skeleton key token which can be used as input for the  */
/* key generate (CSNDPKG) callable service.                        */
/*                                                                 */
/* See the ICSF Application Programmer's Guide for more details.   */
/* --------------------------------------------------------------- */
CSNDPKB:

PKB_RC = 'FFFFFFFF'x;
PKB_RS = 'FFFFFFFF'x;
PKB_exit_data_length  = '00000000'x;
PKB_exit_data  = '';
PKB_reserved_1_length = '00000000'x;
PKB_reserved_1 = '';
PKB_reserved_2_length = '00000000'x;
PKB_reserved_2 = '';
PKB_reserved_3_length = '00000000'x;
PKB_reserved_3 = '';
PKB_reserved_4_length = '00000000'x;
PKB_reserved_4 = '';
PKB_reserved_5_length = '00000000'x;
PKB_reserved_5 = '';

ADDRESS linkpgm "CSNDPKB",
   'PKB_RC'                         'PKB_RS'                     ,
   'PKB_exit_data_length'           'PKB_exit_data'              ,
   'PKB_rule_count'                 'PKB_rule_array'             ,
   'PKB_key_value_structure_length' 'PKB_key_value_structure'    ,
   'PKB_private_key_name_length'    'PKB_private_key_name'       ,
   'PKB_reserved_1_length'          'PKB_reserved_1'             ,
   'PKB_reserved_2_length'          'PKB_reserved_2'             ,
   'PKB_reserved_3_length'          'PKB_reserved_3'             ,
   'PKB_reserved_4_length'          'PKB_reserved_4'             ,
   'PKB_reserved_5_length'          'PKB_reserved_5'             ,
   'PKB_key_token_length'           'PKB_key_token'              ;

if (PKB_RC /= '00000000'x) Then
  do;
    say 'PKB Failed   (rc=' c2x(PKB_RC)' rs='c2x(PKB_rs)')' ;
    exit;
  end;

Return;

/* --------------------------------------------------------------- */
/* CSNDPKG - PKA Key Generate                                      */
/*                                                                 */
/* Generates RSA or ECC key pairs.                                 */
/*                                                                 */
/* See the ICSF Application Programmer's Guide for more details.   */
/* --------------------------------------------------------------- */
CSNDPKG:

PKG_RC                         = 'FFFFFFFF'x;
PKG_RS                         = 'FFFFFFFF'x;
PKG_exit_data_length           = '00000000'x;
PKG_exit_data                  = '';

ADDRESS linkpgm "CSNDPKG",
   'PKG_RC'                          'PKG_RS'                 ,
   'PKG_exit_data_length'            'PKG_exit_data'          ,
   'PKG_rule_count'                  'PKG_rule_array'         ,
   'PKG_regeneration_data_length'    'PKG_regeneration_data'  ,
   'PKG_skeleton_key_id_length'      'PKG_skeleton_key_id'    ,
   'PKG_transport_key_identifier'                             ,
   'PKG_generated_key_token_length'  'PKG_generated_key_token';

if (PKG_RC /= '00000000'x) Then
  do;
    say 'PKG Failed   (rc=' c2x(PKG_RC)' rs='c2x(PKG_rs)')' ;
    exit;
  end;

Return;

/* --------------------------------------------------------------- */
/* CSNBKRC - Key Record Create (CKDS)                              */
/*                                                                 */
/* Adds a key record to the CKDS which can be used by CSNBKRW to   */
/* write a key token to the CKDS.                                  */
/*                                                                 */
/* See the ICSF Application Programmer's Guide for more details.   */
/* --------------------------------------------------------------- */
CSNBKRC:
krc_rc = 'FFFFFFFF'x;
krc_rs = 'FFFFFFFF'x;
krc_exit_data_length = '00000000'x;
krc_exit_data = '';

ADDRESS LINKPGM "CSNBKRC",
                "krc_rc",
                "krc_rs",
                "krc_exit_data_length",
                "krc_exit_data",
                "krc_label";

if (KRC_RC /= '00000000'x) Then
  do;
    say 'KRC Failed   (rc=' c2x(KRC_RC)' rs='c2x(KRC_rs)')' ;
    exit;
  end;

return;

/* --------------------------------------------------------------- */
/* CSNDKRC - Key Record Create (PKDS)                              */
/*                                                                 */
/* Adds a key record and key token to the PKDS.                    */
/*                                                                 */
/* See the ICSF Application Programmer's Guide for more details.   */
/* --------------------------------------------------------------- */
CSNDKRC:
krc_rc = 'FFFFFFFF'x;
krc_rs = 'FFFFFFFF'x;
krc_exit_data_length = '00000000'x;
krc_exit_data = '';
krc_rule_count = '00000000'x;
krc_rule_array = '';

ADDRESS LINKPGM "CSNDKRC",
                "krc_rc",
                "krc_rs",
                "krc_exit_data_length",
                "krc_exit_data",
                "krc_rule_count",
                "krc_rule_array",
                "krc_label",
                "krc_token_length",
                "krc_token";

if (KRC_RC /= '00000000'x) Then
  do;
    say 'KRC Failed   (rc=' c2x(KRC_RC)' rs='c2x(KRC_rs)')' ;
    exit;
  end;

return;

/* --------------------------------------------------------------- */
/* CSNBKRR - Key Record Read (CKDS)                                */
/*                                                                 */
/* Reads a key token from the CKDS.                                */
/*                                                                 */
/* See the ICSF Application Programmer's Guide for more details.   */
/* --------------------------------------------------------------- */
CSNBKRR:
krr_rc = 'FFFFFFFF'x;
krr_rs = 'FFFFFFFF'x;
krr_exit_data_length = '00000000'x;
krr_exit_data = '';
krr_token = copies('00'x,64);

ADDRESS LINKPGM "CSNBKRR",
                "krr_rc",
                "krr_rs",
                "krr_exit_data_length",
                "krr_exit_data",
                "krr_label",
                "krr_token";

if (KRR_RC /= '00000000'x) Then
  do;
    say 'KRR Failed   (rc=' c2x(KRR_RC)' rs='c2x(KRR_rs)')' ;
    exit;
  end;

return;

/* --------------------------------------------------------------- */
/* CSNDKRR - Key Record Read (PKDS)                                */
/*                                                                 */
/* Reads a key token from the PKDS.                                */
/*                                                                 */
/* See the ICSF Application Programmer's Guide for more details.   */
/* --------------------------------------------------------------- */
CSNDKRR:
krr_rc = 'FFFFFFFF'x;
krr_rs = 'FFFFFFFF'x;
krr_exit_data_length = '00000000'x;
krr_exit_data    = '';
krr_rule_count   = '00000000'x;
krr_rule_array   = '';

ADDRESS LINKPGM "CSNDKRR",
                "krr_rc",
                "krr_rs",
                "krr_exit_data_length",
                "krr_exit_data",
                "krr_rule_count",
                "krr_rule_array",
                "krr_label",
                "krr_token_length",
                "krr_token";

if (KRR_RC /= '00000000'x) Then
  do;
    say 'KRR Failed   (rc=' c2x(KRR_RC)' rs='c2x(KRR_rs)')' ;
    exit;
  end;

return;

/* --------------------------------------------------------------- */
/* CSNBKRD - Key Record Delete (CKDS)                              */
/*                                                                 */
/* Deletes a key record from the CKDS.                             */
/*                                                                 */
/* See the ICSF Application Programmer's Guide for more details.   */
/* --------------------------------------------------------------- */
CSNBKRD:
krd_rc = 'FFFFFFFF'x;
krd_rs = 'FFFFFFFF'x;
krd_exit_data_length = '00000000'x;
krd_exit_data = '';
krd_rule_array_count = '00000001'x;
krd_rule_array = 'LABEL-DL';

ADDRESS LINKPGM "CSNBKRD",
                "krd_rc",
                "krd_rs",
                "krd_exit_data_length",
                "krd_exit_data",
                "krd_rule_array_count",
                "krd_rule_array",
                "krd_label";

if (KRD_RC /= '00000000'x & KRD_RS /= '0000271C'x) Then
  say 'KRD Failed   (rc=' c2x(KRD_RC)' rs='c2x(KRD_rs)')' ;

return;

/* --------------------------------------------------------------- */
/* CSNDKRD - Key Record Delete (PKDS)                              */
/*                                                                 */
/* Deletes a key record from the PKDS.                             */
/*                                                                 */
/* See the ICSF Application Programmer's Guide for more details.   */
/* --------------------------------------------------------------- */
CSNDKRD:
krd_rc = 'FFFFFFFF'x;
krd_rs = 'FFFFFFFF'x;
krd_exit_data_length = '00000000'x;
krd_exit_data = '';
krd_rule_array_count = '00000001'x;
krd_rule_array = 'LABEL-DL';

ADDRESS LINKPGM "CSNDKRD",
                "krd_rc",
                "krd_rs",
                "krd_exit_data_length",
                "krd_exit_data",
                "krd_rule_array_count",
                "krd_rule_array",
                "krd_label";

if (KRD_RC /= '00000000'x & KRD_RS /= '0000271C'x) Then
  say 'KRD Failed   (rc=' c2x(KRD_RC)' rs='c2x(KRD_rs)')' ;

return;

/* --------------------------------------------------------------- */
/* CSNDEDH - ECC Diffie-Hellman                                    */
/*                                                                 */
/* Creates symmetric key material from a pair of ECC keys.         */
/*                                                                 */
/* See the ICSF Application Programmer's Guide for more details.   */
/* --------------------------------------------------------------- */
CSNDEDH:

EDH_RC                    = 'FFFFFFFF'x;
EDH_RS                    = 'FFFFFFFF'x;
EDH_exit_data_length      = '00000000'x;
EDH_exit_data             = '';
EDH_private_kek_id_length = '00000000'x;
EDH_private_kek_id        = '';
EDH_chain_vector_length   = '00000000'x;
EDH_chain_vector          = '';
EDH_reserved_length       = '00000000'x;
EDH_reserved              = '';
EDH_reserved2_length      = '00000000'x;
EDH_reserved2             = '';
EDH_reserved3_length      = '00000000'x;
EDH_reserved3             = '';
EDH_reserved4_length      = '00000000'x;
EDH_reserved4             = '';
EDH_reserved5_length      = '00000000'x;
EDH_reserved5             = '';
EDH_output_kek_id_length  = '00000000'x;
EDH_output_kek_id         = '';

ADDRESS linkpgm "CSNDEDH",
   'EDH_RC'                          'EDH_RS'                     ,
   'EDH_exit_data_length'            'EDH_exit_data'              ,
   'EDH_rule_array_count'            'EDH_rule_array'             ,
   'EDH_private_key_id_length'       'EDH_private_key_id'         ,
   'EDH_private_kek_id_length'       'EDH_private_kek_id'         ,
   'EDH_public_key_id_length'        'EDH_public_key_id'          ,
   'EDH_chain_vector_length'         'EDH_chain_vector'           ,
   'EDH_party_id_length'             'EDH_party_id'               ,
   'EDH_key_bit_length'                                           ,
   'EDH_reserved_length'             'EDH_reserved'               ,
   'EDH_reserved2_length'            'EDH_reserved2'              ,
   'EDH_reserved3_length'            'EDH_reserved3'              ,
   'EDH_reserved4_length'            'EDH_reserved4'              ,
   'EDH_reserved5_length'            'EDH_reserved5'              ,
   'EDH_output_kek_id_length'        'EDH_output_kek_id'          ,
   'EDH_output_key_id_length'        'EDH_output_key_id'          ;

if (EDH_RC /= '00000000'x) Then
  do;
    say 'EDH Failed   (rc=' c2x(EDH_RC)' rs='c2x(EDH_rs)')' ;
    exit;
  end;

Return;

/* --------------------------------------------------------------- */
/* Debug ;-)                                                       */
/* --------------------------------------------------------------- */
NOVALUE:
Say "Condition NOVALUE was raised."
Say CONDITION("D") "variable was not initialized."
Say SOURCELINE(sigl)
Exit