/* ***************************************************************** *
 * 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.                                                        *
 * ***************************************************************** */


#include "pkcsprivate.h"

extern CSSM_SPI_MEMORY_FUNCS CssmMemFuncs;



/*****************************************************************************
 * Function: EncryptData - 
 * 
 * Encrypt clear data.
 *
 * Input:
 *  CssmCSPHandle   - CSP handle  
 *  CssmCCHandle    - Context handle
 *  pCssmContext    - Pointer to context 
 *  pCssmClearBufs    - Clear buffers
 *  CssmClearBufCount - Number of clear buffers
 *   
 * Output:
 *  pCssmCipherBufs   - Cipher buffers
 *  CssmCipherBufCount  - Number of cipher buffers
 *  *pCssmBytesEncrypted- Number of bytes encrypted
 *  pCssmRemData    - Remainder data
 *   
 * Returns:
 *  CSSM_OK       - Successful      
 *  CSSM_FAIL     - Failed
 *
 */

CSSM_RETURN CSSMAPI EncryptData(
  CSSM_CSP_HANDLE CssmCSPHandle,
  CSSM_CC_HANDLE CssmCCHandle,
  const CSSM_CONTEXT_PTR pCssmContext,
  const CSSM_DATA_PTR pCssmClearBufs,
  uint32 CssmClearBufCount,
  CSSM_DATA_PTR pCssmCipherBufs,
  uint32 CssmCipherBufCount,
  uint32 *pCssmBytesEncrypted,
  CSSM_DATA_PTR pCssmRemData)
{

  if (pCssmContext->ContextType == CSSM_ALGCLASS_ASYMMETRIC)
    return EncryptDataAsymmetric(CssmCSPHandle,
                   CssmCCHandle,
                   pCssmContext,
                     pCssmClearBufs,
                   CssmClearBufCount,
                   pCssmCipherBufs,
                   CssmCipherBufCount,
                   pCssmBytesEncrypted,
                   pCssmRemData);
  else if (pCssmContext->ContextType == CSSM_ALGCLASS_SYMMETRIC)
    return EncryptDataSymmetric(CssmCSPHandle,
                   CssmCCHandle,
                   pCssmContext,
                     pCssmClearBufs,
                   CssmClearBufCount,
                   pCssmCipherBufs,
                   CssmCipherBufCount,
                   pCssmBytesEncrypted,
                   pCssmRemData);
  else
    return SetErr(CSSM_CSP_INVALID_CONTEXT_HANDLE);

}



/*****************************************************************************
 * Function: EncryptDataAsymmetric - 
 *
 * Encrypt data using asymmetric algorithms.
 *
 * Input:
 *  CssmCSPHandle   - CSP session handle  
 *  CssmCCHandle    - Context handle
 *  pCssmContext    - Pointer to context 
 *  pCssmClearBufs    - Clear buffers
 *  CssmClearBufCount - Number of clear buffers
 *   
 * Output:
 *  pCssmCipherBufs   - Cipher buffers
 *  CssmCipherBufCount  - Number of cipher buffers
 *  *pCssmBytesEncrypted- Number of bytes encrypted
 *  pCssmRemData    - Remainder data
 *   
 * Returns:
 *  CSSM_OK       - Successful      
 *  CSSM_FAIL     - Failed
 *
 */

CSSM_RETURN CSSMAPI EncryptDataAsymmetric(
  CSSM_CSP_HANDLE CssmCSPHandle,
  CSSM_CC_HANDLE CssmCCHandle,
  const CSSM_CONTEXT_PTR pCssmContext,
  const CSSM_DATA_PTR pCssmClearBufs,
  uint32 CssmClearBufCount,
  CSSM_DATA_PTR pCssmCipherBufs,
  uint32 CssmCipherBufCount,
  uint32 *pCssmBytesEncrypted,
  CSSM_DATA_PTR pCssmRemData)
{

  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmKeyAttr;
  CSSM_KEY_PTR        pCssmKey;

  CK_RV           PkcsStatus;
  CK_MECHANISM        PkcsMechanism = {0, NULL_PTR, 0};
  CK_OBJECT_HANDLE      hPkcsKey;
      
  MSMSESSION_PTR        pMsmSession;
  CSSM_BOOL         MsmBufferAllocated = CSSM_FALSE;
#ifdef PKCS11_V20
  CK_ULONG          length;
#else
  CK_USHORT         length;
#endif



  if ((pMsmSession = FindMsmSession(CssmCSPHandle)) == NULL)
    return SetErr(CSSM_CSP_INVALID_CSP_HANDLE);


  // Setting things up for init

  if (pCssmContext->AlgorithmType == CSSM_ALGID_RSA_PKCS)
    PkcsMechanism.mechanism = CKM_RSA_PKCS;
  else if (pCssmContext->AlgorithmType == CSSM_ALGID_RSA_RAW)
    PkcsMechanism.mechanism = CKM_RSA_X_509;
  else
    return SetErr(CSSM_CSP_ALGORITHM_UNSUPPORTED);

  pCssmKeyAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_KEY);
  if (pCssmKeyAttr == NULL)
    return SetErr(CSSM_CSP_INVALID_KEY_POINTER);

  pCssmKey = pCssmKeyAttr->Attribute.Key;

  if (pCssmKey->KeyHeader.BlobType == CSSM_KEYBLOB_REFERENCE &&
    pCssmKey->KeyHeader.Format == CSSM_KEYBLOB_REF_FORMAT_INTEGER &&
    pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PUBLIC_KEY &&
    (pCssmKey->KeyHeader.AlgorithmId == CSSM_ALGID_RSA_PKCS ||
     pCssmKey->KeyHeader.AlgorithmId == CSSM_ALGID_RSA_RAW))
  {
    if (pCssmKey->KeyData.Data == NULL)
      return SetErr(CSSM_CSP_INVALID_KEY_POINTER);

    hPkcsKey = *((CK_OBJECT_HANDLE*) pCssmKey->KeyData.Data);
  }
  else
    return SetErr(CSSM_CSP_INVALID_KEY);

  if ((PkcsStatus = C_EncryptInit(pMsmSession->PkcsSessionHandle, 
                  &PkcsMechanism,
                  hPkcsKey)) != CKR_OK)
    return SetErr(PkcsStatus);


  // Buffer checking and allocation 

  if (CssmClearBufCount != 1 || CssmCipherBufCount != 1)
    return SetErr(CSSM_CSP_VECTOROFBUFS_UNSUPPORTED);

  if ((pCssmClearBufs == NULL) || (pCssmCipherBufs == NULL) ||
    (pCssmRemData == NULL) || (pCssmBytesEncrypted == NULL))
    return SetErr(CSSM_CSP_INVALID_POINTER);

  if ((pCssmClearBufs->Data == NULL) || 
    ((pCssmCipherBufs->Length == 0) && (pCssmCipherBufs->Data != NULL)) ||
    ((pCssmCipherBufs->Length != 0) && (pCssmCipherBufs->Data == NULL)) ||
    ((pCssmRemData->Length == 0) && (pCssmRemData->Data != NULL)) ||
    ((pCssmRemData->Length != 0) && (pCssmRemData->Data == NULL)))
    return SetErr(CSSM_CSP_INVALID_DATA_POINTER);


  length = pCssmKey->KeyHeader.KeySizeInBits / 8;
  if ((pCssmKey->KeyHeader.KeySizeInBits % 8) != 0)
    length++;

  if (pCssmCipherBufs->Data == NULL)
  {
    if ((pCssmCipherBufs->Data = CssmMemFuncs.calloc_func(CssmCSPHandle, 
                                1, 
                                length)) == NULL)
      return SetErr(CSSM_CALLOC_FAILED);
    
    MsmBufferAllocated = CSSM_TRUE;
  }
  else if (pCssmCipherBufs->Length < length)
    return SetErr(CSSM_CSP_ERR_OUTBUF_LENGTH);

  // Now do the encryption
#ifdef PKCS11_V20
  if ((PkcsStatus = C_Encrypt(pMsmSession->PkcsSessionHandle, 
                pCssmClearBufs->Data,
                pCssmClearBufs->Length,
                pCssmCipherBufs->Data,
                &length)) != CKR_OK)
#else
  if ((PkcsStatus = C_Encrypt(pMsmSession->PkcsSessionHandle, 
                pCssmClearBufs->Data,
                (CK_USHORT)pCssmClearBufs->Length,
                pCssmCipherBufs->Data,
                &length)) != CKR_OK)
