RSA BSAFE Crypto-C

Cryptographic Components for C

Search

dhagrsv.c

/* $Id: dhagrsv.c,v 1.8 2004/12/03 02:08:37 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 demonstrates how to use the Crypto-C API to do
 *  Diffie-Hellman key exchange, saving the private value, so that an
 *  application can "pause" in between phase 1 and 2 (as opposed to the
 *  dhagree sample) by serializing the algorithm object.  In this case
 *  the agreed upon key value will be generated using previously-generated
 *  DH parameters.  
 *
 *  Note that in a real application the DH parameters should not 
 *  be hard-coded.
 */

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

/*  This routine takes in a set of Diffie-Hellman parameters (See dhparam.c
 *  for an example which generates a set of Diffie-Hellman parameters.  Note
 *  that the parameters may be transmitted in the clear and both parties who
 *  wish to participate in the key agreement protocol must begin with the
 *  same set of parameters.) and performs phase 1 of the DH key agreement
 *  scheme.  The output publicValue is to be sent to the other party; the
 *  output stateInfo contains the private value and will be used to resume
 *  DH key agreement when a restored algorithm object is needed for phase
 *  2 of the protocol.
 *
 *  Note that the calling application must free publicValue->data and zeroize
 *  and free stateInfo when it is no longer needed.  Needless to say, the
 *  private value in the stateInfo is sensitive data and should be treated
 *  like any other private key.
 */
static int GenerateDHPhase1Values (ITEM *dhParamsBER, ITEM *publicValue,
                                   ITEM *stateInfo,
                                   B_ALGORITHM_OBJ randomAlgorithm,
                                   A_SURRENDER_CTX *surrenderCtx);

/*  This function takes the other party's public value and combines it with
 *  the private value in the stateInfo to derive the secretValue.
 *
 *  Note that the calling application must zeroize and free secretValue->data
 *  when it is no longer needed.
 */
static int GenerateDHPhase2Secret (ITEM *otherPublicValue, ITEM *stateInfo,
                                   ITEM *secretValue,
                                   A_SURRENDER_CTX *surrenderCtx);

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

