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

REXX Sample: Unwrap A Secret Key Using PKCS#11

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

  

/* Rexx */

/* PKCS#11 Unwrap Sample                                             */
/*-------------------------------------------------------------------*/
/* Description:                                                      */
/*                                                                   */
/* This REXX contains samples that show PKCS#11 Unwrap               */
/*  - Create a PKCS #11 token                                        */
/*  - Generate a clear 3072-bit RSA key pair to store in the TKDS    */
/*  - Extract the RSA public key from the RSA key pair               */
/*  - Generate a clear 128-bit AES key                               */
/*  - Encrypt "Hello World" with the AES key                         */
/*  - Wrap (encrypt) the AES key with the RSA public key             */
/*  - Unwrap (decrypt) the AES key with the RSA private key and      */
/*    store the unwrapped key in the TKDS                            */
/*  - Decrypt "Hello World" with the unwrapped key                   */
/*                                                                   */
/* How To Run:                                                       */
/* - Execute this script from TSO                                    */
/*   (e.g. EX 'HLQ.MLD.LLQ(P11UWK)')                                 */
/*-------------------------------------------------------------------*/
SIGNAL ON NOVALUE;

/*-------------------------------------------------------------------*/
/* PKCS#11 Constants (subset)                                        */
/*-------------------------------------------------------------------*/
/* Objects */
CKO_PUBLIC_KEY        = '00000002'X
CKO_PRIVATE_KEY       = '00000003'X
CKO_SECRET_KEY        = '00000004'X

/* Key Types */
CKK_RSA               = '00000000'X
CKK_AES               = '0000001F'X

/* Miscellaneous */
CK_TRUE               = '01'x
CK_FALSE              = '00'x
CKA_CLASS             = '00000000'X
CKA_TOKEN             = '00000001'X
CKA_PRIVATE           = '00000002'X
CKA_LABEL             = '00000003'X
CKA_VALUE             = '00000011'X
CKA_VALUE_LEN         = '00000161'X
CKA_KEY_TYPE          = '00000100'X
CKA_SENSITIVE         = '00000103'X
CKA_SIGN              = '00000108'X
CKA_VERIFY            = '0000010A'X
CKA_MODULUS           = '00000120'X
CKA_MODULUS_BITS      = '00000121'X
CKA_PUBLIC_EXPONENT   = '00000122'X
CKA_IBM_SECURE        = '80000006'X

/* CLEANUP tokens in use for this sample */
Token_Handle   = left('SAMPLE#P11UWK#TOKEN',44)
TRD_Handle     = Token_Handle
Call CSFPTRD

/*********************************************************************/
/* Create a PKCS#11 token to contain PKCS #11 objects.               */
/*********************************************************************/
TRC_rule_count = '00000001'x
TRC_rule_array = 'TOKEN   '
TRC_attr_list  = ,
     'Manufacturer                    ' ||,     /* 32 char Manuf ID */
     'Model#  _P11UWK '                 ||,     /* 16 char Model    */
     'Serial# _P11UWK '                 ||,     /* 16 char Serial#  */
     '00000000'x                                /*  4 char reserved */
TRC_attr_list_length = d2c(length(TRC_attr_list),4)

Call CSFPTRC
say "token handle: " trc_handle

/*********************************************************************/
/* Generate a 3072-bit RSA key pair.                                 */
/*********************************************************************/
 GKP_PubKey_Handle    = copies(' ',44)
 GKP_PrivKey_Handle   = copies(' ',44)
 GKP_PubKey_Attr_List =  '0006'x ||,            /* number attributes */
    CKA_CLASS         || '0004'x || CKO_PUBLIC_KEY      ||,
    CKA_KEY_TYPE      || '0004'x || CKK_RSA             ||,
    CKA_TOKEN         || '0001'x || CK_TRUE             ||,  /* TKDS */
    CKA_MODULUS_BITS  || '0004'x || '00000C00'x         ||,  /* 3072 */
    CKA_LABEL         || '0018'X || 'P11 Clear RSA Public Key' ||,
    CKA_IBM_SECURE    || '0001'X || CK_FALSE;               /* clear */

 GKP_PrivKey_Attr_List = '0005'x ||,          /* number attributes */
    CKA_CLASS         || '0004'x || CKO_PRIVATE_KEY     ||,
    CKA_KEY_TYPE      || '0004'x || CKK_RSA             ||,
    CKA_TOKEN         || '0001'x || CK_TRUE             ||,  /* TKDS */
    CKA_LABEL         || '0019'X || 'P11 Clear RSA Private Key' ||,
    CKA_IBM_SECURE    || '0001'x || CK_FALSE;               /* clear */

 GKP_PubKey_Attr_List_Length = D2C(Length(GKP_PubKey_Attr_List),4)
 GKP_PrivKey_Attr_List_Length = D2C(Length(GKP_PrivKey_Attr_List),4)

 Call CSFPGKP;

