IBM Crypto Education Community - Group home

CSNDDSG example with RSA DSI PKCS #1 v1.5

  
/* Rexx */

/*--------------------------------------------------------------------*/
/* This Rexx sample clist will:                                       */
/* - Build a skeleton RSA private key token using CSNDPKB.            */
/* - Use skeleton token in CSNDPKG to generate a secure RSA private   */
/* key.                                                               */
/* - Store the generated RSA private key in the PKDS.                 */
/* - Extract the public key from the private key.                     */
/* - Store the RSA public key in the PKDS.                            */
/* - Use the RSA key in CSNDDSG to generate a digital signature using */
/* the RSA PKCS-1.1 signature formatting method as defined in the     */
/* RSASSA-PKCS1-v1_5 signature scheme.                                */
/*--------------------------------------------------------------------*/
/* See the ICSF Application Programmer's Guide (APG) for detailed     */
/* information on the callable services used in this sample.          */
/*--------------------------------------------------------------------*/

/* PKDS key label for the generated RSA private and public keys */
RSA_pvt_key_label = left('SAMPLE.RSA.PVT.MOD4096.SIGONLY',64) ;
RSA_pub_key_label = left('SAMPLE.RSA.PUB.MOD4096',64) ;


/*--------------------------------------------------------------------*/
/* Call CSNDPKB to build a skeleton RSA private key token.            */
/*--------------------------------------------------------------------*/
PKB_rc = 'FFFFFFFF'x ;
PKB_rs = 'FFFFFFFF'x ;
exit_data_length = '00000000'x ;
exit_data = '' ;
rule_array_count = '00000002'x ;
rule_array = 'RSA-CRT '||, /* key type */
             'SIG-ONLY' ; /* key usage */
key_value_structure = '0800'x||, /* mod bit length */
                      '0000'x||, /* mod byte length */
                      '0000'x||, /* public exp length */
                      '0000'x||, /* reserved */
                      '0000'x||, /* length of p */
                      '0000'x||, /* length of q */
                      '0000'x||, /* length of dp */
                      '0000'x||, /* length of dq */
                      '0000'x ;

key_value_structure_length = d2c(length(key_value_structure),4) ;
private_key_name_length = '00000000'x ;
private_key_name = '' ;
user_definable_associated_data_length = '00000000'x ;
user_definable_associated_data = '' ;
key_derivation_data_length = '00000000'x ;
key_derivation_data = '' ;
reserved_3_length = '00000000'x ; reserved_3 = '' ;
reserved_4_length = '00000000'x ; reserved_4 = '' ;
reserved_5_length = '00000000'x ; reserved_5 = '' ;
PKB_key_token_length = d2c(3500,4) ;
PKB_key_token = copies('00'x,3500) ;

ADDRESS LINKPGM 'CSNDPKB' ,
                'PKB_rc' ,
                'PKB_rs' ,
                'exit_data_length' ,
                'exit_data' ,
                'rule_array_count' ,
                'rule_array' ,
                'key_value_structure_length' ,
                'key_value_structure' ,
                'private_key_name_length' ,
                'private_key_name' ,
                'user_definable_associated_data_length' ,
                'user_definable_associated_data' ,
                'key_derivation_data_length' ,
                'key_derivation_data' ,
                'reserved_3_length' 'reserved_3' ,
                'reserved_4_length' 'reserved_4' ,
                'reserved_5_length' '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 ;
ELSE
 DO ;
  SAY 'PKB key token length:' c2x(PKB_key_token_length) ;
  PKB_key_token = substr(PKB_key_token,1,c2d(PKB_key_token_length)) ;
  SAY 'PKB key token:' ;
  CALL printblk c2x(PKB_key_token), 64 ;
 END ;


/*--------------------------------------------------------------------*/
/* Use the skeleton token to generate the RSA private/public key.     */
/*--------------------------------------------------------------------*/
PKG_rc = 'FFFFFFFF'x ;
PKG_rs = 'FFFFFFFF'x ;
exit_data_length = '00000000'x ;
exit_data = '' ;
rule_array_count = '00000001'x ;
rule_array = 'MASTER ' ; /* generated key will be encrypted
                            under the master key */
regeneration_data_length = '00000000'x ;
regeneration_data = '' ;
skeleton_key_identifier_length = PKB_key_token_length ;
skeleton_key_identifier = PKB_key_token ;
transport_key_identifier = '' ;
generated_key_token_length = d2c(3500,4) ;
generated_key_token = copies('00'x,3500) ;

