IBM Crypto Education Community

IBM Crypto Education Community

IBM Crypto Education Community

Join the IBM Crypto Education community to explore and understand IBM cryptography technology. This community is operated and maintained by the IBM Crypto Development team.

 View Only

Sample Rexx: Create a hybrid quantum safe algorithm (QSA) key exchange scheme using ML-KEM keys

By Eleanor Chan posted 3 days ago

  

/* Rexx */

/*-------------------------------------------------------------------*/
/* This sample testcase will create a hybrid quantum safe algorithm  */
/* (QSA) key exchange scheme using NIST approved ML-KEM keys.  Refer */
/* to the ICSF Application Programmer's Guide for a detailed         */
/* description of the callable services used in this sample.         */
/*-------------------------------------------------------------------*/
/* The following is required for ML-KEM support:                     */
/* 1. OA66395 on ICSF HCR77D2 or higher                              */
/* 2. Crypto Express8 CCA coprocessor with release 8.4 or later      */
/*     licensed internal code (LIC).                                 */
/*-------------------------------------------------------------------*/

/* STEP 1: Generate ALICE's keys
    MLKEM-priv-A, MLKEM-pub-A: ML-KEM (1024) key pair
    EC-priv-A, EC-pub-A: ECC key pair for key agreement */

PKB_rule_array = 'QSA-PAIR'||'U-DATENC'
PKB_kvs        = '06'x ||,   /* ML-KEM                    */
                 '00'x ||,   /* clear key format skeleton */
                 '1024'x ||, /* algorithm parameter       */
                 '0000'x ||, /* clear key length          */
                 '0000'x ;   /* reserved                  */
CALL PKB
PKG_rule_array = 'MASTER  ' ;
PKG_skeleton_key_id = PKB_token ;
CALL PKG
MLKEM_priv_A   = PKG_token ;
PKX_source_key = MLKEM_priv_A ;
CALL PKX
MLKEM_pub_A    = PKX_token ;

PKB_rule_array = 'ECC-PAIR'||'KEY-MGMT'
PKB_kvs        = '00'x ||,   /* ECC Prime curve */
                 '00'x ||,   /* reserved        */
                 '0100'x ||, /* 256 bits        */
                 '0000'x ||, /* pvt key length  */
                 '0000'x ;   /* pub key length  */
CALL PKB
PKG_rule_array = 'MASTER  ' ;
PKG_skeleton_key_id = PKB_token ;
CALL PKG
EC_priv_A      = PKG_token ;
PKX_source_key = EC_priv_A ;
CALL PKX
EC_pub_A       = PKX_token ;

/* ALICE sends MLKEM-pub-A and EC-pub-A to BOB */


/* STEP 2: Generate BOB's keys
    EC-priv-B, EC-pub-B: ECC key pair for key agreement */

PKB_rule_array = 'ECC-PAIR'||'KEY-MGMT'
kvs            = '00'x ||,   /* Prime curve    */
                 '00'x ||,   /* reserved       */
                 '0100'x ||, /* 256 bits       */
                 '0000'x ||, /* pvt key length */
                 '0000'x ;   /* pub key length */
CALL PKB
CALL PKG
EC_priv_B      = PKG_token ;
PKX_source_key = PKG_token ;
CALL PKX
EC_pub_B       = PKX_token ;


/* STEP 3: Bob uses his own AES CIPHER key and ALICE's ML-KEM public
    key to generate an encrypted RANDOM secret key encrypted by his
    AES key and Alice's public key. */

AES_ciph_B = , /* BOB's AES CIPHER key */
'010000880500000003012058C870E9D3194F0000000000000000020200000100'x||,
'001A0000000002800002000102C000FF0003E800000002029300F1E4326C2A6E'x||,
'802300A246C4FAEBB08C9FCCD0FB3FF8561D0A031EE7662545E9AC3E1EF4FEB4'x||,
'03A2341B3AD11E52A762E307278566AC9C692154B8BD27A1B6BF16EC301319A1'x||,
'3BE6A6755CEE1FB0'x

