/***************************************************************************
 * Copyright 1998 International Business Machines Corporation. All Rights
 * Reserved.
 *
 * Please read this carefully.  Your use of this reference implementation of
 * certain of the IETF public-key infrastructure specifications ("Software")
 * indicates your acceptance of the following.  If you do not agree to the
 * following, do not install or use any of the Software.
 *
 * Permission to use, reproduce, distribute and create derivative works from
 * the Software ("Software Derivative Works"), and to distribute such Software
 * Derivative Works is hereby granted to you by International Business
 * Machines Corporation ("IBM").  This permission includes a license under the
 * patents of IBM that are necessarily infringed by your use of the Software
 * as provided by IBM.
 *
 * IBM licenses the Software to you on an "AS IS" basis, without warranty of
 * any kind.  IBM HEREBY EXPRESSLY DISCLAIMS ALL WARRANTIES OR CONDITIONS,
 * EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OR CONDITIONS OF MERCHANTABILITY, NON INFRINGEMENT AND FITNESS
 * FOR A PARTICULAR PURPOSE.  You are solely responsible for determining the
 * appropriateness of using this Software and assume all risks associated with
 * the use of this Software, including but not limited to the risks of program
 * errors, damage to or loss of data, programs or equipment, and
 * unavailability or interruption of operations.
 *
 * IBM WILL NOT BE LIABLE FOR ANY DIRECT DAMAGES OR FOR ANY SPECIAL,
 * INCIDENTAL, OR  INDIRECT DAMAGES OR FOR ANY ECONOMIC CONSEQUENTIAL DAMAGES
 * (INCLUDING LOST PROFITS OR SAVINGS), EVEN IF IBM HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.  IBM will not be liable for the loss of, or
 * damage to, your records or data, or any damages claimed by you based on a
 * third party claim.
 *
 * IBM wishes to obtain your feedback to assist in improving the Software. You
 * grant IBM a world-wide, royalty-free right to use, copy, distribute,
 * sublicense and prepare derivative works based upon any feedback, including
 * materials, error corrections, Software Derivatives, enhancements,
 * suggestions and the like that you provide to IBM relating to the Software
 * (this does not include products for which you charge a royalty and
 * distribute to IBM under other terms and conditions).
 *
 * You agree to distribute the Software and any Software Derivatives under a
 * license agreement that: 1) is sufficient to notify all licensees of the
 * Software and Software Derivatives that IBM assumes no liability for any
 * claim that may arise regarding the Software or Software Derivatives, and 2)
 * that disclaims all warranties, both express and implied, from IBM regarding
 * the Software and Software Derivatives.  (If you include this Agreement with
 * any distribution of the Software or Software Derivatives you will have met
 * this requirement.)  You agree that you will not delete any copyright
 * notices in the Software.
 *
 * This Agreement is the exclusive statement of your rights in the Software as
 * provided by IBM.   Except for the rights granted to you in the second
 * paragraph above, You are not granted any other patent rights, including but
 * not limited to the right to make combinations of the Software with products
 * that infringe IBM patents. You agree to comply with all applicable laws and
 * regulations, including all export and import laws and regulation.  This
 * Agreement is governed by the laws of the State of New York.  This Agreement
 * supersedes all other communications, understandings or agreements we may
 * have had prior to this Agreement.
 ****************************************************************************/


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


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

#include <iomanip.h>
#include <iostream.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "cssm.h"
#include "cssmutility.h"
#include "cryptoutility.h"

extern CSSM_GUID IBM_BSAFE_CSP_GUID;

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


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

int
TestRandomDataGeneration(CSSM_CSP_HANDLE cspHandle)
{
   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)
{
   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++)
      {
         GenerateKeyPair(cspHandle,
                         CSSM_ALGID_SHA1WithRSA,
                         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)
{
   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)
{
   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)
{
   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;

   GenerateKeyPair(cspHandle,
                   CSSM_ALGID_SHA1WithRSA,
                   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)
{
   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 keyRecoveryBlock;
   CSSM_DATA decryptedData;
   clock_t startTime;
   clock_t finishTime;
   double duration;

   GenerateKeyPair(cspHandle,
                   CSSM_ALGID_SHA1WithRSA,
                   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,
                             keyRecoveryBlock);
         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;
         cout << "KeyRecoveryBlock: ";
         DumpData(cout, keyRecoveryBlock);
         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)
{
   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 keyRecoveryBlock;
   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,
                         keyRecoveryBlock,
                         CSSM_TRUE);
         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;
         cout << "KeyRecoveryBlock: ";
         DumpData(cout, keyRecoveryBlock);
         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)
{
   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: GenerateKeyPair
//------------------------------------------------------------

void
GenerateKeyPair(CSSM_CSP_HANDLE cspHandle,
                CSSM_ALGORITHMS keyPairType,
                uint32 modulusBits,
                CSSM_KEY& publicKey,
                CSSM_KEY& privateKey)
{
   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,
                                           keyPairType,
                                           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)
{
   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)
{
   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: SignData_With_CSSM
//------------------------------------------------------------

void 
SignData_With_CSSM(CSSM_CSP_HANDLE cspHandle,
                   uint32 algorithmID,
                   CSSM_KEY& privateKey,
                   const CSSM_DATA& dataToSign,
                   CSSM_DATA& signature)
{
   CSSM_CC_HANDLE ccHandle;

   /*** WARNING: bug workaround from Cylink CSP ***/
   /*** WARNING: bug workaround from Cylink CSP ***/
   if ( CSSM_FALSE == CSSM_CompareGuids(privateKey.KeyHeader.CspId, IBM_BSAFE_CSP_GUID) && 
      algorithmID == CSSM_ALGID_SHA1WithDSA)
      algorithmID = CSSM_ALGID_DSA;
   /*** WARNING: bug workaround from Cylink CSP ***/
   /*** WARNING: bug workaround from Cylink CSP ***/

   ccHandle = CSSM_CSP_CreateSignatureContext(cspHandle,
                                              algorithmID,
                                              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_SignData
//------------------------------------------------------------

void
SHA1WithRSA_SignData(CSSM_CSP_HANDLE cspHandle,
                     CSSM_KEY& privateKey,
                     const CSSM_DATA& dataToSign,
                     CSSM_DATA& signature)
{
   SignData_With_CSSM(cspHandle,
                      CSSM_ALGID_SHA1WithRSA,
                      privateKey,
                      dataToSign,
                      signature);
}


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

void
SHA1WithRSA_VerifyData(CSSM_CSP_HANDLE cspHandle,
                       CSSM_KEY& publicKey,
                       const CSSM_DATA& signature,
                       const CSSM_DATA& dataToVerify,
                       CSSM_BOOL& isVerified)
{
   CSSM_CC_HANDLE ccHandle;

   ccHandle = CSSM_CSP_CreateSignatureContext(cspHandle,
                                              CSSM_ALGID_DSA,
                                              //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,
                    CSSM_DATA& keyRecoveryBlock,
                    CSSM_BOOL forceKRBGeneration)
{
   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,
                CSSM_DATA& keyRecoveryBlock,
                CSSM_BOOL forceKRBGeneration)
{
   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)
{
   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)
{
   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);
}