#endif
  {
    if (MsmBufferAllocated)
    {
      CssmMemFuncs.free_func(CssmCSPHandle,  pCssmCipherBufs->Data);
      pCssmCipherBufs->Length = 0;
      pCssmCipherBufs->Data = NULL;
    }

    return SetErr(PkcsStatus);
  }


  *pCssmBytesEncrypted = pCssmCipherBufs->Length = length;
  pCssmRemData->Length = 0;

  return CSSM_OK;

}



/*****************************************************************************
 * Function: EncryptDataSymmetric - 
 * 
 * Encrypt data using symmetric algorithms.
 *
 * Input:
 *  CssmCSPHandle   - CSP session handle  
 *  CssmCCHandle    - Context handle
 *  pCssmContext    - Pointer to context 
 *  pCssmClearBufs    - Clear buffers
 *  CssmClearBufCount - Number of clear buffers
 *   
 * Output:
 *  pCssmCipherBufs   - Cipher buffers
 *  CssmCipherBufCount  - Number of cipher buffers
 *  *pCssmBytesEncrypted- Number of bytes encrypted
 *  pCssmRemData    - Remainder data
 *   
 * Returns:
 *  CSSM_OK       - Successful      
 *  CSSM_FAIL     - Failed
 *
 */

CSSM_RETURN CSSMAPI EncryptDataSymmetric(
  CSSM_CSP_HANDLE CssmCSPHandle,
  CSSM_CC_HANDLE CssmCCHandle,
  const CSSM_CONTEXT_PTR pCssmContext,
  const CSSM_DATA_PTR pCssmClearBufs,
  uint32 CssmClearBufCount,
  CSSM_DATA_PTR pCssmCipherBufs,
  uint32 CssmCipherBufCount,
  uint32 *pCssmBytesEncrypted,
  CSSM_DATA_PTR pCssmRemData)
{

  int CssmRc = CSSM_OK;
  
  if ((CssmRc = EncryptDataInitSymmetric(CssmCSPHandle, CssmCCHandle, pCssmContext)) != CSSM_OK)
    return CssmRc;

  if ((CssmRc = EncryptDataUpdateSymmetric(CssmCSPHandle, 
                CssmCCHandle, 
                pCssmClearBufs, 
                CssmClearBufCount,
                pCssmCipherBufs, 
                CssmCipherBufCount, 
                pCssmBytesEncrypted)) != CSSM_OK)
    return CssmRc;

  CssmRc = EncryptDataFinalSymmetric(CssmCSPHandle, CssmCCHandle, pCssmRemData);
  return CssmRc;
}



/*****************************************************************************
 * Function: EncryptDataInitSymmetric - Init stage of symmetric encryption.
 *
 * Input:
 *  CssmCSPHandle   - CSP session handle  
 *  CssmCCHandle    - Context handle
 *  pCssmContext    - Pointer to context 
 *   
 * Output:
 *  None
 *   
 * Returns:
 *  CSSM_OK       - Successful      
 *  CSSM_FAIL     - Failed
 *
 */

CSSM_RETURN CSSMAPI EncryptDataInitSymmetric(
  CSSM_CSP_HANDLE CssmCSPHandle,
  CSSM_CC_HANDLE CssmCCHandle,
  const CSSM_CONTEXT_PTR pCssmContext)
{

  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmKeyAttr = NULL;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmModeAttr = NULL;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmInitVectorAttr = NULL;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmEffectiveKeyBitsAttr = NULL;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmWordSizeAttr = NULL;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmRoundsAttr = NULL;
  CSSM_KEY_PTR        pCssmKey;
  CSSM_DATA         CssmData;
  CSSM_DB_UNIQUE_RECORD_PTR pCssmUniqueRecord;
  CSSM_DL_DB_HANDLE     hCssmDlDb;

  CK_RV           PkcsStatus;
  CK_MECHANISM        PkcsMechanism = {0, NULL_PTR, 0};
  CK_OBJECT_HANDLE      hPkcsKey;
#ifdef PKCS11_V20
  CK_RC2_PARAMS       PkcsRc2Params;
#else
  CK_USHORT         PkcsRc2Params;
#endif
  CK_RC2_CBC_PARAMS     PkcsRc2CbcParams;
#ifdef PKCS11_V20
  CK_RC5_PARAMS       PkcsRc5Params;
  CK_RC5_CBC_PARAMS     PkcsRc5CbcParams;
#endif
  MSMSESSION_PTR        pMsmSession;
  CSSM_BOOL         MsmBufferAllocated = CSSM_FALSE;




  if ((pMsmSession = FindMsmSession(CssmCSPHandle)) == NULL)
    return SetErr(CSSM_CSP_INVALID_CSP_HANDLE);

  if (pCssmContext->ContextType != CSSM_ALGCLASS_SYMMETRIC)
    return SetErr(CSSM_CSP_INVALID_CONTEXT);

  pCssmKeyAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_KEY);
  if (pCssmKeyAttr == NULL)
    return SetErr(CSSM_CSP_PARAM_NO_KEY); 
  
  pCssmKey = pCssmKeyAttr->Attribute.Key;

  if (pCssmKey->KeyHeader.BlobType == CSSM_KEYBLOB_REFERENCE &&
    pCssmKey->KeyHeader.Format == CSSM_KEYBLOB_REF_FORMAT_INTEGER &&
    pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY &&
    pCssmKey->KeyHeader.AlgorithmId == pCssmContext->AlgorithmType)
  {
    if (pCssmKey->KeyData.Data == NULL)
      return SetErr(CSSM_CSP_INVALID_KEY_POINTER);

    hPkcsKey = *((CK_OBJECT_HANDLE*) pCssmKey->KeyData.Data);
  }
  else if (pCssmKey->KeyHeader.BlobType == CSSM_KEYBLOB_RAW &&
       pCssmKey->KeyHeader.Format == CSSM_KEYBLOB_RAW_FORMAT_CDSA &&
       pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY &&
       pCssmKey->KeyHeader.AlgorithmId == pCssmContext->AlgorithmType)
  {
    CssmData.Data = (uint8*) pCssmKey;
    CssmData.Length = sizeof(CSSM_KEY);

    hCssmDlDb.DLHandle = CssmCSPHandle;
    hCssmDlDb.DBHandle = pMsmSession->CssmHandleInfo.SubServiceID;
    pCssmUniqueRecord = DataInsert(hCssmDlDb,
                     CSSM_DL_DB_RECORD_SYMMETRIC_KEY,
                     NULL,
                     &CssmData);

    if (pCssmUniqueRecord == NULL)
    {
      return CSSM_FAIL;
    }

    hPkcsKey = *((CK_OBJECT_HANDLE*)pCssmUniqueRecord->RecordIdentifier.Data);
  }
  else
  {
    return SetErr(CSSM_CSP_INVALID_KEY);
  }

  pCssmModeAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_MODE);
  if (pCssmModeAttr == NULL)
    return SetErr(CSSM_CSP_PARAM_NO_MODE);

  pCssmInitVectorAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_INIT_VECTOR);

  switch (pCssmContext->AlgorithmType)
  {
    case CSSM_ALGID_DES:
          
      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_ECB:
          PkcsMechanism.mechanism = CKM_DES_ECB;
          break;
        
        case CSSM_ALGMODE_CBC:
          PkcsMechanism.mechanism = CKM_DES_CBC;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
#ifdef PKCS11_V20
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
#else
          PkcsMechanism.usParameterLen = (CK_USHORT) pCssmInitVectorAttr->Attribute.Data->Length;
#endif
          break;

#ifdef PKCS11_V20
        case CSSM_ALGMODE_CBCPadIV8:
          PkcsMechanism.mechanism = CKM_DES_CBC_PAD;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          break;
#endif
          
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;


    case CSSM_ALGID_3DES_2KEY:
    case CSSM_ALGID_3DES_3KEY:
    
      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_ECB:
          PkcsMechanism.mechanism = CKM_DES3_ECB;
          break;
        
        case CSSM_ALGMODE_CBC:
          PkcsMechanism.mechanism = CKM_DES3_CBC;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
#ifdef PKCS11_V20
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
#else
          PkcsMechanism.usParameterLen = (CK_USHORT) pCssmInitVectorAttr->Attribute.Data->Length;
#endif
          break;

#ifdef PKCS11_V20
        case CSSM_ALGMODE_CBCPadIV8:
          PkcsMechanism.mechanism = CKM_DES3_CBC_PAD;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR);
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          break;
#endif        
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;


    case CSSM_ALGID_RC2:
      
      pCssmEffectiveKeyBitsAttr = CSSM_GetContextAttribute(pCssmContext, 
                                 CSSM_ATTRIBUTE_EFFECTIVE_BITS);
      if (pCssmEffectiveKeyBitsAttr == NULL)
        return SetErr(CSSM_CSP_PARAM_NO_EFFECTIVE_BITS);

      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_ECB:
          PkcsMechanism.mechanism = CKM_RC2_ECB;