PKE_rule_array = 'ZERO-PAD'||'RANDOM  '||'AES-ENC ' ;
PKE_keyvalue   = '01010101010101010202020202020202'x||,
                 '00000000000000000000000000000000'x ;
PKE_sym_key_identifier = AES_ciph_B ;
PKE_public_key_identifier = MLKEM_pub_A ;
CALL PKE

/* PKE returns a random 32-byte value encrypted with BOB's AES key
   in the keyvalue parameter.  The random keyvalue is also encrypted
   with ALICE's ML-KEM public key and returned in the
   PKA_enciph_keyvalue parameter. */


/* STEP 4: Bob calls EDH using his private ECC key, Alice's public
    ECC key, and his own encrypted random symmetric key to generate
    a shared secret key. */

EDH_rule_array  = 'DERIV01 '||'KEY-AES '||'QSA-ECDH'||'IHKEYAES' ;
EDH_priv_key_id = EC_priv_B ;
EDH_priv_kek_id = '' ;
EDH_publ_key_id = EC_pub_A ;
EDH_hybrid_key_id = AES_ciph_B ;
EDH_party_identifier = 'ALICE01234BOB56789' ;
EDH_key_bit_length = d2c(256,4) ;
EDH_initial_vector = '01010101010101010202020202020202'x ;
EDH_hybrid_ciphertext = PKE_keyvalue ;
EDH_output_kek_id  = '' ;
EDH_output_key_id  = AES_CIPHER_skeleton ;
CALL EDH

/* calculate VP of BOB's secret key */
KYT2_rule_array = 'AES     '||'GENERATE'||'CMACZERO' ;
KYT2_key_identifier = EDH_output_key_id ;
CALL KYT2 ;
BOB_VP = KYT2_VP ;


/* STEP 5: ALICE calls EDH on her side with her ECC private key,
    BOB's ECC public key, and her own ML-KEM private key to
    generate a shared secret key. */

EDH_rule_array  = 'DERIV01 '||'KEY-AES '||'QSA-ECDH'||'IHKEYKYB'
EDH_priv_key_id = EC_priv_A ;
EDH_priv_kek_id = '' ;
EDH_publ_key_id = EC_pub_B ;
EDH_hybrid_key_id = MLKEM_priv_A ;
EDH_party_identifier = 'ALICE01234BOB56789' ;
EDH_key_bit_length = d2c(256,4) ;
EDH_initial_vector = '' ;
EDH_hybrid_ciphertext = PKE_PKA_enciph_keyvalue ; /* output from PKE */
EDH_output_kek_id  = '' ;
EDH_output_key_id  = AES_CIPHER_skeleton ;
CALL EDH

/* calculate VP of ALICE's secret key */
KYT2_rule_array = 'AES     '||'GENERATE'||'CMACZERO' ;
KYT2_key_identifier = EDH_output_key_id ;
CALL KYT2
ALICE_VP = KYT2_VP ;


/* Step 6: Check that the VP of BOB's secret key matches the VP of
   ALICE's secret key to ensure both keys match. */

IF ALICE_VP = BOB_VP THEN
 SAY 'BOB and ALICE shared secret VPs match. SUCCESS!!'


/*-------------------------------------------------------------------*/
GETOUT:
EXIT

/*-------------------------------------------------------------------*/
/* PKA Key Token Build                                               */
/*-------------------------------------------------------------------*/
PKB:

PKB_rc = 'FFFFFFFF'x ;
PKB_rs = 'FFFFFFFF'x ;
exit_data_length = '00000000'x ;
exit_data = '' ;
PKB_rule_count = d2c(length(PKB_rule_array)/8,4) ;
PKB_kvs_length = d2c(length(PKB_kvs),4) ;
PKB_private_name_length    = '00000000'x ;
PKB_private_name           = '' ;
PKB_user_assoc_data_length = '00000000'x ;
PKB_user_assoc_data        = '' ;
PKB_key_deriv_data_length  = '00000000'x ;
PKB_key_deriv_data         = '' ;
PKB_reserved_field3_length = '00000000'x ;
PKB_reserved_field3        = '' ;
PKB_reserved_field4_length = '00000000'x ;
PKB_reserved_field4        = '' ;
PKB_reserved_field5_length = '00000000'x ;
PKB_reserved_field5        = '' ;
PKB_token_length = d2c(8000,4) ; /* max */
PKB_token        = d2c(0,8000) ;