/*-------------------------------------------------------------------*/
/*  Find and extract the public key.                                 */
/*-------------------------------------------------------------------*/
/* Lookup the public key handle */
TRL_handle           = token_handle
TRL_rule_count       = '00000001'x
TRL_rule_array       = 'OBJECT  '
TRL_srch_tmpl_length = '00000020'x
TRL_srch_tmpl        = '0001'x ||,              /* number attributes */
    CKA_LABEL       || '0018'X || 'P11 Clear RSA Public Key'
TRL_handle_count     = '00000010'x      /* expect one 44-byte handle */
TRL_list_length      = '00000DAC'x
TRL_output_list      = copies('00'x,3500)

CALL CSFPTRL

if c2d(TRL_handle_count) < 1 then
  do
    say "Public key not found. Check SAF authorization to the token."
    exit
  end

public_key_handle = TRL_output_list

/* Get the public key value */
GAV_handle           = public_key_handle
GAV_attr_list_length = '00000DAC'x
GAV_attr_list        = copies('00'x,3500)

CALL CSFPGAV

/*-------------------------------------------------------------------*/
/*  Generate a 128-bit AES clear key                                 */
/*-------------------------------------------------------------------*/
 GSK_AttrList    =    '0006'x||,              /* number attributes */
    CKA_CLASS         ||'0004'x|| CKO_SECRET_KEY      ||,
    CKA_KEY_TYPE      ||'0004'x|| CKK_AES             ||,
    CKA_TOKEN         ||'0001'x|| CK_TRUE             ||,   /* TKDS  */
    CKA_VALUE_LEN     ||'0004'x|| '00000010'x         ||, /* 16 byte */
    CKA_LABEL         ||'0011'X|| 'P11 Clear AES Key' ||,
    CKA_IBM_SECURE    ||'0001'X|| CK_FALSE;                 /* clear */

 GSK_AttrListLength   = D2C( Length( GSK_AttrList ),4);

 Call CSFPGSK;

/*  - Encrypt "Hello World" with the AES key                         */
SKE_rule_array_count      = '00000002'X;
/* Using the CBC-PAD option defaults the chaining selection to ONLY  */
SKE_rule_array            = 'AES     CBC-PAD ';
SKE_key_handle            = GSK_Handle;
SKE_iv_length             = '00000010'X;
SKE_iv                    = COPIES('00'X,C2D(SKE_iv_length));
SKE_chain_data_len        = '00000080'X;
SKE_chain_data            = COPIES('00'X,C2D(SKE_chain_data_len));
SKE_clear_text            = 'Hello World';
Call CSFPSKE;

/*  - Wrap (encrypt) the AES key with the RSA public key             */
WPK_rule_array_count      = '00000001'X;
WPK_rule_array            = 'PKCS-1.2';
WPK_source_key_handle     = GSK_Handle;
WPK_wrapping_key_handle   = GKP_PubKey_Handle
Call CSFPWPK;


/*  - Unwrap (decrypt) the AES key with the RSA private key and      */
/*    store the unwrapped key in the TKDS                            */
UWK_rule_array_count      = '00000001'X;
UWK_rule_array            = 'PKCS-1.2';
UWK_unwrapping_key_handle = GKP_PrivKey_Handle;
UWK_wrapped_key_length    = D2C(LENGTH(WPK_wrapped_key),4);
UWK_wrapped_key           = WPK_wrapped_key;
UWK_attribute_list        = '0002'X ||,
       CKA_TOKEN            || '0001'X || CK_TRUE ||,
       CKA_KEY_TYPE         || '0004'X || CKK_AES   ;