#ifdef PKCS11_V20
          PkcsRc2Params = pCssmEffectiveKeyBitsAttr->Attribute.Uint32;
          PkcsMechanism.pParameter = &PkcsRc2Params;
          PkcsMechanism.ulParameterLen = sizeof(PkcsRc2Params);
#else
          PkcsRc2Params = (CK_USHORT) pCssmEffectiveKeyBitsAttr->Attribute.Uint32;
          PkcsRc2Params = htons(PkcsRc2Params);
          PkcsMechanism.pParameter = &PkcsRc2Params;
          PkcsMechanism.usParameterLen = sizeof(PkcsRc2Params);
#endif
          break;
        
        case CSSM_ALGMODE_CBC:
          PkcsMechanism.mechanism = CKM_RC2_CBC;
#ifdef PKCS11_V20
          PkcsRc2CbcParams.ulEffectiveBits = pCssmEffectiveKeyBitsAttr->Attribute.Uint32;
#else
          PkcsRc2CbcParams.usEffectiveBits = (CK_USHORT)pCssmEffectiveKeyBitsAttr->Attribute.Uint32;
#endif
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
          if (pCssmInitVectorAttr->Attribute.Data->Length != IVLEN)
            return SetErr(CSSM_CSP_INVALID_IV_SIZE);
          memcpy(PkcsRc2CbcParams.iv, pCssmInitVectorAttr->Attribute.Data->Data, IVLEN);
          PkcsMechanism.pParameter = &PkcsRc2CbcParams;
#ifdef PKCS11_V20
          PkcsMechanism.ulParameterLen = sizeof(PkcsRc2CbcParams);
#else
          PkcsMechanism.usParameterLen = sizeof(PkcsRc2CbcParams);
#endif
          break;

#ifdef PKCS11_V20
        case CSSM_ALGMODE_CBCPadIV8:
          PkcsMechanism.mechanism = CKM_RC2_CBC_PAD;
          PkcsRc2CbcParams.ulEffectiveBits = pCssmEffectiveKeyBitsAttr->Attribute.Uint32;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
          if (pCssmInitVectorAttr->Attribute.Data->Length != IVLEN)
            return SetErr(CSSM_CSP_INVALID_IV_SIZE);
          memcpy(PkcsRc2CbcParams.iv, pCssmInitVectorAttr->Attribute.Data->Data, IVLEN);
          PkcsMechanism.pParameter = &PkcsRc2CbcParams;
          PkcsMechanism.ulParameterLen = sizeof(PkcsRc2CbcParams);
          break;
#endif        
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;


    case CSSM_ALGID_RC4:
    
      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_NONE:
          PkcsMechanism.mechanism = CKM_RC4;
          break;
      
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;

#ifdef PKCS11_V20
    case CSSM_ALGID_RC5:

      pCssmWordSizeAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_BLOCK_SIZE);
      if (pCssmWordSizeAttr == NULL)
        return SetErr(CSSM_CSP_PARAM_NO_PARAM);   
        //return SetErr(CSSM_CSP_PARAM_NO_BLOCK_SIZE);    

      pCssmRoundsAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_ROUNDS);
      if (pCssmRoundsAttr == NULL)
        return SetErr(CSSM_CSP_PARAM_NO_ROUNDS);


      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_ECB:
          PkcsMechanism.mechanism = CKM_RC5_ECB;
          PkcsRc5Params.ulWordsize = pCssmWordSizeAttr->Attribute.Uint32; 
          PkcsRc5Params.ulRounds = pCssmRoundsAttr->Attribute.Uint32;   
          PkcsMechanism.pParameter = &PkcsRc5Params;
          PkcsMechanism.ulParameterLen = sizeof(PkcsRc5Params);
          break;
        
        case CSSM_ALGMODE_CBC:
          PkcsMechanism.mechanism = CKM_RC5_CBC;
          PkcsRc5CbcParams.ulWordsize = pCssmWordSizeAttr->Attribute.Uint32;  
          PkcsRc5CbcParams.ulRounds = pCssmRoundsAttr->Attribute.Uint32;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
          PkcsRc5CbcParams.pIv = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsRc5CbcParams.ulIvLen = pCssmInitVectorAttr->Attribute.Data->Length;
          PkcsMechanism.pParameter = &PkcsRc5CbcParams;
          PkcsMechanism.ulParameterLen = sizeof(PkcsRc5CbcParams);
          break;
      
        case CSSM_ALGMODE_CBCPadIV8:
          PkcsMechanism.mechanism = CKM_RC5_CBC_PAD;
          PkcsRc5CbcParams.ulWordsize = pCssmWordSizeAttr->Attribute.Uint32;  
          PkcsRc5CbcParams.ulRounds = pCssmRoundsAttr->Attribute.Uint32;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
          PkcsRc5CbcParams.pIv = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsRc5CbcParams.ulIvLen = pCssmInitVectorAttr->Attribute.Data->Length;
          PkcsMechanism.pParameter = &PkcsRc5CbcParams;
          PkcsMechanism.ulParameterLen = sizeof(PkcsRc5CbcParams);
          break;
        
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;


    case CSSM_ALGID_CAST:
    
      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_ECB:
          PkcsMechanism.mechanism = CKM_CAST_ECB;
          break;
        
        case CSSM_ALGMODE_CBC:
          PkcsMechanism.mechanism = CKM_CAST_CBC;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          break;
      
        case CSSM_ALGMODE_CBCPadIV8:
          PkcsMechanism.mechanism = CKM_CAST_CBC_PAD;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR);
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          break;
        
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;


    case CSSM_ALGID_CAST3:
    
      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_ECB:
          PkcsMechanism.mechanism = CKM_CAST3_ECB;
          break;
        
        case CSSM_ALGMODE_CBC:
          PkcsMechanism.mechanism = CKM_CAST3_CBC;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          break;
      
        case CSSM_ALGMODE_CBCPadIV8:
          PkcsMechanism.mechanism = CKM_CAST3_CBC_PAD;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR);
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          break;
        
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;


    case CSSM_ALGID_CAST5:
    
      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_ECB:
          PkcsMechanism.mechanism = CKM_CAST5_ECB;
          break;
        
        case CSSM_ALGMODE_CBC:
          PkcsMechanism.mechanism = CKM_CAST5_CBC;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          break;
      
        case CSSM_ALGMODE_CBCPadIV8:
          PkcsMechanism.mechanism = CKM_CAST5_CBC_PAD;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR);
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          break;
        
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;


    case CSSM_ALGID_IDEA:
    
      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_ECB:
          PkcsMechanism.mechanism = CKM_IDEA_ECB;
          break;
        
        case CSSM_ALGMODE_CBC:
          PkcsMechanism.mechanism = CKM_IDEA_CBC;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          break;
      
        case CSSM_ALGMODE_CBCPadIV8:
          PkcsMechanism.mechanism = CKM_IDEA_CBC_PAD;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR);
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          break;
        
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;


    case CSSM_ALGID_CDMF:
    
      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_ECB:
          PkcsMechanism.mechanism = CKM_CDMF_ECB;
          break;
        
        case CSSM_ALGMODE_CBC:
          PkcsMechanism.mechanism = CKM_CDMF_CBC;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          break;
      
        case CSSM_ALGMODE_CBCPadIV8:
          PkcsMechanism.mechanism = CKM_CDMF_CBC_PAD;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR);
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          break;
        
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;
#endif

    default:
      return SetErr(CSSM_CSP_ALGORITHM_UNSUPPORTED);      
  }


  // Call Pkcs11 Init

  if ((PkcsStatus = C_EncryptInit(pMsmSession->PkcsSessionHandle, 
                  &PkcsMechanism,
                  hPkcsKey)) != CKR_OK)
    return SetErr(PkcsStatus);

  return CSSM_OK;
}