ADDRESS LINKPGM 'CSNDPKB' ,
                'PKB_rc'                     'PKB_rs' ,
                'exit_data_length'           'exit_data' ,
                'PKB_rule_count'             'PKB_rule_array' ,
                'PKB_kvs_length'             'PKB_kvs' ,
                'PKB_private_name_length'    'PKB_private_name' ,
                'PKB_user_assoc_data_length' 'PKB_user_assoc_data' ,
                'PKB_key_deriv_data_length'  'PKB_key_deriv_data' ,
                'PKB_reserved_field3_length' 'PKB_reserved_field3' ,
                'PKB_reserved_field4_length' 'PKB_reserved_field4' ,
                'PKB_reserved_field5_length' 'PKB_reserved_field5' ,
                'PKB_token_length'           'PKB_token' ;

SAY 'PKB: rc =' c2x(PKB_rc) 'rs =' c2x(PKB_rs) ;
IF PKB_rc \= '00000000'x THEN
 DO
  SAY 'PKB FAILED' ;
  SIGNAL GETOUT ;
 END
ELSE
 DO
  PKB_token = substr(PKB_token,1,c2d(PKB_token_length)) ;
  SAY 'PKB token length:' c2x(PKB_token_length) ;
  SAY 'PKB token:' ;
  SAY c2x(PKB_token) ;
 END

SAY
RETURN

/*-------------------------------------------------------------------*/
/* PKA Key Generate                                                  */
/*-------------------------------------------------------------------*/
PKG:

PKG_rc = 'FFFFFFFF'x ;
PKG_rs = 'FFFFFFFF'x ;
exit_data_length = '00000000'x ;
exit_data = '' ;
PKG_rule_array_count  = d2c(length(PKG_rule_array)/8,4) ;
PKG_regen_data_length = '00000000'x ;
PKG_regen_data        = '' ;
PKG_skeleton_key_id_length = d2c(length(PKG_skeleton_key_id),4) ;
PKG_transport_key_id  = ''
PKG_token_length      = d2c(8000,4) ;
PKG_token             = d2c(0,8000) ;

ADDRESS LINKPGM 'CSNDPKG' ,
                'PKG_rc'                     'PKG_rs' ,
                'exit_data_length'           'exit_data' ,
                'PKG_rule_array_count'       'PKG_rule_array' ,
                'PKG_regen_data_length'      'PKG_regen_data' ,
                'PKG_skeleton_key_id_length' 'PKG_skeleton_key_id' ,
                'PKG_transport_key_id' ,
                'PKG_token_length'           'PKG_token' ;

SAY 'PKG: rc =' c2x(PKG_rc) 'rs =' c2x(PKG_rs) ;
IF PKG_rc \= '00000000'x THEN
 DO
  SAY 'PKG FAILED' ;
  SIGNAL GETOUT ;
 END
ELSE
 DO
  PKG_token = SUBSTR(PKG_token,1,c2d(PKG_token_length)) ;
  SAY 'PKG generated token length:' c2x(PKG_token_length) ;
  SAY 'PKG generated token:' ;
  SAY c2x(PKG_token) ;
 END

SAY
RETURN

/*-------------------------------------------------------------------*/
/* PKA Public Key Extract                                            */
/*-------------------------------------------------------------------*/
PKX:

PKX_rc = 'FFFFFFFF'x ;
PKX_rs = 'FFFFFFFF'x ;
exit_data_length = '00000000'x ;
exit_data = '' ;
PKX_rule_array_count  = '00000000'x ;
PKX_rule_array        = '' ;
PKX_source_key_length = d2c(length(PKX_source_key),4) ;
PKX_token_length      = d2c(8000,4) ;
PKX_token             = copies('00'x,8000) ;

