//********************************************************************************
//
// cdsatest.cpp: based on Kendal's cdsadriver
//
//********************************************************************************


//------------------------------------------------------------
// include
//------------------------------------------------------------

#include "cssm.h"

#include <iomanip.h>
#include <iostream.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>


//------------------------------------------------------------
// macros
//------------------------------------------------------------

#define FUNCTION_TRACE_LEVEL 2


//------------------------------------------------------------
// class: FunctionTracer
//------------------------------------------------------------

class FunctionTracer
{
public:
   FunctionTracer(unsigned level,
                  const char* funcName)
   :  d_level(level),
      d_funcName(new char[strlen(funcName)+1])
   {
      strcpy(d_funcName, funcName);
#ifdef FUNCTION_TRACE_LEVEL
      if (d_level <= FUNCTION_TRACE_LEVEL)
         cout << "---> " << d_funcName << endl;
#endif
   }
   ~FunctionTracer(void)
   {
#ifdef FUNCTION_TRACE_LEVEL
      if (d_level <= FUNCTION_TRACE_LEVEL)
         cout << "<--- " << d_funcName << endl;
#endif
      delete[] d_funcName;
   }
private:
   unsigned d_level;
   char* d_funcName;
};


//------------------------------------------------------------
// functions
//------------------------------------------------------------

// memory management

static void* DefaultMalloc(uint32 size,
                           void* allocRef = NULL);
static void DefaultFree(void* memPtr,
                        void* allocRef = NULL);
static void* DefaultRealloc(void* memPtr,
                            uint32 size,
                            void* allocRef = NULL);
static void* DefaultCalloc(uint32 num,
                           uint32 size,
                           void* allocRef = NULL);

// CSSM utility

static void DumpData(ostream& os,
                     CSSM_DATA& data);
static void DumpData(ostream& os,
                     CSSM_BOOL& data);
static void ThrowCSSMException(uint32 errcode);
static void InitializeCSSM(void);
static CSSM_CSP_HANDLE AttachCSP(void);

// test suite

static int TestRandomDataGeneration(CSSM_CSP_HANDLE cspHandle);
static int TestRSAKeyPairGeneration(CSSM_CSP_HANDLE cspHandle);
static int TestRC4KeyGeneration(CSSM_CSP_HANDLE cspHandle);
static int TestSHA1Digest(CSSM_CSP_HANDLE cspHandle);
static int TestSHA1WithRSASignVerify(CSSM_CSP_HANDLE cspHandle);
static int TestRSAPKCSEncryptDecrypt(CSSM_CSP_HANDLE cspHandle);
static int TestRC4EncryptDecrypt(CSSM_CSP_HANDLE cspHandle);

// crypto

static void GenerateRandomData(CSSM_CSP_HANDLE cspHandle,
                               uint32 randomDataSize,
                               CSSM_DATA& randomData);
static void RSA_GenerateKeyPair(CSSM_CSP_HANDLE cspHandle,
                                uint32 modulusBits,
                                CSSM_KEY& publicKey,
                                CSSM_KEY& privateKey);
static void RC4_GenerateKey(CSSM_CSP_HANDLE cspHandle,
                            uint32 keySizeInBits,
                            CSSM_KEY& secretKey);
static void SHA1_DigestData(CSSM_CSP_HANDLE cspHandle,
                            const CSSM_DATA& dataToDigest,
                            CSSM_DATA& digest);
static void SHA1WithRSA_SignData(CSSM_CSP_HANDLE cspHandle,
                                 CSSM_KEY& privateKey,
                                 const CSSM_DATA& dataToSign,
                                 CSSM_DATA& signature);
static void SHA1WithRSA_VerifyData(CSSM_CSP_HANDLE cspHandle,
                                   CSSM_KEY& publicKey,
                                   const CSSM_DATA& signature,
                                   const CSSM_DATA& dataToVerify,
                                   CSSM_BOOL& isVerified);
static void RSAPKCS_EncryptData(CSSM_CSP_HANDLE cspHandle,
                                const CSSM_KEY& rsaKey,
                                const CSSM_DATA& dataToEncrypt,
                                CSSM_DATA& encryptedData);
static void RC4_EncryptData(CSSM_CSP_HANDLE cspHandle,
                            const CSSM_KEY& rc4Key,
                            const CSSM_DATA& dataToEncrypt,
                            CSSM_DATA& encryptedData);
static void RSAPKCS_DecryptData(CSSM_CSP_HANDLE cspHandle,
                                const CSSM_KEY& rsaKey,
                                const CSSM_DATA& dataToDecrypt,
                                CSSM_DATA& decryptedData);
static void RC4_DecryptData(CSSM_CSP_HANDLE cspHandle,
                            const CSSM_KEY& rc4Key,
                            const CSSM_DATA& dataToDecrypt,
                            CSSM_DATA& decryptedData);


//------------------------------------------------------------
// function: main
//------------------------------------------------------------

