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: Generate an RSA key for generating a digital signature using the RSA PKCS-PSS formatting method

By Eysha Shirrine Powers posted Wed March 25, 2020 05:30 PM

  

/* Rexx */

/*--------------------------------------------------------------------*/
/* This Rexx sample clist will:                                       */
/* - Build a skeleton RSA private key token using CSNDPKB with        */
/*   key-usage FR-PSS, which renders the RSA private key usable with  */
/*   the PKCS-PSS digital-signature hash formatting method.           */
/* - Use skeleton token in CSNDPKG to generate a secure RSA private   */
/*   key.                                                             */
/* - Store the generated RSA private key in the PKDS using CSNDKRC.   */
/* - Use the RSA private key in CSNDDSG to generate a digital         */
/*   signature using the RSA PKCS-PSS signature formatting method as  */
/*   defined in the RSA PKCS #11 v2.2 standard for the RSASSA-PSS     */
/*   signature scheme.                                                */
/* - If signature will be sent to receiver system for verification,   */
/*   use CSNDPKX to extract the RSA public key from the private key.  */
/*   Send the public key, signature and message or hash to receiver.  */
/*                                                                    */
/*   (The remaining steps are performed on the receiver system.)      */
/* - Store the RSA public key in the PKDS using CSNDKRC.              */
/* - Use the RSA public key in CSNDDSV to verify the signature.       */
/*--------------------------------------------------------------------*/
/* See the ICSF Application Programmer's Guide (APG) for detailed     */
/* information on the callable services used in this sample.          */
/*                                                                    */
/* PKCS-PSS formatting method is supported on ICSF HCR77C0 and CEX5C  */
/* and above.  The coprocessor ECC master key must be active. If the  */
/* ECC master key is not active, see the ICSF Administrator's Guide   */
/* "Updating the key data sets with additional master keys".          */
/*--------------------------------------------------------------------*/

/* PKDS key label for the generated RSA private key */
RSA_pvt_key_label = left('SAMPLE.RSA.MOD2048.PSS',64) ;

/* PKDS key label for the RSA public key */
RSA_pub_key_label = left('SAMPLE.RSA.MOD2048.PSS.PUBLIC',64) ;

/*--------------------------------------------------------------------*/
/* Call CSNDPKB to build a skeleton RSA private key token.            */
/* Key type must be RSA-AESM (modulus-exponent form) or RSA-AESC      */
/* (Chinese Remainder Theorem form).  Key types RSA-AESM and RSA-AESC */
/* require ICSF HCR77C0 or higher.                                    */
/*--------------------------------------------------------------------*/
PKB_rc              = 'FFFFFFFF'x ;
PKB_rs              = 'FFFFFFFF'x ;
exit_data_length    = '00000000'x ;
exit_data           = '' ;
rule_array_count    = '00000003'x ;
rule_array          = 'RSA-AESM'||,  /* key type  */
                      'SIG-ONLY'||,  /* key usage */
                      'FR-PSS  ' ;   /* format restriction */

key_value_structure = '0800'x||,  /* mod bit length     */
                      '0000'x||,  /* mod byte length    */
                      '0003'x||,  /* public  exp length */
                      '0000'x||,  /* private exp length */
                      '010001'x ; /* public exponent    */
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) ;

/* CALL CSNDPKB */
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 ;
  PKB_key_token = substr(PKB_key_token,1,c2d(PKB_key_token_length)) ;
  SAY 'PKB key token length:' c2x(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 key. A CEX5C or */
/* higher is required and the ECC master key must be active.          */
/*--------------------------------------------------------------------*/
PKG_rc           = 'FFFFFFFF'x ;
PKG_rs           = 'FFFFFFFF'x ;
exit_data_length = '00000000'x ;
exit_data        = '' ;
rule_array_count = d2c(1,4) ;
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) ;

/* CALL CSNDPKG */
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 key in the PKDS. */
key_label        = RSA_pvt_key_label ;
key_token_length = generated_key_token_length ;
key_token        = generated_key_token ;
CALL PKRC ;

/*--------------------------------------------------------------------*/
/* Use the generated RSA private key to generate a signature using    */
/* the PKCS-PSS 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-PSS'||,  /* formatting method */
                     'MESSAGE '||,  /* data type         */
                     'SHA-256 ' ;   /* hash method       */