/*****************************************************************************
 * Function: EncryptDataUpdateSymmetric 
 * 
 * Update stage of symmetric encryption.
 *
 * Input:
 *  CssmCSPHandle   - CSP session handle  
 *  CssmCCHandle    - Context handle
 *  pCssmClearBufs    - Clear buffers
 *  CssmClearBufCount - Number of clear buffers
 *   
 * Output:
 *  pCssmCipherBufs   - Cipher buffers
 *  CssmCipherBufCount  - Number of cipher buffers
 *  *pCssmBytesEncrypted- Number of bytes encrypted
 *   
 * Returns:
 *  CSSM_OK       - Successful      
 *  CSSM_FAIL     - Failed
 *
 */

CSSM_RETURN CSSMAPI EncryptDataUpdateSymmetric(
  CSSM_CSP_HANDLE CssmCSPHandle,
  CSSM_CC_HANDLE CssmCCHandle,
  const CSSM_DATA_PTR pCssmClearBufs,
  uint32 CssmClearBufCount,
  CSSM_DATA_PTR pCssmCipherBufs,
  uint32 CssmCipherBufCount,
  uint32 *pCssmBytesEncrypted)
{

  MSMSESSION_PTR        pMsmSession;
  CSSM_BOOL         MsmBufferAllocated = CSSM_FALSE;

  CK_RV           PkcsStatus;

  CSSM_CONTEXT_PTR      pCssmContext;
  uint32            CssmContextType;
  uint32            CssmAlgoId;

#ifdef PKCS11_V20
  CK_ULONG          length;
#else
  CK_USHORT         length;
#endif


  if ((pMsmSession = FindMsmSession(CssmCSPHandle)) == NULL)
    return SetErr(CSSM_CSP_INVALID_CSP_HANDLE);

  if ((pCssmContext = CSSM_GetContext(CssmCCHandle)) == NULL)
    return SetErr(CSSM_INVALID_CONTEXT_HANDLE);

  CssmContextType = pCssmContext->ContextType;
  CssmAlgoId = pCssmContext->AlgorithmType;
  CSSM_FreeContext(pCssmContext);

  if (CssmContextType != CSSM_ALGCLASS_SYMMETRIC) 
    return SetErr(CSSM_CSP_INVALID_CONTEXT);
  
  if (CssmClearBufCount != 1 || CssmCipherBufCount != 1)
    return SetErr(CSSM_CSP_VECTOROFBUFS_UNSUPPORTED);

  if ((pCssmClearBufs == NULL) || (pCssmCipherBufs == NULL) || (pCssmBytesEncrypted == NULL)) 
    return SetErr(CSSM_CSP_INVALID_POINTER);

  if ((pCssmClearBufs->Data == NULL) || 
    ((pCssmCipherBufs->Length == 0) && (pCssmCipherBufs->Data != NULL)) ||
    ((pCssmCipherBufs->Length != 0) && (pCssmCipherBufs->Data == NULL)))
    return SetErr(CSSM_CSP_INVALID_DATA_POINTER);

  if (CssmAlgoId == CSSM_ALGID_RC4 && pCssmClearBufs->Length > IBMPKCS11_RC4MAXBUFLEN)
    return SetErr(CSSM_CSP_ERR_INBUF_LENGTH);

  length = pCssmClearBufs->Length + REMDATALEN;

  if (pCssmCipherBufs->Data == NULL)
  {
    if ((pCssmCipherBufs->Data = CssmMemFuncs.calloc_func(CssmCSPHandle, 
                                1, 
                                length)) == NULL)
      return SetErr(CSSM_CALLOC_FAILED);
    
    MsmBufferAllocated = CSSM_TRUE;
  }
  else if (pCssmCipherBufs->Length < length)
    return SetErr(CSSM_CSP_ERR_OUTBUF_LENGTH);


  // Now do the update

#ifdef PKCS11_V20
  if ((PkcsStatus = C_EncryptUpdate(pMsmSession->PkcsSessionHandle, 
                    pCssmClearBufs->Data,
                    pCssmClearBufs->Length,
                    pCssmCipherBufs->Data,
                    &length)) != CKR_OK)
#else
  if ((PkcsStatus = C_EncryptUpdate(pMsmSession->PkcsSessionHandle, 
                    pCssmClearBufs->Data,
                    (CK_USHORT)pCssmClearBufs->Length,
                    pCssmCipherBufs->Data,
                    &length)) != CKR_OK)
#endif
  {
    if (MsmBufferAllocated)
    {
      CssmMemFuncs.free_func(CssmCSPHandle,  pCssmCipherBufs->Data);
      pCssmCipherBufs->Length = 0;
      pCssmCipherBufs->Data = NULL;
    }

    return SetErr(PkcsStatus);
  }

  *pCssmBytesEncrypted = pCssmCipherBufs->Length = length;

  return CSSM_OK;

}



/*****************************************************************************
 * Function: EncryptDataFinalSymmetric - 
 * 
 * Final stage of symmetric encryption.
 *
 * Input:
 *  CssmCSPHandle   - Attach session handle 
 *  CssmCCHandle    - Context handle
 *   
 * Output:
 *  pCssmRemData    - Remainder data
 *   
 * Returns:
 *  CSSM_OK       - Successful      
 *  CSSM_FAIL     - Failed
 *
 */

CSSM_RETURN CSSMAPI EncryptDataFinalSymmetric(
  CSSM_CSP_HANDLE CssmCSPHandle,
  CSSM_CC_HANDLE CssmCCHandle,
  CSSM_DATA_PTR pCssmRemData)
{

  CSSM_CONTEXT_PTR      pCssmContext;

  CK_RV           PkcsStatus;

  MSMSESSION_PTR        pMsmSession;
  CSSM_BOOL         MsmBufferAllocated = CSSM_FALSE;
  uint32            CssmContextType;

#ifdef PKCS11_V20
  CK_ULONG          length;
#else
  CK_USHORT         length;
#endif


  if ((pMsmSession = FindMsmSession(CssmCSPHandle)) == NULL)
    return SetErr(CSSM_CSP_INVALID_CSP_HANDLE);

  if ((pCssmContext = CSSM_GetContext(CssmCCHandle)) == NULL)
    return SetErr(CSSM_INVALID_CONTEXT_HANDLE);

  CssmContextType = pCssmContext->ContextType;
  CSSM_FreeContext(pCssmContext);

  if (CssmContextType != CSSM_ALGCLASS_SYMMETRIC) 
    return SetErr(CSSM_CSP_INVALID_CONTEXT);

  if (pCssmRemData == NULL)
    return SetErr(CSSM_CSP_INVALID_POINTER);

  if (((pCssmRemData->Length == 0) && (pCssmRemData->Data != NULL)) ||
    ((pCssmRemData->Length != 0) && (pCssmRemData->Data == NULL)))
    return SetErr(CSSM_CSP_INVALID_DATA_POINTER);
  

  if (pCssmRemData->Data == NULL)
  {
    pCssmRemData->Length = REMDATALEN;

    if ((pCssmRemData->Data = CssmMemFuncs.calloc_func(CssmCSPHandle, 
                               1, 
                               pCssmRemData->Length)) == NULL)
      return SetErr(CSSM_CALLOC_FAILED);
  
    MsmBufferAllocated = CSSM_TRUE;
  }
  else if (pCssmRemData->Length < REMDATALEN)
    return SetErr(CSSM_CSP_ERR_OUTBUF_LENGTH);


  // Now do the final

#ifdef PKCS11_V20
  if ((PkcsStatus = C_EncryptFinal(pMsmSession->PkcsSessionHandle, 
                   pCssmRemData->Data, 
                   &length)) != CKR_OK)
#else
  if ((PkcsStatus = C_EncryptFinal(pMsmSession->PkcsSessionHandle, 
                   pCssmRemData->Data, 
                   &length)) != CKR_OK)
#endif
  {
    if (MsmBufferAllocated)
    {
      CssmMemFuncs.free_func(CssmCSPHandle,  pCssmRemData->Data);
      pCssmRemData->Length = 0;
      pCssmRemData->Data = NULL;
    }

    return SetErr(PkcsStatus);
  }

  pCssmRemData->Length = length;
  return CSSM_OK;

}