int
main(int argc, char* argv[])
{
   FunctionTracer funcTracer(1, "main()");

   int rc = EXIT_SUCCESS;
   CSSM_CSP_HANDLE cspHandle;

   try
   {
      // initialize CSSM

      InitializeCSSM();

      // attach service providers

      cspHandle = AttachCSP();

      // test suite

      if (EXIT_SUCCESS == rc) rc = TestRandomDataGeneration(cspHandle);
      if (EXIT_SUCCESS == rc) rc = TestRSAKeyPairGeneration(cspHandle);
      if (EXIT_SUCCESS == rc) rc = TestRC4KeyGeneration(cspHandle);
      if (EXIT_SUCCESS == rc) rc = TestSHA1Digest(cspHandle);
      if (EXIT_SUCCESS == rc) rc = TestSHA1WithRSASignVerify(cspHandle);
      if (EXIT_SUCCESS == rc) rc = TestRSAPKCSEncryptDecrypt(cspHandle);
      if (EXIT_SUCCESS == rc) rc = TestRC4EncryptDecrypt(cspHandle);
   }
   catch (const char* msg)
   {
      cerr << "EXCEPTION: " << msg << endl;
      rc = EXIT_FAILURE;
   }
   catch (...)
   {
      cerr << "EXCEPTION: NO_MSG" << endl;
      rc = EXIT_FAILURE;
   }

   return rc;
}


//********************************************************************************
//
// memory management
//
//********************************************************************************


//------------------------------------------------------------
// function: DefaultMalloc
//------------------------------------------------------------

void*
DefaultMalloc(uint32 size,
              void* allocRef)
{
   FunctionTracer funcTracer(4, "DefaultMalloc()");

   return malloc(size);
}


//------------------------------------------------------------
// function: DefaultFree
//------------------------------------------------------------

void
DefaultFree(void* memPtr,
            void* allocRef)
{
   FunctionTracer funcTracer(4, "DefaultFree()");

   free(memPtr);
}


//------------------------------------------------------------
// function: DefaultRealloc
//------------------------------------------------------------

void*
DefaultRealloc(void* memPtr,
               uint32 size,
               void* allocRef)
{
   FunctionTracer funcTracer(4, "DefaultRealloc()");

   return realloc(memPtr, size);
}


//------------------------------------------------------------
// function: DefaultCalloc
//------------------------------------------------------------

void*
DefaultCalloc(uint32 num,
              uint32 size,
              void* allocRef)
{
   FunctionTracer funcTracer(4, "DefaultCalloc()");

   return calloc(num, size);
}


//********************************************************************************
//
// CSSM utility
//
//********************************************************************************


//------------------------------------------------------------
// function: DumpData
//------------------------------------------------------------

void
DumpData(ostream& os,
         CSSM_DATA& data)
{
   uint32 i;
   char originalFill = os.fill('0');
   os.setf(ios::hex, ios::basefield);
   for (i = 0; i < data.Length; i++)
   {
      if (i == 0) os << "0x";
      os << setw(2) << (int)data.Data[i];
   }
   os.fill(originalFill);
   os.unsetf(ios::hex);
}


//------------------------------------------------------------
// function: DumpData
//------------------------------------------------------------

void
DumpData(ostream& os,
         CSSM_BOOL& data)
{
   if (CSSM_TRUE == data)
      os << "TRUE";
   else
      os << "FALSE";
}


//------------------------------------------------------------
// function: ThrowCSSMException
//------------------------------------------------------------

void
ThrowCSSMException(uint32 errcode)
{
   FunctionTracer funcTracer(4, "ThrowCSSMException()");

   static char msg[64];

   sprintf(msg, "CSSM_ERROR_CODE = %lu", errcode);

   throw msg;
}


//------------------------------------------------------------
// function: InitializeCSSM
//------------------------------------------------------------

void
InitializeCSSM(void)
{
   FunctionTracer funcTracer(2, "InitializeCSSM()");

   CSSM_VERSION version = { CSSM_MAJOR, CSSM_MINOR };
   CSSM_MEMORY_FUNCS memoryFuncs = { DefaultMalloc, DefaultFree, DefaultRealloc, DefaultCalloc, NULL };

   if (CSSM_FAIL == CSSM_Init(&version, &memoryFuncs, NULL))
      ThrowCSSMException(CSSM_GetError()->error);
}


//------------------------------------------------------------
// function: AttachCSP
//------------------------------------------------------------