private_key_length = d2c(64,4) ;
private_key        = RSA_pvt_key_label ;

data               = '00000020'x||,           /* salt length */
                     'MESSAGE TO BE HASHED' ; /* message     */
data_length        = d2c(length(data),4) ;

sig_field_length   = '00000100'x ;
sig_bit_length     = '00000800'x ;
sig_field          = copies('00'x,c2d(sig_field_length)) ;

/* CALL CSNDDSG */
ADDRESS LINKPGM 'CSNDDSG' ,
                'DSG_rc' ,
                'DSG_rs' ,
                'exit_data_length' ,
                'exit_data' ,
                'rule_array_count' ,
                'rule_array' ,
                'private_key_length' ,
                'private_key' ,
                'data_length' ,
                'data' ,
                'sig_field_length' ,
                'sig_bit_length' ,
                'sig_field' ;

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

/*------------------------------------------------------------------*/
/* If signature will be sent to receiver system for verification,   */
/* use CSNDPKX to extract the RSA public key from the private key.  */
/* Send the public key, signature and message or hash to receiver.  */
/*------------------------------------------------------------------*/

/* Extract the public key from the RSA private 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 = d2c(64,4) ;
source_key_identifier   = RSA_pvt_key_label ;
public_key_token_length = d2c(3500,4) ;
public_key_token = copies('00'x,c2d(public_key_token_length)) ;

/* CALL CSNDPKX */
ADDRESS LINKPGM 'CSNDPKX' ,
                'PKX_rc' ,
                'PKX_rs' ,
                'exit_data_length' ,
                'exit_data' ,
                'rule_array_count' ,
                'rule_array' ,
                'source_key_identifier_length' ,
                'source_key_identifier' ,
                'public_key_token_length' ,
                '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 ;
  public_key_token = ,
     substr(public_key_token,1,c2d(public_key_token_length)) ;
  SAY 'public key token:' ;
  CALL PRINTBLK c2x(public_key_token), 64 ;
 END ;

/*-----------------------------------------------------------*/
/* The remaining steps are performed on the receiver system. */
/*-----------------------------------------------------------*/

/* Store the RSA public key in the PKDS. */
key_label        = RSA_pub_key_label ;
key_token_length = public_key_token_length ;
key_token        = public_key_token ;
CALL PKRC ;

/* Use the RSA public key to verify the signature. */
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-PSS'||,  /* formatting method */
                   'MESSAGE '||,  /* data type         */
                   'SHA-256 ' ;   /* hash method       */

public_key_identifier_length = d2c(64,4) ;
public_key_identifier        = RSA_pub_key_label ;
data             = '00000020'x||,           /* salt length */
                   'MESSAGE TO BE HASHED' ; /* message     */
data_length      = d2c(length(data),4) ;
/* FROM CSNDDSG
sig_field_length
sig_field
*/

/* CALL CSNDDSV */
ADDRESS LINKPGM 'CSNDDSV' ,
                'DSV_rc' ,
                'DSV_rs' ,
                'exit_data_length' ,
                'exit_data' ,
                'rule_array_count' ,
                'rule_array' ,
                'public_key_identifier_length' ,
                'public_key_identifier' ,
                'data_length' ,
                'data' ,
                'sig_field_length' ,
                'sig_field' ;

IF DSV_rc /= '00000000'x THEN
  SAY 'DSV failed: rc =' c2x(DSV_rc) 'rs =' c2x(DSV_rs) ;
ELSE
 DO ;
  SAY 'PKCS-PSS signature verified' ;
 END ;


EXIT ;

/*--------------------------------------------------------------------*/
/* PKDS Key Record Create                                             */
/* - Store the key token in the PKDS                                  */
/*--------------------------------------------------------------------*/
PKRC:

/* parameter list */
PKRC_rc          = 'FFFFFFFF'x ;
PKRC_rs          = 'FFFFFFFF'x ;
exit_data_length = '00000000' ;
exit_data        = '' ;
rule_array_count = '00000000'x ;
rule_array       = '' ;

/* CALL CSNDKRC */
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 ;

RETURN ;

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

 

0 comments
22 views

Permalink