int MAIN(int argc, char *argv[])
{
  ITEM dhParametersBER = {NULL, 0};

  unsigned char dhParamsBER[154] = {
    0x30, 0x81, 0x97, 0x06, 0x09, 0x2a, 0x86, 0x48,
    0x86, 0xf7, 0x0d, 0x01, 0x03, 0x01, 0x30, 0x81,
    0x89, 0x02, 0x41, 0x00, 0xaf, 0xbb, 0x7e, 0xe7,
    0xf3, 0xc2, 0x6c, 0xa0, 0x4e, 0xab, 0x0d, 0x62,
    0xea, 0x0d, 0x3f, 0xdd, 0xce, 0x97, 0x8b, 0xe1,
    0xe8, 0x6b, 0xbe, 0x67, 0x21, 0x1c, 0x59, 0x5c,
    0x15, 0x41, 0x0e, 0x5b, 0xe4, 0xe5, 0x47, 0x39,
    0xc6, 0x0d, 0x3f, 0xc3, 0x22, 0xb9, 0x64, 0x58,
    0xc8, 0x40, 0x4c, 0x0e, 0x61, 0xea, 0xb7, 0x33,
    0xfa, 0xfa, 0x2a, 0xa5, 0x4c, 0x6a, 0x06, 0x48,
    0x60, 0xa8, 0x7f, 0xc1, 0x02, 0x40, 0x68, 0x66,
    0x62, 0x61, 0x34, 0x6b, 0x19, 0x5e, 0xd6, 0x73,
    0x38, 0x6a, 0x94, 0x21, 0xeb, 0xd0, 0x61, 0x4f,
    0x20, 0xc6, 0x33, 0xc1, 0x69, 0x08, 0x67, 0xd0,
    0x40, 0x03, 0xac, 0x00, 0x69, 0x5e, 0x2e, 0x34,
    0x0e, 0xca, 0x38, 0xb2, 0x1b, 0x18, 0x65, 0x52,
    0x32, 0x16, 0x08, 0x9a, 0x4f, 0x68, 0x8b, 0x01,
    0x4f, 0x0a, 0xb3, 0x6a, 0xfd, 0xa7, 0x16, 0xad,
    0xe7, 0x90, 0x4c, 0x8a, 0x73, 0xbf, 0x02, 0x02,
    0x01, 0xf8
  };

  B_ALGORITHM_OBJ randomAlgorithm = (B_ALGORITHM_OBJ)NULL_PTR;

  A_SURRENDER_CTX generalSurrenderContext;
  int generalFlag;

  ITEM alicePublic = {NULL, 0}, alicePrivate = {NULL, 0};
  ITEM bobPublic = {NULL, 0}, bobPrivate = {NULL, 0};
  ITEM aliceSecret = {NULL, 0}, bobSecret = {NULL, 0};

  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 ("Diffie-Hellman Key Agreement Algorithm\n");
    RSA_PrintMessage ("======================================\n");

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

    RSA_PrintMessage ("\n   Use previously-generated DH parameters\n");
    RSA_PrintMessage ("   ======================================\n");

    dhParametersBER.data = dhParamsBER;
    dhParametersBER.len = sizeof (dhParamsBER);

    RSA_PrintMessage ("\n   Key Agreement -- Phase 1\n");
    RSA_PrintMessage ("   ========================\n");

    /*  generalFlag is for the surrender function */
    /*  Both parties start with a common set of parameters and generate
        public and private values.  Note that in this example, Alice and
        Bob are sharing the same random algorithm object.  This is simply
        done to present the same GenerateDHPhase1Values() function with
        a random algorithm object in a different state so that Alice and
        Bob generate different public/private values.  In a real-world
        situation, Alice and Bob would both have different random algorithm
        objects which were independently-seeded.  */
    generalFlag = 0;
    if ((status = GenerateDHPhase1Values (&dhParametersBER, &alicePublic,
                                          &alicePrivate, randomAlgorithm,
                                          &generalSurrenderContext)) != 0)
      break;

    RSA_PrintBuf ("Alice's Public Value", alicePublic.data, alicePublic.len);

    generalFlag = 0;
    if ((status = GenerateDHPhase1Values (&dhParametersBER, &bobPublic,
                                          &bobPrivate, randomAlgorithm,
                                          &generalSurrenderContext)) != 0)
      break;

    RSA_PrintBuf ("Bob's Public Value", bobPublic.data, bobPublic.len);

    RSA_PrintMessage ("\n   Key Agreement -- Phase 2\n");
    RSA_PrintMessage ("   ========================\n");
    RSA_PrintMessage ("   Both sides exchange public values...\n");

    generalFlag = 0;
    if ((status = GenerateDHPhase2Secret (&bobPublic, &alicePrivate,
                                          &aliceSecret,
                                          &generalSurrenderContext)) != 0)
      break;

    RSA_PrintBuf ("Secret Value Derived by Alice", aliceSecret.data,
                  aliceSecret.len);

    generalFlag = 0;
    if ((status = GenerateDHPhase2Secret (&alicePublic, &bobPrivate,
                                          &bobSecret,
                                          &generalSurrenderContext)) != 0)
      break;

    RSA_PrintBuf ("SecretValue Derived by Bob", bobSecret.data,
                  bobSecret.len);

    if (aliceSecret.len != bobSecret.len) {
      status = RSA_DEMO_E_INFO_DOES_NOT_VERIFY;
      break;
    }

    if (T_memcmp (aliceSecret.data, bobSecret.data, bobSecret.len) != 0) {
      status = RSA_DEMO_E_INFO_DOES_NOT_VERIFY;
      break;
    }

    RSA_PrintMessage ("\nSuccess!  Keys agree!!\n");
  } while (0);

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

  T_memset (alicePrivate.data, 0, alicePrivate.len);
  T_memset (aliceSecret.data, 0, aliceSecret.len);
  T_memset (bobPrivate.data, 0, bobPrivate.len);
  T_memset (bobSecret.data, 0, bobSecret.len);
  T_free (alicePublic.data);
  T_free (alicePrivate.data);
  T_free (aliceSecret.data);
  T_free (bobPublic.data);
  T_free (bobPrivate.data);
  T_free (bobSecret.data);

  B_DestroyAlgorithmObject (&randomAlgorithm);

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

/*  This routine takes in a set of Diffie-Hellman parameters (See dhparam.c
 *  for an example which generates a set of Diffie-Hellman parameters.  Note
 *  that the parameters may be transmitted in the clear and both parties who
 *  wish to participate in the key agreement protocol must begin with the
 *  same set of parameters.) and performs phase 1 of the DH key agreement
 *  scheme.  The output publicValue is to be sent to the other party; the
 *  output stateInfo contains the private value and will be used to resume
 *  DH key agreement when a restored algorithm object is needed for phase
 *  2 of the protocol.
 *
 *  Note that the calling application must free publicValue->data and zeroize
 *  and free stateInfo when it is no longer needed.  Needless to say, the
 *  private value in the stateInfo is sensitive data and should be treated
 *  like any other private key.
 */
