RSA BSAFE Crypto-C

Cryptographic Components for C

Search

p11rsaencrypt.c

/* $Id: p11rsaencrypt.c,v 1.7 2004/12/03 02:08:39 sparki Exp $ */
/*
 * Copyright (C) 1998-2004 RSA Security Inc.
 *
 * This file shall only be used to demonstrate how to interface to an
 * RSA Security Inc. licensed development product.
 *
 * You have a royalty-free right to use, reproduce and distribute this
 * demonstration file, provided that you agree that RSA Security Inc.
 * has no warranty, implied or otherwise, or liability for this
 * demonstration file (including any modified version).  This software
 * is provided "as is" without warranties or representations of any
 * kind. RSA Security disclaims all conditions and warranties, statutory
 * and otherwise, both express and implied, with respect to the software,
 * its quality and performance, including but not limited to, all
 * implied warranties of merchantability, fitness for a particular
 * purpose, title and noninfringement of third party rights. Without
 * limiting the foregoing, RSA Security does not warrant that the
 * software is error-free or that errors in the product will be
 * corrected. You agree that RSA Security shall not be liable for any
 * direct, indirect, incidental, special, consequential, punitive or
 * other damages whatsoever resulting from your use of this software
 * or any modified version.
 *
 *
 */

/*  This program will generate a RSA keypair, then use the given hardware
 *  to encrypt and decrypt data using this keypair.
*/

#include "bsafe.h"
#include "demoutil.h"  /* in samples/common/include */
#include "bsfutil.h"   /* in samples/common/include */
#include "surrctx.h"   /* in samples/common/include */
#include "rsautil.h"   /* in samples/pkalg/rsa */

#define RSA_MODULUS_BITS 512
#define MAX_RSA_MODULUS_BITS 2048
#define MAX_BLOCK_SIZE ((MAX_RSA_MODULUS_BITS + 7) / 8)


#ifdef CRYPTOC_APP
#define MAIN p11rsaencryptMain
#else
#define MAIN main
#endif