CSSM_CSP_HANDLE
AttachCSP(void)
{
   FunctionTracer funcTracer(2, "AttachCSP()");

   CSSM_LIST* moduleListPtr = CSSM_ListModules(CSSM_SERVICE_CSP, CSSM_FALSE);
   if (!moduleListPtr)
      ThrowCSSMException(CSSM_GetError()->error);

   // assume there is only one CSP addin module installed

   CSSM_MODULE_INFO* moduleInfoPtr = CSSM_GetModuleInfo(&(moduleListPtr->Items[0].GUID),
                                                        CSSM_SERVICE_CSP,
                                                        CSSM_ALL_SUBSERVICES,
                                                        CSSM_INFO_LEVEL_ALL_ATTR);
   if (!moduleInfoPtr)
      ThrowCSSMException(CSSM_GetError()->error);

   CSSM_CSP_HANDLE cspHandle;
   CSSM_API_MEMORY_FUNCS memoryFuncs = { DefaultMalloc, DefaultFree, DefaultRealloc, DefaultCalloc, NULL };

   cspHandle = CSSM_ModuleAttach(&(moduleListPtr->Items[0].GUID),
                                 &moduleInfoPtr->Version,
                                 &memoryFuncs,
                                 0,
                                 0,
                                 0,
                                 NULL,
                                 NULL);
   if (!cspHandle)
      ThrowCSSMException(CSSM_GetError()->error);

   if (CSSM_FreeModuleInfo(moduleInfoPtr) == CSSM_FAIL)
      ThrowCSSMException(CSSM_GetError()->error);

   if (CSSM_FreeList(moduleListPtr) == CSSM_FAIL)
      ThrowCSSMException(CSSM_GetError()->error);

   return cspHandle;
}



//********************************************************************************
//
// test suite
//
//********************************************************************************


//------------------------------------------------------------
// function: TestRandomDataGeneration
//------------------------------------------------------------

int
TestRandomDataGeneration(CSSM_CSP_HANDLE cspHandle)
{
   FunctionTracer funcTracer(1, "TestRandomDataGeneration()");

   int rc = EXIT_SUCCESS;
   CSSM_DATA randomData;
   static const uint32 RANDOM_DATA_SIZE_ARRAY[] = { 1, 2, 4, 8, 16 };
   static const uint32 RANDOM_DATA_SIZE_ARRAY_SIZE = sizeof(RANDOM_DATA_SIZE_ARRAY) / sizeof(uint32);
   uint32 i;

   try
   {
      for (i = 0; i < RANDOM_DATA_SIZE_ARRAY_SIZE; i++)
      {
         GenerateRandomData(cspHandle, RANDOM_DATA_SIZE_ARRAY[i], randomData);
         cout << "RandomData: ";
         DumpData(cout, randomData);
         cout << endl;
         DefaultFree(randomData.Data);
      }
   }
   catch (const char* msg)
   {
      cerr << "EXCEPTION: " << msg << endl;
      rc = EXIT_FAILURE;
   }
   catch (...)
   {
      cerr << "EXCEPTION: NO_MSG" << endl;
      rc = EXIT_FAILURE;
   }

   return rc;
}


//------------------------------------------------------------
// function: TestRSAKeyPairGeneration
//------------------------------------------------------------

int
TestRSAKeyPairGeneration(CSSM_CSP_HANDLE cspHandle)
{
   FunctionTracer funcTracer(1, "TestRSAKeyPairGeneration()");

   int rc = EXIT_SUCCESS;
   CSSM_KEY publicKey;
   CSSM_KEY privateKey;
   static const uint32 MODULUS_BITS_ARRAY[] = { 512, 768, 1024 };
   static const uint32 MODULUS_BITS_ARRAY_SIZE = sizeof(MODULUS_BITS_ARRAY) / sizeof(uint32);
   uint32 i;

   try
   {
      for (i = 0; i < MODULUS_BITS_ARRAY_SIZE; i++)
      {
         RSA_GenerateKeyPair(cspHandle,
                             MODULUS_BITS_ARRAY[i],
                             publicKey,
                             privateKey);
         cout << "PublicKeySize: " << publicKey.KeyHeader.KeySizeInBits << endl;
         cout << "PrivateKeySize: " << privateKey.KeyHeader.KeySizeInBits << endl;
         DefaultFree(publicKey.KeyData.Data);
         DefaultFree(privateKey.KeyData.Data);
      }
   }
   catch (const char* msg)
   {
      cerr << "EXCEPTION: " << msg << endl;
      rc = EXIT_FAILURE;
   }
   catch (...)
   {
      cerr << "EXCEPTION: NO_MSG" << endl;
      rc = EXIT_FAILURE;
   }

   return rc;
}


//------------------------------------------------------------
// function: TestRC4KeyGeneration
//------------------------------------------------------------