static int GenerateDHPhase1Values(ITEM *dhParamsBER, ITEM *publicValue,
  ITEM *stateInfo, B_ALGORITHM_OBJ randomAlgorithm,
  A_SURRENDER_CTX *surrenderCtx)
{
  int status;
  B_ALGORITHM_OBJ dhAgree = NULL;
  ITEM bsfStateInfo = {NULL, 0};

  B_ALGORITHM_METHOD *DH_AGREE_SAMPLE_CHOOSER[] = {
    &AM_DH_KEY_AGREE,
    (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
  };



  A_DH_KEY_AGREE_PARAMS *getParams = NULL;

  publicValue->data = NULL;
  publicValue->len = 0;
  stateInfo->data = NULL;
  stateInfo->len = 0;

  do {
    /*  Creating and setting the dhAgree object with the algorithm
     *  information for creating the phase 1 keys.
     */
    if ((status = B_CreateAlgorithmObject (&dhAgree)) != 0)
      break;

    if ((status = B_SetAlgorithmInfo (dhAgree, AI_DHKeyAgreeBER,
                                      (POINTER)dhParamsBER)) != 0)
      break;

    if ((status = B_KeyAgreeInit (dhAgree, NULL, DH_AGREE_SAMPLE_CHOOSER,
                                  surrenderCtx)) != 0)
      break;

    /*  Find out how big the prime is so we know how many bytes to
        allocate for the public value buffer.  */
    if ((status = B_GetAlgorithmInfo ((POINTER *)&getParams, dhAgree,
                                      AI_DHKeyAgree)) != 0)
      break;

    publicValue->len = getParams->prime.len;
    publicValue->data = T_malloc (publicValue->len);
    if (publicValue->data == NULL) {
      status = RSA_DEMO_E_ALLOC;
      break;
    }

    if ((status = B_KeyAgreePhase1 (dhAgree, publicValue->data,
                                    &publicValue->len, publicValue->len,
                                    randomAlgorithm, surrenderCtx)) != 0)
      break;

    /*  Obtaining the state information from the algorithm object
     *  so it can be used to restore the algorithm object in order to
     *  resume this operation later.
     */
    if ((status = B_GetAlgorithmState (&bsfStateInfo, dhAgree)) != 0)
      break;

    /*  Since bsfStateInfo is a pointer to memory belonging to the Crypto-C
     *  library, we make our own copy for use later because the buffer which
     *  bsfStateInfo points might be changed by subsequent Crypto-C calls.
     */
    stateInfo->len = bsfStateInfo.len;
    stateInfo->data = T_malloc (bsfStateInfo.len);
    if (stateInfo->data == NULL) {
      status = RSA_DEMO_E_ALLOC;
      break;
    }

    T_memcpy (stateInfo->data, bsfStateInfo.data, stateInfo->len);
  } while (0);

  if (status != 0) {
    T_free (publicValue->data);
    publicValue->data = NULL;
    publicValue->len = 0;

    T_memset (stateInfo->data, 0, stateInfo->len);
    T_free (stateInfo->data);
    stateInfo->data = NULL;
    stateInfo->len = 0;

    RSA_PrintError ("GenerateDHPhase1Values", status);
  }

  B_DestroyAlgorithmObject (&dhAgree);

  return status;
}  /* end GenerateDHPhase1Values */

/*  This function takes the other party's public value and combines it with
 *  the private value in the stateInfo to derive the secretValue.
 *
 *  Note that the calling application must zeroize and free secretValue->data
 *  when it is no longer needed.
 */
static int GenerateDHPhase2Secret(ITEM*otherPublicValue, ITEM*stateInfo,
  ITEM*secretValue, A_SURRENDER_CTX*surrenderCtx)
{
  int status;
  B_ALGORITHM_OBJ dhAgree = NULL;

  B_ALGORITHM_METHOD *DH_AGREE_SAMPLE_CHOOSER[] = {
    &AM_DH_KEY_AGREE,
    (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
  };

  A_DH_KEY_AGREE_PARAMS *getParams = NULL;

  secretValue->data = NULL;
  secretValue->len = 0;

  do {
    if ((status = B_CreateAlgorithmObject (&dhAgree)) != 0)
      break;

    /*  Restore the algorithm object with the information retrieved following
     *  Phase 1.  This will allow us to continue with Phase 2 to derive a
     *  secret value given our private value and the other party's public
     *  value.
     */
    if ((status = B_SetAlgorithmState (dhAgree, AI_DHKeyAgree, stateInfo,
                                       DH_AGREE_SAMPLE_CHOOSER)) != 0)
      break;

    /*  Find out how big the prime is so we know how many bytes to
        allocate for the secret value buffer.  */
    if ((status = B_GetAlgorithmInfo ((POINTER *)&getParams, dhAgree,
                                      AI_DHKeyAgree)) != 0)
      break;

    secretValue->len = getParams->prime.len;
    secretValue->data = T_malloc (secretValue->len);
    if (secretValue->data == NULL) {
      status = RSA_DEMO_E_ALLOC;
      break;
    }

    if ((status = B_KeyAgreePhase2 (dhAgree, secretValue->data,
                                    &secretValue->len, secretValue->len,
                                    otherPublicValue->data,
                                    otherPublicValue->len,
                                    surrenderCtx)) != 0)
      break;
  } while (0);

  B_DestroyAlgorithmObject (&dhAgree);

  if (status != 0) {
    if (secretValue->data != NULL)
    {
      T_memset (secretValue->data, 0, secretValue->len);
      T_free (secretValue->data);
      secretValue->data = NULL;
      secretValue->len = 0;
    }

    RSA_PrintError ("GenerateDHPhase2Secret", status);
  }

  return status;
}  /* end GenerateDHPhase2Secret */

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