RSA BSAFE Crypto-C

Cryptographic Components for C

Search

ecdh.c

/* $Id: ecdh.c,v 1.7 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 will demonstrate the EC Diffie-Hellman key agreement
 *  scheme where two parties exchange public values to agree upon
 *  a shared secret key.
 */

#include "bsafe.h"
#include "demoutil.h"  /* in samples/common/include */
#include "bsfutil.h"   /* in samples/common/include */
#include "ecutil.h"    /* in samples/pkalg/ecc */

B_ALGORITHM_METHOD *EC_DH_CHOOSER[] = {
  &AM_ECFP_DH_KEY_AGREE,
  &AM_ECF2POLY_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
};



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

int MAIN(int argc, char *argv[])
{
  int status;
  char userInput[RSA_DEMO_MAX_LINE_LEN];

  B_ALGORITHM_OBJ randomAlgorithm = (B_ALGORITHM_OBJ)NULL_PTR;
  B_ALGORITHM_OBJ alice = (B_ALGORITHM_OBJ)NULL_PTR;
  B_ALGORITHM_OBJ bob = (B_ALGORITHM_OBJ)NULL_PTR;
  B_ALGORITHM_OBJ ecParamsObj = (B_ALGORITHM_OBJ)NULL_PTR;
  B_EC_PARAMS commonECParams;
  A_EC_PARAMS *cryptocECParams;
  A_EC_PARAMS ecParams = {0, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0,
      NULL, 0, NULL, 0, 0, 0};

  unsigned int fieldElementLen, maxPhase1Len, maxPhase2Len;
  unsigned char *alicePublicValue = NULL_PTR;
  unsigned char *bobPublicValue = NULL_PTR;
  unsigned int alicePublicValueLen, bobPublicValueLen;
  unsigned char *aliceSecretValue = NULL_PTR;
  unsigned char *bobSecretValue = NULL_PTR;
  unsigned int aliceSecretValueLen, bobSecretValueLen;

  ITEM aTableItem = {NULL, 0};

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

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

    if ((status = RSA_GetCommand (userInput, sizeof (userInput),
                                  "Generate new parameters (y/n)")) != 0)
      break;

    if ((userInput[0] == 'y') || (userInput[0] == 'Y')) {
      if ((status = RSA_CreateECParamsObject (&ecParamsObj,
                                              randomAlgorithm)) != 0)
        break;
    } else {
      if ((status = RSA_CreateECParamsObject (&ecParamsObj,
                                              NULL)) != 0)
        break;
    }

    if ((status = RSA_PrintECParamInfo (ecParamsObj, AI_ECParameters)) != 0)
      break;

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

    if ((status = B_CreateAlgorithmObject (&bob)) != 0)
      break;

    /*  Set algorithm object to AI_EC_DHKeyAgree  */
    /*  First get the EC parameters that Alice and Bob will have in common */
    if ((status = B_GetAlgorithmInfo ((POINTER *)&cryptocECParams, ecParamsObj,
                                      AI_ECParameters)) != 0)
      break;

    if ((status = RSA_AllocAndCopyECParamInfo (&ecParams,
                                               cryptocECParams)) != 0)
      break;

    commonECParams.parameterInfoType = AI_ECParameters;
    commonECParams.parameterInfoValue = (POINTER)&ecParams;

    /*  Provide Alice and Bob with the same EC parameters  */
    if ((status = B_SetAlgorithmInfo (alice, AI_EC_DHKeyAgree,
                                      (POINTER)&commonECParams)) != 0)
      break;

    if ((status = B_SetAlgorithmInfo (bob, AI_EC_DHKeyAgree,
                                      (POINTER)&commonECParams)) != 0)
      break;

    if ((status = RSA_GetCommand (userInput, sizeof (userInput),
                                  "Generate accelerator tables (y/n)")) != 0)
      break;

    if ((userInput[0] == 'y') || (userInput[0] == 'Y')) {
      if ((status = RSA_BuildAccelTable (&aTableItem, ecParamsObj)) != 0)
        break;

      /*  Alice and Bob can also optionally receive the acceleration tables
       *  corresponding with the EC parameters they have.
       */
      if ((status = B_SetAlgorithmInfo (alice, AI_ECAcceleratorTable,
                                        (POINTER)&aTableItem)) != 0)
        break;

      if ((status = B_SetAlgorithmInfo (bob, AI_ECAcceleratorTable,
                                        (POINTER)&aTableItem)) != 0)
        break;
    }

    /*  Initialize key agreement protocol  */
    if ((status = B_KeyAgreeInit (alice, (B_KEY_OBJ)NULL_PTR, EC_DH_CHOOSER,
                                  (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    if ((status = B_KeyAgreeInit (bob, (B_KEY_OBJ)NULL_PTR, EC_DH_CHOOSER,
                                  (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    /*  The largest size of phase 1 output we can get is one byte larger
     *  than twice the field element size.  For phase 2, the size of the
     *  output should be the same as the field element size.  (See
     *  Library Reference Manual entry on AI_EC_DHKeyAgree for more details)
     */
    fieldElementLen = (ecParams.fieldElementBits + 7) / 8;
    RSA_PrintMessage ("EC Parameters:  Field element length = %u bytes\n",
                      fieldElementLen);

    maxPhase1Len = (fieldElementLen * 2) + 1;
    maxPhase2Len = fieldElementLen;

    /*  Phase 1  */
    RSA_PrintMessage ("\nKey Agreement -- Phase 1\n");
    RSA_PrintMessage ("========================\n");

    alicePublicValue = T_malloc (maxPhase1Len);
    if (alicePublicValue == NULL_PTR) {
      status = RSA_DEMO_E_ALLOC;
      break;
    }

    bobPublicValue = T_malloc (maxPhase1Len);
    if (bobPublicValue == NULL_PTR) {
      status = RSA_DEMO_E_ALLOC;
      break;
    }

    if ((status = B_KeyAgreePhase1 (alice, alicePublicValue,
                                    &alicePublicValueLen, maxPhase1Len,
                                    randomAlgorithm,
                                    (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    RSA_PrintBuf ("Alice's public value", alicePublicValue,
                  alicePublicValueLen);

    if ((status = B_KeyAgreePhase1 (bob, bobPublicValue,
                                    &bobPublicValueLen, maxPhase1Len,
                                    randomAlgorithm,
                                    (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    RSA_PrintBuf ("Bob's public value", bobPublicValue, bobPublicValueLen);

    /*  Phase 2  */
    RSA_PrintMessage ("\nKey Agreement -- Phase 2\n");
    RSA_PrintMessage ("========================\n");

    aliceSecretValue = T_malloc (maxPhase2Len);
    if (aliceSecretValue == NULL_PTR) {
      status = RSA_DEMO_E_ALLOC;
      break;
    }

    bobSecretValue = T_malloc (maxPhase2Len);
    if (bobSecretValue == NULL_PTR) {
      status = RSA_DEMO_E_ALLOC;
      break;
    }

    if ((status = B_KeyAgreePhase2 (alice, aliceSecretValue,
                                    &aliceSecretValueLen, maxPhase2Len,
                                    bobPublicValue, bobPublicValueLen,
                                    (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    RSA_PrintBuf ("Value derived by Alice", aliceSecretValue,
                  aliceSecretValueLen);

    if ((status = B_KeyAgreePhase2 (bob, bobSecretValue,
                                    &bobSecretValueLen, maxPhase2Len,
                                    alicePublicValue, alicePublicValueLen,
                                    (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    RSA_PrintBuf ("Value derived by Bob", bobSecretValue, bobSecretValueLen);

    /*  Alice and Bob should derive the same secret value  */
    if ((aliceSecretValueLen == bobSecretValueLen) &&
        (T_memcmp (aliceSecretValue, bobSecretValue,
                   aliceSecretValueLen)) == 0) {
      RSA_PrintMessage ("Success!  ");
      RSA_PrintMessage ("Alice and Bob's secret keys agree.\n");
    } else {
      RSA_PrintMessage ("Alice and Bob do not have matching secret values.");
      status = RSA_DEMO_E_INFO_DOES_NOT_VERIFY;
    }
  } while(0);

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

  RSA_FreeECParamInfo (&ecParams);

  if (aTableItem.data != NULL)
  {
    T_memset (aTableItem.data, 0, aTableItem.len);
    T_free (aTableItem.data);
  }

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

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

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

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

  B_DestroyAlgorithmObject (&randomAlgorithm);
  B_DestroyAlgorithmObject (&alice);
  B_DestroyAlgorithmObject (&bob);

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

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