int
TestRC4KeyGeneration(CSSM_CSP_HANDLE cspHandle)
{
   FunctionTracer funcTracer(1, "TestRC4KeyGeneration()");

   int rc = EXIT_SUCCESS;
   CSSM_KEY secretKey;
   static const uint32 KEY_SIZE_IN_BITS_ARRAY[] = { 40, 56, 64, 80, 128 };
   static const uint32 KEY_SIZE_IN_BITS_ARRAY_SIZE = sizeof(KEY_SIZE_IN_BITS_ARRAY) / sizeof(uint32);
   uint32 i;

   try
   {
      for (i = 0; i < KEY_SIZE_IN_BITS_ARRAY_SIZE; i++)
      {
         RC4_GenerateKey(cspHandle,
                         KEY_SIZE_IN_BITS_ARRAY[i],
                         secretKey);
         cout << "SecretKeySize: " << secretKey.KeyHeader.KeySizeInBits << endl;
         DefaultFree(secretKey.KeyData.Data);
      }
   }
   catch (const char* msg)
   {
      cerr << "EXCEPTION: " << msg << endl;
      rc = EXIT_FAILURE;
   }
   catch (...)
   {
      cerr << "EXCEPTION: NO_MSG" << endl;
      rc = EXIT_FAILURE;
   }

   return rc;
}


//------------------------------------------------------------
// function: TestSHA1Digest
//------------------------------------------------------------

int
TestSHA1Digest(CSSM_CSP_HANDLE cspHandle)
{
   FunctionTracer funcTracer(1, "TestSHA1Digest()");

   int rc = EXIT_SUCCESS;
   static const char* DATA_TO_DIGEST_ARRAY[] =
   {
      "Kendal",
      "Ian",
      "Avery",
      "Adam",
      "Marvin",
      "Zheng-wen"
   };
   static const uint32 DATA_TO_DIGEST_ARRAY_SIZE = sizeof(DATA_TO_DIGEST_ARRAY) / sizeof(char*);
   uint32 i;
   CSSM_DATA dataToDigest;
   CSSM_DATA digest;

   try
   {
      for (i = 0; i < DATA_TO_DIGEST_ARRAY_SIZE; i++)
      {
         dataToDigest.Length = strlen(DATA_TO_DIGEST_ARRAY[i]);
         dataToDigest.Data = (uint8*)DATA_TO_DIGEST_ARRAY[i];
         SHA1_DigestData(cspHandle,
                         dataToDigest,
                         digest);
         cout << "Digest(" << DATA_TO_DIGEST_ARRAY[i] << "): ";
         DumpData(cout, digest);
         cout << endl;
         DefaultFree(digest.Data);
      }
   }
   catch (const char* msg)
   {
      cerr << "EXCEPTION: " << msg << endl;
      rc = EXIT_FAILURE;
   }
   catch (...)
   {
      cerr << "EXCEPTION: NO_MSG" << endl;
      rc = EXIT_FAILURE;
   }

   return rc;
}


//------------------------------------------------------------
// function: TestSHA1WithRSASignVerify
//------------------------------------------------------------

int
TestSHA1WithRSASignVerify(CSSM_CSP_HANDLE cspHandle)
{
   FunctionTracer funcTracer(1, "TestSHA1WithRSASignVerify()");

   int rc = EXIT_SUCCESS;
   static const char* DATA_TO_SIGN_ARRAY[] =
   {
      "Kendal",
      "Ian",
      "Avery",
      "Adam",
      "Marvin",
      "Zheng-wen"
   };
   static const uint32 DATA_TO_SIGN_ARRAY_SIZE = sizeof(DATA_TO_SIGN_ARRAY) / sizeof(char*);
   uint32 i;
   CSSM_KEY publicKey;
   CSSM_KEY privateKey;
   CSSM_DATA dataToSign;
   CSSM_DATA signature;
   CSSM_BOOL isVerified;

   RSA_GenerateKeyPair(cspHandle,
                       512,
                       publicKey,
                       privateKey);

   try
   {
      for (i = 0; i < DATA_TO_SIGN_ARRAY_SIZE; i++)
      {
         dataToSign.Length = strlen(DATA_TO_SIGN_ARRAY[i]);
         dataToSign.Data = (uint8*)DATA_TO_SIGN_ARRAY[i];

         SHA1WithRSA_SignData(cspHandle,
                              privateKey,
                              dataToSign,
                              signature);
         cout << "Signature(" << DATA_TO_SIGN_ARRAY[i] << "): ";
         DumpData(cout, signature);
         cout << endl;

         SHA1WithRSA_VerifyData(cspHandle,
                                publicKey,
                                signature,
                                dataToSign,
                                isVerified);
         cout << "IsVerified: ";
         DumpData(cout, isVerified);
         cout << endl;

         DefaultFree(signature.Data);
      }
   }
   catch (const char* msg)
   {
      cerr << "EXCEPTION: " << msg << endl;
      rc = EXIT_FAILURE;
   }
   catch (...)
   {
      cerr << "EXCEPTION: NO_MSG" << endl;
      rc = EXIT_FAILURE;
   }

   DefaultFree(publicKey.KeyData.Data);
   DefaultFree(privateKey.KeyData.Data);

   return rc;
}


//------------------------------------------------------------
// function: TestRSAPKCSEncryptDecrypt
//------------------------------------------------------------

