RSA BSAFE Crypto-C

Cryptographic Components for C

Search

intelrnd.c

/* $Id: intelrnd.c,v 1.8 2004/12/03 02:08:40 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 series of random values using the
 * Intel hardware random device.  You must link with sec32ipi.lib.
 */

#include "bsafe.h"
#include "demoutil.h"  /* in samples/common/include */

#define BYTES_TO_GENERATE 128

/* GenerateSeed will place a random seed in seedBytes.  The amount of
 * data placed in seedBytes will be less than or equal to
 * seedMaxLength.  If the Intel hardware random number generator is
 * not available, then GenerateSeed will fall back to gathering seed
 * data from the user.
 */
int GenerateSeed(unsigned char *seedBytes, unsigned int seedMaxLength)
{
  int status;
  B_ALGORITHM_OBJ randomAlgorithm = (B_ALGORITHM_OBJ)NULL_PTR;

#if RSA_PLATFORM == RSA_I386_486
  POINTER *oemTagList = (POINTER *)NULL_PTR;
  B_ALGORITHM_METHOD *CHOOSER[] = {
                (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
        };

  /* The software chooser.  The AM_HW_RANDOM method in this chooser
     will be replaced with the hardware method. */
  B_ALGORITHM_METHOD *SOFTWARE_CHOOSER[] = {
    &AM_HW_RANDOM,
    (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 table lists the hardware algorithm methods that could be
     available.  This list isn't the list of algorithms that will be
     used.  That is determined by the hardware availablity. */
  HW_TABLE_ENTRY *HARDWARE_CHOOSER[] = {
    &HW_INTEL_RANDOM,
    (HW_TABLE_ENTRY *)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

  };



  unsigned int index, intelHardwarePresent = 0;
#endif

  do {
    /* Create the session chooser.  This call will combine the
       elements of the software chooser, with those in the hardware
       chooser.  For each item in the software chooser that references
       a hardware method, the hardware method replaces it.

       This function will associate a hardware method with a software
       method so that when a software method is called, it turns to
       the hardware.  In this case, HW_INTEL_RANDOM will be called
       when AM_HW_RANDOM is referenced.

       If more than one hardware method can be matched to a single
       software method, then the hardware method listed first in the
       hardware chooser is associated with that software method.  The
       list can be modified at run time by creating the hardware
       chooser at run time. */
#if RSA_PLATFORM == RSA_I386_486
    if ((status = B_CreateSessionChooser (SOFTWARE_CHOOSER, &CHOOSER,
                                          (POINTER *)HARDWARE_CHOOSER,
                                          (ITEM *)NULL_PTR,
                                          (POINTER *)NULL_PTR,
                                          &oemTagList)) != 0)
      break;

    RSA_PrintMessage ("Session chooser successfully created.\n");
    RSA_PrintMessage ("OEM tag(s) returned by B_CreateSessionChooser:\n");
    index = 0;
    do {
      status = T_strcmp ((char *)oemTagList[index], "AM_HW_RANDOM.com.Intel");
      if (status == 0)
        intelHardwarePresent = 1;
      RSA_PrintMessage ("     %s\n", oemTagList[index++]);
    } while (oemTagList[index] != NULL_PTR);
    RSA_PrintMessage ("End of OEM tag list.\n");
    if (intelHardwarePresent) {
      RSA_PrintMessage ("Intel hardware found.  Continuing.\n");
    } else {
      RSA_PrintMessage ("Intel hardware not found.  Using software.\n");
      status = 1; break;
    }

    /* Create the algorithm object.  This object will
       "control" the random byte generation, storing any state that
       needs to be stored. */
    if ((status = B_CreateAlgorithmObject (&randomAlgorithm)) != 0)
      break;
    RSA_PrintMessage ("Created the random algorithm object.\n");

    /* Set the algorithm info.  We will specify AI_HW_Random,
       which will point to the hardware method that was associated to
       AI_HW_Random in the call to B_CreateSessionChooser. */
    if ((status = B_SetAlgorithmInfo (randomAlgorithm, AI_HW_Random,
                                      NULL_PTR)) != 0)
      break;
    RSA_PrintMessage ("Set the algorithm info.\n");

    /* Initialize randomAlgorithm to generate random bytes.
       Here we pass the CHOOSER that was created in the call to
       B_CreateSessionChooser above.  This chooser contains pointers
       to the hardware method that was associated with
       AI_HW_Random.

       If the Intel hardware was not available, then we will fall back
       to gathering the seed from the user. */
    if ((status = B_RandomInit (randomAlgorithm, CHOOSER,
                                (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;
    RSA_PrintMessage ("Initialized the random algorithm object for\n");
    RSA_PrintMessage ("random number generation.\n");

    /* Generate the random bytes.  Here we are asking the
       Crypto-C SDK to generate some 64 random bytes, storing the data
       in seedBytes.  The last parameter is a surrender context.  In
       this case, generating 64 random bytes should be very quick, so
       we will pass in a properly cast NULL_PTR. */
    if ((status = B_GenerateRandomBytes (randomAlgorithm, seedBytes,
                                         seedMaxLength,
                                         (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    /* Destroy the algorithm object.  This step will free any
       allocated memory used by randomAlgorithm.  The memory is
       zeroized before it is deallocated, so that potentially
       sensitive information is not left in memory. */
    B_DestroyAlgorithmObject (&randomAlgorithm);
    RSA_PrintMessage ("Destroyed random algorithm object.\n");

    /* Free the session chooser.  It is important to free the
       session chooser, so that any handles to hardware and allocated
       memory are released. */
    if ((status = B_FreeSessionChooser (&CHOOSER, &oemTagList)) != 0)
      break;
    RSA_PrintMessage ("Free'd session chooser.\n");
#else
    status = RSA_DEMO_E_NOT_IMPLEMENTED;
    break;
#endif
  } while (0);

  /* If an error has ocurred, then print out a summary of the error. */
  if (status != 0) {
    /* There's been an error.  Return the status code. */
    RSA_PrintError ("Intel RNG unavailable!\n", 0);

    /* Print out the extended error information, if available.  This
       information will give us a better idea of what went wrong with
       the hardware. */
    {
      ITEM errorData = {NULL, 0};
      POINTER am = NULL;

      /* Call B_GetExtendedErrorInfo to retrieve the error information.
         The data returned in the data field of errorData is a structure
         of A_RSA_EXTENDED_ERROR type.  The third parameter will contain
         a pointer to the alorithm method (AM) that was in use when the
         error was encountered. */
      if (randomAlgorithm != NULL)
        B_GetExtendedErrorInfo (randomAlgorithm, &errorData, &am);

#if RSA_PLATFORM == RSA_I386_486
      if (am == (POINTER)&HW_INTEL_RANDOM) {
        /* Print out the error information. */
        RSA_PrintMessage ("Code: %d\n",
                          ((A_RSA_EXTENDED_ERROR *)errorData.data)->errorCode);
        RSA_PrintMessage ("Message: %s",
                          ((A_RSA_EXTENDED_ERROR *)errorData.data)->errorMsg);
      }
#endif
    }

    /* Try the following to deallocate and clear any memory properly. */
    B_DestroyAlgorithmObject (&randomAlgorithm);

#if RSA_PLATFORM == RSA_I386_486
    if ((CHOOSER != (B_ALGORITHM_METHOD **)NULL_PTR) ||
        (oemTagList != (POINTER *)NULL_PTR))
      B_FreeSessionChooser (&CHOOSER, &oemTagList);
#endif

    /* An error occurred, so it is necessary to request a seed
       directly from the user.  In this case, we will demonstrate the
       less secure method of having the user type in the seed.  A better
       method would use the intra-keystroke timings along with mouse
       movement timings. */
    RSA_PrintMessage ("Please type a seed (%d chars max): ", seedMaxLength);
    RSA_GetCommand ((char *)seedBytes, seedMaxLength, NULL);
  }

  RSA_PrintBuf ("Random seed", seedBytes, seedMaxLength);

  return (seedMaxLength);
}  /* end GenerateSeed */

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

int MAIN(int argc, char *argv[])
{
  B_ALGORITHM_OBJ randomAlgorithm = (B_ALGORITHM_OBJ)NULL_PTR;
  unsigned char *randomSeed = NULL_PTR;
  unsigned int randomSeedLen = 0;
  unsigned char *randomByteBuffer = NULL_PTR;
  int status;

  B_ALGORITHM_METHOD *RANDOM_CHOOSER[] = {
    &AM_SHA_RANDOM,
    (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

  };

  do {
    /* 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 ("Generating random bytes.\n");

    /* Create a random algorithm object. */
    if ((status = B_CreateAlgorithmObject (&randomAlgorithm)) != 0)
      break;

    /* Set the random algorithm object to SHA1. */
    if ((status = B_SetAlgorithmInfo (randomAlgorithm, AI_SHA1Random,
                                      NULL_PTR)) != 0)
      break;

    /* Initialize the random algorithm. */
    if ((status = B_RandomInit (randomAlgorithm, RANDOM_CHOOSER,
                                (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    /* Get a random seed, and pass it to the random algorithm
       object.  This seed will be generated by the Intel hardware
       random device.  If the device cannot be found, or fails during
       processing, we will request that the user enters a seed
       value. */
    RSA_PrintMessage ("Getting seed value.\n");
    randomSeedLen = BYTES_TO_GENERATE;
    randomSeed = (unsigned char *)T_malloc (randomSeedLen);
    GenerateSeed (randomSeed, randomSeedLen);

    /* Now we have a random seed and its length.  Pass both
       into B_RandomUpdate. */
    if ((status = B_RandomUpdate (randomAlgorithm, randomSeed, randomSeedLen,
                                  (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    /* Generate.  First, prepare a buffer for receiving the
       random bytes before calling B_GenerateRandomBytes. */
    randomByteBuffer = T_malloc (BYTES_TO_GENERATE);
    if (randomByteBuffer == NULL_PTR) {
      status = RSA_DEMO_E_ALLOC;
      break;
    }

    RSA_PrintMessage ("Generated random bytes.\n");

    T_memset (randomByteBuffer, 0, BYTES_TO_GENERATE);

    if ((status = B_GenerateRandomBytes (randomAlgorithm, randomByteBuffer,
                                         BYTES_TO_GENERATE,
                                         (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    RSA_PrintBuf ("Random data", randomByteBuffer, BYTES_TO_GENERATE);
  } while (0);

  if (status != 0)
    RSA_PrintError ("intelrnd", status);

  /*  Remember to destroy all objects, and free all memory  */
  B_DestroyAlgorithmObject (&randomAlgorithm);

  if (randomSeed != NULL_PTR)
  {
    T_memset (randomSeed, 0, randomSeedLen);
    T_free (randomSeed);
  }

  if (randomByteBuffer != NULL_PTR)
    T_free (randomByteBuffer);

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

#if RSA_PLATFORM == RSA_I386_486
/* This function is required to link properly when using the Intel
 * hardware random device.  In this case, though, we will not use the
 * function, so we will return a 0, to indicate success.
 */
int T_GetDynamicList(HW_TABLE_LIST *hardwareTable, POINTER *tagList)
{
  /* These arguments are not used and are only included to suppress
     some compiler warnings. */
  UNUSED_ARG(hardwareTable);
  UNUSED_ARG(tagList);

  return 0;
}
#endif

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