UWK_attribute_list_len    = D2C(LENGTH(UWK_attribute_list),4);
 Call CSFPUWK;

/*  - Decrypt "Hello World" with the unwrapped key                   */
SKD_rule_array_count      = '00000002'X;
/* Using the CBC-PAD option defaults the chaining selection to ONLY  */
SKD_rule_array            = 'AES     CBC-PAD ';
SKD_key_handle            = Left(UWK_target_key_handle,44) ;
SKD_iv_length             = '00000010'X;
SKD_iv                    = '';
SKD_chain_data_len        = '00000080'X;
SKD_chain_data            = COPIES('00'X,C2D(SKD_chain_data_len));
SKD_clear_text            = COPIES('00'X,C2D(SKE_cipher_text_len));
SKD_clear_text_len        = SKE_cipher_text_len;
SKD_cipher_text_len       = D2C(LENGTH(SKE_cipher_text),4);
SKD_cipher_text           = SKE_cipher_text;
 Call CSFPSKD;

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

exit;

/* --------------------------------------------------------------- */
/* CSFPGKP - PKCS #11 Generate Key Pair                            */
/*                                                                 */
/* Generates an asymmetric key pair.                               */
/*                                                                 */
/* See the ICSF Application Programmer's Guide for more details.   */
/* --------------------------------------------------------------- */
CSFPGKP:

 GKP_RC = 'FFFFFFFF'x
 GKP_RS = 'FFFFFFFF'x
 GKP_Exit_Length = '00000000'x
 GKP_Exit_Data = ''
 GKP_Handle = Left(Token_Handle,44)
 GKP_Rule_Count = '00000000'x
 GKP_Rule_Array = ''

 address linkpgm 'CSFPGKP'                                       ,
                 'GKP_RC'                    'GKP_RS'            ,
                 'GKP_Exit_Length'           'GKP_Exit_Data'     ,
                 'GKP_Handle'                                    ,
                 'GKP_Rule_Count'            'GKP_Rule_Array'    ,
                 'GKP_PubKey_Attr_List_Length'                   ,
                 'GKP_PubKey_Attr_List'                          ,
                 'GKP_PubKey_Handle'                             ,
                 'GKP_PrivKey_Attr_List_Length'                  ,
                 'GKP_PrivKey_Attr_List'                         ,
                 'GKP_PrivKey_Handle'

 if (GKP_rc /= '00000000'x) Then
  do
   say "GKP Failed: RC =" c2x(GKP_rs) "RS =" c2x(GKP_rs)
   exit
  end
 else
   do
     say '  Private key handle:' GKP_PrivKey_Handle
     say '  Public key handle:' GKP_PubKey_Handle
   end

return

/* --------------------------------------------------------------- */
/* CSFPGSK - PKCS #11 Generate Secret Key                          */
/*                                                                 */
/* Generates a symmetric key.                                      */
/*                                                                 */
/* See the ICSF Application Programmer's Guide for more details.   */
/* --------------------------------------------------------------- */
CSFPGSK:

   GSK_RC           = 'FFFFFFFF'x ;
   GSK_RS           = 'FFFFFFFF'x ;
   GSK_Exit_Length  = '00000000'x ;
   GSK_Exit_Data    = '' ;
   GSK_Rule_Count   = '00000001'x;
   GSK_Rule_Array   = 'KEY     ';
   GSK_Handle       = Left(Token_Handle,44) ;
   GSK_Parms_List = ''
   GSK_Parms_List_Length = '00000000'x

   address linkpgm 'CSFPGSK'                                   ,
                   'GSK_RC'                'GSK_RS'            ,
                   'GSK_Exit_Length'       'GSK_Exit_Data'     ,
                   'GSK_Handle'                                ,
                   'GSK_Rule_Count'        'GSK_Rule_Array'    ,
                   'GSK_AttrListLength'    'GSK_AttrList'      ,
                   'GSK_Parms_List_Length' 'GSK_Parms_List'    ;

 if (GSK_rc /= '00000000'x) Then
  do
   say "GSK Failed: RC =" c2x(GSK_rs) "RS =" c2x(GSK_rs)
   exit
  end
 else
   do
     say '  Secret key handle:' GSK_Handle
   end