/*****************************************************************************
 * Function: DecryptData - 
 * 
 * Decrypt previously encrypted data.
 *
 * Input:
 *  CssmCSPHandle   - CSP session handle  
 *  CssmCCHandle    - Context handle
 *  pCssmContext    - Pointer to context 
 *  pCssmCipherBufs   - Cipher buffers
 *  CssmCipherBufCount  - Number of cipher buffers
 *   
 * Output:
 *  pCssmClearBufs    - Clear buffers
 *  CssmClearBufCount - Number of clear buffers
 *  *pCssmBytesDecrypted- Number of bytes decrypted
 *  pCssmRemData    - Remainder data
 *   
 * Returns:
 *  CSSM_OK       - Successful      
 *  CSSM_FAIL     - Failed
 *
 */

CSSM_RETURN CSSMAPI DecryptData(
  CSSM_CSP_HANDLE CssmCSPHandle,
  CSSM_CC_HANDLE CssmCCHandle,
  const CSSM_CONTEXT_PTR pCssmContext,
  const CSSM_DATA_PTR pCssmCipherBufs,
  uint32 CssmCipherBufCount,
  CSSM_DATA_PTR pCssmClearBufs,
  uint32 CssmClearBufCount,
  uint32 *pCssmBytesDecrypted,
  CSSM_DATA_PTR pCssmRemData)
{

  if (pCssmContext->ContextType == CSSM_ALGCLASS_ASYMMETRIC)
    return DecryptDataAsymmetric(CssmCSPHandle,
                   CssmCCHandle,
                   pCssmContext,
                     pCssmCipherBufs,
                   CssmCipherBufCount,
                   pCssmClearBufs,
                   CssmClearBufCount,
                   pCssmBytesDecrypted,
                   pCssmRemData);
  else if (pCssmContext->ContextType == CSSM_ALGCLASS_SYMMETRIC)
    return DecryptDataSymmetric(CssmCSPHandle,
                   CssmCCHandle,
                   pCssmContext,
                     pCssmCipherBufs,
                   CssmCipherBufCount,
                   pCssmClearBufs,
                   CssmClearBufCount,
                   pCssmBytesDecrypted,
                   pCssmRemData);
  else
    return SetErr(CSSM_CSP_INVALID_CONTEXT_HANDLE);

}



/*****************************************************************************
 * Function: DecryptDataAsymmetric - 
 * 
 * Decrypt previously encrypted data using asymmetric algorithms.
 *
 * Input:
 *  CssmCSPHandle   - CSP session handle  
 *  CssmCCHandle    - Context handle
 *  pCssmContext    - Pointer to context 
 *  pCssmCipherBufs   - Cipher buffers
 *  CssmCipherBufCount  - Number of cipher buffers
 *   
 * Output:
 *  pCssmClearBufs    - Clear buffers
 *  CssmClearBufCount - Number of clear buffers
 *  *pCssmBytesDecrypted- Number of bytes decrypted
 *  pCssmRemData    - Remainder data
 *   
 * Returns:
 *  CSSM_OK       - Successful      
 *  CSSM_FAIL     - Failed
 *
 */

CSSM_RETURN CSSMAPI DecryptDataAsymmetric(
  CSSM_CSP_HANDLE CssmCSPHandle,
  CSSM_CC_HANDLE CssmCCHandle,
  const CSSM_CONTEXT_PTR pCssmContext,
  const CSSM_DATA_PTR pCssmCipherBufs,
  uint32 CssmCipherBufCount,
  CSSM_DATA_PTR pCssmClearBufs,
  uint32 CssmClearBufCount,
  uint32 *pCssmBytesDecrypted,
  CSSM_DATA_PTR pCssmRemData)
{

  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmKeyAttr;
  CSSM_KEY_PTR        pCssmKey;

  CK_RV           PkcsStatus;
  CK_MECHANISM        PkcsMechanism = {0, NULL_PTR, 0};
  CK_OBJECT_HANDLE      hPkcsKey;
      
  MSMSESSION_PTR        pMsmSession;
  CSSM_BOOL         MsmBufferAllocated = CSSM_FALSE;

#ifdef PKCS11_V20
  CK_ULONG          length;
#else
  CK_USHORT         length;
#endif



  if ((pMsmSession = FindMsmSession(CssmCSPHandle)) == NULL)
    return SetErr(CSSM_CSP_INVALID_CSP_HANDLE);


  // Setting things up for init

  if (pCssmContext->AlgorithmType == CSSM_ALGID_RSA_PKCS)
    PkcsMechanism.mechanism = CKM_RSA_PKCS;
  else if (pCssmContext->AlgorithmType == CSSM_ALGID_RSA_RAW)
    PkcsMechanism.mechanism = CKM_RSA_X_509;
  else
    return SetErr(CSSM_CSP_ALGORITHM_UNSUPPORTED);


  pCssmKeyAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_KEY);
  if (pCssmKeyAttr == NULL)
    return SetErr(CSSM_CSP_INVALID_KEY_POINTER);

  pCssmKey = pCssmKeyAttr->Attribute.Key;

  if (pCssmKey->KeyHeader.BlobType == CSSM_KEYBLOB_REFERENCE &&
    pCssmKey->KeyHeader.Format == CSSM_KEYBLOB_REF_FORMAT_INTEGER &&
    pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY &&
    (pCssmKey->KeyHeader.AlgorithmId == CSSM_ALGID_RSA_PKCS ||
     pCssmKey->KeyHeader.AlgorithmId == CSSM_ALGID_RSA_RAW))
  {
    if (pCssmKey->KeyData.Data == NULL)
      return SetErr(CSSM_CSP_INVALID_KEY_POINTER);

    hPkcsKey = (CK_OBJECT_HANDLE) *(pCssmKey->KeyData.Data);
  } 
  else
    return SetErr(CSSM_CSP_INVALID_KEY);

  if ((PkcsStatus = C_DecryptInit(pMsmSession->PkcsSessionHandle, 
                  &PkcsMechanism,
                  hPkcsKey)) != CKR_OK)
    return SetErr(PkcsStatus);


  // Buffer checking and allocation 

  if (CssmClearBufCount != 1 || CssmCipherBufCount != 1)
    return SetErr(CSSM_CSP_VECTOROFBUFS_UNSUPPORTED);

  if ((pCssmClearBufs == NULL) || (pCssmCipherBufs == NULL) ||
    (pCssmBytesDecrypted == NULL) || (pCssmRemData == NULL))
    return SetErr(CSSM_CSP_INVALID_POINTER);

  if ((pCssmCipherBufs->Data == NULL) || 
    ((pCssmClearBufs->Length == 0) && (pCssmClearBufs->Data != NULL)) ||
    ((pCssmClearBufs->Length != 0) && (pCssmClearBufs->Data == NULL)) ||
    ((pCssmRemData->Length == 0) && (pCssmRemData->Data != NULL)) ||
    ((pCssmRemData->Length != 0) && (pCssmRemData->Data == NULL)))
    return SetErr(CSSM_CSP_INVALID_DATA_POINTER);


  length = pCssmKey->KeyHeader.KeySizeInBits / 8;
  if ((pCssmKey->KeyHeader.KeySizeInBits % 8) != 0)
    length++;

  if (pCssmClearBufs->Data == NULL)
  {
    if ((pCssmClearBufs->Data = CssmMemFuncs.calloc_func(CssmCSPHandle, 
                               1, 
                               length)) == NULL)
      return SetErr(CSSM_CALLOC_FAILED);
    
    MsmBufferAllocated = CSSM_TRUE;
  }
  else if (pCssmClearBufs->Length < length)
    return SetErr(CSSM_CSP_ERR_OUTBUF_LENGTH);


  // Now do the encryption
#ifdef PKCS11_V20
  if ((PkcsStatus = C_Decrypt(pMsmSession->PkcsSessionHandle, 
                pCssmCipherBufs->Data,
                pCssmCipherBufs->Length,
                pCssmClearBufs->Data,
                &length)) != CKR_OK)
#else
  if ((PkcsStatus = C_Decrypt(pMsmSession->PkcsSessionHandle, 
                pCssmCipherBufs->Data,
                (USHORT) pCssmCipherBufs->Length,
                pCssmClearBufs->Data,
                &length)) != CKR_OK)
#endif
  {
    if (MsmBufferAllocated)
    {
      CssmMemFuncs.free_func(CssmCSPHandle, pCssmClearBufs->Data);
      pCssmClearBufs->Length = 0;
      pCssmClearBufs->Data = NULL_PTR;
    }

    return SetErr(PkcsStatus);
  }


  *pCssmBytesDecrypted = pCssmClearBufs->Length = length;
  pCssmRemData->Length = 0;

  return CSSM_OK;

}