int
TestRSAPKCSEncryptDecrypt(CSSM_CSP_HANDLE cspHandle)
{
   FunctionTracer funcTracer(1, "TestRSAPKCSEncryptDecrypt()");

   int rc = EXIT_SUCCESS;
   static const char* DATA_TO_ENCRYPT_ARRAY[] =
   {
      "Kendal",
      "Ian",
      "Avery",
      "Adam",
      "Marvin",
      "Zheng-wen"
   };
   static const uint32 DATA_TO_ENCRYPT_ARRAY_SIZE = sizeof(DATA_TO_ENCRYPT_ARRAY) / sizeof(char*);
   uint32 i;
   CSSM_KEY publicKey;
   CSSM_KEY privateKey;
   CSSM_DATA dataToEncrypt;
   CSSM_DATA encryptedData;
   CSSM_DATA decryptedData;
   clock_t startTime;
   clock_t finishTime;
   double duration;

   RSA_GenerateKeyPair(cspHandle,
                       512,
                       publicKey,
                       privateKey);

   try
   {
      for (i = 0; i < DATA_TO_ENCRYPT_ARRAY_SIZE; i++)
      {
         dataToEncrypt.Length = strlen(DATA_TO_ENCRYPT_ARRAY[i]) + 1;
         dataToEncrypt.Data = (uint8*)DATA_TO_ENCRYPT_ARRAY[i];

         startTime = clock();
         RSAPKCS_EncryptData(cspHandle,
                             publicKey,
                             dataToEncrypt,
                             encryptedData);
         finishTime = clock();
         duration = (double)(finishTime - startTime) / CLOCKS_PER_SEC;
         cout << "RSAPKCSEncryption-ElapseTime(secs): " << duration << endl;
         cout << "EncryptedData(" << DATA_TO_ENCRYPT_ARRAY[i] << "): ";
         DumpData(cout, encryptedData);
         cout << endl;

         RSAPKCS_DecryptData(cspHandle,
                             privateKey,
                             encryptedData,
                             decryptedData);
         cout << "DecryptedData: " << (char*)decryptedData.Data << endl;

         DefaultFree(encryptedData.Data);
         DefaultFree(decryptedData.Data);
      }
   }
   catch (const char* msg)
   {
      cerr << "EXCEPTION: " << msg << endl;
      rc = EXIT_FAILURE;
   }
   catch (...)
   {
      cerr << "EXCEPTION: NO_MSG" << endl;
      rc = EXIT_FAILURE;
   }

   DefaultFree(publicKey.KeyData.Data);
   DefaultFree(privateKey.KeyData.Data);

   return rc;
}


//------------------------------------------------------------
// function: TestRC4EncryptDecrypt
//------------------------------------------------------------

int
TestRC4EncryptDecrypt(CSSM_CSP_HANDLE cspHandle)
{
   FunctionTracer funcTracer(1, "TestRC4EncryptDecrypt()");

   int rc = EXIT_SUCCESS;
   static const char* DATA_TO_ENCRYPT_ARRAY[] =
   {
      "Kendal",
      "Ian",
      "Avery",
      "Adam",
      "Marvin",
      "Zheng-wen"
   };
   static const uint32 DATA_TO_ENCRYPT_ARRAY_SIZE = sizeof(DATA_TO_ENCRYPT_ARRAY) / sizeof(char*);
   uint32 i;
   CSSM_KEY secretKey;
   CSSM_DATA dataToEncrypt;
   CSSM_DATA encryptedData;
   CSSM_DATA decryptedData;
   clock_t startTime;
   clock_t finishTime;
   double duration;

   RC4_GenerateKey(cspHandle,
                   40,
                   secretKey);

   try
   {
      for (i = 0; i < DATA_TO_ENCRYPT_ARRAY_SIZE; i++)
      {
         dataToEncrypt.Length = strlen(DATA_TO_ENCRYPT_ARRAY[i]) + 1;
         dataToEncrypt.Data = (uint8*)DATA_TO_ENCRYPT_ARRAY[i];

         startTime = clock();
         RC4_EncryptData(cspHandle,
                         secretKey,
                         dataToEncrypt,
                         encryptedData);
         finishTime = clock();
         duration = (double)(finishTime - startTime) / CLOCKS_PER_SEC;
         cout << "RC4Encryption-ElapseTime(secs): " << duration << endl;
         cout << "EncryptedData(" << DATA_TO_ENCRYPT_ARRAY[i] << "): ";
         DumpData(cout, encryptedData);
         cout << endl;

         RC4_DecryptData(cspHandle,
                         secretKey,
                         encryptedData,
                         decryptedData);
         cout << "DecryptedData: " << (char*)decryptedData.Data << endl;

         DefaultFree(encryptedData.Data);
         DefaultFree(decryptedData.Data);
      }
   }
   catch (int errorCode)
   {
      cerr << "errorCode = " << errorCode << endl;
      rc = EXIT_FAILURE;
   }
   catch (const char* msg)
   {
      cerr << "EXCEPTION: " << msg << endl;
      rc = EXIT_FAILURE;
   }
   catch (...)
   {
      cerr << "EXCEPTION: NO_MSG" << endl;
      rc = EXIT_FAILURE;
   }

   DefaultFree(secretKey.KeyData.Data);

   return rc;
}


