RSA BSAFE Crypto-C

Cryptographic Components for C

Search

x931.c

/* $Id: x931.c,v 1.7 2004/12/03 02:08:34 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 sample demonstrates how to perform RSA digital signing and 
 * verifying according to the ANSI X9.31 standard.
*/
#include "bsafe.h"
#include "demoutil.h"  /* in samples/common/include */
#include "surrctx.h"   /* in samples/common/include */

B_ALGORITHM_METHOD *X931_SAMPLE_CHOOSER[] = {
  &AM_X931_RANDOM,
  &AM_SHA,
  &AM_FORMAT_X931,
  &AM_RSA_CRT_X931_ENCRYPT,
  &AM_EXTRACT_X931,
  &AM_RSA_X931_DECRYPT,
  &AM_RSA_STRONG_KEY_GEN,
  (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
};


#define NUMBER_OF_RANDOM_BYTES 128
#define MAX_SEED_BYTES 385

#define RSA_MODULUS_BITS 512
#define BLOCK_SIZE ((RSA_MODULUS_BITS + 7) / 8)

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

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

  ITEM randomSeed = {NULL_PTR, 0};
  unsigned char *randomByteBuffer = NULL_PTR;
  A_X931_RANDOM_PARAMS x931Params;

  A_RSA_KEY_GEN_PARAMS keygenParams;
  A_X931_PARAMS x931params;
  B_SIGN_VERIFY_PARAMS signVerifyParams;

  static unsigned char f4Data[] = {0x01, 0x00, 0x01};

  A_SURRENDER_CTX generalSurrenderContext;
  int generalFlag;

  unsigned char inputData[] = "Sign and verify this sentence";
  unsigned int inputDataLen;

  unsigned char signature[BLOCK_SIZE];
  unsigned int signatureLen;

  int status;

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

  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 ("Digital Signature Generation and Verification in\n");
    RSA_PrintMessage ("compliance with the X9.31 Standard.\n");
    RSA_PrintMessage ("================================================\n");

    /*  Generate random bytes using AI_X931Random.  This AI satisfies
     *  the requirements of independent generation of large and private
     *  prime factors, as specified by the ANSI X.931 standard.
     */

    RSA_PrintMessage ("\nGenerating random bytes\n");
    RSA_PrintMessage ("=======================\n");

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

    /* Set the random algorithm object to use AI_X931Random.
       Before we can call B_SetAlgorithmInfo, we need to prepare the
       X9.31 parameters.  The A_X931_RANDOM_PARAMS structure
       contains two parameters:  the number of independent streams
       of randomness and an ITEM containing random seed data to be
       divided up among the streams. */

    /* Set the number of streams in the A_X931_RANDOM_PARAMS
       structure. */
    x931Params.numberOfStreams = 6;

    /* In order to obtain a seed, we need to allocate space for it,
       and then request it from the user.  Note that the following
       method of seed gathering is insecure.  A real application would
       use a more secure method of seed gathering to ensure the
       security of the application.  */
    randomSeed.data = T_malloc (MAX_SEED_BYTES);
    if (randomSeed.data == NULL_PTR) {
      status = RSA_DEMO_E_ALLOC;
      break;
    }

    /* Prompt the user until enough seed data is provided */
    randomSeed.len = 0;
    do {
      RSA_PrintMessage ("We need at least %d bytes of random seed data.\n",
                        20 * x931Params.numberOfStreams - randomSeed.len);
      RSA_PrintMessage ("Enter a random seed (%d bytes maximum): ",
                        MAX_SEED_BYTES - 1 - randomSeed.len);
      RSA_GetCommand ((char *)randomSeed.data + randomSeed.len,
                      MAX_SEED_BYTES - randomSeed.len, NULL);
      randomSeed.len = T_strlen ((char *)randomSeed.data);

      RSA_PrintBuf ("Random Seed", randomSeed.data, randomSeed.len);

      x931Params.seed.data = randomSeed.data;
      x931Params.seed.len = randomSeed.len;

      /* Specify the required operation and pass the parameters 
             to the algorithm object */
      status = B_SetAlgorithmInfo (randomAlgorithm, AI_X931Random,
                                   (POINTER)&x931Params);

      /* Quit if the buffer is filled, whether or not status is 0 */
      if (randomSeed.len == MAX_SEED_BYTES - 1)
        break;
    } while (status == BE_ALGORITHM_INFO);

    if (status != 0)
      break;

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

    /*  Since the random seed has already been passed in via
        the x931Params structure, we do not have to call
        B_RandomUpdate(). */

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

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

    RSA_PrintBuf ("Random Bytes", randomByteBuffer, NUMBER_OF_RANDOM_BYTES);

    RSA_PrintMessage ("\nGenerating a Keypair (AI_RSAStrongKeyGen)\n");
    RSA_PrintMessage ("====================\n");

    /*  Create the algorithm and key objects  */
    if ((status = B_CreateAlgorithmObject (&keypairGenerator)) != 0)
      break;

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

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

    /*  Specify RSA Strong Key Generation and supply parameters  */
    keygenParams.modulusBits = RSA_MODULUS_BITS;
    keygenParams.publicExponent.data = f4Data;
    keygenParams.publicExponent.len = 3;

    if ((status = B_SetAlgorithmInfo (keypairGenerator, AI_RSAStrongKeyGen,
                                      (POINTER)&keygenParams)) != 0)
      break;

    /*  Initialize using an appropriate routine from the chooser  */
    if ((status = B_GenerateInit (keypairGenerator, X931_SAMPLE_CHOOSER,
                                  (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    /*  Note that the update is not required for key generation  */

    /*  Generate  */
    /*  generalFlag is for the surrender function */
    generalFlag = 0;
    if ((status = B_GenerateKeypair (keypairGenerator, publicKey, privateKey,
                                     randomAlgorithm,
                                     &generalSurrenderContext)) != 0)
      break;

    RSA_PrintMessage ("Key pair successfully generated!\n");

    RSA_PrintMessage ("\nComputing a Digital Signature\n");
    RSA_PrintMessage ("=============================\n");

    inputDataLen = T_strlen ((char *)inputData);

    RSA_PrintBuf ("Data to Sign", inputData, inputDataLen);

    /*  Create an algorithm object */
    if ((status = B_CreateAlgorithmObject (&digitalSigner)) != 0)
      break;

    /*  Set the algorithm object to AI_SignVerify */
    x931params.blockLen = ((RSA_MODULUS_BITS + 7) / 8);
    x931params.oidNum = 3;

    /*  Currently, x931params third parameter: ITEM OID of A_X931_PARAMS
     *  is used only when "formatX931PKCS" is specified in the
     *  formatMethodName in the B_SIGN_VERIFY_PARAMS struct.
     *  In this case, since we are not interested in obtaining the
     *  BER encoding of the OID, we can leave this information uninitialized.
     */
    signVerifyParams.encryptionMethodName = (unsigned char *)"rsaSignX931";
    signVerifyParams.encryptionParams = NULL_PTR;
    signVerifyParams.digestMethodName = (unsigned char *)"sha1";
    signVerifyParams.digestParams = NULL_PTR;
    signVerifyParams.formatMethodName = (unsigned char *)"formatX931";
    signVerifyParams.formatParams = (POINTER)&x931params;

    if ((status = B_SetAlgorithmInfo (digitalSigner, AI_SignVerify,
                                      (POINTER)&signVerifyParams)) != 0)
      break;

    /*  Init */
    if ((status = B_SignInit (digitalSigner, privateKey, X931_SAMPLE_CHOOSER,
                              (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    /*  Update  -- digest the data to sign */
    RSA_PrintMessage ("Digesting the input data...\n");
    if ((status = B_SignUpdate (digitalSigner, inputData, inputDataLen,
                                (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    /*  Final --  Encrypt the digest and output the result to a
                  signature buffer */
    RSA_PrintMessage ("Encrypting the digest...\n");
    if ((status = B_SignFinal (digitalSigner, signature, &signatureLen,
                               sizeof (signature), (B_ALGORITHM_OBJ)NULL_PTR,
                               (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    RSA_PrintBuf ("Digital Signature", signature, signatureLen);

    RSA_PrintMessage ("\nVerifying the Digital Signature\n");
    RSA_PrintMessage ("===============================\n");

    /*  Create an algorithm object */
    if ((status = B_CreateAlgorithmObject (&digitalVerifier)) != 0)
      break;

    /*  Set the algorithm object to the same AI */
    signVerifyParams.encryptionMethodName = (unsigned char *)"rsaVerifyX931";
    signVerifyParams.encryptionParams = NULL_PTR;
    signVerifyParams.digestMethodName = (unsigned char *)"sha1";
    signVerifyParams.digestParams = NULL_PTR;
    signVerifyParams.formatMethodName = (unsigned char *)"formatX931";
    signVerifyParams.formatParams = (POINTER)&x931params;

    if ((status = B_SetAlgorithmInfo (digitalVerifier, AI_SignVerify,
                                      (POINTER)&signVerifyParams)) != 0)
      break;

    /*  Init */
    if ((status = B_VerifyInit (digitalVerifier, publicKey,
                                X931_SAMPLE_CHOOSER,
                                (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    /*  Update */
    if ((status = B_VerifyUpdate (digitalVerifier, inputData, inputDataLen,
                                  (A_SURRENDER_CTX *)NULL_PTR)) != 0)
    break;

    /*  Final */
    generalFlag = 0;
    if ((status = B_VerifyFinal (digitalVerifier, signature, signatureLen,
                                 (B_ALGORITHM_OBJ)NULL_PTR,
                                 &generalSurrenderContext)) != 0)
    break;

  } while (0);

  if (status != 0)
    RSA_PrintError ("x931", status);
  else
    RSA_PrintMessage ("\nSuccess!  Digital Signature verified.\n");

  /*  Destroy all key and algorithm objects  */
  B_DestroyAlgorithmObject (&randomAlgorithm);
  B_DestroyAlgorithmObject (&keypairGenerator);
  B_DestroyAlgorithmObject (&digitalSigner);
  B_DestroyAlgorithmObject (&digitalVerifier);
  B_DestroyKeyObject (&privateKey);
  B_DestroyKeyObject (&publicKey);

  /*  Free up any memory allocated */
  if (randomSeed.data != NULL_PTR)
  {
    T_memset (randomSeed.data, 0, randomSeed.len);
    T_free (randomSeed.data);
  }

  if (randomByteBuffer != NULL_PTR)
  {
    T_memset (randomByteBuffer, 0, NUMBER_OF_RANDOM_BYTES);
    T_free (randomByteBuffer);
  }

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

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