/*****************************************************************************
 * Function: DecryptDataSymmetric 
 *
 * Decrypt previously encrypted data using symmetric algorithms.
 *
 * Input:
 *  CssmCSPHandle   - Attach session handle 
 *  CssmCCHandle    - Context handle
 *  pCssmContext    - Pointer to context 
 *  pCssmCipherBufs   - Cipher buffers
 *  CssmCipherBufCount  - Number of cipher buffers
 *   
 * Output:
 *  pCssmClearBufs    - Clear buffers
 *  CssmClearBufCount - Number of clear buffers
 *  *pCssmBytesDecrypted- Number of bytes decrypted
 *  pCssmRemData    - Remainder data
 *   
 * Returns:
 *  CSSM_OK       - Successful      
 *  CSSM_FAIL     - Failed
 *
 */

CSSM_RETURN CSSMAPI DecryptDataSymmetric(
  CSSM_CSP_HANDLE CssmCSPHandle,
  CSSM_CC_HANDLE CssmCCHandle,
  const CSSM_CONTEXT_PTR pCssmContext,
  const CSSM_DATA_PTR pCssmCipherBufs,
  uint32 CssmCipherBufCount,
  CSSM_DATA_PTR pCssmClearBufs,
  uint32 CssmClearBufCount,
  uint32 *pCssmBytesDecrypted,
  CSSM_DATA_PTR pCssmRemData)
{

  int CssmRc = CSSM_OK;
  
  if ((CssmRc = DecryptDataInitSymmetric(CssmCSPHandle, CssmCCHandle, pCssmContext)) != CSSM_OK)
    return CssmRc;

  if ((CssmRc = DecryptDataUpdateSymmetric(CssmCSPHandle, 
                CssmCCHandle, 
                pCssmCipherBufs, 
                CssmCipherBufCount, 
                pCssmClearBufs, 
                CssmClearBufCount,
                pCssmBytesDecrypted)) != CSSM_OK)
    return CssmRc;

  CssmRc = DecryptDataFinalSymmetric(CssmCSPHandle, CssmCCHandle, pCssmRemData);
  return CssmRc;

}



/*****************************************************************************
 * Function: DecryptDataInitSymmetric 
 *
 * Init stage of symmetric decryption. 
 *
 * Input:
 *  CssmCSPHandle   - Attach session handle 
 *  CssmCCHandle    - Context handle
 *  pCssmContext    - Pointer to context
 *   
 * Output:
 *  None
 *   
 * Returns:
 *  CSSM_OK       - Successful      
 *  CSSM_FAIL     - Failed
 *
 */

CSSM_RETURN CSSMAPI DecryptDataInitSymmetric(
  CSSM_CSP_HANDLE CssmCSPHandle,
  CSSM_CC_HANDLE CssmCCHandle,
  const CSSM_CONTEXT_PTR pCssmContext)
{

  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmKeyAttr;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmModeAttr = NULL;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmInitVectorAttr = NULL;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmEffectiveKeyBitsAttr = NULL;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmWordSizeAttr = NULL;
  CSSM_CONTEXT_ATTRIBUTE_PTR  pCssmRoundsAttr = NULL;
  CSSM_KEY_PTR        pCssmKey;
  CSSM_DATA         CssmData;
  CSSM_DB_UNIQUE_RECORD_PTR pCssmUniqueRecord;
  CSSM_DL_DB_HANDLE     hCssmDlDb;

  CK_RV           PkcsStatus;
  CK_MECHANISM        PkcsMechanism = {0, NULL_PTR, 0};
  CK_OBJECT_HANDLE      hPkcsKey;

#ifdef PKCS11_V20
  CK_RC2_PARAMS       PkcsRc2Params;
#else
  CK_USHORT         PkcsRc2Params;
#endif

  CK_RC2_CBC_PARAMS     PkcsRc2CbcParams;
#ifdef PKCS11_V20
  CK_RC5_PARAMS       PkcsRc5Params;
  CK_RC5_CBC_PARAMS     PkcsRc5CbcParams;
#endif

  MSMSESSION_PTR        pMsmSession;
  CSSM_BOOL         MsmBufferAllocated = CSSM_FALSE;




  if ((pMsmSession = FindMsmSession(CssmCSPHandle)) == NULL)
    return SetErr(CSSM_CSP_INVALID_CSP_HANDLE);

  if (pCssmContext->ContextType != CSSM_ALGCLASS_SYMMETRIC)
    return SetErr(CSSM_CSP_INVALID_CONTEXT_HANDLE);

  pCssmKeyAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_KEY);
  if (pCssmKeyAttr == NULL)
    return SetErr(CSSM_CSP_PARAM_NO_KEY); 
  
  pCssmKey = pCssmKeyAttr->Attribute.Key;

  if (pCssmKey->KeyHeader.BlobType == CSSM_KEYBLOB_REFERENCE &&
    pCssmKey->KeyHeader.Format == CSSM_KEYBLOB_REF_FORMAT_INTEGER &&
    pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY &&
    pCssmKey->KeyHeader.AlgorithmId == pCssmContext->AlgorithmType)
  {
    if (pCssmKey->KeyData.Data == NULL)
      return SetErr(CSSM_CSP_INVALID_KEY_POINTER);

    hPkcsKey = *((CK_OBJECT_HANDLE*)pCssmKey->KeyData.Data);
  }
  else if (pCssmKey->KeyHeader.BlobType == CSSM_KEYBLOB_RAW &&
       pCssmKey->KeyHeader.Format == CSSM_KEYBLOB_RAW_FORMAT_CDSA &&
       pCssmKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY &&
       pCssmKey->KeyHeader.AlgorithmId == pCssmContext->AlgorithmType)
  {
    CssmData.Data = (uint8*) pCssmKey;
    CssmData.Length = sizeof(CSSM_KEY);

    hCssmDlDb.DLHandle = CssmCSPHandle;
    hCssmDlDb.DBHandle = pMsmSession->CssmHandleInfo.SubServiceID;
    pCssmUniqueRecord = DataInsert(hCssmDlDb,
                     CSSM_DL_DB_RECORD_SYMMETRIC_KEY,
                     NULL,
                     &CssmData);

    if (pCssmUniqueRecord == NULL)
    {
      return CSSM_FAIL;
    }

    hPkcsKey = *((CK_OBJECT_HANDLE*)pCssmUniqueRecord->RecordIdentifier.Data);
  }
  else
  {
    return SetErr(CSSM_CSP_INVALID_KEY);
  }

  pCssmModeAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_MODE);
  if (pCssmModeAttr == NULL)
    return SetErr(CSSM_CSP_PARAM_NO_MODE);

  pCssmInitVectorAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_INIT_VECTOR);

  switch (pCssmContext->AlgorithmType)
  {
    case CSSM_ALGID_DES:
    
      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_ECB:
          PkcsMechanism.mechanism = CKM_DES_ECB;
          break;
        
        case CSSM_ALGMODE_CBC:
          PkcsMechanism.mechanism = CKM_DES_CBC;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
#ifdef PKCS11_V20
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
#else
          PkcsMechanism.usParameterLen = (CK_USHORT) pCssmInitVectorAttr->Attribute.Data->Length;
#endif
          break;

#ifdef PKCS11_V20
          
        case CSSM_ALGMODE_CBCPadIV8:
          PkcsMechanism.mechanism = CKM_DES_CBC_PAD;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR);
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          break;
#endif
          
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;


    case CSSM_ALGID_3DES_2KEY:
    case CSSM_ALGID_3DES_3KEY:
    
      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_ECB:
          PkcsMechanism.mechanism = CKM_DES3_ECB;
          break;
        
        case CSSM_ALGMODE_CBC:
          PkcsMechanism.mechanism = CKM_DES3_CBC;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
#ifdef PKCS11_V20
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
#else
          PkcsMechanism.usParameterLen = (CK_USHORT) pCssmInitVectorAttr->Attribute.Data->Length;
#endif          
          break;

#ifdef PKCS11_V20
        case CSSM_ALGMODE_CBCPadIV8:
          PkcsMechanism.mechanism = CKM_DES3_CBC_PAD;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR);
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          break;
#endif
          
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;


    case CSSM_ALGID_RC2:

      pCssmEffectiveKeyBitsAttr = CSSM_GetContextAttribute(pCssmContext, 
                                 CSSM_ATTRIBUTE_EFFECTIVE_BITS);
      if (pCssmEffectiveKeyBitsAttr == NULL)
        return SetErr(CSSM_CSP_PARAM_NO_EFFECTIVE_BITS);

      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_ECB:
          PkcsMechanism.mechanism = CKM_RC2_ECB;
          