//********************************************************************************
//
// crypto
//
//********************************************************************************


//------------------------------------------------------------
// function: GenerateRandomData
//------------------------------------------------------------

void
GenerateRandomData(CSSM_CSP_HANDLE cspHandle,
                   uint32 randomDataSize,
                   CSSM_DATA& randomData)
{
   FunctionTracer funcTracer(3, "GenerateRandomData()");

   CSSM_CC_HANDLE ccHandle;

   ccHandle = CSSM_CSP_CreateRandomGenContext(cspHandle,
                                              CSSM_ALGID_MD5Random,
                                              NULL,
                                              randomDataSize);
   if (!ccHandle)
      ThrowCSSMException(CSSM_GetError()->error);

   randomData.Data = 0;
   randomData.Length = 0;

   if (CSSM_FAIL == CSSM_GenerateRandom(ccHandle, &randomData))
   {
      uint32 errcode = CSSM_GetError()->error;
      CSSM_DeleteContext(ccHandle);
      ThrowCSSMException(errcode);
   }
   CSSM_DeleteContext(ccHandle);
}


//------------------------------------------------------------
// function: GenerateRandomData
//------------------------------------------------------------

void
RSA_GenerateKeyPair(CSSM_CSP_HANDLE cspHandle,
                    uint32 modulusBits,
                    CSSM_KEY& publicKey,
                    CSSM_KEY& privateKey)
{
   FunctionTracer funcTracer(3, "GenerateRandomData()");

   CSSM_CC_HANDLE ccHandle;
   uint32 keyUsage = CSSM_KEYUSE_SIGN|CSSM_KEYUSE_VERIFY|CSSM_KEYUSE_ENCRYPT|CSSM_KEYUSE_DECRYPT;
   uint32 keyAttr = CSSM_KEYATTR_PERMANENT;

   ccHandle = CSSM_CSP_CreateKeyGenContext(cspHandle,
                                           CSSM_ALGID_RSA,
                                           NULL,
                                           modulusBits,
                                           NULL,
                                           NULL,
                                           NULL,
                                           NULL,
                                           NULL);
   if (!ccHandle)
      ThrowCSSMException(CSSM_GetError()->error);

   memset(&publicKey, 0, sizeof(CSSM_KEY));
   memset(&privateKey, 0, sizeof(CSSM_KEY));

   if (CSSM_FAIL == CSSM_GenerateKeyPair(ccHandle,
                                         keyUsage,
                                         keyAttr,
                                         NULL,
                                         &publicKey,
                                         keyUsage,
                                         keyAttr,
                                         NULL,
                                         &privateKey))
   {
      uint32 errcode = CSSM_GetError()->error;
      CSSM_DeleteContext(ccHandle);
      ThrowCSSMException(errcode);
   }

   CSSM_DeleteContext(ccHandle);
}


//------------------------------------------------------------
// function: RC4_GenerateKey
//------------------------------------------------------------

void
RC4_GenerateKey(CSSM_CSP_HANDLE cspHandle,
                uint32 keySizeInBits,
                CSSM_KEY& secretKey)
{
   FunctionTracer funcTracer(3, "RC4_GenerateKey()");

   CSSM_CC_HANDLE ccHandle;
   uint32 keyUsage = CSSM_KEYUSE_ENCRYPT|CSSM_KEYUSE_DECRYPT;
   uint32 keyAttr = CSSM_KEYATTR_PERMANENT;

   ccHandle = CSSM_CSP_CreateKeyGenContext(cspHandle,
                                           CSSM_ALGID_RC4,
                                           NULL,
                                           keySizeInBits,
                                           NULL,
                                           NULL,
                                           NULL,
                                           NULL,
                                           NULL);
   if (!ccHandle)
      ThrowCSSMException(CSSM_GetError()->error);

   memset(&secretKey, 0, sizeof(CSSM_KEY));

   if (CSSM_FAIL == CSSM_GenerateKey(ccHandle,
                                     keyUsage,
                                     keyAttr,
                                     NULL,
                                     &secretKey))
   {
      uint32 errcode = CSSM_GetError()->error;
      CSSM_DeleteContext(ccHandle);
      ThrowCSSMException(errcode);
   }

   CSSM_DeleteContext(ccHandle);
}


//------------------------------------------------------------
// function: SHA1_DigestData
//------------------------------------------------------------