return

/* --------------------------------------------------------------- */
/* CSFPGAV - PKCS #11 Get Attribute Value                          */
/*                                                                 */
/* Retrieves the attributes of an object.                          */
/*                                                                 */
/* See the ICSF Application Programmer's Guide for more details.   */
/* --------------------------------------------------------------- */
CSFPGAV:

gav_rc          = 'FFFFFFFF'x
gav_rs          = 'FFFFFFFF'x
gav_exit_length = '00000000'x
gav_exit_data   = ''
gav_rule_count  = '00000000'x
gav_rule_array  = ''

ADDRESS LINKPGM 'CSFPGAV'                                         ,
                'gav_rc'                 'gav_rs'                 ,
                'gav_exit_length'        'gav_exit_data'          ,
                'gav_handle'                                      ,
                'gav_rule_count'         'gav_rule_array'         ,
                'gav_attr_list_length'   'gav_attr_list'

IF (gav_rc /= '00000000'x) THEN
  DO
    SAY 'GAV Failed   (rc=' C2X(gav_rc)' rs='C2X(gav_rs)')'
    EXIT
  END

/* Parse the output */
num_attributes = c2d(substr(gav_attr_list,1,2))
index = 3
/* DO i = 1 TO num_attributes  */
DO i = 1 TO num_attributes
  tag    = substr(gav_attr_list,index,4)
  length = c2d(substr(gav_attr_list,index+4,2))
  value  = substr(gav_attr_list,index+6,length)

  IF tag = CKA_MODULUS_BITS THEN
    DO
      say "modulus size:" c2d(value)
    END
  IF tag = CKA_MODULUS THEN
    DO
      say "modulus:" c2x(value)
    END
  IF tag = CKA_PUBLIC_EXPONENT THEN
    DO
      say "public exponent:" c2x(value)
    END
  index = index + 6 + length
END

RETURN

/* --------------------------------------------------------------- */
/* CSFPTRC - PKCS #11 Token Record Create                          */
/*                                                                 */
/* Initializes a PKCS #11 token, creates or copies token or        */
/* session objects.                                                */
/*                                                                 */
/* See the ICSF Application Programmer's Guide for more details.   */
/* --------------------------------------------------------------- */
CSFPTRC:

TRC_rc           = 'FFFFFFFF'x
TRC_rs           = 'FFFFFFFF'x
TRC_exit_length  = '00000000'x
TRC_exit_data    = ''
TRC_handle       = token_handle

ADDRESS linkpgm 'CSFPTRC'                                     ,
                'TRC_rc'                'TRC_rs'              ,
                'TRC_exit_length'       'TRC_exit_data'       ,
                'TRC_handle'                                  ,
                'TRC_rule_count'        'TRC_rule_array'      ,
                'TRC_attr_list_length'  'TRC_attr_list'

if (TRC_rc /= '00000000'x) then
  do
   say "TRC Failed: RC =" c2x(TRC_rc) "RS =" c2x(TRC_rs)
   exit
  end

return

/* --------------------------------------------------------------- */
/* CSFPTRL - PKCS #11 Token Record List                            */
/*                                                                 */
/* Lists PKCS #11 tokens or objects.                               */
/*                                                                 */
/* See the ICSF Application Programmer's Guide for more details.   */
/* --------------------------------------------------------------- */
CSFPTRL:

TRL_RC              = 'FFFFFFFF'x ;
TRL_RS              = 'FFFFFFFF'x ;
TRL_Exit_Length     = '00000000'x ;
TRL_Exit_Data       = '' ;

address linkpgm 'CSFPTRL'                                    ,
                'TRL_RC'               'TRL_RS'              ,
                'TRL_Exit_Length'      'TRL_Exit_Data'       ,
                'TRL_Handle'                                 ,
                'TRL_Rule_Count'       'TRL_Rule_Array'      ,
                'TRL_srch_tmpl_Length' 'TRL_srch_tmpl'       ,
                'TRL_List_Length'      'TRL_Handle_Count'    ,
                'TRL_Output_List'

if (TRL_rc /= '00000000'x) then
  do
   say "TRL Failed: RC =" c2x(TRL_rc) "RS =" c2x(TRL_rs)
   exit
  end