#ifdef PKCS11_V20
          PkcsRc2Params = pCssmEffectiveKeyBitsAttr->Attribute.Uint32;
          PkcsMechanism.pParameter = &PkcsRc2Params;
          PkcsMechanism.ulParameterLen = sizeof(PkcsRc2Params);
#else
          PkcsRc2Params = (CK_USHORT) pCssmEffectiveKeyBitsAttr->Attribute.Uint32;
          PkcsRc2Params = htons(PkcsRc2Params);
          PkcsMechanism.pParameter = &PkcsRc2Params;
          PkcsMechanism.usParameterLen = sizeof(PkcsRc2Params);
#endif
          
          break;
        
        case CSSM_ALGMODE_CBC:
          PkcsMechanism.mechanism = CKM_RC2_CBC;
#ifdef PKCS11_V20
          PkcsRc2CbcParams.ulEffectiveBits = pCssmEffectiveKeyBitsAttr->Attribute.Uint32;
#else
          PkcsRc2CbcParams.usEffectiveBits = (CK_USHORT) pCssmEffectiveKeyBitsAttr->Attribute.Uint32;
#endif
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
          if (pCssmInitVectorAttr->Attribute.Data->Length != IVLEN)
            return SetErr(CSSM_CSP_INVALID_IV_SIZE);
          memcpy(PkcsRc2CbcParams.iv, pCssmInitVectorAttr->Attribute.Data->Data, IVLEN);
          PkcsMechanism.pParameter = &PkcsRc2CbcParams;
#ifdef PKCS11_V20
          PkcsMechanism.ulParameterLen = sizeof(PkcsRc2CbcParams);
#else
          PkcsMechanism.usParameterLen = sizeof(PkcsRc2CbcParams);
#endif
          break;
      
#ifdef PKCS11_V20
        case CSSM_ALGMODE_CBCPadIV8:
          PkcsMechanism.mechanism = CKM_RC2_CBC_PAD;
          PkcsRc2CbcParams.ulEffectiveBits = pCssmEffectiveKeyBitsAttr->Attribute.Uint32;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
          if (pCssmInitVectorAttr->Attribute.Data->Length != IVLEN)
            return SetErr(CSSM_CSP_INVALID_IV_SIZE);
          memcpy(PkcsRc2CbcParams.iv, pCssmInitVectorAttr->Attribute.Data->Data, IVLEN);
          PkcsMechanism.pParameter = &PkcsRc2CbcParams;
          PkcsMechanism.ulParameterLen = sizeof(PkcsRc2CbcParams);
          break;
#endif
          
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;


    case CSSM_ALGID_RC4:

      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_NONE:
          PkcsMechanism.mechanism = CKM_RC4;
          break;
      
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;


#ifdef PKCS11_V20

      pCssmWordSizeAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_BLOCK_SIZE);
      if (pCssmWordSizeAttr == NULL)
        return SetErr(CSSM_CSP_PARAM_NO_PARAM);   
        //return SetErr(CSSM_CSP_PARAM_NO_BLOCK_SIZE);    

      pCssmRoundsAttr = CSSM_GetContextAttribute(pCssmContext, CSSM_ATTRIBUTE_ROUNDS);
      if (pCssmRoundsAttr == NULL)
        return SetErr(CSSM_CSP_PARAM_NO_ROUNDS);


      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_ECB:
          PkcsMechanism.mechanism = CKM_RC5_ECB;
          PkcsRc5Params.ulWordsize = pCssmWordSizeAttr->Attribute.Uint32; 
          PkcsRc5Params.ulRounds = pCssmRoundsAttr->Attribute.Uint32;   
          PkcsMechanism.pParameter = &PkcsRc5Params;
          PkcsMechanism.ulParameterLen = sizeof(PkcsRc5Params);
          break;
        
        case CSSM_ALGMODE_CBC:
          PkcsMechanism.mechanism = CKM_RC5_CBC;
          PkcsRc5CbcParams.ulWordsize = pCssmWordSizeAttr->Attribute.Uint32;  
          PkcsRc5CbcParams.ulRounds = pCssmRoundsAttr->Attribute.Uint32;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
          PkcsRc5CbcParams.pIv = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsRc5CbcParams.ulIvLen = pCssmInitVectorAttr->Attribute.Data->Length;
          PkcsMechanism.pParameter = &PkcsRc5CbcParams;
          PkcsMechanism.ulParameterLen = sizeof(PkcsRc5CbcParams);
          break;
      
        case CSSM_ALGMODE_CBCPadIV8:
          PkcsMechanism.mechanism = CKM_RC5_CBC_PAD;
          PkcsRc5CbcParams.ulWordsize = pCssmWordSizeAttr->Attribute.Uint32;  
          PkcsRc5CbcParams.ulRounds = pCssmRoundsAttr->Attribute.Uint32;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
          PkcsRc5CbcParams.pIv = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsRc5CbcParams.ulIvLen = pCssmInitVectorAttr->Attribute.Data->Length;
          PkcsMechanism.pParameter = &PkcsRc5CbcParams;
          PkcsMechanism.ulParameterLen = sizeof(PkcsRc5CbcParams);
          break;
  
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;


    case CSSM_ALGID_CAST:
    
      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_ECB:
          PkcsMechanism.mechanism = CKM_CAST_ECB;
          break;
        
        case CSSM_ALGMODE_CBC:
          PkcsMechanism.mechanism = CKM_CAST_CBC;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          break;
      
        case CSSM_ALGMODE_CBCPadIV8:
          PkcsMechanism.mechanism = CKM_CAST_CBC_PAD;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR);
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          break;
        
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;


    case CSSM_ALGID_CAST3:
    
      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_ECB:
          PkcsMechanism.mechanism = CKM_CAST3_ECB;
          break;
        
        case CSSM_ALGMODE_CBC:
          PkcsMechanism.mechanism = CKM_CAST3_CBC;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          break;
      
        case CSSM_ALGMODE_CBCPadIV8:
          PkcsMechanism.mechanism = CKM_CAST3_CBC_PAD;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR);
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          break;
        
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;


    case CSSM_ALGID_CAST5:
    
      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_ECB:
          PkcsMechanism.mechanism = CKM_CAST5_ECB;
          break;
        
        case CSSM_ALGMODE_CBC:
          PkcsMechanism.mechanism = CKM_CAST5_CBC;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          break;
      
        case CSSM_ALGMODE_CBCPadIV8:
          PkcsMechanism.mechanism = CKM_CAST5_CBC_PAD;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR);
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          break;
        
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;


    case CSSM_ALGID_IDEA:
    
      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_ECB:
          PkcsMechanism.mechanism = CKM_IDEA_ECB;
          break;
        
        case CSSM_ALGMODE_CBC:
          PkcsMechanism.mechanism = CKM_IDEA_CBC;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          break;
      
        case CSSM_ALGMODE_CBCPadIV8:
          PkcsMechanism.mechanism = CKM_IDEA_CBC_PAD;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR);
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          break;
        
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;


    case CSSM_ALGID_CDMF:
    
      switch (pCssmModeAttr->Attribute.Uint32)
      {
        case CSSM_ALGMODE_ECB:
          PkcsMechanism.mechanism = CKM_CDMF_ECB;
          break;
        
        case CSSM_ALGMODE_CBC:
          PkcsMechanism.mechanism = CKM_CDMF_CBC;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR); 
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          break;
      
        case CSSM_ALGMODE_CBCPadIV8:
          PkcsMechanism.mechanism = CKM_CDMF_CBC_PAD;
          if (pCssmInitVectorAttr == NULL)
            return SetErr(CSSM_CSP_PARAM_NO_INIT_VECTOR);
          PkcsMechanism.pParameter = pCssmInitVectorAttr->Attribute.Data->Data;
          PkcsMechanism.ulParameterLen = pCssmInitVectorAttr->Attribute.Data->Length;
          break;
        
        default:
          return SetErr(CSSM_CSP_INVALID_ALGORITHM_MODE);
      }

      break;