void
SHA1_DigestData(CSSM_CSP_HANDLE cspHandle,
                const CSSM_DATA& dataToDigest,
                CSSM_DATA& digest)
{
   FunctionTracer funcTracer(3, "SHA1_DigestData()");

   CSSM_CC_HANDLE ccHandle;

   ccHandle = CSSM_CSP_CreateDigestContext(cspHandle,
                                           CSSM_ALGID_SHA1);
   if (!ccHandle)
      ThrowCSSMException(CSSM_GetError()->error);

   digest.Data = 0;
   digest.Length = 0;

   if (CSSM_FAIL == CSSM_DigestData(ccHandle,
                                    (const CSSM_DATA_PTR)&dataToDigest,
                                    1,
                                    &digest))
   {
      uint32 errcode = CSSM_GetError()->error;
      CSSM_DeleteContext(ccHandle);
      ThrowCSSMException(errcode);
   }

   CSSM_DeleteContext(ccHandle);
}


//------------------------------------------------------------
// function: SHA1WithRSA_SignData
//------------------------------------------------------------

void
SHA1WithRSA_SignData(CSSM_CSP_HANDLE cspHandle,
                     CSSM_KEY& privateKey,
                     const CSSM_DATA& dataToSign,
                     CSSM_DATA& signature)
{
   FunctionTracer funcTracer(3, "SHA1WithRSA_SignData()");

   CSSM_CC_HANDLE ccHandle;

   ccHandle = CSSM_CSP_CreateSignatureContext(cspHandle,
                                              CSSM_ALGID_SHA1WithRSA,
                                              NULL,
                                              &privateKey);
   if (!ccHandle)
      ThrowCSSMException(CSSM_GetError()->error);

   signature.Data = 0;
   signature.Length = 0;

   if (CSSM_FAIL == CSSM_SignData(ccHandle,
                                  (const CSSM_DATA_PTR)&dataToSign,
                                  1,
                                  &signature))
   {
      uint32 errcode = CSSM_GetError()->error;
      CSSM_DeleteContext(ccHandle);
      ThrowCSSMException(errcode);
   }

   CSSM_DeleteContext(ccHandle);
}


//------------------------------------------------------------
// function: SHA1WithRSA_VerifyData
//------------------------------------------------------------

void
SHA1WithRSA_VerifyData(CSSM_CSP_HANDLE cspHandle,
                       CSSM_KEY& publicKey,
                       const CSSM_DATA& signature,
                       const CSSM_DATA& dataToVerify,
                       CSSM_BOOL& isVerified)
{
   FunctionTracer funcTracer(3, "SHA1WithRSA_VerifyData()");

   CSSM_CC_HANDLE ccHandle;

   ccHandle = CSSM_CSP_CreateSignatureContext(cspHandle,
                                              CSSM_ALGID_SHA1WithRSA,
                                              NULL,
                                              &publicKey);
   if (!ccHandle)
      ThrowCSSMException(CSSM_GetError()->error);

   isVerified = CSSM_VerifyData(ccHandle,
                                (const CSSM_DATA_PTR)&dataToVerify,
                                1,
                                (const CSSM_DATA_PTR)&signature);

   CSSM_DeleteContext(ccHandle);
}


//------------------------------------------------------------
// function: RSAPKCS_EncryptData
//------------------------------------------------------------

void
RSAPKCS_EncryptData(CSSM_CSP_HANDLE cspHandle,
                    const CSSM_KEY& rsaKey,
                    const CSSM_DATA& dataToEncrypt,
                    CSSM_DATA& encryptedData)
{
   FunctionTracer funcTracer(3, "RSAPKCS_EncryptData()");

   CSSM_CC_HANDLE ccHandle;
   CSSM_DATA remData = { 0, 0 };
   uint32 numBytesEncrypted = 0;

   ccHandle = CSSM_CSP_CreateAsymmetricContext(cspHandle,
                                               CSSM_ALGID_RSA_PKCS,
                                               NULL,
                                               (const CSSM_KEY_PTR)&rsaKey,
                                               CSSM_PADDING_NONE);
   if (!ccHandle)
      ThrowCSSMException(CSSM_GetError()->error);

   encryptedData.Length = 0;
   encryptedData.Data = 0;

   if (CSSM_FAIL == CSSM_EncryptData(ccHandle,
                                     (const CSSM_DATA_PTR)&dataToEncrypt,
                                     1,
                                     &encryptedData,
                                     1,
                                     &numBytesEncrypted,
                                     &remData))
   {
      uint32 errcode = CSSM_GetError()->error;
      CSSM_DeleteContext(ccHandle);
      ThrowCSSMException(errcode);
   }

   CSSM_DeleteContext(ccHandle);
   encryptedData.Length = numBytesEncrypted + remData.Length;
   encryptedData.Data = (uint8*)DefaultRealloc(encryptedData.Data, encryptedData.Length);
   memmove(encryptedData.Data + numBytesEncrypted, remData.Data, remData.Length);
}


//------------------------------------------------------------
// function: RC4_EncryptData
//------------------------------------------------------------