ADDRESS LINKPGM 'CSNDPKG' ,
                'PKG_rc' ,
                'PKG_rs' ,
                'exit_data_length' ,
                'exit_data' ,
                'rule_array_count' ,
                'rule_array' ,
                'regeneration_data_length' ,
                'regeneration_data' ,
                'skeleton_key_identifier_length' ,
                'skeleton_key_identifier' ,
                'transport_key_identifier' ,
                'generated_key_token_length' ,
                'generated_key_token' ;

IF PKG_rc /= '00000000'x THEN
 DO ;
  SAY 'PKG failed: rc =' c2x(PKG_rc) 'rs =' c2x(PKG_rs) ;
  EXIT ;
 END ;
ELSE
 DO ;
  SAY 'PKG generated key token length:' c2x(generated_key_token_length);
  generated_key_token = ,
   substr(generated_key_token,1,c2d(generated_key_token_length)) ;
  SAY 'PKG generated key token:' ;
  CALL PRINTBLK c2x(generated_key_token), 64 ;
 END ;


/* Store the generated RSA private/public key in the PKDS */
PKRC_rc = 'FFFFFFFF'x ;
PKRC_rs = 'FFFFFFFF'x ;
exit_data_length = '00000000' ;
exit_data = '' ;
rule_array_count = '00000000'x ;
rule_array = '' ;
key_label = RSA_pvt_key_label ;
key_token_length = generated_key_token_length ;
key_token = generated_key_token ;

ADDRESS LINKPGM 'CSNDKRC' ,
                'PKRC_rc' ,
                'PKRC_rs' ,
                'exit_data_length' ,
                'exit_data' ,
                'rule_array_count' ,
                'rule_array' ,
                'key_label' ,
                'key_token_length' ,
                'key_token' ;

IF PKRC_rc /= '00000000'x THEN
 DO ;
  SAY 'PKRC failed: rc =' c2x(PKRC_rc) 'rs =' c2x(PKRC_rs) ;
  EXIT ;
 END ;


/*--------------------------------------------------------------------*/
/* Extract the public key from the private/public key.                */
/*--------------------------------------------------------------------*/
PKX_rc = 'FFFFFFFF'x ;
PKX_rs = 'FFFFFFFF'x ;
exit_data_length = '00000000'x ;
exit_data = '' ;
rule_array_count = '00000000'x ;
rule_array = '' ;
source_key_identifier_length = generated_key_token_length ;
source_key_identifier = generated_key_token ;
target_public_key_token_length = d2c(3500,4) ;
target_public_key_token = copies('00'x,3500) ;

ADDRESS LINKPGM 'CSNDPKX' ,
                'PKX_rc' ,
                'PKX_rs' ,
                'exit_data_length' ,
                'exit_data' ,
                'rule_array_count' ,
                'rule_array' ,
                'source_key_identifier_length' ,
                'source_key_identifier' ,
                'target_public_key_token_length' ,
                'target_public_key_token' ;

IF PKX_rc /= '00000000'x THEN
 DO ;
  SAY 'PKX failed: rc =' c2x(PKX_rc) 'rs =' c2x(PKX_rs) ;
  EXIT ;
 END ;
ELSE
 DO ;
  SAY 'PKX target_public_key_token_length:' ,
   c2x(target_public_key_token_length) ;
  target_public_key_token = ,
   substr(target_public_key_token,1,c2d(target_public_key_token_length))
  SAY 'PKX public key token:' ;
  CALL PRINTBLK c2x(target_public_key_token), 64 ;
 END ;


/* Store the RSA public key in the PKDS */
PKRC_rc = 'FFFFFFFF'x ;
PKRC_rs = 'FFFFFFFF'x ;
exit_data_length = '00000000' ;
exit_data = '' ;
rule_array_count = '00000000'x ;
rule_array = '' ;
key_label = RSA_pub_key_label ;
key_token_length = target_public_key_token_length ;
key_token = target_public_key_token ;

ADDRESS LINKPGM 'CSNDKRC' ,
                'PKRC_rc' ,
                'PKRC_rs' ,
                'exit_data_length' ,
                'exit_data' ,
                'rule_array_count' ,
                'rule_array' ,
                'key_label' ,
                'key_token_length' ,
                'key_token' ;

IF PKRC_rc /= '00000000'x THEN
 DO ;
  SAY 'PKRC failed: rc =' c2x(PKRC_rc) 'rs =' c2x(PKRC_rs) ;
  EXIT ;
 END ;


/*--------------------------------------------------------------------*/
/* Use the generated RSA private key to generate a signature using    */
/* the PKCS-1.1 digital signature formatting hash method.             */
/*--------------------------------------------------------------------*/
DSG_rc = 'FFFFFFFF'x ;
DSG_rs = 'FFFFFFFF'x ;
exit_data_length = '00000000'x ;
exit_data = '' ;
rule_array_count = '00000004'x ;
rule_array = 'RSA '||, /* algorithm */
             'PKCS-1.1'||, /* formatting method */
             'MESSAGE '||, /* data specifies message */
             'SHA-256 ' ; /* hash method */