int MAIN(int argc, char *argv[])
{
  B_ALGORITHM_OBJ randomAlgorithm = (B_ALGORITHM_OBJ)NULL_PTR;
  B_ALGORITHM_OBJ rsaEncryptor = (B_ALGORITHM_OBJ)NULL_PTR;
  B_ALGORITHM_OBJ rsaDecryptor = (B_ALGORITHM_OBJ)NULL_PTR;
  B_KEY_OBJ publicKey = (B_KEY_OBJ)NULL_PTR;
  B_KEY_OBJ privateKey = (B_KEY_OBJ)NULL_PTR;

  A_SURRENDER_CTX generalSurrenderContext;
  int generalFlag;

  ITEM *cryptocPublicKeyBER;
  ITEM myPublicKeyBER = {NULL, 0};

  ITEM *getPrivateKey;
  ITEM privateKeyBER = {NULL, 0};

  /* This could be a DES or RC4 key, for example: */
  unsigned char dataToEncryptWithRSA[] = {
    0x4a, 0x72, 0x55, 0x36, 0xda, 0x2f, 0xb9, 0x51
  };

  unsigned int dataToEncryptLen = sizeof(dataToEncryptWithRSA);

  unsigned char encryptedData[MAX_BLOCK_SIZE];
  unsigned char decryptedData[MAX_BLOCK_SIZE];
  unsigned int outputLenUpdate, outputLenFinal, outputLenTotal;

  int status;

  char userInput[RSA_DEMO_MAX_LINE_LEN];

  /*  Stores the device (hardware or software) that is
   *  being used */
  ITEM deviceName = {NULL, 0};

  /*  Contains the information needed to connect to the hardware */
  B_PKCS11_SESSION p11Session;
  ITEM passphrase = {NULL, 0};
  unsigned char *tokenLabel = NULL;
  unsigned int libraryNameLen = 0;

  ITEM publicBER = {NULL, 0};
  KI_TOKEN_INFO privateToken = {NULL, 0, NULL, 0};
  KI_TOKEN_INFO *tokenInfo = NULL;

  /*  This chooser contains the AMs to be used by the hardware.  Since some
   *  platforms do not support public key operations, (normally public key
   *  operations are faster in software), the software AMs for the public key
   *  operations are used.
   */
  B_ALGORITHM_METHOD *RSA_GEN_HW_CHOOSER[] = {
    (B_ALGORITHM_METHOD *)&AM_PKCS11_RSA_PRIVATE_DECRYPT,
    &AM_RSA_ENCRYPT,
    &AM_SHA,
    (B_ALGORITHM_METHOD *)NULL_PTR
    /* This will fix a problem that the IA64 compiler finds when *
                 * seeing a short chooser list */
                #ifdef IA64_FORCE_LARGE
                                IA64_FORCE_LARGE
                #endif

  };

  /*  This chooser contains the AMs to be used if the hardware AMs are not
   *  available.  Be careful not to insert two AMs that are for the same
   *  operation as the new chooser will take the AM that is first and if
   *  this is not the one that is needed an error will be generated.
   */
  B_ALGORITHM_METHOD *RSA_GEN_SW_CHOOSER[] = {
    &AM_SHA,
    &AM_SHA_RANDOM,
    &AM_RSA_KEY_GEN,
    &AM_RSA_ENCRYPT,
    &AM_RSA_CRT_DECRYPT,
    (B_ALGORITHM_METHOD *)NULL_PTR
    /* This will fix a problem that the IA64 compiler finds when *
                 * seeing a short chooser list */
                #ifdef IA64_FORCE_LARGE
                                IA64_FORCE_LARGE
                #endif

  };

  /*  This contains the new chooser that is generated */
  B_ALGORITHM_CHOOSER hwChooserGen = (B_ALGORITHM_CHOOSER)NULL_PTR;

  /* see samples/common/source/surrctx.c for RSA_GeneralSurrenderFunction */
  generalSurrenderContext.Surrender = RSA_GeneralSurrenderFunction;
  generalSurrenderContext.handle = (POINTER)&generalFlag;
  generalSurrenderContext.reserved = NULL_PTR;

  do {
    /* Initialize these fields to facilitate graceful cleanup on
       error conditions. */
    T_memset ((POINTER)&p11Session, 0, sizeof (p11Session));

    /* The RSA_* demo code utilities are described in
       common/include/demoutil.h.  This procedure simply checks the
       command-line arguments for input or output options. */
    if ((status = RSA_SetOptions (argc, argv)) != 0)
      break;

    RSA_PrintMessage ("RSA PKCS #11 Encryption Algorithm\n");
    RSA_PrintMessage ("=================================\n");

    /* The information needed in order to access the hardware platform */
    p11Session.sessionHandle = 0;

    /* We could supply a CK_FUNCTION_LIST for the device we want this
       B_PKCS11_SESSION information to identify.  However, we specify
       NULL here to indicate that Crypto-C should obtain the CK_FUNCTION_LIST
       using the libraryName and tokenLabel to identify the device for this
       session. */
    p11Session.cryptokiFunctions = NULL_PTR;

    /* This name will be the one that Crypto-C tries to load with, for
       example, LoadLibrary.  */
    RSA_PrintMessage ("Enter name of PKCS #11 shared library");
    if ((status = RSA_GetCommand (userInput, sizeof (userInput),
                                  " (blank to omit)")) != 0)
      break;

    /* p11Session.libraryName should be a NUL-terminated string */
    libraryNameLen = T_strlen (userInput) + 1;
    p11Session.libraryName = (char *)T_malloc (libraryNameLen);
    if (p11Session.libraryName == NULL) {
      status = RSA_DEMO_E_ALLOC;
      break;
    }

    T_memcpy ((unsigned char *)p11Session.libraryName, (unsigned char *)userInput,
               libraryNameLen);

    RSA_PrintMessage ("Enter token name");
    if ((status = RSA_GetCommand (userInput, sizeof (userInput),
                                  " (blank to omit)")) != 0)
      break;

    if (userInput[0] != '\0') {
      p11Session.tokenLabel.len = T_strlen (userInput);
      tokenLabel = T_malloc (p11Session.tokenLabel.len);

      /* We don't want to free p11Session.tokenLabel ourselves, since
         in the case where no token name is supplied, Crypto-C places
         its own buffer in p11Session.tokenLabel.data */
      p11Session.tokenLabel.data = tokenLabel;
      if (p11Session.tokenLabel.data == NULL) {
        status = RSA_DEMO_E_ALLOC;
        break;
      }

      T_memcpy ((unsigned char *)p11Session.tokenLabel.data, (unsigned char *)userInput,
                p11Session.tokenLabel.len);
    }

    RSA_PrintMessage ("Enter passphrase or PIN to access PKCS #11 device");
    if ((status = RSA_GetCommand (userInput, sizeof (userInput),
                                  " (blank to omit)")) != 0)
      break;

    if (userInput[0] != '\0') {
      p11Session.passPhrase.len = T_strlen (userInput);
      p11Session.passPhrase.data = T_malloc (p11Session.passPhrase.len);
      if (p11Session.passPhrase.data == NULL) {
        status = RSA_DEMO_E_ALLOC;
        break;
      }

      T_memcpy ((unsigned char *)p11Session.passPhrase.data, (unsigned char *)userInput,
                p11Session.passPhrase.len);
      T_memset ((unsigned char *)userInput, 0, sizeof (userInput));
    }

    p11Session.surrenderContext = (A_SURRENDER_CTX *)NULL_PTR;

    RSA_PrintBuf ("Data to Encrypt", dataToEncryptWithRSA, dataToEncryptLen);

    if ((status = RSA_CreateRandomAlgorithmObject (&randomAlgorithm)) != 0)
      break;

    if ((status = B_CreateHardwareChooser
       (RSA_GEN_HW_CHOOSER, &hwChooserGen,
        RSA_GEN_SW_CHOOSER, HI_PKCS11Session,
        (POINTER)&p11Session)) != 0)
    break;

    /* We can either use the PKCS #11 device as one for hardware key storage
       or a crypto accelerator.  If it's a key storage device, prompt the user
       for the files containing the token information.  We make the assumption
       that the device will not be performing any public key operations; the
       user must supply the public key BER that corresponds to the private key
       token information.  If it's strictly an accelerator, we give the option
       to generate a software keypair and then feed it to the encrypt
       routines. */
    RSA_PrintMessage ("To use a key token, supply the file containing the");
    status = RSA_GetFileToAllocBuffer
               (&privateToken.manufacturerId.data,
                &privateToken.manufacturerId.len,
                " manufacturer ID\n(blank otherwise)");

    if (status != RSA_DEMO_E_CANCEL) {
      /* We want to use a token and have the manufacturer's ID */
      if ((status = RSA_GetFileToAllocBuffer
                      (&privateToken.internalKey.data,
                       &privateToken.internalKey.len,
                       "Enter private key token info (blank to cancel)")) != 0)
        break;

      RSA_PrintMessage ("Enter corresponding public key BER");
      if ((status = RSA_GetFileToAllocBuffer
                      (&publicBER.data, &publicBER.len,
                       " (blank to cancel)")) != 0)
        break;

      if ((status = B_CreateKeyObject (&publicKey)) != 0)
        break;

      if ((status = B_SetKeyInfo (publicKey, KI_RSAPublicBER,
                                  (POINTER)&publicBER)) != 0)
        break;

      if ((status = B_CreateKeyObject (&privateKey)) != 0)
        break;

      if ((status = B_SetKeyInfo (privateKey, KI_Token,
                                  (POINTER)&privateToken)) != 0)
        break;
    } else {
      /* Generate a software keypair.
         The following function is in samples/pkalg/rsa/rsautil.c */
      status = RSA_CreateRSAKeypair (&publicKey, &privateKey,
                                     RSA_MODULUS_BITS, randomAlgorithm);

    }

    if (status != 0)
      break;

    RSA_PrintMessage ("\n   Distributing Your Public Key\n");
    RSA_PrintMessage ("   ============================\n");

    status = B_GetKeyInfo ((POINTER *)&cryptocPublicKeyBER, publicKey,
                           KI_RSAPublicBER);
    if (status == 0) {
      /* We are using a public key which has been set in software */
      myPublicKeyBER.len = cryptocPublicKeyBER->len;
      myPublicKeyBER.data = T_malloc (myPublicKeyBER.len);
      if (myPublicKeyBER.data == NULL_PTR) {
        status = RSA_DEMO_E_ALLOC;
        break;
      }

      T_memcpy (myPublicKeyBER.data, cryptocPublicKeyBER->data,
                myPublicKeyBER.len);

      RSA_PrintMessage ("The public key DER-encoded as X.509\n");
      RSA_PrintBuf ("SubjectPublicKeyInfo type", myPublicKeyBER.data,
                    myPublicKeyBER.len);
    } else
      status = 0; /* not a fatal error */

    RSA_PrintMessage ("   Encrypting with the RSA Public Key\n");
    RSA_PrintMessage ("   ==================================\n");

    /*  Create an Algorithm Object */
    if ((status = B_CreateAlgorithmObject (&rsaEncryptor)) != 0)
      break;

    /*  Set the algorithm object to AI_PKCS_RSAPublic */
    if ((status = B_SetAlgorithmInfo (rsaEncryptor, AI_PKCS_RSAPublic,
                                      NULL_PTR)) != 0)
      break;

    /*  Init -- encrypt with the recipient's public key */
    if ((status = B_EncryptInit (rsaEncryptor, publicKey, hwChooserGen,
                                 (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    /*  Find out which device is doing the signing  */
    if ((status = B_GetDevice (&deviceName, rsaEncryptor)) != 0)
      break;

    RSA_PrintBuf ("Device Used for Encryption",
                  deviceName.data, deviceName.len);

    /*  Update */
    generalFlag = 0;
    if ((status = B_EncryptUpdate (rsaEncryptor, encryptedData,
                                   &outputLenUpdate, sizeof (encryptedData),
                                   dataToEncryptWithRSA, dataToEncryptLen,
                                   randomAlgorithm,
                                   &generalSurrenderContext)) != 0)
      break;

    /*  Final  */
    generalFlag = 0;
    if ((status = B_EncryptFinal (rsaEncryptor,
                                  encryptedData + outputLenUpdate,
                                  &outputLenFinal,
                                  sizeof (encryptedData) - outputLenUpdate,
                                  randomAlgorithm,
                                  &generalSurrenderContext)) != 0)
      break;

    outputLenTotal = outputLenUpdate + outputLenFinal;
    RSA_PrintBuf ("Encrypted Data", encryptedData, outputLenTotal);

    RSA_PrintMessage ("   Decrypting with the RSA Private Key\n");
    RSA_PrintMessage ("   ===================================\n");

    status = B_GetKeyInfo ((POINTER *)&getPrivateKey, privateKey,
                           KI_PKCS_RSAPrivateBER);

    if (status == 0) {
      /* We have a private key which was set in software */
      privateKeyBER.len = getPrivateKey->len;
      privateKeyBER.data = T_malloc (privateKeyBER.len);
      if (privateKeyBER.data == NULL_PTR) {
        status = RSA_DEMO_E_ALLOC;
        break;
      }

      T_memcpy (privateKeyBER.data, getPrivateKey->data,
                privateKeyBER.len);

      RSA_PrintMessage ("The private key encoded as a PKCS #8\n");
      RSA_PrintBuf ("PrivateKeyInfo type", privateKeyBER.data,
                    privateKeyBER.len);
    } else
      status = 0; /* not a fatal error */

    status = B_GetKeyInfo ((POINTER *)&tokenInfo, privateKey, KI_Token);
    if (status == 0) {
      /* We have a private key in hardware */
      RSA_PrintMessage ("\nPrivate key token information\n");
      RSA_PrintBuf ("KI_TOKEN_INFO.manufacturerId",
                    tokenInfo->manufacturerId.data,
                    tokenInfo->manufacturerId.len);
      RSA_PrintBuf ("KI_TOKEN_INFO.internalKey", tokenInfo->internalKey.data,
                    tokenInfo->internalKey.len);
    } else
      status = 0; /* not a fatal error */

    /*  Create an Algorithm Object */
    if ((status = B_CreateAlgorithmObject (&rsaDecryptor)) != 0)
      break;

    /*  Set the algorithm object to AI_PKCS_RSAPrivate */
    if ((status = B_SetAlgorithmInfo (rsaDecryptor, AI_PKCS_RSAPrivate,
                                      NULL_PTR)) != 0)
      break;

    /*  Init -- Use the private key associated with the public
                key used to encrypt */
    if ((status = B_DecryptInit (rsaDecryptor, privateKey, hwChooserGen,
                                 (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    /*  Find out which device is doing the decrypting  */
    if ((status = B_GetDevice (&deviceName, rsaDecryptor)) != 0)
      break;

    RSA_PrintBuf ("Device Used for Decryption",
                  deviceName.data, deviceName.len);

    /*  Update */
    generalFlag = 0;
    if ((status = B_DecryptUpdate (rsaDecryptor, decryptedData,
                                   &outputLenUpdate, sizeof (decryptedData),
                                   encryptedData, outputLenTotal, NULL_PTR,
                                   &generalSurrenderContext)) != 0)
      break;

    /*  Final */
    generalFlag = 0;
    if ((status = B_DecryptFinal (rsaDecryptor,
                                  decryptedData + outputLenUpdate,
                                  &outputLenFinal,
                                  sizeof (decryptedData) - outputLenUpdate,
                                  NULL_PTR, &generalSurrenderContext)) != 0)
      break;

    outputLenTotal = outputLenUpdate + outputLenFinal;

    RSA_PrintBuf ("Decrypted Data", decryptedData, outputLenTotal);

    if ((outputLenTotal == dataToEncryptLen) &&
        (T_memcmp (dataToEncryptWithRSA, decryptedData,
                   outputLenTotal)) == 0) {
      RSA_PrintMessage ("Success!  ");
      RSA_PrintMessage ("The decrypted data matches the original data.\n");
    } else {
      RSA_PrintMessage ("The decrypted data does not match the original data.");
      status = RSA_DEMO_E_INFO_DOES_NOT_VERIFY;
    }
  } while (0);

  if (status != 0)
  {
    RSA_PrintError ("pkcs11rsasign", status);
    if (status == BE_KEY_INFO)
    {
      RSA_PrintMessage("This could be due to an error when entering \n");
      RSA_PrintMessage("the token information or the dll library \n");
    }
  }

  /*  Destroy all objects  */
  B_DestroyAlgorithmObject (&randomAlgorithm);
  B_DestroyAlgorithmObject (&rsaEncryptor);
  B_DestroyAlgorithmObject (&rsaDecryptor);
  B_DestroyHardwareChooser (&hwChooserGen);
  B_DestroyKeyObject (&privateKey);
  B_DestroyKeyObject (&publicKey);

  /*  Free up any memory allocated  */
  if (myPublicKeyBER.data != NULL_PTR)
    T_free (myPublicKeyBER.data);

  if (privateKeyBER.data != NULL_PTR)
    T_free (privateKeyBER.data);

  if (publicBER.data != NULL)
    T_free (publicBER.data);

  if (privateToken.manufacturerId.data != NULL)
    T_free (privateToken.manufacturerId.data);

  if (privateToken.internalKey.data!= NULL)
    T_free (privateToken.internalKey.data);

  if (p11Session.libraryName != NULL)
    T_free ((unsigned char *)p11Session.libraryName);

  if (tokenLabel != NULL)
    T_free (tokenLabel);

  if (p11Session.passPhrase.data != NULL)
    T_free (p11Session.passPhrase.data);

  return (status);
} /*  end main  */

Copyright (c) 1999-2005 RSA Security Inc. All rights reserved. 068-001001-6210-001-000 - 6.2.1