void
RC4_EncryptData(CSSM_CSP_HANDLE cspHandle,
                const CSSM_KEY& rc4Key,
                const CSSM_DATA& dataToEncrypt,
                CSSM_DATA& encryptedData)
{
   FunctionTracer funcTracer(3, "RC4_EncryptData()");

   CSSM_CC_HANDLE ccHandle;
   CSSM_DATA remData = { 0, 0 };
   uint32 numBytesEncrypted = 0;

   ccHandle = CSSM_CSP_CreateSymmetricContext(cspHandle,
                                              CSSM_ALGID_RC4,
                                              CSSM_ALGMODE_NONE,
                                              (const CSSM_KEY_PTR)&rc4Key,
                                              NULL,
                                              CSSM_PADDING_NONE,
                                              0);
   if (!ccHandle)
      ThrowCSSMException(CSSM_GetError()->error);

   encryptedData.Length = 0;
   encryptedData.Data = 0;

   if (CSSM_FAIL == CSSM_EncryptData(ccHandle,
                                     (const CSSM_DATA_PTR)&dataToEncrypt,
                                     1,
                                     &encryptedData,
                                     1,
                                     &numBytesEncrypted,
                                     &remData))
   {
      uint32 errcode = CSSM_GetError()->error;
      CSSM_DeleteContext(ccHandle);
      ThrowCSSMException(errcode);
   }

   CSSM_DeleteContext(ccHandle);
   encryptedData.Length = numBytesEncrypted + remData.Length;
   encryptedData.Data = (uint8*)DefaultRealloc(encryptedData.Data, encryptedData.Length);
   memmove(encryptedData.Data + numBytesEncrypted, remData.Data, remData.Length);
}


//------------------------------------------------------------
// function: RSAPKCS_DecryptData
//------------------------------------------------------------

void
RSAPKCS_DecryptData(CSSM_CSP_HANDLE cspHandle,
                    const CSSM_KEY& rsaKey,
                    const CSSM_DATA& dataToDecrypt,
                    CSSM_DATA& decryptedData)
{
   FunctionTracer funcTracer(3, "RSAPKCS_DecryptData()");

   CSSM_CC_HANDLE ccHandle;
   CSSM_DATA remData = { 0, 0 };
   uint32 numBytesDecrypted = 0;

   ccHandle = CSSM_CSP_CreateAsymmetricContext(cspHandle,
                                               CSSM_ALGID_RSA_PKCS,
                                               NULL,
                                               (const CSSM_KEY_PTR)&rsaKey,
                                               CSSM_PADDING_NONE);
   if (!ccHandle)
      ThrowCSSMException(CSSM_GetError()->error);

   decryptedData.Length = 0;
   decryptedData.Data = 0;

   if (CSSM_FAIL == CSSM_DecryptData(ccHandle,
                                     (const CSSM_DATA_PTR)&dataToDecrypt,
                                     1,
                                     &decryptedData,
                                     1,
                                     &numBytesDecrypted,
                                     &remData))
   {
      uint32 errcode = CSSM_GetError()->error;
      CSSM_DeleteContext(ccHandle);
      ThrowCSSMException(errcode);
   }

   CSSM_DeleteContext(ccHandle);
   decryptedData.Length = numBytesDecrypted + remData.Length;
   decryptedData.Data = (uint8*)DefaultRealloc(decryptedData.Data, decryptedData.Length);
   memmove(decryptedData.Data + numBytesDecrypted, remData.Data, remData.Length);
}


//------------------------------------------------------------
// function: RC4_DecryptData
//------------------------------------------------------------

void
RC4_DecryptData(CSSM_CSP_HANDLE cspHandle,
                const CSSM_KEY& rc4Key,
                const CSSM_DATA& dataToDecrypt,
                CSSM_DATA& decryptedData)
{
   FunctionTracer funcTracer(3, "RC4_DecryptData()");

   CSSM_CC_HANDLE ccHandle;
   CSSM_DATA remData = { 0, 0 };
   uint32 numBytesDecrypted = 0;

   ccHandle = CSSM_CSP_CreateSymmetricContext(cspHandle,
                                              CSSM_ALGID_RC4,
                                              CSSM_ALGMODE_NONE,
                                              (const CSSM_KEY_PTR)&rc4Key,
                                              NULL,
                                              CSSM_PADDING_NONE,
                                              0);
   if (!ccHandle)
      ThrowCSSMException(CSSM_GetError()->error);

   decryptedData.Length = 0;
   decryptedData.Data = 0;

   if (CSSM_FAIL == CSSM_DecryptData(ccHandle,
                                     (const CSSM_DATA_PTR)&dataToDecrypt,
                                     1,
                                     &decryptedData,
                                     1,
                                     &numBytesDecrypted,
                                     &remData))
   {
      uint32 errcode = CSSM_GetError()->error;
      CSSM_DeleteContext(ccHandle);
      ThrowCSSMException(errcode);
   }

   CSSM_DeleteContext(ccHandle);
   decryptedData.Length = numBytesDecrypted + remData.Length;
   decryptedData.Data = (uint8*)DefaultRealloc(decryptedData.Data, decryptedData.Length);
   memmove(decryptedData.Data + numBytesDecrypted, remData.Data, remData.Length);
}