ADDRESS LINKPGM 'CSNDPKX' ,
                'PKX_rc' ,
                'PKX_rs' ,
                'exit_data_length' ,
                'exit_data' ,
                'PKX_rule_array_count' ,
                'PKX_rule_array' ,
                'PKX_source_key_length' ,
                'PKX_source_key' ,
                'PKX_token_length' ,
                'PKX_token' ;

SAY 'PKX: rc =' c2x(PKX_rc) 'rs =' c2x(PKX_rs)
IF PKX_rc /= '00000000'x THEN
 DO ;
  SAY 'PKX FAILED' ;
  SIGNAL GETOUT ;
 END ;
ELSE
 DO ;
  PKX_token = substr(PKX_token,1,c2d(PKX_token_length)) ;
  SAY 'PKX public key token length:' c2x(PKX_token_length) ;
  SAY 'PKX token:' ;
  SAY c2x(PKX_token)
 END

SAY
RETURN

/*-------------------------------------------------------------------*/
/* PKA Encrypt                                                       */
/*-------------------------------------------------------------------*/
PKE:

PKE_rc = 'FFFFFFFF'x ;
PKE_rs = 'FFFFFFFF'x ;
exit_data_length = '00000000'x
exit_data = ''
PKE_rule_array_count = d2c(length(PKE_rule_array)/8,4) ;
PKE_keyvalue_length  = d2c(length(PKE_keyvalue),4) ;
PKE_sym_key_identifier_length = d2c(length(PKE_sym_key_identifier),4) ;
PKE_public_key_identifier_length = ,
   d2c(length(PKE_public_key_identifier),4) ;
PKE_PKA_enciph_keyvalue_length = d2c(1568,4) ;
PKE_PKA_enciph_keyvalue = d2c(0,1568) ;

ADDRESS LINKPGM 'CSNDPKE' ,
                'PKE_rc' ,
                'PKE_rs' ,
                'exit_data_length' ,
                'exit_data' ,
                'PKE_rule_array_count' ,
                'PKE_rule_array' ,
                'PKE_keyvalue_length' ,
                'PKE_keyvalue' ,
                'PKE_sym_key_identifier_length' ,
                'PKE_sym_key_identifier' ,
                'PKE_public_key_identifier_length' ,
                'PKE_public_key_identifier' ,
                'PKE_PKA_enciph_keyvalue_length' ,
                'PKE_PKA_enciph_keyvalue' ;

SAY 'PKE: rc =' c2x(PKE_rc) 'rs =' c2x(PKE_rs)
IF PKE_rc /= '00000000'x THEN
 DO
  SAY 'PKE FAILED' ;
  SIGNAL GETOUT ;
 END
ELSE
 DO
  PKE_PKA_enciph_keyvalue = ,
    substr(PKE_PKA_enciph_keyvalue,1,,
     c2d(PKE_PKA_enciph_keyvalue_length))
  SAY 'PKE_PKA_enciph_keyvalue_length:' ,
     c2x(PKE_PKA_enciph_keyvalue_length) ;
  SAY 'PKE_PKA_enciph_keyvalue:' ;
  SAY c2x(PKE_PKA_enciph_keyvalue) ;
  SAY
  SAY 'PKE_keyvalue_length:' c2x(PKE_keyvalue_length) ;
  SAY 'PKE_keyvalue:' ;
  SAY c2x(PKE_keyvalue)
 END

SAY
RETURN

/*-------------------------------------------------------------------*/
/* ECC Diffie-Hellman                                                */
/*-------------------------------------------------------------------*/
EDH:

EDH_rc = 'FFFFFFFF'x ;
EDH_rs = 'FFFFFFFF'x ;
exit_data_length = '00000000'x
exit_data = ''
EDH_rule_array_count = d2c(length(EDH_rule_array)/8,4) ;
EDH_priv_key_id_length = d2c(length(EDH_priv_key_id),4) ;
EDH_priv_kek_id_length = d2c(length(EDH_priv_KEK_id),4) ;
EDH_publ_key_id_length = d2c(length(EDH_publ_key_id),4) ;
EDH_hybrid_key_id_length = d2c(length(EDH_hybrid_key_id),4) ;
EDH_party_identifier_length = d2c(length(EDH_party_identifier),4) ;
EDH_initial_vector_length = d2c(length(EDH_initial_vector),4) ;
EDH_hybrid_ciphertext_length = d2c(length(EDH_hybrid_ciphertext),4) ;
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 = d2c(length(EDH_output_KEK_id),4)
AES_CIPHER_skeleton = , /* created using CSNBKTB2 */
'0100003805000000000000000000000000000000000000000000020200000100'x||,
'001A0000000000000002000102C000000003E00000000000'x ;
EDH_output_key_id_length = d2c(9992,4) ;
EDH_output_key_id = left(AES_CIPHER_skeleton,9992) ;

ADDRESS LINKPGM 'CSNDEDH' ,
                'EDH_rc' ,
                'EDH_rs' ,
                'exit_data_length' ,
                'exit_data' ,
                'EDH_rule_array_count' ,
                'EDH_rule_array' ,
                'EDH_priv_key_id_length' ,
                'EDH_priv_key_id' ,
                'EDH_priv_kek_id_length' ,
                'EDH_priv_kek_id' ,
                'EDH_publ_key_id_length' ,
                'EDH_publ_key_id' ,
                'EDH_hybrid_key_id_length' ,
                'EDH_hybrid_key_id' ,
                'EDH_party_identifier_length' ,
                'EDH_party_identifier' ,
                'EDH_key_bit_length' ,
                'EDH_initial_vector_length' ,
                'EDH_initial_vector' ,
                'EDH_hybrid_ciphertext_length' ,
                'EDH_hybrid_ciphertext' ,
                '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' ;

SAY 'EDH: rc =' c2x(EDH_rc) 'rs =' c2x(EDH_rs) ;
IF EDH_rc /= '00000000'x THEN
 DO
  SAY 'EDH FAILED' ;
  SIGNAL GETOUT ;
 END
ELSE
 DO
  EDH_output_key_id = ,
     substr(EDH_output_key_id,1,c2d(EDH_output_key_id_length)) ;
  SAY 'EDH output_key_identifier_length:' ,
     c2x(EDH_output_key_id_length) ;
  SAY 'EDH output_key_identifier:' ;
  SAY c2x(EDH_output_key_id) ;
 END

SAY
RETURN

/*-------------------------------------------------------------------*/
/* Key Test2                                                         */
/*-------------------------------------------------------------------*/
KYT2:

KYT2_rc = 'FFFFFFFF'x ;
KYT2_rs = 'FFFFFFFF'x ;
exit_data_length = '00000000'x
exit_data = ''
KYT2_rule_array_count = d2c(length(KYT2_rule_array)/8,4) ;
KYT2_key_identifier_length = d2c(length(KYT2_key_identifier),4) ;
KYT2_kek_identifier_length = '00000000'x ;
KYT2_kek_identifier        = ''
KYT2_reserved_length = d2c(0,4) ;
KYT2_reserved        = 'ignore me' ;
KYT2_VP_length  = d2c(8,4) ;
KYT2_VP         = d2c(0,c2d(KYT2_VP_length)) ;

ADDRESS LINKPGM 'CSNBKYT2' ,
                'KYT2_rc'                    'KYT2_rs' ,
                'exit_data_length'           'exit_data' ,
                'KYT2_rule_array_count'      'KYT2_rule_array' ,
                'KYT2_key_identifier_length' 'KYT2_key_identifier' ,
                'KYT2_kek_identifier_length' 'KYT2_kek_identifier' ,
                'KYT2_reserved_length'       'KYT2_reserved' ,
                'KYT2_VP_length'             'KYT2_VP' ;

IF KYT2_rc /= '00000000'x THEN
 DO
  SAY 'KYT2 failed: rc =' c2x(KYT2_rc) 'rs =' c2x(KYT2_rs) ;
  SIGNAL GETOUT ;
 END
ELSE
 DO
  SAY 'KYT2 VP length:' c2x(KYT2_VP_length) ;
  SAY 'KYT2 VP:' c2x(KYT2_VP) ;
 END

SAY
RETURN

0 comments
12 views

Permalink