#endif
      
    default:
      return SetErr(CSSM_CSP_ALGORITHM_UNSUPPORTED);
  }


  // Init

  if ((PkcsStatus = C_DecryptInit(pMsmSession->PkcsSessionHandle, 
                  &PkcsMechanism,
                  hPkcsKey)) != CKR_OK)
    return SetErr(PkcsStatus);

  return CSSM_OK;

}



/*****************************************************************************
 * Function: DecryptDataUpdateSymmetric
 *
 * Update stage of symmetric decryption. 
 *
 * Input:
 *  CssmCSPHandle   - Attach session handle 
 *  CssmCCHandle    - Context handle
 *  pCssmCipherBufs   - Cipher buffers
 *  CssmCipherBufCount  - Number of cipher buffers
 *   
 * Output:
 *  pCssmClearBufs    - Clear buffers
 *  CssmClearBufCount - Number of clear buffers
 *  *pCssmBytesDecrypted- Number of bytes decrypted
 *   
 * Returns:
 *  CSSM_OK       - Successful      
 *  CSSM_FAIL     - Failed
 *
 */

CSSM_RETURN CSSMAPI DecryptDataUpdateSymmetric(
  CSSM_CSP_HANDLE CssmCSPHandle,
  CSSM_CC_HANDLE CssmCCHandle,
  const CSSM_DATA_PTR pCssmCipherBufs,
  uint32 CssmCipherBufCount,
  CSSM_DATA_PTR pCssmClearBufs,
  uint32 CssmClearBufCount,
  uint32 *pCssmBytesDecrypted)
{

  CSSM_CONTEXT_PTR      pCssmContext;

  CK_RV           PkcsStatus;

  MSMSESSION_PTR        pMsmSession;
  CSSM_BOOL         MsmBufferAllocated = CSSM_FALSE;
  uint32            CssmContextType;
  uint32            CssmAlgoId;


#ifdef PKCS11_V20
  CK_ULONG          length;
#else
  CK_USHORT         length;
#endif



  if ((pMsmSession = FindMsmSession(CssmCSPHandle)) == NULL)
    return SetErr(CSSM_CSP_INVALID_CSP_HANDLE);
  
  if ((pCssmContext = CSSM_GetContext(CssmCCHandle)) == NULL)
    return SetErr(CSSM_INVALID_CONTEXT_HANDLE);

  CssmContextType = pCssmContext->ContextType;
  CSSM_FreeContext(pCssmContext);

  if (CssmContextType != CSSM_ALGCLASS_SYMMETRIC) 
    return SetErr(CSSM_CSP_INVALID_CONTEXT);
  
  if (CssmClearBufCount != 1 || CssmCipherBufCount != 1)
    return SetErr(CSSM_CSP_VECTOROFBUFS_UNSUPPORTED);

  if ((pCssmClearBufs == NULL) || (pCssmCipherBufs == NULL) || (pCssmBytesDecrypted == NULL))
    return SetErr(CSSM_CSP_INVALID_POINTER);

  if ((pCssmCipherBufs->Data == NULL) || 
    ((pCssmClearBufs->Length == 0) && (pCssmClearBufs->Data != NULL)) ||
    ((pCssmClearBufs->Length != 0) && (pCssmClearBufs->Data == NULL)))
    return SetErr(CSSM_CSP_INVALID_DATA_POINTER);

  if (CssmAlgoId == CSSM_ALGID_RC4 && pCssmCipherBufs->Length > IBMPKCS11_RC4MAXBUFLEN)
    return SetErr(CSSM_CSP_ERR_INBUF_LENGTH);

  length = pCssmCipherBufs->Length + REMDATALEN;
  
  if (pCssmClearBufs->Data == NULL)
  {
    if ((pCssmClearBufs->Data = CssmMemFuncs.calloc_func(CssmCSPHandle, 
                                1, 
                                length)) == NULL)
      return SetErr(CSSM_CALLOC_FAILED);

    MsmBufferAllocated = CSSM_TRUE;
  }
  else if (pCssmClearBufs->Length < length)
    return SetErr(CSSM_CSP_ERR_OUTBUF_LENGTH);


  // Now do the update

#ifdef PKCS11_V20
  if ((PkcsStatus = C_DecryptUpdate(pMsmSession->PkcsSessionHandle, 
                    pCssmCipherBufs->Data,
                    pCssmCipherBufs->Length,
                    pCssmClearBufs->Data,
                    &length)) != CKR_OK)
#else
  if ((PkcsStatus = C_DecryptUpdate(pMsmSession->PkcsSessionHandle, 
                    pCssmCipherBufs->Data,
                    (CK_USHORT) pCssmCipherBufs->Length,
                    pCssmClearBufs->Data,
                    &length)) != CKR_OK)
#endif
  {
    if (MsmBufferAllocated)
    {
      CssmMemFuncs.free_func(CssmCSPHandle,  pCssmClearBufs->Data);
      pCssmClearBufs->Length = 0;
      pCssmClearBufs->Data = NULL;
    }

    return SetErr(PkcsStatus);
  }
  
  *pCssmBytesDecrypted = pCssmClearBufs->Length = length;

  return CSSM_OK;

}



/*****************************************************************************
 * Function: DecryptDataFinalSymmetric 
 *
 * Final stage of symmetric decryption. 
 *
 * Input:
 *  CssmCSPHandle   - Attach session handle 
 *  CssmCCHandle    - Context handle
 *   
 * Output:
 *  pCssmRemData    - Remainder data
 *   
 * Returns:
 *  CSSM_OK       - Successful      
 *  CSSM_FAIL     - Failed
 *
 */

CSSM_RETURN CSSMAPI DecryptDataFinalSymmetric(
  CSSM_CSP_HANDLE CssmCSPHandle,
  CSSM_CC_HANDLE CssmCCHandle,
  CSSM_DATA_PTR pCssmRemData)
{

  CSSM_CONTEXT_PTR      pCssmContext;

  CK_RV           PkcsStatus;

  MSMSESSION_PTR        pMsmSession;
  CSSM_BOOL         MsmBufferAllocated = CSSM_FALSE;
  uint32            CssmContextType;

#ifdef PKCS11_V20
  CK_ULONG          length;
#else
  CK_USHORT         length;
#endif


  if ((pMsmSession = FindMsmSession(CssmCSPHandle)) == NULL)
    return SetErr(CSSM_CSP_INVALID_CSP_HANDLE);
  
  if ((pCssmContext = CSSM_GetContext(CssmCCHandle)) == NULL)
    return SetErr(CSSM_INVALID_CONTEXT_HANDLE);

  CssmContextType = pCssmContext->ContextType;
  CSSM_FreeContext(pCssmContext);

  if (CssmContextType != CSSM_ALGCLASS_SYMMETRIC) 
    return SetErr(CSSM_CSP_INVALID_CONTEXT);

  if (pCssmRemData == NULL)
    return SetErr(CSSM_CSP_INVALID_POINTER);

  if (((pCssmRemData->Length == 0) && (pCssmRemData->Data != NULL)) ||
    ((pCssmRemData->Length != 0) && (pCssmRemData->Data == NULL)))
    return SetErr(CSSM_CSP_INVALID_DATA_POINTER);
    
  if (pCssmRemData->Data == NULL)
  {
    pCssmRemData->Length = REMDATALEN;

    if ((pCssmRemData->Data = CssmMemFuncs.calloc_func(CssmCSPHandle, 
                               1, 
                               pCssmRemData->Length)) == NULL)
      return SetErr(CSSM_CALLOC_FAILED);
  
    MsmBufferAllocated = CSSM_TRUE;
  }
  else if (pCssmRemData->Length < REMDATALEN)
    return SetErr(CSSM_CSP_ERR_OUTBUF_LENGTH);


  // Now do the final

#ifdef PKCS11_V20
  if ((PkcsStatus = C_DecryptFinal(pMsmSession->PkcsSessionHandle, 
                   pCssmRemData->Data, 
                   &length)) != CKR_OK)
#else
  if ((PkcsStatus = C_DecryptFinal(pMsmSession->PkcsSessionHandle, 
                   pCssmRemData->Data, 
                   &length)) != CKR_OK)
#endif
  {
    if (MsmBufferAllocated)
    {
      CssmMemFuncs.free_func(CssmCSPHandle, pCssmRemData->Data);
      pCssmRemData->Length = 0;
      pCssmRemData->Data = NULL;
    }

    return SetErr(PkcsStatus);
  }

  pCssmRemData->Length = length;

  return CSSM_OK;

}
