/* 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