RSA BSAFE Crypto-C

Cryptographic Components for C

Search

bslec.c

/* $Id: bslec.c,v 1.4 2004/12/03 02:08:36 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.
 *
 *
 */

#include <stdio.h>
#include "aglobal.h"
#include "bsafe.h"
#include "bslec.h"
#include "demochos.h"

static int RSA_ReadFile PROTO_LIST
  ((char *, unsigned char *, unsigned int *, unsigned int));
static int RSA_WriteFile PROTO_LIST
  ((char *, unsigned char *, unsigned int));

/***********************************************************************/
/* symmetric key generation, block and stream cipher                   */
/***********************************************************************/

/***********************************************************************/

int BSL_BlockEncrypt(B_ALGORITHM_OBJ *algorithmObject,
  unsigned char *outputData, unsigned int *outputDataLen,
  unsigned char *inputData, unsigned int inputDataLen)
{
  int status;

  /* if last call (inputData == NULL_PTR) finish up */
  if (inputData == (unsigned char *)NULL_PTR) {
    status = B_EncryptFinal
      (*algorithmObject, outputData, outputDataLen,
       BLOCK_OUT_BYTES(0), (B_ALGORITHM_OBJ)NULL_PTR,
       (A_SURRENDER_CTX *)NULL_PTR);

    /* cleanup object */
    B_DestroyAlgorithmObject (algorithmObject);

    return (status);
  }

  /* if not final call, process this input chunk */
  status = B_EncryptUpdate
    (*algorithmObject, outputData, outputDataLen,
     BLOCK_OUT_BYTES(inputDataLen), inputData, inputDataLen,
     (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR);

  /* cleanup only if an error occurred */
  if (status != 0)
    B_DestroyAlgorithmObject (algorithmObject);

  return (status);
}

/***********************************************************************/

int BSL_BlockDecrypt(B_ALGORITHM_OBJ *algorithmObject,
  unsigned char *outputData, unsigned int *outputDataLen,
  unsigned char *inputData, unsigned int inputDataLen)
{
  int status;

  /* if last call (inputData == NULL_PTR) finish up */
  if (inputData == (unsigned char *)NULL_PTR) {
    status = B_DecryptFinal
      (*algorithmObject, outputData, outputDataLen,
       BLOCK_OUT_BYTES(0), (B_ALGORITHM_OBJ)NULL_PTR,
       (A_SURRENDER_CTX *)NULL_PTR);

    /* cleanup object */
    B_DestroyAlgorithmObject (algorithmObject);

    return (status);
  }

  /* if not final call, process this input chunk */
  status = B_DecryptUpdate
    (*algorithmObject, outputData, outputDataLen,
     BLOCK_OUT_BYTES(inputDataLen), inputData, inputDataLen,
     (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR);
  
  /* cleanup only if an error occurred */
  if (status != 0)
    B_DestroyAlgorithmObject (algorithmObject);

  return (status);
}

/***********************************************************************/
/* EC key generation, password-based private key protection,           */
/* digital signatures and digital envelopes                            */
/***********************************************************************/

/* define parameters for password-based encryption */
#define PBE_ITERATION_COUNT 1000

int BSL_MakeECKeyPairFromSeed(unsigned char *publicKey,
  unsigned int *publicKeyLen, unsigned char *ppPrivateKey,
  unsigned int *ppPrivateKeyLen, A_EC_PARAMS *ecParams,
  unsigned char *pbeParams, unsigned int *pbeParamsLen, unsigned char *seed,
  unsigned int seedLen, unsigned char *password, unsigned int passwordLen)
{
  B_EC_PARAMS keyGenParams;
  B_ALGORITHM_OBJ generateAlgorithmObj = NULL_PTR;
  B_ALGORITHM_OBJ pbEncryptionAlgorithmObj = NULL_PTR;
  B_ALGORITHM_OBJ randomAlgorithmObj = NULL_PTR;
  B_ALGORITHM_OBJ saltDigestAlgorithmObj = NULL_PTR;
  B_KEY_OBJ passwordKeyObj = NULL_PTR;
  B_KEY_OBJ privateKeyObj = NULL_PTR;
  B_KEY_OBJ publicKeyObj = NULL_PTR;
  B_PBE_PARAMS pbeParamsStruct;
  ITEM passwordItem, *keyItemPtr, *pbeBERItemPtr;
  int status;
  unsigned char pbeSaltBuf[16];
  unsigned int digestLen, outputLen;
  
  /* do {} while(0); provides convenient way to ensure cleanup upon error */
  do {

    /* create random algorithm objects and set algorithm info */
    status = B_CreateAlgorithmObject (&randomAlgorithmObj);
    if (status != 0)
      break;

    status = B_SetAlgorithmInfo (randomAlgorithmObj, AI_SHA1Random, NULL_PTR);
    if (status != 0)
      break;

    /* call random init, update with supplied seed bytes */
    status = B_RandomInit
      (randomAlgorithmObj, DEMO_ALGORITHM_CHOOSER,
       (A_SURRENDER_CTX *)NULL_PTR);
    if (status != 0)
      break;

    status = B_RandomUpdate
      (randomAlgorithmObj, seed, seedLen, (A_SURRENDER_CTX *)NULL_PTR);
    if (status != 0)
      break;

    /* create generate algorithm object */
    status = B_CreateAlgorithmObject (&generateAlgorithmObj);
    if (status != 0)
      break;

    /* set up key generation parameters and set algorithm object */
    keyGenParams.parameterInfoType = AI_ECParameters;
    keyGenParams.parameterInfoValue = (POINTER)ecParams;
    
    status = B_SetAlgorithmInfo
      (generateAlgorithmObj, AI_ECKeyGen, (POINTER)&keyGenParams);
    if (status != 0)
      break;

    /* generate init */
    status = B_GenerateInit
      (generateAlgorithmObj, DEMO_ALGORITHM_CHOOSER,
       (A_SURRENDER_CTX *)NULL_PTR);
    if (status != 0)
      break;

    /* create private and public key objects */
    status = B_CreateKeyObject (&privateKeyObj);
    if (status != 0)
      break;

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

    /* generate keys and store in key objects (may take a few moments) */
    status = B_GenerateKeypair
      (generateAlgorithmObj, publicKeyObj, privateKeyObj,
       randomAlgorithmObj, (A_SURRENDER_CTX *)NULL_PTR);
    if (status != 0)
      break;

    /* get the public and private components, and store them in the
       supplied buffers */

    status = B_GetKeyInfo
      ((POINTER *)&keyItemPtr, publicKeyObj, KI_ECPublicComponent);
    if (status != 0)
      break;

    T_memcpy ((POINTER)publicKey, (POINTER)keyItemPtr->data, keyItemPtr->len);
    *publicKeyLen = keyItemPtr->len;

    status = B_GetKeyInfo
      ((POINTER *)&keyItemPtr, privateKeyObj, KI_ECPrivateComponent);
    if (status != 0)
      break;

    /* if supplied password is NULL, copy unencrypted private key info
       to the supplied buffer
     */
    if (password == (unsigned char *)NULL_PTR) {
      T_memcpy
        ((POINTER)ppPrivateKey, (POINTER)keyItemPtr->data, keyItemPtr->len);
      *ppPrivateKeyLen = keyItemPtr->len;
    }
    /* otherwise; encrypt the private key under the supplied password */
    else {
      /* first, generate a password-based encryption salt value by
         digesting the private key and the supplied password
       */
      status = B_CreateAlgorithmObject (&saltDigestAlgorithmObj);
      if (status != 0)
        break;

      status = B_SetAlgorithmInfo (saltDigestAlgorithmObj, AI_MD5, NULL_PTR);
      if (status != 0)
        break;

      status = B_DigestInit
        (saltDigestAlgorithmObj, NULL_PTR, DEMO_ALGORITHM_CHOOSER,
         (A_SURRENDER_CTX *)NULL_PTR);
      if (status != 0)
        break;

      status = B_DigestUpdate
        (saltDigestAlgorithmObj, password, passwordLen,
         (A_SURRENDER_CTX *)NULL_PTR);
      if (status != 0)
        break;
  
      status = B_DigestUpdate
        (saltDigestAlgorithmObj, keyItemPtr->data, keyItemPtr->len,
         (A_SURRENDER_CTX *)NULL_PTR);
      if (status != 0)
        break;

      status = B_DigestFinal
        (saltDigestAlgorithmObj, pbeSaltBuf, &digestLen, sizeof(pbeSaltBuf),
         (A_SURRENDER_CTX *)NULL_PTR);
      if (status != 0)
        break;

      /* create password-based encryption algorithm object */
      status = B_CreateAlgorithmObject (&pbEncryptionAlgorithmObj);
      if (status != 0)
        break;

      /* setup password-based encryption parameters */
      pbeParamsStruct.salt = pbeSaltBuf;
      pbeParamsStruct.iterationCount = PBE_ITERATION_COUNT;
    /******************************************************************
      Note: The password-based encryption iteration count supplied is
            hard-coded above.  The chosen value is arbitrary and may have
            security ramifications. See PKCS #5.
     ******************************************************************/

      /* set algorithm object */
      status = B_SetAlgorithmInfo
        (pbEncryptionAlgorithmObj, AI_MD5WithDES_CBCPad,
         (POINTER)&pbeParamsStruct);
      if (status != 0)
        break;

      /* get the PBE parameters in their BER encoded form */
      status = B_GetAlgorithmInfo
        ((POINTER *)&pbeBERItemPtr, pbEncryptionAlgorithmObj,
         AI_MD5WithDES_CBCPadBER);
      if (status != 0)
        break;

      /* return encoded pbe parameters and length to the caller in the
         supplied args.
       */
      T_memcpy
        ((POINTER)pbeParams, (POINTER)pbeBERItemPtr->data, pbeBERItemPtr->len);
      *pbeParamsLen = pbeBERItemPtr->len;

      /* create key object */
      status = B_CreateKeyObject (&passwordKeyObj);
      if (status != 0)
        break;

      /* setup password item and set key info */
      passwordItem.data = password;
      passwordItem.len = passwordLen;
      status = B_SetKeyInfo (passwordKeyObj, KI_Item, (POINTER)&passwordItem);
      if (status != 0)
        break;

      /* encrypt the private key */
      status = B_EncryptInit
        (pbEncryptionAlgorithmObj, passwordKeyObj,
         DEMO_ALGORITHM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR);
      if (status != 0)
        break;

      status = B_EncryptUpdate
        (pbEncryptionAlgorithmObj, ppPrivateKey, &outputLen,
         PP_PRIV_KEY_BYTES(ecParams->fieldElementBits),
         keyItemPtr->data, keyItemPtr->len,
         (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR);
      if (status != 0)
        break;

      *ppPrivateKeyLen = outputLen;
      status = B_EncryptFinal
        (pbEncryptionAlgorithmObj, ppPrivateKey + *ppPrivateKeyLen,
         &outputLen,
         PP_PRIV_KEY_BYTES(ecParams->fieldElementBits) - *ppPrivateKeyLen,
         (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR);
      if (status != 0)
        break;

      *ppPrivateKeyLen += outputLen;
    }
  } while (0);

  /* cleanup objects */
  B_DestroyAlgorithmObject (&generateAlgorithmObj);
  B_DestroyAlgorithmObject (&pbEncryptionAlgorithmObj);
  B_DestroyAlgorithmObject (&randomAlgorithmObj);
  B_DestroyAlgorithmObject (&saltDigestAlgorithmObj);
  B_DestroyKeyObject (&passwordKeyObj);
  B_DestroyKeyObject (&privateKeyObj);
  B_DestroyKeyObject (&publicKeyObj);

  return (status);
}

/***********************************************************************/

int BSL_ECDSAWithSHA1SignInit(B_ALGORITHM_OBJ *algorithmObject,
  A_EC_PRIVATE_KEY *ppPrivateKey, unsigned char *password,
  unsigned int passwordLen, unsigned char *pbeParams,
  unsigned int pbeParamsLen)
{
  B_ALGORITHM_OBJ pbEncryptionAlgorithmObj = NULL_PTR;
  B_KEY_OBJ passwordKeyObj = NULL_PTR;
  B_KEY_OBJ privateKeyObj = NULL_PTR;
  B_DIGEST_SPECIFIER digestAlgorithm;
  ITEM passwordItem, privateKeyItem, pbEncryptionInfoItem;
  int status;
  unsigned char *privateKeyBuf = NULL_PTR;
  unsigned int outputLen, privateKeyBufLen, ppPrivateKeyLen = 0;

  /* initialize algorithm object to NULL pointer */
  *algorithmObject = NULL_PTR;

  /* do {} while(0); provides convenient way to ensure cleanup upon error */
  do {
    
    /* set up an algorithm to create signature */
    status = B_CreateAlgorithmObject (algorithmObject);
    if (status != 0)
      break;

    /* set algorithm info to make signature with ECDSA and SHA1 */
    digestAlgorithm.digestInfoType = AI_SHA1;
    digestAlgorithm.digestInfoParams = NULL_PTR;
    
    status = B_SetAlgorithmInfo
      (*algorithmObject, AI_EC_DSAWithDigest, (POINTER)&digestAlgorithm);
    if (status != 0)
      break;

    /* create a key object for the private key */
    status = B_CreateKeyObject (&privateKeyObj);
    if (status != 0)
      break;

    /* if supplied password is NULL, use the private key data supplied
     */
    if (password == (unsigned char *)NULL_PTR) {
      status = B_SetKeyInfo (privateKeyObj, KI_ECPrivate,
                             (POINTER)ppPrivateKey);
    }
    else {
      /* otherwise, a password is supplied, so decrypt the private key with the
           password and set the key info with the result
       */
      /* create password-based encryption algorithm object */
      status = B_CreateAlgorithmObject (&pbEncryptionAlgorithmObj);
      if (status != 0)
        break;

      /* set up the ITEM which supplies the password-based encryption
         algorithm info.  This contains the salt and iteration count
         which were specified when the private key was password-encrypted.
       */
      pbEncryptionInfoItem.data = pbeParams;
      pbEncryptionInfoItem.len = pbeParamsLen;

      /* set algorithm object */
      status = B_SetAlgorithmInfo
        (pbEncryptionAlgorithmObj, AI_MD5WithDES_CBCPadBER,
         (POINTER)&pbEncryptionInfoItem);
      if (status != 0)
        break;
      /******************************************************************
        Note: The choice of MD5 with DES for password-based private key
        decryption corresponds to the password-based encryption algorithm
        used by the BSL_MakeECKeyPairFromSeed() routine above. The call
        to SetAlgorithmInfo() will return BE_WRONG_ALGORITHM_INFO if the
        algorithm information conveyed in the pbeParams argument is other
        than MD5 and DES.  In this case it would be necessary to call
        SetAlgorithmInfo() with other candidate algorithm info choices
        (such as AI_MD5WithRC2_CBCPadBER or AI_SHA1WithDES_CBCBER) until
        the call is successful.
       ******************************************************************/

      /* create key object */
      status = B_CreateKeyObject (&passwordKeyObj);
      if (status != 0)
        break;

      /* setup password item and set key info */
      passwordItem.data = password;
      passwordItem.len = passwordLen;
      status = B_SetKeyInfo (passwordKeyObj, KI_Item, (POINTER)&passwordItem);
      if (status != 0)
        break;

      /* allocate a buffer to hold the decrypted private key.
         Since the decrypted size will be smaller than the encrypted size,
           we can allocate a buffer of the size of the encrypted key. */
      ppPrivateKeyLen = ppPrivateKey->privateKey.len;
      if ((privateKeyBuf = (unsigned char *)
                           T_malloc (ppPrivateKeyLen))
          == (unsigned char *)NULL_PTR) {
        status = BE_ALLOC;
        break;
      }

      /* decrypt the private key component */
      status = B_DecryptInit
        (pbEncryptionAlgorithmObj, passwordKeyObj, DEMO_ALGORITHM_CHOOSER,
         (A_SURRENDER_CTX *)NULL_PTR);
      if (status != 0)
        break;

      status = B_DecryptUpdate
        (pbEncryptionAlgorithmObj, privateKeyBuf, &outputLen, ppPrivateKeyLen,
         ppPrivateKey->privateKey.data, ppPrivateKeyLen,
         (B_ALGORITHM_OBJ)NULL_PTR,
         (A_SURRENDER_CTX *)NULL_PTR);
      if (status != 0)
        break;

      privateKeyBufLen = outputLen;
      status = B_DecryptFinal
        (pbEncryptionAlgorithmObj, privateKeyBuf + privateKeyBufLen,
         &outputLen, ppPrivateKeyLen - privateKeyBufLen,
         (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR);
      if (status != 0)
        break;

      privateKeyBufLen += outputLen;

      /* save the encrypted private key component */
      privateKeyItem = ppPrivateKey->privateKey;

      /* use the decrypted private key bytes */
      ppPrivateKey->privateKey.data = privateKeyBuf;
      ppPrivateKey->privateKey.len = privateKeyBufLen;
      
      status = B_SetKeyInfo (privateKeyObj, KI_ECPrivate,
                             (POINTER)ppPrivateKey);

      /* restore the encrypted private key component */
      ppPrivateKey->privateKey = privateKeyItem;
    }

    if (status != 0)
      break;

    /* call the signature init */
    status = B_SignInit
      (*algorithmObject, privateKeyObj, DEMO_ALGORITHM_CHOOSER,
       (A_SURRENDER_CTX *)NULL_PTR);
    if (status != 0)
        break;

  } while (0);

  /* cleanup only if an error occurred */
  if (status != 0)
    B_DestroyAlgorithmObject (algorithmObject);

  /* cleanup objects */
  B_DestroyAlgorithmObject (&pbEncryptionAlgorithmObj);
  B_DestroyKeyObject (&passwordKeyObj);
  B_DestroyKeyObject (&privateKeyObj);
  
  /* if privateKeyBuf is not NULL, zeroize and free memory */
  if (privateKeyBuf != (unsigned char *)NULL_PTR) {
    T_memset ((POINTER)privateKeyBuf, 0, ppPrivateKeyLen);
    T_free ((POINTER)privateKeyBuf);
  }

  return (status);
}

/***********************************************************************/

int BSL_ECDSAWithSHA1SignUpdate(B_ALGORITHM_OBJ *algorithmObject,
  unsigned char *input, unsigned int inputLen)
{
  int status;

  /* call sign update to process input data */
  status = B_SignUpdate
    (*algorithmObject, input, inputLen, (A_SURRENDER_CTX *)NULL_PTR);

  /* cleanup only if an error occurred */
  if (status != 0)
    B_DestroyAlgorithmObject (algorithmObject);

  return (status);
}

/***********************************************************************/

int BSL_ECDSAWithSHA1SignFinal(B_ALGORITHM_OBJ *algorithmObject,
  unsigned char *signature, unsigned int *signatureLen,
  unsigned int maxSignatureLen, unsigned char *seed, unsigned int seedLen)
{
  int status;
  B_ALGORITHM_OBJ randomAlgorithmObj;

  /* do {} while(0); provides convenient way to ensure cleanup upon error */
  do {
    /* create random algorithm object and set algorithm info */
    status = B_CreateAlgorithmObject (&randomAlgorithmObj);
    if (status != 0)
      break;

    status = B_SetAlgorithmInfo (randomAlgorithmObj, AI_SHA1Random, NULL_PTR);
    if (status != 0)
      break;

    /* call random init, update with supplied seed bytes */
    status = B_RandomInit
             (randomAlgorithmObj, DEMO_ALGORITHM_CHOOSER,
              (A_SURRENDER_CTX *)NULL_PTR);
    if (status != 0)
      break;

    status = B_RandomUpdate
             (randomAlgorithmObj, seed, seedLen, (A_SURRENDER_CTX *)NULL_PTR);
    if (status != 0)
      break;

    status = B_SignFinal
             (*algorithmObject, signature, signatureLen, maxSignatureLen,
              randomAlgorithmObj, (A_SURRENDER_CTX *)NULL_PTR);

  } while (0);

  /* cleanup object */
  B_DestroyAlgorithmObject (algorithmObject);
  B_DestroyAlgorithmObject (&randomAlgorithmObj);

  return (status);
}

/***********************************************************************/

int BSL_ECDSAWithSHA1VerifyInit(B_ALGORITHM_OBJ *algorithmObject,
  A_EC_PUBLIC_KEY *publicKey)
{
  B_KEY_OBJ publicKeyObj = NULL_PTR;
  B_DIGEST_SPECIFIER digestAlgorithm;
  int status;

  /* initialize algorithm object to NULL pointer */
  *algorithmObject = NULL_PTR;

  /* do {} while(0); provides convenient way to ensure cleanup upon error */
  do {
    
    /* create algorithm object for verifying signature */
    status = B_CreateAlgorithmObject (algorithmObject);
    if (status != 0)
      break;

    /* set algorithm object to ECDSA with SHA1 signature */
    digestAlgorithm.digestInfoType = AI_SHA1;
    digestAlgorithm.digestInfoParams = NULL_PTR;
    
    status = B_SetAlgorithmInfo
      (*algorithmObject, AI_EC_DSAWithDigest, (POINTER)&digestAlgorithm);
    if (status != 0)
      break;
    /******************************************************************
       Note: The choice of ECDSA with SHA1 for signature verification
       corresponds to the use of ECDSA and SHA1 for signature creation
       in the BSL_ECDSAWithSHA1SignInit() routine above.  If this
       routine were intended to handle other signature algorithms, it
       would be necessary to pass around algorithm identifier
       information with the signature.
     ******************************************************************/

    /* create and set up a key object for public key decryption */
    status = B_CreateKeyObject (&publicKeyObj);
    if (status != 0)
      break;

    status = B_SetKeyInfo
      (publicKeyObj, KI_ECPublic, (POINTER)publicKey);
    if (status != 0)
      break;

    /* call the verify init */
    status = B_VerifyInit
      (*algorithmObject, publicKeyObj,
       DEMO_ALGORITHM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR);
    if (status != 0)
      break;

  } while (0);

  /* cleanup only if an error occurred */
  if (status != 0)
    B_DestroyAlgorithmObject (algorithmObject);
  
  /* cleanup object */
  B_DestroyKeyObject (&publicKeyObj);

  return (status);
}

/***********************************************************************/

int BSL_ECDSAWithSHA1VerifyUpdate(B_ALGORITHM_OBJ *algorithmObject,
  unsigned char *input, unsigned int inputLen)
{
  int status;

  /* call the verify update */
  status = B_VerifyUpdate
    (*algorithmObject, input, inputLen, (A_SURRENDER_CTX *)NULL_PTR);

  /* cleanup only if an error occurred */
  if (status != 0)
    B_DestroyAlgorithmObject (algorithmObject);
  
  return (status);
}

/***********************************************************************/

int BSL_ECDSAWithSHA1VerifyFinal(B_ALGORITHM_OBJ *algorithmObject,
  unsigned char *signature, unsigned int signatureLen)
{
  int status;

  /* call the verify final */
  status = B_VerifyFinal
    (*algorithmObject, signature, signatureLen,
     (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR);

  /* cleanup object */
  B_DestroyAlgorithmObject (algorithmObject);
  
  return (status);
}

/***********************************************************************/

int BSL_SealDESWithECESEnvelopeSetup(B_ALGORITHM_OBJ *algorithmObject,
  unsigned char *encryptedKey, unsigned int *encryptedKeyLen,
  unsigned char *IV, unsigned char *seed, unsigned int seedLen,
  A_EC_PUBLIC_KEY *publicKey)
{
  B_ALGORITHM_OBJ keyEncryptionAlgorithmObj = NULL_PTR;
  B_ALGORITHM_OBJ randomAlgorithmObj = NULL_PTR;
  B_KEY_OBJ publicKeyObj = NULL_PTR;
  B_KEY_OBJ secretKeyObj = NULL_PTR;
  int status;
  unsigned char secretKeyBuf[8], *secretKeyPtr;
  unsigned int outLen, maxOutLen;

  /* initialize algorithm object to NULL pointer */
  *algorithmObject = NULL_PTR;

  /* do {} while(0); provides convenient way to ensure cleanup upon error */
  do {

    /* create random algorithm object and set algorithm info */
    status = B_CreateAlgorithmObject (&randomAlgorithmObj);
    if (status != 0)
      break;

    status = B_SetAlgorithmInfo (randomAlgorithmObj, AI_SHA1Random, NULL_PTR);
    if (status != 0)
      break;

    /* call random init, update with supplied seed bytes */
    status = B_RandomInit
      (randomAlgorithmObj, DEMO_ALGORITHM_CHOOSER,
       (A_SURRENDER_CTX *)NULL_PTR);
    if (status != 0)
      break;

    status = B_RandomUpdate
      (randomAlgorithmObj, seed, seedLen, (A_SURRENDER_CTX *)NULL_PTR);
    if (status != 0)
      break;

    /* generate 8 random bytes for secret DES key */
    status = B_GenerateRandomBytes
      (randomAlgorithmObj, secretKeyBuf, 8, (A_SURRENDER_CTX *)NULL_PTR);
    if (status != 0)
      break;

    /* create key object for data encryption */
    status = B_CreateKeyObject (&secretKeyObj);
    if (status != 0)
      break;
    
    /* set the data encryption key object with the DES key and request
       to have the parity automatically adjusted
     */
    status = B_SetKeyInfo (secretKeyObj, KI_DES8Strong, (POINTER)secretKeyBuf);
    if (status != 0)
      break;

    /* request a pointer to the same DES key with parity adjusted
       See FIPS 46-1
     */
    status = B_GetKeyInfo ((POINTER *)&secretKeyPtr, secretKeyObj, KI_DES8);
    if (status != 0)
      break;

    /* generate 8 random bytes for Initialization Vector (IV) */
    status = B_GenerateRandomBytes
      (randomAlgorithmObj, IV, 8, (A_SURRENDER_CTX *)NULL_PTR);
    if (status != 0)
      break;

    /* create an algorithm for encrypting the data encryption key */
    status = B_CreateAlgorithmObject (&keyEncryptionAlgorithmObj);
    if (status != 0)
      break;
    
    /* set up algorithm for public key encryption */
    status = B_SetAlgorithmInfo
      (keyEncryptionAlgorithmObj, AI_EC_ES, NULL_PTR);
    if (status != 0)
      break;

    /* create public key object */
    status = B_CreateKeyObject (&publicKeyObj);
    if (status != 0)
      break;

    /* set up public key */
    status = B_SetKeyInfo
      (publicKeyObj, KI_ECPublic, (POINTER)publicKey);
    if (status != 0)
      break;

    /* encrypt the data encryption key */
    status = B_EncryptInit
      (keyEncryptionAlgorithmObj, publicKeyObj, DEMO_ALGORITHM_CHOOSER,
       (A_SURRENDER_CTX *)NULL_PTR);
    if (status != 0)
      break;

    /* maximum size of encrypted data with ECES:
       21 + data to encrypt len + twice the field element length
       The data to encrypt is the symmetric key, in this case a DES key */
    maxOutLen = MAX_ENC_SYMKEY_LEN(publicKey->curveParams.fieldElementBits);
    
    status = B_EncryptUpdate
      (keyEncryptionAlgorithmObj, encryptedKey, &outLen, maxOutLen,
       secretKeyPtr, 8, randomAlgorithmObj, (A_SURRENDER_CTX *)NULL_PTR);
    if (status != 0)
      break;

    *encryptedKeyLen = outLen;
    status = B_EncryptFinal
      (keyEncryptionAlgorithmObj, encryptedKey + *encryptedKeyLen,
       &outLen, maxOutLen - *encryptedKeyLen, randomAlgorithmObj,
       (A_SURRENDER_CTX *)NULL_PTR);
    if (status != 0)
      break;

    *encryptedKeyLen += outLen;

    /* create algorithm object for data encryption */
    status = B_CreateAlgorithmObject (algorithmObject);
    if (status != 0)
      break;

    /* set up algorithm for DES CBC data encryption */
    status = B_SetAlgorithmInfo
      (*algorithmObject, AI_DES_CBCPadIV8, (POINTER)IV);
    if (status != 0)
      break;
    /******************************************************************
       Note: The choice of DES CBC for envelope data encryption
       is arbitrary and may have security considerations.  RC2 CBC may
       also be used.
     ******************************************************************/

    /* call the encrypt init with the data encryption key */
    status = B_EncryptInit
      (*algorithmObject, secretKeyObj, DEMO_ALGORITHM_CHOOSER,
       (A_SURRENDER_CTX *)NULL_PTR);
    if (status != 0)
      break;
    
  } while (0);

  /* cleanup only if an error occurred */
  if (status != 0)
    B_DestroyAlgorithmObject (algorithmObject);

  /* cleanup objects */
  B_DestroyAlgorithmObject (&keyEncryptionAlgorithmObj);
  B_DestroyAlgorithmObject (&randomAlgorithmObj);
  B_DestroyKeyObject (&publicKeyObj);
  B_DestroyKeyObject (&secretKeyObj);

  /* zeroize secret key buffer */
  T_memset ((POINTER)secretKeyBuf, 0, sizeof (secretKeyBuf));

  return (status);
}

/***********************************************************************/

int BSL_OpenDESWithECESEnvelopeSetup(B_ALGORITHM_OBJ *algorithmObject,
  unsigned char *encryptedKey, unsigned int encryptedKeyLen,
  unsigned char *IV, A_EC_PRIVATE_KEY *ppPrivateKey, unsigned char *password,
  unsigned int passwordLen, unsigned char *pbeParams,
  unsigned int pbeParamsLen)
{
  B_ALGORITHM_OBJ keyDecryptAlgorithmObj = NULL_PTR;
  B_ALGORITHM_OBJ pbEncryptionAlgorithmObj = NULL_PTR;
  B_KEY_OBJ passwordKeyObj = NULL_PTR;
  B_KEY_OBJ privateKeyObj = NULL_PTR;
  B_KEY_OBJ secretKeyObj = NULL_PTR;
  ITEM dataKeyItem, passwordItem, privateKeyItem, pbEncryptionInfoItem;
  int status;
  unsigned char *dataKeyBuf = NULL_PTR;
  unsigned char *privateKeyBuf = NULL_PTR;
  unsigned int dataKeyBufLen, outputLen, privateKeyBufLen, ppPrivateKeyLen = 0;

  /* initialize algorithm object to NULL pointer */
  *algorithmObject = NULL_PTR;

  /* do {} while(0); provides convenient way to ensure cleanup upon error */
  do {
    
    /* create a key object for the private key */
    status = B_CreateKeyObject (&privateKeyObj);
    if (status != 0)
      break;

    /* if supplied password is NULL, use the private key data supplied
     */
    if (password == (unsigned char *)NULL_PTR) {
      /* set the private key info */
      status = B_SetKeyInfo
               (privateKeyObj, KI_ECPrivate, (POINTER)ppPrivateKey);
    }
    else {
      /* otherwise, the password is supplied, so use it to decrypt the private
         key and set the key info with the result
       */
      /* create password-based encryption algorithm object */
      status = B_CreateAlgorithmObject (&pbEncryptionAlgorithmObj);
      if (status != 0)
        break;

      /* set up the ITEM which supplies the password-based encryption
         algorithm info.  This contains the salt and iteration count
         which were specified when the private key was password-encrypted.
       */
      pbEncryptionInfoItem.data = pbeParams;
      pbEncryptionInfoItem.len = pbeParamsLen;

      /* set algorithm object */
      status = B_SetAlgorithmInfo
        (pbEncryptionAlgorithmObj, AI_MD5WithDES_CBCPadBER,
         (POINTER)&pbEncryptionInfoItem);
      if (status != 0)
        break;
      /******************************************************************
        Note: The choice of MD5 with DES for password-based private key
        decryption corresponds to the password-based encryption algorithm
        used by the BSL_MakeECKeyPairFromSeed() routine above. The call
        to SetAlgorithmInfo() will return BE_WRONG_ALGORITHM_INFO if the
        algorithm information conveyed in the pbeParams argument is other
        than MD5 and DES.  In this case it would be necessary to call
        SetAlgorithmInfo() with other candidate algorithm info choices
        (such as AI_MD5WithDES_CBCPadBER or AI_MD2WithRC2_CBCBER) until
        the call is successful.
       ******************************************************************/

      /* create key object */
      status = B_CreateKeyObject (&passwordKeyObj);
      if (status != 0)
        break;

      /* setup password item and set key info */
      passwordItem.data = password;
      passwordItem.len = passwordLen;
      status = B_SetKeyInfo (passwordKeyObj, KI_Item, (POINTER)&passwordItem);
      if (status != 0)
        break;

      /* allocate a buffer to hold the decrypted private key.
         Since the decrypted size will be smaller than the encrypted size,
           we can allocate a buffer of the size of the encrypted key.   */
      ppPrivateKeyLen = ppPrivateKey->privateKey.len;
      if ((privateKeyBuf = (unsigned char *)T_malloc (ppPrivateKeyLen))
          == (unsigned char *)NULL_PTR) {
        status = BE_ALLOC;
        break;
      }

      /* decrypt the private key DER */
      status = B_DecryptInit
        (pbEncryptionAlgorithmObj, passwordKeyObj, DEMO_ALGORITHM_CHOOSER,
         (A_SURRENDER_CTX *)NULL_PTR);
      if (status != 0)
        break;

      status = B_DecryptUpdate
        (pbEncryptionAlgorithmObj, privateKeyBuf, &outputLen, ppPrivateKeyLen,
         ppPrivateKey->privateKey.data, ppPrivateKeyLen,
         (B_ALGORITHM_OBJ)NULL_PTR,
         (A_SURRENDER_CTX *)NULL_PTR);
      if (status != 0)
        break;

      privateKeyBufLen = outputLen;
      status = B_DecryptFinal
        (pbEncryptionAlgorithmObj, privateKeyBuf + privateKeyBufLen,
         &outputLen, ppPrivateKeyLen - privateKeyBufLen,
         (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR);
      if (status != 0)
        break;

      privateKeyBufLen += outputLen;

      /* save the encrypted private key component */
      privateKeyItem = ppPrivateKey->privateKey;

      /* use the decrypted private key bytes */
      ppPrivateKey->privateKey.data = privateKeyBuf;
      ppPrivateKey->privateKey.len = privateKeyBufLen;
      
      status = B_SetKeyInfo (privateKeyObj, KI_ECPrivate,
                             (POINTER)ppPrivateKey);

      /* restore the encrypted private key component */
      ppPrivateKey->privateKey = privateKeyItem;

    }

    if (status != 0)
      break;

    /* create algorithm object for decrypting key */
    status = B_CreateAlgorithmObject (&keyDecryptAlgorithmObj);
    if (status != 0)
      break;

    /* set algorithm object to RSA private key decryption */
    status = B_SetAlgorithmInfo
      (keyDecryptAlgorithmObj, AI_EC_ES, NULL_PTR);
    if (status != 0)
      break;

    /* allocate a buffer to hold the decrypted data encryption key.
       Since the decrypted size will be smaller than the encrypted size,
         we can allocate a buffer of the size of the encrypted key. */
    if ((dataKeyBuf = (unsigned char *)T_malloc (dataKeyBufLen = encryptedKeyLen))
        == (unsigned char *)NULL_PTR) {
      status = BE_ALLOC;
      break;
    }
    
    /* now, decrypt the data encryption key with the private key */
    status = B_DecryptInit
      (keyDecryptAlgorithmObj, privateKeyObj,
       DEMO_ALGORITHM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR);
    if (status != 0)
      break;

    status = B_DecryptUpdate
      (keyDecryptAlgorithmObj, dataKeyBuf, &outputLen, encryptedKeyLen,
       encryptedKey, encryptedKeyLen, (B_ALGORITHM_OBJ)NULL_PTR,
       (A_SURRENDER_CTX *)NULL_PTR);
    if (status != 0)
      break;

    dataKeyBufLen = outputLen;
    status = B_DecryptFinal
      (keyDecryptAlgorithmObj, dataKeyBuf + dataKeyBufLen,
       &outputLen, encryptedKeyLen - dataKeyBufLen,
       (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR);
    if (status != 0)
      break;

    dataKeyBufLen += outputLen;

    /* create key object for secret key decryption */
    status = B_CreateKeyObject (&secretKeyObj);
    if (status != 0)
      break;

    /* use the decrypted data encryption key bytes */
    dataKeyItem.data = dataKeyBuf;
    dataKeyItem.len = dataKeyBufLen;

    /* set the data encryption key info */
    status = B_SetKeyInfo (secretKeyObj, KI_Item, (POINTER)&dataKeyItem);
    if (status != 0)
      break;

    /* set up an algorithm object for data decryption */
    status = B_CreateAlgorithmObject (algorithmObject);
    if (status != 0)
      break;

    /* set algorithm info for decrypting DES CBC with padding */
    status = B_SetAlgorithmInfo
      (*algorithmObject, AI_DES_CBCPadIV8, (POINTER)IV);
    if (status != 0)
      break;
    /******************************************************************
       Note: The choice of DES CBC for envelope data decryption
       corresponds to the use of DES CBC for envelope data encryption
       in the BSL_SealDESRSAEnvelopeSetup() routine above.  If this
       routine were intended to handle other signature algorithms, such
       as RC2 CBC, it would be necessary to pass around algorithm
       identifier information with the encrypted data.
     ******************************************************************/

    /* call the decrypt init with the data encryption key */
    status = B_DecryptInit
      (*algorithmObject, secretKeyObj,
       DEMO_ALGORITHM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR);
    if (status != 0)
      break;
    
  } while (0);

  /* cleanup only if an error occurred */
  if (status != 0)
    B_DestroyAlgorithmObject (algorithmObject);
  
  /* cleanup objects */
  B_DestroyAlgorithmObject (&keyDecryptAlgorithmObj);
  B_DestroyAlgorithmObject (&pbEncryptionAlgorithmObj);
  B_DestroyKeyObject (&passwordKeyObj);
  B_DestroyKeyObject (&privateKeyObj);
  B_DestroyKeyObject (&secretKeyObj);

  /* if dataKeyBuf is not NULL, zeroize and free memory */
  if (dataKeyBuf != (unsigned char *)NULL_PTR) {
    T_memset ((POINTER)dataKeyBuf, 0, encryptedKeyLen);
    T_free ((POINTER)dataKeyBuf);
  }

  /* if privateKeyBuf is not NULL, zeroize and free memory */
  if (privateKeyBuf != (unsigned char *)NULL_PTR) {
    T_memset ((POINTER)privateKeyBuf, 0, ppPrivateKeyLen);
    T_free ((POINTER)privateKeyBuf);
  }

  return (status);
}

/*****************************************************************************
 *
 * BSL_ECDSAWithSHA1SignFile
 * -------------------------
 * Creates an ECDSA Digital Signature on a data file using the SHA1 message
 * digest algorithm and the supplied private key.  If the value of the
 * password is NULL_PTR, the private key should be supplied in its
 * unprotected form.  The signature is then stored in the specified file.
 *
 *****************************************************************************/

/* A_EC_PRIVATE_KEY *ppPrivateKey: input: private key */
/* unsigned char *password: input: buffer of private key protection */
 /* password bytes */
/* unsigned int passwordLen: input: number of password bytes */
/* unsigned char *pbeParams: input: buffer of password-based */
 /* encryption algorithm parameters */
 /* bytes */
/* unsigned int pbeParamsLen: input: number of PBE params bytes */
/* unsigned char *seed: input: buffer of seed bytes */
/* unsigned int seedLen: input: number of seed bytes */
int BSL_ECDSAWithSHA1SignFile(char *signatureOutFilename, char *dataInFilename,
  A_EC_PRIVATE_KEY *ppPrivateKey, unsigned char *password,
  unsigned int passwordLen, unsigned char *pbeParams,
  unsigned int pbeParamsLen, unsigned char *seed, unsigned int seedLen)
{
  B_ALGORITHM_OBJ algorithmObject = NULL_PTR;
  int status;
  unsigned char inputBuffer[1024];
  unsigned char *signature = NULL_PTR;
  unsigned int inputLen, signatureLen, maxSignatureLen;
  FILE *file = (FILE *) NULL_PTR;
  
  do {
    /* Open for reading the input file. */
    if ((file = fopen (dataInFilename, "rb")) == NULL)
      /* could not open file */
    return (BE_DATA);
  
    /* Initializate algorithm objects used to calculate signatures */
    if ((status = BSL_ECDSAWithSHA1SignInit
         (&algorithmObject, ppPrivateKey, password,
          passwordLen, pbeParams, pbeParamsLen)) != 0)
      break;

    /* Create signature for contents of inputBuffer */
    do  {
    /* Iteratively read and process the input data in order to produce
       signature.
     */
      inputLen = fread (inputBuffer, 1, 1024, file);
      if ((status = BSL_ECDSAWithSHA1SignUpdate
        (&algorithmObject, inputBuffer, inputLen)) != 0)
        break;
    } while (inputLen == 1024); 
    if (status != 0)
      break;

    /* Allocate space to hold the signature */
    maxSignatureLen = MAX_SIGNATURE_LEN(ppPrivateKey->curveParams.order.len);
    signature = T_malloc(maxSignatureLen);
    if (signature == NULL_PTR) {
      status = BE_ALLOC;
      break;
    }
    /* Finalizes the signature computation */
    if ((status = BSL_ECDSAWithSHA1SignFinal
         (&algorithmObject, signature, &signatureLen, maxSignatureLen,
          seed, seedLen)) != 0)
      break;
    fclose (file);
    
    /* Write the signature to the specified file */
    if ((status = RSA_WriteFile
         (signatureOutFilename, signature, signatureLen)) != 0)
      break;
  } while (0);

  T_free (signature);
  
  return (status);
}        
      
/*****************************************************************************
 *
 * BSL_ECDSAWithSHA1VerifyFile
 * ---------------------------
 * Verifies an ECDSA Digital Signature on a data file using the SHA1 message
 * digest algorithm and the supplied public key.  A zero is returned if
 * the signature is successfully verified, a non-zero error value is
 * returned otherwise.
 *
 *****************************************************************************/

/* A_EC_PUBLIC_KEY *publicKey: input: public key */
int BSL_ECDSAWithSHA1VerifyFile(char *signatureInFilename, char *dataInFilename,
   A_EC_PUBLIC_KEY *publicKey)
{
  B_ALGORITHM_OBJ algorithmObject = NULL_PTR;
  int status;
  unsigned char inputBuffer[1024];
  unsigned char *signature = NULL_PTR;
  unsigned int inputLen, signatureLen, maxSignatureLen;
  FILE *file = (FILE *) NULL_PTR;
  
  do {
    /* Open for reading file to be verified */
    if ((file = fopen (dataInFilename, "rb")) == NULL)
      /* could not open file */
      return (BE_DATA);
    /* Allocate space to hold the signature that will be read in. */
    maxSignatureLen = MAX_SIGNATURE_LEN(publicKey->curveParams.order.len);
    signature = T_malloc(maxSignatureLen);
    if (signature == NULL_PTR) {
      status = BE_ALLOC;
      break;
    }
    /* Read the signature that is used to verify the inputBuffer */
    if ((status = RSA_ReadFile (signatureInFilename, signature,
                            &signatureLen, maxSignatureLen)) != 0)
      break;
    /* Initializate algorithm objects used to verify signatures */
    if ((status = BSL_ECDSAWithSHA1VerifyInit
         (&algorithmObject, publicKey)) != 0)
        break;
    /* Iteratively read and process data in input file in order to verify its
       signature.
     */
    do  {
      inputLen = fread (inputBuffer, 1, 1024, file);
      if ((status = BSL_ECDSAWithSHA1VerifyUpdate
         (&algorithmObject, inputBuffer, inputLen)) != 0)
        break;
    } while (inputLen == 1024);
    /* Finalizes signature verification using the supplied signature */
    if ((status = BSL_ECDSAWithSHA1VerifyFinal
         (&algorithmObject, signature, signatureLen)) != 0)
        break;
    fclose (file);
  } while (0);

  T_free (signature);
  /* A zero return status means signature verification was successful */
  return (status);
}

/*****************************************************************************
 *
 * BSL_SealFileDESWithECESEnvelope
 * ------------------------------
 * Computes an ECES Digital Envelope for a data file using a random key
 * for DES data encryption.  The DES key is then encrypted with the supplied
 * EC public key.  The DES key and IV values are both generated by an
 * random object using the supplied seed value.
 *
 *****************************************************************************/

/* unsigned char *seed: input: buffer of seed bytes */
/* unsigned int seedLen: input: number of seed bytes */
/* A_EC_PUBLIC_KEY *publicKey: input: public key */
int BSL_SealFileDESWithECESEnvelope(char *encryptedKeyOutFilename,
  char *ivOutFilename, char *encryptedDataOutFilename, char *dataInFilename,
  unsigned char *seed, unsigned int seedLen, A_EC_PUBLIC_KEY *publicKey)
{
  B_ALGORITHM_OBJ algorithmObject = NULL_PTR;
  int status;
  unsigned char inputData[1024], encryptedData[1024], IV[8];
  unsigned char *encryptedKey = NULL_PTR;
  unsigned int maxEncryptedKeyLen;
  unsigned int inputDataLen, encryptedKeyLen, encryptedDataLen, len;
  FILE *inputFile  = (FILE *) NULL_PTR;
  FILE *outputFile  = (FILE *) NULL_PTR;
  
  do {
    /* Open for reading plaintext file */
    if ((inputFile = fopen (dataInFilename, "rb")) == NULL) {
      /* could not open file */
      status = BE_DATA;
      break;
    }
    /* Open output file for writing */
   if (encryptedDataOutFilename[0] == '-'
       && encryptedDataOutFilename[1] == '\0')
    /* use stdout */
    outputFile = stdout;
   else 
     if ((outputFile = fopen (encryptedDataOutFilename, "wb")) == NULL) {
       /* could not open file */
       status = BE_DATA;
       break;
     }

   /* Allocate space to hold the encrypted DES Key.
      Since we know the DES key is 8 bytes long, the maximum length of
      the encrypted key is 21 + 8 + (2 * field element length in bytes). */
   maxEncryptedKeyLen =
     MAX_ENC_SYMKEY_LEN(publicKey->curveParams.fieldElementBits);
   encryptedKey = T_malloc(maxEncryptedKeyLen);
   if (encryptedKey == NULL_PTR) {
     status = BE_ALLOC;
     break;
   }
   
   /* Sets up algorithm object for computing the ECES envelope */
   if ((status = BSL_SealDESWithECESEnvelopeSetup
                 (&algorithmObject, encryptedKey, &encryptedKeyLen,
                  IV, seed, seedLen, publicKey)) != 0)
     break;

   /* Do the actual digital envelope encryption by iteratively reading data
      in chunks of 1024 bytes.
    */
   do {
     inputDataLen = fread (inputData, 1, 1024, inputFile);
     if ((status = BSL_BlockEncrypt
                   (&algorithmObject, encryptedData, &encryptedDataLen,
                    inputData, inputDataLen)) != 0)
       break;
     if (fwrite
         (encryptedData, 1, encryptedDataLen, outputFile) < encryptedDataLen) {
       status = BE_DATA;
       break;
     }
   } while (inputDataLen == 1024);
   if (status != 0)
     break;
   /* Pass in NULL_PTR for the input to indicate the end of input */
   if ((status = BSL_BlockEncrypt
                 (&algorithmObject, encryptedData, &len,
                  (unsigned char *)NULL_PTR, 0)) != 0)
     break;
   /* Write out last of encrypted data to file. */
   if (fwrite (encryptedData, 1, len, outputFile) < len) {
     status = BE_DATA;
     break;
   }
    
   /* Write the IV to the specified file */
   if ((status = RSA_WriteFile (ivOutFilename, IV, 8)) != 0)
     break;

   /* Write the encrypted DES key to the specified file */
   if ((status = RSA_WriteFile (encryptedKeyOutFilename, encryptedKey,
                            encryptedKeyLen)) != 0)
     break;

  } while (0);
  T_free (encryptedKey);
  if (inputFile != NULL)
    fclose (inputFile);
  if (outputFile != NULL && outputFile != stdout)
    fclose (outputFile);
  return (status);
}

/*****************************************************************************
 *
 * BSL_OpenFileDESWithECESEnvelope
 * ------------------------------
 * Opens an EC Digital Envelope for a data file using the supplied private
 * key.  If the password is NULL_PTR, the private key must be in its
 * unprotected form.
 *
 *****************************************************************************/

/* A_EC_PRIVATE_KEY *ppPrivateKey: input: private key */
/* unsigned char *password: input: buffer of password bytes */
/* unsigned int passwordLen: input: number of password bytes */
/* unsigned char *pbeParams: input: buffer of password-based encryption */
 /* algorithm parameters bytes */
/* unsigned int pbeParamsLen: input: number of PBE params bytes */
int BSL_OpenFileDESWithECESEnvelope(char *dataOutFilename,
  char *encryptedKeyInFilename, char *ivInFilename,
  char *encryptedDataInFilename, A_EC_PRIVATE_KEY *ppPrivateKey,
  unsigned char *password, unsigned int passwordLen, unsigned char *pbeParams,
   unsigned int pbeParamsLen)
{
  B_ALGORITHM_OBJ algorithmObject = NULL_PTR;
  int status;
  unsigned char outputData[1024], encryptedData[1024], IV[8];
  unsigned char *encryptedKey = NULL_PTR;
  unsigned int maxEncryptedKeyLen;  
  unsigned int outputDataLen, encryptedKeyLen, encryptedDataLen, len, ivLen;
  FILE *outputFile = (FILE *) NULL_PTR;
  FILE *inputFile = (FILE *) NULL_PTR;
  do {
    /* Open the file of encrypted data */
    if ((inputFile = fopen (encryptedDataInFilename, "rb")) == NULL) {
      /* could not open file */
      status = BE_DATA;
      break;
    }
    /* Open the output file for writing */
    if (dataOutFilename[0] == '-'
       && dataOutFilename[1] == '\0')
    /* use stdout */
      outputFile = stdout;
    else 
      if ((outputFile = fopen (dataOutFilename, "wb")) == NULL) {
        /* could not open file */
        status = BE_DATA;
        break;
      } 

    /* Allocate space to hold the encrypted DES Key.
       Since we know the DES key is 8 bytes long, the maximum length of
       the encrypted key is 21 + 8 + (2 * field element length).
       Note that the curve parameters in the EC private key are never
       encrypted.  The only sensitive information contained in the private
       key is the private component.  */
    maxEncryptedKeyLen =
      MAX_ENC_SYMKEY_LEN(ppPrivateKey->curveParams.fieldElementBits);
    encryptedKey = T_malloc(maxEncryptedKeyLen);
    if (encryptedKey == NULL_PTR) {
      status = BE_ALLOC;
      break;
    }    

    /* Read in the encrypted DES key that is to be used to open the envelope */
    if ((status = RSA_ReadFile (encryptedKeyInFilename, encryptedKey,
                            &encryptedKeyLen, maxEncryptedKeyLen)) != 0)
      break;

    /* Read in the IV */
    if ((status = RSA_ReadFile
         (ivInFilename, IV, &ivLen, 8)) != 0)
      break;


    /* Set up algorithm Object to open an ECES envelope */
    if ((status = BSL_OpenDESWithECESEnvelopeSetup
         (&algorithmObject, encryptedKey, encryptedKeyLen, IV, ppPrivateKey,
          password, passwordLen, pbeParams, pbeParamsLen)) != 0)
      break;

    /* Perform the actual digital envelope decryption by iteratively
       reading through encrypted data in chunks of 1024 bytes.
     */
    do {
      encryptedDataLen = fread (encryptedData, 1, 1024, inputFile);
      if ((status = BSL_BlockDecrypt
         (&algorithmObject, outputData, &outputDataLen, encryptedData,
          encryptedDataLen)) != 0)
        break;
      if (fwrite
        (outputData, 1, outputDataLen, outputFile) < outputDataLen) {
        status = BE_DATA;
        break;      
      }
    } while (encryptedDataLen == 1024);
    if (status != 0)
      break;
    /* Pass in NULL_PTR to indicate end of input data stream */
    if ((status = BSL_BlockDecrypt
         (&algorithmObject, outputData, &len,
          (unsigned char *)NULL_PTR, 0)) != 0)
      break;

    /* Write the last data to a file */
     if (fwrite (outputData, 1, len, outputFile) < len) {
      status = BE_DATA;
      break;
      }
    
  } while (0);

  T_free (encryptedKey);
  
  if (inputFile != NULL)
    fclose (inputFile);
  if (outputFile != NULL && outputFile != stdout)  
    fclose (outputFile);
  return (status);
}
    
/* Read a file of up to length maxOutputLen bytes, storing it in
     output and returning its length in outputLen.
   Return 0 on success or 1 if error or if user cancels by entering a blank.
 */
static int RSA_ReadFile(char *filename, unsigned char *output,
  unsigned int *outputLen, unsigned int maxOutputLen)
{
  FILE *file = (FILE *) NULL_PTR;
  unsigned char dummy;
  
  if ((file = fopen (filename, "rb")) == NULL)
      /* could not open file */
    return (BE_DATA);
  
  /* fread () returns the number of items read in.  Expect an end of file
       after the read.
   */
  *outputLen = fread (output, 1, maxOutputLen, file);
  if (*outputLen == maxOutputLen)
    /* Read exactly maxOutputLen bytes, so reading one more will set 
         end of file if there were exactly maxOutputLen bytes in the file.
     */
     fread (&dummy, 1, 1, file);
  
  if (!feof (file)) {
    fclose (file);
    return (BE_DATA);
  }
  
  fclose (file);
  return (0);
}

/* Write the input data of length inputLen to a file.
   Return 0 on success or 1 if error or if user cancels by entering a blank.
 */
static int RSA_WriteFile(char *filename, unsigned char *input,
  unsigned int inputLen)
{
  FILE *file = (FILE *) NULL_PTR;
  
  if (filename[0] == '-' && filename[1] == '\0')
    /* use stdout */
    file = stdout;
  else {
    if ((file = fopen (filename, "wb")) == NULL)
      /* could not open file */
      return (BE_DATA);
  }
  
  if (fwrite (input, 1, inputLen, file) < inputLen) {
    fclose (file);
    return (BE_DATA);
  }
  else {
    if (file == stdout)
      /* Printing to screen, so print a new line. */
      printf ("\n");
  }

  if (file != stdout)
    fclose (file);
  
  return (0);
}

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