return

/* --------------------------------------------------------------- */
/* CSFPTRD - PKCS #11 Token Record Delete                          */
/*                                                                 */
/* Deletes a PKCS #11 token, token object, session object or state */
/* object.                                                         */
/*                                                                 */
/* See the ICSF Application Programmer's Guide for more details.   */
/* --------------------------------------------------------------- */
CSFPTRD:

TRD_rc           = 'FFFFFFFF'x
TRD_rs           = 'FFFFFFFF'x
TRD_exit_length  = '00000000'x
TRD_exit_data    = ''
TRD_rule_count   = '00000001'x
TRD_rule_array   = 'TOKEN   '

ADDRESS linkpgm 'CSFPTRD'                                   ,
                'TRD_rc'              'TRD_rs'              ,
                'TRD_exit_length'     'TRD_exit_data'       ,
                'TRD_handle'                                ,
                'TRD_rule_count'      'TRD_rule_array'

if (TRD_rc /= '00000000'x) & ,
   ^(TRD_rc = '00000008'x & TRD_rs = '00000BD3'x) then
   say "TRD Failed: RC =" c2x(TRD_rc) "RS =" c2x(TRD_rs)

return
/*********************************************************************/
/* Encrypt using the AES-128 key                                     */
/*********************************************************************/
/* --------------------------------------------------------------- */
/* CSFPSKE - PKCS #11 Secret Key Encrypt                           */
/*                                                                 */
/* Encrypts plain text into cipher text using the AES 128 bit key  */
/* generated earlier in the sample.                             */
/*                                                                 */
/* See the ICSF Application Programmer's Guide for more details.   */
/* --------------------------------------------------------------- */
CSFPSKE:
SKE_RC                    = 'FFFFFFFF'X;
SKE_RS                    = 'FFFFFFFF'X;
SKE_clear_text_len        = D2C(LENGTH(SKE_clear_text),4);
SKE_clear_text_id         = '00000000'X;
SKE_cipher_text_len       = '00000010'X;;
SKE_cipher_text           = COPIES('00'X,C2D(SKE_cipher_text_len));
SKE_cipher_text_id        = '00000000'X;
SKE_exit_length           = '00000000'x ;
SKE_exit_data             = '' ;
say 'Text to Encrypt:' SKE_clear_text
ADDRESS LINKPGM 'CSFPSKE'                               ,
                'SKE_RC'               'SKE_RS'         ,
                'SKE_exit_length'      'SKE_exit_data'  ,
                'SKE_rule_array_count' 'SKE_rule_array' ,
                'SKE_key_handle'                        ,
                'SKE_iv_length'        'SKE_iv'         ,
                'SKE_chain_data_len'   'SKE_chain_data' ,
                'SKE_clear_text_len'   'SKE_clear_text' ,
                'SKE_clear_text_id'                     ,
                'SKE_cipher_text_len'  'SKE_cipher_text',
                'SKE_cipher_text_id'                    ;
if (SKE_rc /= '00000000'x) then
   say "SKE Failed: RC =" c2x(SKE_rc) "RS =" c2x(SKE_rs)
else
   say "Cipher text:" c2x(SKE_cipher_text)

return

/*********************************************************************/
/* Wrap the 128 bit AES key with the RSA Public key                  */
/*********************************************************************/
/* --------------------------------------------------------------- */
/* CSFPWPK - PKCS #11 Wrap Key                                     */
/*                                                                 */
/* Wraps the generated AES 128 bit key with the RSA public key that*/
/* was previously created.                                         */
/*                                                                 */
/* See the ICSF Application Programmer's Guide for more details.   */
/* --------------------------------------------------------------- */
CSFPWPK:

WPK_RC                    = 'FFFFFFFF'X;
WPK_RS                    = 'FFFFFFFF'X;;
WPK_init_vector_length    = '00000000'x;
WPK_init_vector           = '';
WPK_wrapped_key_length    = '00000180'X;
WPK_wrapped_key           = COPIES('00'X,C2D(WPK_wrapped_key_length));
WPK_Exit_Length           = '00000000'x ;
WPK_Exit_Data             = '' ;