RSA_private_key_length = d2c(64,4) ;
RSA_private_key = RSA_pvt_key_label ;
DSG_data_length = '00000014'x
DSG_data = 'MESSAGE TO BE HASHED' ;
signature_field_length = '00000100'x ;
signature_bit_length = '00000800'x ;
signature_field = copies('00'x,c2d(signature_field_length)) ;

ADDRESS LINKPGM 'CSNDDSG' ,
                'DSG_rc' ,
                'DSG_rs' ,
                'exit_data_length' ,
                'exit_data' ,
                'rule_array_count' ,
                'rule_array' ,
                'RSA_private_key_length' ,
                'RSA_private_key' ,
                'DSG_data_length' ,
                'DSG_data' ,
                'signature_field_length' ,
                'signature_bit_length' ,
                'signature_field' ;

IF DSG_rc /= '00000000'x THEN
 DO ;
  SAY 'DSG failed: rc =' c2x(DSG_rc) 'rs =' c2x(DSG_rs) ;
  EXIT ;
 END ;
ELSE
 DO ;
  signature_field = ,
   substr(signature_field,1,c2d(signature_field_length)) ;
  SAY 'signature field length:' c2x(signature_field_length) ;
  SAY 'signature bit length:' c2x(signature_bit_length) ;
  SAY 'signature:' ;
  CALL PRINTBLK c2x(signature_field), 64 ;
 END ;


/*--------------------------------------------------------------------*/
/* The RSA public key, message and digital signature are sent to a    */
/* client for verification.                                           */
/*--------------------------------------------------------------------*/
DSV_rc = 'FFFFFFFF'x ;
DSV_rs = 'FFFFFFFF'x ;
exit_data_length = '00000000'x ;
exit_data = '' ;
rule_array_count = '00000004'x ;
rule_array = 'RSA '||, /* algorithm */
             'PKCS-1.1'||, /* formatting method */
             'MESSAGE '||, /* data specifies message */
             'SHA-256 ' ; /* hash method */
RSA_public_key_length = d2c(64,4) ;
RSA_public_key = RSA_pub_key_label ;
DSV_data_length = '00000014'x
DSV_data = 'MESSAGE TO BE HASHED' ;
signature_field_length = '00000100'x
signature_field = ,
'8DFBE671A97E7AA07CA6A23753EA326E4C1A325FD05E874B8570D9DEF5928787'x||,
'1D05B2818825F41C9EF3E6A3A492ACCCFE177D84DAD42C7837FCA463A6A65B42'x||,
'4DC52B17F232D776939ED170E9AD8E272E92ED4C492595A98CA59C925060EEE6'x||,
'A0D772E2692AC083FDE411369752B57EB92F04671915F822FF0D925B9064FC18'x||,
'A3272D1C01FDC71FCF3CD555344E231411A7155C3A126A5DBFB67F3C52E4CE00'x||,
'E9E5F4B568EC47214C869433B400C285B95A1895B51AD34CB2E9772E0871A290'x||,
'0575B185BFEC9907A85A95603D6EA073EF0B6B6DDA1B6D62ECB6044E669E584A'x||,
'D24A271763D7D4F3FD85B07FDDA71ADF43D267CB767056A98ED58B06619B00A4'x ;

ADDRESS LINKPGM 'CSNDDSV' ,
                'DSV_rc' ,
                'DSV_rs' ,
                'exit_data_length' ,
                'exit_data' ,
                'rule_array_count' ,
                'rule_array' ,
                'RSA_public_key_length' ,
                'RSA_public_key' ,
                'DSV_data_length' ,
                'DSV_data' ,
                'signature_field_length' ,
                'signature_field' ;

IF DSV_rc /= '00000000'x THEN
 SAY 'DSV failed: rc =' c2x(DSV_rc) 'rs =' c2x(DSV_rs) ;
ELSE
 SAY 'DSV SIGNATURE VERIFIED'


EXIT ;

/*--------------------------------------------------------------------*/
/* PRINTBLK:                                                          */
/* Helper routine to display hex data with a fixed line length        */
/*--------------------------------------------------------------------*/
PRINTBLK:
ARG data, max

/* The maximum length of an output line */
line_length = max
data_length = LENGTH(data)
num_lines = data_length % line_length

/* Parse the data */
IF data_length // line_length <> 0 THEN num_lines = num_lines + 1
index = 1
DO num_lines
SAY SUBSTR(data,index,line_length)
index = index + line_length
END

RETURN