ADDRESS LINKPGM 'CSFPWPK'                                      ,
                'WPK_RC'                 'WPK_RS'              ,
                'WPK_exit_data_length'   'WPK_exit_data'       ,
                'WPK_rule_array_count'   'WPK_rule_array'      ,
                'WPK_source_key_handle'                        ,
                'WPK_wrapping_key_handle'                      ,
                'WPK_init_vector_length' 'WPK_init_vector'     ,
                'WPK_wrapped_key_length' 'WPK_wrapped_key'     ;

if (WPK_rc /= '00000000'x) then
   say "WPK Failed: RC =" c2x(WPK_rc) "RS =" c2x(WPK_rs)

say 'Wrapped key' c2x(WPK_wrapped_key)
return

/*********************************************************************/
/* Unwrap the 128 bit AES key with the RSA Private key               */
/*********************************************************************/
/* --------------------------------------------------------------- */
/* CSFPUWK - PKCS #11 Unwrap Key                                   */
/*                                                                 */
/* Unwraps the AES 128 bit key using the RSA private key           */
/*                                                                 */
/* See the ICSF Application Programmer's Guide for more details.   */
/* --------------------------------------------------------------- */
CSFPUWK:

UWK_RC                    = 'FFFFFFFF'X;
UWK_RS                    = 'FFFFFFFF'X;
UWK_init_vector_length    = '000000000'x;
UWK_init_vector           = '';
UWK_Exit_Length           = '00000000'x ;
UWK_Exit_Data             = '' ;
UWK_target_key_handle     = Left('',44) ;

ADDRESS LINKPGM 'CSFPUWK'                                      ,
                'UWK_RC'                 'UWK_RS'              ,
                'UWK_exit_data_length'   'UWK_exit_data'       ,
                'UWK_rule_array_count'   'UWK_rule_array'      ,
                'UWK_wrapped_key_length' 'UWK_wrapped_key'     ,
                'UWK_init_vector_length' 'UWK_init_vector'     ,
                'UWK_unwrapping_key_handle'                    ,
                'UWK_attribute_list_len' 'UWK_attribute_list' ,
                'UWK_target_key_handle'                      ;

if (UWK_rc /= '00000000'x) then
   say "UWK Failed: RC =" c2x(UWK_rc) "RS =" c2x(UWK_rs)

return

/*********************************************************************/
/* Decrypt using the AES-128 key                                     */
/*********************************************************************/
/* --------------------------------------------------------------- */
/* CSFPSKD - PKCS #11 Secret Key Decrypt                           */
/*                                                                 */
/* Decrypts cipher text into plain text using the AES 128 bit key  */
/* that was unwrapped earlier in the sample.                       */
/*                                                                 */
/* See the ICSF Application Programmer's Guide for more details.   */
/* --------------------------------------------------------------- */
CSFPSKD:
SKD_RC                    = 'FFFFFFFF'X;
SKD_RS                    = 'FFFFFFFF'X;
SKD_cipher_text_id        = '00000000'X;
SKD_clear_text_id         = '00000000'X;
SKD_Exit_Length           = '00000000'x ;
SKD_Exit_Data             = '' ;
ADDRESS LINKPGM 'CSFPSKD'                               ,
                'SKD_RC'               'SKD_RS'         ,
                'SKD_exit_data_length' 'SKD_exit_data'  ,
                'SKD_rule_array_count' 'SKD_rule_array' ,
                'SKD_key_handle'                        ,
                'SKD_iv_length'        'SKD_iv'         ,
                'SKD_chain_data_len'   'SKD_chain_data' ,
                'SKD_cipher_text_len'  'SKD_cipher_text',
                'SKD_cipher_text_id'                    ,
                'SKD_clear_text_len'   'SKD_clear_text' ,
                'SKD_clear_text_id'                     ;
if (SKD_rc /= '00000000'x) then
   say "SKD Failed: RC =" c2x(SKD_rc) "RS =" c2x(SKD_rs)
Else
   say "Decrypted Text:" SKD_clear_text

return

NOVALUE:
SAY "Condition NOVALUE was raised."
SAY CONDITION("D") "variable was not initialized."
SAY SOURCELINE(sigl)
EXIT;

0 comments
17 views

Permalink