

  /*
   *  Object %name    : %
   *  State           :  %state%
   *  Creation date   :  Wed Nov 17 17:25:55 2004
   *  Last modified   :  %modify_time%
   */
  /** @file
   *  \brief A brief description of this module
   *
   *  \version CRYS_DES.c#1:csrc:6
   *  \author adams
   *  \remarks Copyright (C) 2004 by Discretix Technologies Ltd.
   *           All Rights reserved
   */



/************* Include Files ****************/

/* .............. CRYS level includes ................. */

#include "DX_VOS_Mem.h"
#include "DX_VOS_Memmap.h"
#include "error.h"
#include "CRYS_DES_error.h"
#include "CRYS_DES.h"
#include "SEPDriver.h" 
#include "crys_host_op_code.h"
#include "gen.h"


/************************ Defines ******************************/



/************************ Enums ******************************/


/************************ MACROS ******************************/


/************************ Global Data ******************************/

#ifndef CRYS_NO_EXT_IF_MODE_SUPPORT
extern CRYSError_t  CRYS_CALLBACK_Handler();
#else
#define CRYS_CALLBACK_Handler DX_NULL
#endif

/************* Private function prototype ****************/


/************************ Public Functions ******************************/

/* ------------------------------------------------------------
 * @brief This function is used to initialize the DES machine.
 *        In order to operate the DES machine the first function that should be
 *        called is this function.
 *
 *        The function executes the following major steps:
 *
 *        1. Validates all of the inputs of the function. If one of the received 
 *           parameters is not valid it shall return an error:
 *
 *           - verifying that the context pointer is not DX_NULL (*ContextID_ptr).
 *           - verifying the pointer of the IV counter is not DX_NULL 
 *             if the modes that is selected are CBC.
 *           - verifying that the pointer to the key buffer is not DX_NULL 
 *           - verifying the values of the number of keys is valid ( 0- 2 ).
 *           - verifying the value of the operation mode is valid ( 0 - 2 ) 
 *        2. Decrypting the received context to the working context after capturing 
 *           the working context by calling the CRYS_CCM_GetContext() call.
 *
 *        3. Initializing the working context by the following:
 *           - loading the keys.
 *           - loading the IV counters.
 *           - loading the control field 
 *           - loading the operation mode. 
 *           - loading the DecryptEncrypt flag and the key size.
 *           - loading the key size.
 *        4. Encrypting the information in the working context and storing 
 *           it to the users received context. After then the working context is released.
 *           This state is operated by calling the CRYS_CCM_EncryptAndReleaseContext call.
 *        5. Exit the handler with the OK code.
 *
 *      
 *
 * @param[in] ContextID_ptr - a pointer to the DES context buffer allocated by the user that
 *                       is used for the DES machine operation.
 *
 * @param[in,out] IV_ptr - this parameter is the buffer of the IV or counters on mode CTR.
 *                          On ECB mode this parameter has no use.
 *                          On CBC this parameter should containe the IV values.
 *
 * @param[in] Key_ptr -  a pointer to the users key buffer.
 *
 * @param[in] NumOfKeys - the number of keys used by the module ( 1 - 3 )
 *
 * @param[in] EncryptDecryptFlag - This flag determains if the DES shall perform an Encrypt operation [0] or a
 *                           Decrypt operation [1].
 *
 * @param[in] OperationMode - The operation mode : ECB or CBC.
 * 
 * @return CRYSError_t - On success CRYS_OK is returned, on failure a
 *                        value MODULE_* CRYS_DES_error.h
 */

CEXPORT_C CRYSError_t  CRYS_DES_Init( CRYS_DESUserContext_t*    ContextID_ptr,
                                      CRYS_DES_Iv_t             IV_ptr,
                                      CRYS_DES_Key_t*           Key_ptr,
                                      CRYS_DES_NumOfKeys_t      NumOfKeys,
                                      CRYS_DES_EncryptMode_t    EncryptDecryptFlag,
                                      CRYS_DES_OperationMode_t  OperationMode )
{
  /* The return error identifier */
  CRYSError_t         Error;
  
  /* sram offset */
  DxUint32_t          sramOffset;
  
  /* read parameter */
  DxUint32_t          messageParam[4];
  
  /* max length */
  DxUint32_t          maxLength;
   
  /*-----------------------------
      CODE
  --------------------------------*/
  Error = CRYS_OK;
                   
  #ifndef CRYS_NO_DES_SUPPORT                                      
    
  /* ............... checking the parameters validity ................... */
   
  /* if the users context ID pointer is DX_NULL return an error */
  if( ContextID_ptr == DX_NULL )
  {
    Error = CRYS_DES_INVALID_USER_CONTEXT_POINTER_ERROR;
    goto end_function;
  }   
      
  /* check if the operation mode is legal */
  if( OperationMode >= CRYS_DES_NumOfModes )
  {
    Error = CRYS_DES_ILLEGAL_OPERATION_MODE_ERROR;
    goto end_function;
  }       
      
  /* if the operation mode selected is CBC then check the validity of
     the IV counter pointer */    
  if( OperationMode == CRYS_DES_CBC_mode && IV_ptr == DX_NULL )
  {
    Error = CRYS_DES_INVALID_IV_PTR_ON_NON_ECB_MODE_ERROR;
    goto end_function;
  }   
      
  /* If the number of keys in invalid return an error */
  if( NumOfKeys >= CRYS_DES_NumOfKeysOptions || NumOfKeys == 0 )  
  {   
    Error = CRYS_DES_ILLEGAL_NUM_OF_KEYS_ERROR;
    goto end_function;
  }   
     
  /*check the valisity of the key pointer */
  if( Key_ptr == DX_NULL )
  {
    Error = CRYS_DES_INVALID_KEY_POINTER_ERROR;
    goto end_function;
  }   
      
  /* Check the Encrypt / Decrypt flag validity */
  if( EncryptDecryptFlag >= CRYS_DES_EncryptNumOfOptions )
  {
    Error = CRYS_DES_INVALID_ENCRYPT_MODE_ERROR;
    goto end_function;
  }
  
   /* lock access to the SEP */
   Error = SEPDriver_Lock();
   
   if(Error != DX_OK)
   {
       goto end_function;
   }
   
  /*----------------------------
    start sending message to SEP 
  -----------------------------*/
  sramOffset = 0;
   
  /* start the message */
  SEPDriver_StartMessage(&sramOffset);
  
  /* prepare params */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_DES_INIT_OP_CODE;
  messageParam[1] = NumOfKeys;
  messageParam[2] = EncryptDecryptFlag;
  messageParam[3] = OperationMode;
  
  /* send params */
  Error = SEPDriver_WriteParamater((DxUint32_t)messageParam , 
                           sizeof(DxUint32_t),
                           sizeof(DxUint32_t),
                           &sramOffset , 
                           DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
  
  if(IV_ptr == DX_NULL)
  {
    sramOffset += 4 * sizeof(DxUint32_t);
  }
  else
  {
    /* send IV */
    Error = SEPDriver_WriteParamater((DxUint32_t)IV_ptr , 
                              sizeof(CRYS_DES_Iv_t) ,
                              4 * sizeof(DxUint32_t), 
                              &sramOffset , 
                              DX_FALSE);
    if(Error != DX_OK)
    {
        goto end_function_unlock;
    }
  }
   
  /* send key */
  Error = SEPDriver_WriteParamater((DxUint32_t)Key_ptr , 
                            8 * sizeof(DxUint32_t) ,
                            8 * sizeof(DxUint32_t) , 
                            &sramOffset , 
                            DX_TRUE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
  /* send rest of params */
  Error = SEPDriver_WriteParamater((DxUint32_t)&messageParam[1] , 
                           sizeof(DxUint32_t) * 3,
                           sizeof(DxUint32_t) * 3,
                           &sramOffset , 
                           DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
  /* end message */
  SEPDriver_EndMessage(sramOffset);
            
  /* wait for the response */
  Error = SEPDriver_POLL_FOR_REPONSE();
  if(Error != DX_OK)
  {
  	goto end_function_unlock;
  }
   
  /*-------------------
      start reading message from the SEP 
  ---------------------*/
   
  /* start the message */
  Error = SEPDriver_StartIncomingMessage(&sramOffset);
  if(Error != DX_OK)
  {
  	goto end_function_unlock;
  }
   
  /* read opcode + status */
  Error = SEPDriver_ReadParamater((DxUint32_t)messageParam , 
                          sizeof(DxUint32_t) * 2,
                          sizeof(DxUint32_t) * 2,
                          &sramOffset , 
                          DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
  /* check the opcode */
  if(messageParam[0] != DX_SEP_HOST_SEP_PROTOCOL_HOST_DES_INIT_OP_CODE)
  {
    Error = DX_WRONG_OPCODE_FROM_SEP_ERR;
    goto end_function_unlock;
  }
   
  /* check the status */
  if(messageParam[1] != CRYS_OK)
  {
    Error = messageParam[1];
    goto end_function_unlock;
  }
   
  /* read the context */
  maxLength = ((sizeof(CRYS_DESUserContext_t) + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t);
  Error = SEPDriver_ReadParamater((DxUint32_t)ContextID_ptr,
                           sizeof(CRYS_DESUserContext_t),
                           maxLength,
                           &sramOffset,
                           DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
  /* ...................... end of function ................................ */   

end_function_unlock:   

  /* lock access to the SEP */
  SEPDriver_Unlock();


end_function:   

  return Error;
   
  #endif /* CRYS_NO_DES_SUPPORT */                                    
   
}/* END OF DES_Init */   
                         
/** ------------------------------------------------------------
 * @brief This function is used to operate a block on the DES machine.
 *        This function should be called after the CRYS_DES_Init function
 *        was called.
 *
 *        The function executes the following major steps:
 *
 *        1.Checks the validation of all of the inputs of the function.
 *          If one of the received parameters is not valid it shall return an error.
 *
 *          The major checkers that are run over the received parameters:
 *          - verifying that the context pointer is not DX_NULL (*ContextID_ptr).
 *          - verifying the pointer of the data_in buffer is not DX_NULL.
 *          - verifying that the pointer to the data_out buffer is not DX_NULL. 
 *          - verifying the values of the data_in buffers size is not 0 and a multiple of 16 bytes.
 *
 *        2.Decrypting the received context to the working context after 
 *          capturing the working context by calling the CRYS_CCM_GetContext() call.
 *
 *        3.executing the DES operation on the hardware by calling the 
 *          low level DES function LLF_DES_Block.
 *        4.Encrypting the information in the working context and storing it 
 *          to the users received context. After then the working context is released.
 *          This state is operated by calling the CRYS_CCM_ReleaseContext call.
 *        5.Exit the handler with the OK code.  
 *      
 *
 * @param[in] ContextID_ptr - a pointer to the DES context buffer allocated by the user that
 *                       is used for the DES machine operation. this should be the same context that was
 *                       used on the previous call of this session.
 *
 *
 * @param[in] DataIn_ptr - The pointer to the buffer of the input data to the DES. The pointer does 
 *                   not need to be aligned.
 *
 * @param[in] DataInSize - The size of the input data(must be not 0 and must be multiple of 8 bytes).
 *
 * @param[in/out] DataOut_ptr - The pointer to the buffer of the output data from the DES. The pointer does not 
 *                        need to be aligned to 32 bits.  
 *
 * @return CRYSError_t - On success CRYS_OK is returned, on failure a
 *                        value MODULE_* CRYS_DES_error.h
 */
 CEXPORT_C CRYSError_t  CRYS_DES_Block( CRYS_DESUserContext_t*    ContextID_ptr,   
                                        DxUint8_t*                DataIn_ptr,     
                                        DxUint32_t                DataInSize,     
                                        DxUint8_t*                DataOut_ptr )
 {                              
  /* The return error identifiers */
  CRYSError_t         Error;
   
  /* address of the first table in the input list */
  DxUint32_t          firstInputLLITableAddr;
   
  /* address of the first table in the output list */
  DxUint32_t          firstOutputLLITableAddr;
   
  /* number of entries in the first input tables */
  DxUint32_t          numInTableEntries;
   
  /* number of entries in the first output tables */
  DxUint32_t          numOutTableEntries;
  
  /* size of data in the first table */
  DxUint32_t          firstTableSize;
   
  /* sram offset */
  DxUint32_t          sramOffset;
  
  /* read parameter */
  DxUint32_t          messageParam[6];
  
  /* max length */
  DxUint32_t          maxLength;
   
  /*-------------------
    CODE
  ----------------------*/
  
  Error = CRYS_OK;
                       
  #ifndef CRYS_NO_DES_SUPPORT                                    
   
  /* ............... checking the parameters validity ................... */
  
  /* if the users context ID pointer is DX_NULL return an error */
  if( ContextID_ptr == DX_NULL )
  {
    Error = CRYS_DES_INVALID_USER_CONTEXT_POINTER_ERROR;
    goto end_function;
  }
  
  /* if the users Data In pointer is illegal return an error */
  if( DataIn_ptr == DX_NULL )
  {
    Error = CRYS_DES_DATA_IN_POINTER_INVALID_ERROR;
    goto end_function;
  }
   
  /* if the users Data Out pointer is illegal return an error */
  if( DataOut_ptr == DX_NULL )
  {
    Error = CRYS_DES_DATA_OUT_POINTER_INVALID_ERROR;
    goto end_function;
  }
  
  /* checking that there is no overlapping between the data input and data out put buffer
     except the inplace case that is legal */
  if( DataIn_ptr != DataOut_ptr )
  {
    /* checking the case that the input buffer is in a higher address then the output buffer */
    if ( DataIn_ptr > DataOut_ptr )
    {
      /* if after adding the size to the data out pointer it is larger then the data in pointer 
         return the overlap error */
      if( DataOut_ptr + DataInSize > DataIn_ptr )
      {
        Error = CRYS_DES_DATA_OUT_DATA_IN_OVERLAP_ERROR;
        goto end_function;
      }     
    }/* end of DataIn_ptr > DataOut_ptr */   
          
    /* checking the case that the output buffer is in a higher address then the input buffer */      
    else
    {
      /* if after adding the size to the data in pointer it is larger then the data out pointer 
         return the overlap error */
      if( DataIn_ptr + DataInSize > DataOut_ptr )  
      {
        Error = CRYS_DES_DATA_OUT_DATA_IN_OVERLAP_ERROR;
        goto end_function;
      }   
    }/* end of DataOut_ptr > DataIn_ptr */   
      
  }/* end of DataIn_ptr != DataOut_ptr case */   

  /* if the data size is zero or not a multiple of 16 bytes return error */
  if( DataInSize == 0 || (DataInSize % CRYS_DES_BLOCK_SIZE_IN_BYTES) != 0 )
  {
    Error = CRYS_DES_DATA_SIZE_ILLEGAL;
    goto end_function;
  }
  
   /* lock access to the SEP */
   Error = SEPDriver_Lock();
   
   if(Error != DX_OK)
   {
       goto end_function;
   }

  /* send the message to SEP */
  sramOffset = 0;
   
  /* start the message */
  SEPDriver_StartMessage(&sramOffset);
  
  /* prepare params */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_DES_BLOCK_OP_CODE;
  /*write the opcode */
  Error = SEPDriver_WriteParamater((DxUint32_t)messageParam , 
                           sizeof(DxUint32_t) ,
                           sizeof(DxUint32_t) ,
                           &sramOffset , 
                           DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }

   if(DataInSize != CRYS_DES_BLOCK_SIZE_IN_BYTES)
   {
	  /* prepare LLI table */
	  Error = SEPDriver_PrepareSymDMATables((DxUint32_t)DataIn_ptr,
	                                         (DxUint32_t)DataOut_ptr,
	                                         DataInSize,
	                                         CRYS_DES_BLOCK_SIZE_IN_BYTES,
	                                         &firstInputLLITableAddr,
	                                         &firstOutputLLITableAddr,
	                                         &numInTableEntries,
	                                         &numOutTableEntries,
	                                         &firstTableSize);                                     
	  if(Error != DX_OK)
	  {
	    goto end_function_unlock;
	  }
	  messageParam[1] = firstInputLLITableAddr;
	  messageParam[2] = numInTableEntries;
	  messageParam[3] = firstOutputLLITableAddr;
	  messageParam[4] = numOutTableEntries;
	  messageParam[5] = firstTableSize;
	  
	  /* send params */
	  Error = SEPDriver_WriteParamater((DxUint32_t)&messageParam[1] , 
	                           sizeof(DxUint32_t) * 5,
	                           sizeof(DxUint32_t) * 5,
	                           &sramOffset , 
	                           DX_FALSE);
	  if(Error != DX_OK)
	  {
	      goto end_function_unlock;
	  }
   }
   else
   { /*case of only one DES block use direct DES instead of DMA*/
	  /*copy data and update offset to the correct size*/
	  Error = SEPDriver_WriteParamater((DxUint32_t)DataIn_ptr , 
	                                   DataInSize,
	                                   CRYS_DES_BLOCK_SIZE_IN_BYTES *2,
	                                   &sramOffset , 
	                                   DX_TRUE);
	  if(Error != DX_OK)
	  {
	      goto end_function_unlock;
	  }
	  Error = SEPDriver_WriteParamater((DxUint32_t)&DataInSize , 
	                           sizeof(DxUint32_t),
	                           sizeof(DxUint32_t),
	                           &sramOffset , 
	                           DX_TRUE);
	  if(Error != DX_OK)
	  {
	      goto end_function_unlock;
	  }
   	
   }
   
   
  /* send context */
  maxLength = ((sizeof(CRYS_DESUserContext_t) + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t);
  Error = SEPDriver_WriteParamater((DxUint32_t)ContextID_ptr , 
                            sizeof(CRYS_DESUserContext_t) ,
                            maxLength, 
                            &sramOffset , 
                            DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
  /* end message */
  SEPDriver_EndMessage(sramOffset);
            
  /* wait for the response */
  Error = SEPDriver_WaitForResponse(SEP_DRIVER_POLLING , 0 , CRYS_CALLBACK_Handler , SEP_DRIVER_TIMEOUT_WAIT_FOR_INIFINITY);
  if(Error != DX_OK)
  {
  	goto end_function_unlock;
  }
   
  /*-------------------
    start reading message from the SEP 
  ---------------------*/ 
   
  if(DataInSize > CRYS_DES_BLOCK_SIZE_IN_BYTES)
  {
	  /* free the tables */
	  Error = SEPDriver_FreeDMATables();
	  if(Error != DX_OK)
	  {
	  	goto end_function_unlock;
	  }
  }
  /* start the message */
  Error = SEPDriver_StartIncomingMessage(&sramOffset);
  if(Error != DX_OK)
  {
  	goto end_function_unlock;
  }
  /* read opcode + status */
  Error = SEPDriver_ReadParamater((DxUint32_t)messageParam , 
                          sizeof(DxUint32_t) * 2,
                          sizeof(DxUint32_t) * 2,
                          &sramOffset , 
                          DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
  /* check the opcode */
  if(messageParam[0] != DX_SEP_HOST_SEP_PROTOCOL_HOST_DES_BLOCK_OP_CODE)
  {
    Error = DX_WRONG_OPCODE_FROM_SEP_ERR;
    goto end_function_unlock;
  }
   
  /* check the status */
  if(messageParam[1] != CRYS_OK)
  {
    Error = messageParam[1];
    goto end_function_unlock;
  }

  if(DataInSize == CRYS_DES_BLOCK_SIZE_IN_BYTES)
  {
	  /* read opcode + status  */
	  Error = SEPDriver_ReadParamater((DxUint32_t)DataOut_ptr , 
	                          DataInSize,
	                          CRYS_DES_BLOCK_SIZE_IN_BYTES,
	                          &sramOffset , 
	                          DX_FALSE);
	  if(Error != DX_OK)
	  {
	      goto end_function_unlock;
	  }
  }
   
  /* read the context */
  maxLength = ((sizeof(CRYS_DESUserContext_t) + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t);
  Error = SEPDriver_ReadParamater((DxUint32_t)ContextID_ptr,
                          sizeof(CRYS_DESUserContext_t),
                          maxLength,
                          &sramOffset,
                          DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
     
end_function_unlock:

  /* lock access to the SEP */
  SEPDriver_Unlock();
   
end_function:
   
  return Error;
   
  #endif /* CRYS_NO_DES_SUPPORT */   
 
}/* END OF CRYS_DES_Block */ 

/**
 * @brief This function is used to end the DES operation seesion.
 *        It is the last function called on the DES operation.
 *
 *
 *        The function executes the following major steps:
 *
 *        1. Checks the validity of all of the inputs of the function. 
 *           If one of the received parameters is not valid it shall return an error.
 *
 *           The major checkers that are run over the received parameters:
 *           - verifying that the context pointer is not DX_NULL (*ContextID_ptr). 
 *        2. Clearing the users context.
 *        3. Exit the handler with the OK code.
 *      
 *
 * @param[in] ContextID_ptr - a pointer to the DES context buffer allocated by the user that
 *                       is used for the DES machine operation. this should be the same context that was
 *                       used on the previous call of this session.
 *
 *
 * @return CRYSError_t - On success CRYS_OK is returned, on failure a
 *                        value MODULE_* CRYS_DES_error.h
 */
CEXPORT_C CRYSError_t  CRYS_DES_Free(CRYS_DESUserContext_t  *ContextID_ptr )
{
  
  /* The return error identifier */
  CRYSError_t Error;

  /*-----------------------
      CODE
  --------------------------*/
  Error = CRYS_OK;
                          
  #ifndef CRYS_NO_DES_SUPPORT                                 
 
  /* ............... checking the parameters validity ................... */
  
  /* if the users context ID pointer is DX_NULL return an error */
  if( ContextID_ptr == DX_NULL )
  {
    Error = CRYS_DES_INVALID_USER_CONTEXT_POINTER_ERROR;
    goto end_function;
  } 
    
  /* .............. clearing the users context .......................... */ 
  DX_VOS_MemSet( ContextID_ptr , 0 , sizeof(CRYS_DESUserContext_t) );   

   /* ................. end of function ..................................... */
   /* ----------------------------------------------------------------------- */
    
end_function:
   
  return Error; 
   
  #endif /* CRYS_NO_DES_SUPPORT */                                
 
}/* END OF CRYS_DES_Free */

/**
 * @brief This function is used to operate the DES machine in one integrated operation.
 *
 *        The actual macros that will be used by the users are:
 *      
 *
 * @param[in,out] IVCounter_ptr - this parameter is the buffer of the IV or counters on mode CTR.
 *                          On ECB mode this parameter has no use.
 *                          On CBC mode this parameter should containe the IV values.
 *
 * @param[in] Key_ptr - a pointer to the users key buffer.
 *
 * @param[in] KeySize - Thenumber of keys used by the DES as defined in the enum.
 *
 * @param[in] EncryptDecryptFlag - This flag determains if the DES shall perform an Encrypt operation [0] or a
 *                           Decrypt operation [1].
 *
 * @param[in] OperationMode - The operation mode : ECB or CBC.
 *
 * @param[in] DataIn_ptr - The pointer to the buffer of the input data to the DES.
 *                   The pointer does not need to be word-aligned.
 *
 * @param[in] DataInSize - The size of the input data (must be not 0 and must be multiple of 8 bytes).
 *
 * @param[in,out] DataOut_ptr - The pointer to the buffer of the output data from the DES. 
 *                        The pointer does not need to be word-aligned.  
 *
 * @return CRYSError_t - On success CRYS_OK is returned, on failure a
 *                        value MODULE_* CRYS_DES_error.h
 */
 CEXPORT_C CRYSError_t  CRYS_DES(CRYS_DES_Iv_t            IV_ptr,
                                 CRYS_DES_Key_t*          Key_ptr,
                                 CRYS_DES_NumOfKeys_t     NumOfKeys,
                                 CRYS_DES_EncryptMode_t   EncryptDecryptFlag,
                                 CRYS_DES_OperationMode_t OperationMode,             
                                 DxUint8_t*               DataIn_ptr,             /* in */ 
                                 DxUint32_t               DataInSize,              /* in */ 
                                 DxUint8_t*               DataOut_ptr )           /* in / out */ 
{    
  /* The return error identifier */
  CRYSError_t         Error;
   
  /* address of the first table in the input list */
  DxUint32_t          firstInputLLITableAddr;
   
  /* address of the first table in the output list */
  DxUint32_t          firstOutputLLITableAddr;
   
  /* number of entries in the first input tables */
  DxUint32_t          numInTableEntries;
  
  /* number of entries in the first output tables */
  DxUint32_t          numOutTableEntries;
  
  /* first table data size */
  DxUint32_t          firstTableSize;
   
  /* sram offset */
  DxUint32_t          sramOffset;
  
  /* read parameter */
  DxUint32_t          messageParam[9];
   
  /*--------------------------------
      CODE
  ---------------------------------*/
  
  Error = CRYS_OK;

  #ifndef CRYS_NO_DES_SUPPORT  
  
                              
  /* check if the operation mode is legal */
    if( OperationMode >= CRYS_DES_NumOfModes )
	{
		return CRYS_DES_ILLEGAL_OPERATION_MODE_ERROR;
	}       

	/* if the operation mode selected is CBC then check the validity of
	the IV counter pointer */    
	if( OperationMode == CRYS_DES_CBC_mode && IV_ptr == DX_NULL )
	{
		return CRYS_DES_INVALID_IV_PTR_ON_NON_ECB_MODE_ERROR;
	}   

	/* If the number of keys in invalid return an error */
	if( NumOfKeys >= CRYS_DES_NumOfKeysOptions || NumOfKeys == 0 )  
	{   
		return CRYS_DES_ILLEGAL_NUM_OF_KEYS_ERROR;
	}   

	/*check the valisity of the key pointer */
	if( Key_ptr == DX_NULL )
	{
		return CRYS_DES_INVALID_KEY_POINTER_ERROR;
	}   

	/* Check the Encrypt / Decrypt flag validity */
	if( EncryptDecryptFlag >= CRYS_DES_EncryptNumOfOptions )
	{
		return CRYS_DES_INVALID_ENCRYPT_MODE_ERROR;
	}
	  
  /* if the users Data In pointer is illegal return an error */
  if( DataIn_ptr == DX_NULL )
  {
    Error = CRYS_DES_DATA_IN_POINTER_INVALID_ERROR;
    goto end_function;
  }
   
  /* if the users Data Out pointer is illegal return an error */
  if( DataOut_ptr == DX_NULL )
  {
    Error = CRYS_DES_DATA_OUT_POINTER_INVALID_ERROR;
    goto end_function;
  }
  
  /* checking that there is no overlapping between the data input and data out put buffer
     except the inplace case that is legal */
  if( DataIn_ptr != DataOut_ptr )
  {
    /* checking the case that the input buffer is in a higher address then the output buffer */
    if ( DataIn_ptr > DataOut_ptr )
    {
      /* if after adding the size to the data out pointer it is larger then the data in pointer 
         return the overlap error */
      if( DataOut_ptr + DataInSize > DataIn_ptr )
      {
        Error = CRYS_DES_DATA_OUT_DATA_IN_OVERLAP_ERROR;
        goto end_function;
      }     
    }/* end of DataIn_ptr > DataOut_ptr */   
          
    /* checking the case that the output buffer is in a higher address then the input buffer */      
    else
    {
      /* if after adding the size to the data in pointer it is larger then the data out pointer 
         return the overlap error */
      if( DataIn_ptr + DataInSize > DataOut_ptr )  
      {
        Error = CRYS_DES_DATA_OUT_DATA_IN_OVERLAP_ERROR;
        goto end_function;
      }   
    }/* end of DataOut_ptr > DataIn_ptr */   
      
  }/* end of DataIn_ptr != DataOut_ptr case */   

  /* if the data size is zero or not a multiple of 16 bytes return error */
  if( DataInSize == 0 || (DataInSize % CRYS_DES_BLOCK_SIZE_IN_BYTES) != 0 )
  {
    Error = CRYS_DES_DATA_SIZE_ILLEGAL;
    goto end_function;
  }

 
   /* lock access to the SEP */
   Error = SEPDriver_Lock();
   
   if(Error != DX_OK)
   {
       goto end_function;
   }

  /*----------------------------
    start sending message to SEP 
  -----------------------------*/
  sramOffset = 0;
   
  /* start the message */
  SEPDriver_StartMessage(&sramOffset);
  
  /* prepare params */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_DES_OP_CODE;
  messageParam[1] = NumOfKeys;
  messageParam[2] = EncryptDecryptFlag;
  messageParam[3] = OperationMode;
  /* send params */
  Error = SEPDriver_WriteParamater((DxUint32_t)messageParam,
                           sizeof(DxUint32_t) ,
                           sizeof(DxUint32_t) ,
                           &sramOffset , 
                           DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }

  if(DataInSize != CRYS_DES_BLOCK_SIZE_IN_BYTES)
  {
	  /* prepare LLI table */
	  Error = SEPDriver_PrepareSymDMATables((DxUint32_t)DataIn_ptr,
	                                         (DxUint32_t)DataOut_ptr,
	                                         DataInSize,
	                                         CRYS_DES_BLOCK_SIZE_IN_BYTES,
	                                         &firstInputLLITableAddr,
	                                         &firstOutputLLITableAddr,
	                                         &numInTableEntries,
	                                         &numOutTableEntries,
	                                         &firstTableSize);                                    
	  if(Error != DX_OK)
	  {
	    goto end_function_unlock;
	  }
  	
	  messageParam[4] = firstInputLLITableAddr;
	  messageParam[5] = numInTableEntries;
	  messageParam[6] = firstOutputLLITableAddr;
	  messageParam[7] = numOutTableEntries;
	  messageParam[8] = firstTableSize;
  
  }
   
   
  /* send IV */
  if(IV_ptr == DX_NULL)
  {
    sramOffset += 4 * sizeof(DxUint32_t);
  }
  else
  {
    /* send IV */
    Error = SEPDriver_WriteParamater((DxUint32_t)IV_ptr , 
                              sizeof(CRYS_DES_Iv_t) ,
                              4 * sizeof(DxUint32_t), 
                              &sramOffset , 
                              DX_FALSE);
    if(Error != DX_OK)
    {
        goto end_function_unlock;
    }
  }
   
  /* send key */
  Error = SEPDriver_WriteParamater((DxUint32_t)Key_ptr , 
                           8 * sizeof(DxUint32_t) , 
                           8 * sizeof(DxUint32_t),
                           &sramOffset , 
                           DX_TRUE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
  
  if(DataInSize != CRYS_DES_BLOCK_SIZE_IN_BYTES)
  {
	  /* send rest of params */
	  Error = SEPDriver_WriteParamater((DxUint32_t)&messageParam[1] , 
	                           sizeof(DxUint32_t) * 8,
	                           sizeof(DxUint32_t) * 8,
	                           &sramOffset , 
	                           DX_FALSE);
	  if(Error != DX_OK)
	  {
	      goto end_function_unlock;
	  }
  }
  else
  {
	  /* send rest of params */
	  Error = SEPDriver_WriteParamater((DxUint32_t)&messageParam[1] , 
	                           sizeof(DxUint32_t) * 3,
	                           sizeof(DxUint32_t) * 3,
	                           &sramOffset , 
	                           DX_FALSE);
	  if(Error != DX_OK)
	  {
	      goto end_function_unlock;
	  }

	  /* send data */
	  Error = SEPDriver_WriteParamater((DxUint32_t)DataIn_ptr , 
	                           DataInSize,
	                           CRYS_DES_BLOCK_SIZE_IN_BYTES*2,
	                           &sramOffset , 
	                           DX_FALSE);
	  if(Error != DX_OK)
	  {
	      goto end_function_unlock;
	  }
	  /* send rest of params */
	  Error = SEPDriver_WriteParamater((DxUint32_t)&DataInSize , 
	                           sizeof(DxUint32_t) ,
	                           sizeof(DxUint32_t) ,
	                           &sramOffset , 
	                           DX_FALSE);
	  if(Error != DX_OK)
	  {
	      goto end_function_unlock;
	  }
  	
  }
  /* end message */
  SEPDriver_EndMessage(sramOffset);
   
  /* wait for the response */
  Error = SEPDriver_WaitForResponse(SEP_DRIVER_POLLING , 0 , CRYS_CALLBACK_Handler , SEP_DRIVER_TIMEOUT_WAIT_FOR_INIFINITY);
  if(Error != DX_OK)
  {
  	goto end_function_unlock;
  }
   
  /*-------------------
    start reading message from the SEP 
  ---------------------*/ 
   
  if(DataInSize > CRYS_DES_BLOCK_SIZE_IN_BYTES)
  {
	 /* free the tables */
	  Error = SEPDriver_FreeDMATables();
	  if(Error != DX_OK)
	  {
	  	goto end_function_unlock;
	  }
  }
  /* start the message */
  Error = SEPDriver_StartIncomingMessage(&sramOffset);
  if(Error != DX_OK)
  {
  	goto end_function_unlock;
  }
   
  /* read opcode + status  */
  Error = SEPDriver_ReadParamater((DxUint32_t)messageParam , 
                          sizeof(DxUint32_t) * 2,
                          sizeof(DxUint32_t) * 2,
                          &sramOffset , 
                          DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
  /* check the opcode */
  if(messageParam[0] != DX_SEP_HOST_SEP_PROTOCOL_HOST_DES_OP_CODE)
  {
    Error = DX_WRONG_OPCODE_FROM_SEP_ERR;
    goto end_function_unlock;
  }
   
  /* check the status */
  if(messageParam[1] != CRYS_OK)
  {
    Error = messageParam[1];
    goto end_function_unlock;
  }

  if(DataInSize == CRYS_DES_BLOCK_SIZE_IN_BYTES)
  {
	  /* read opcode + status  */
	  Error = SEPDriver_ReadParamater((DxUint32_t)DataOut_ptr , 
	                          DataInSize,
	                          CRYS_DES_BLOCK_SIZE_IN_BYTES,
	                          &sramOffset , 
	                          DX_FALSE);
	  if(Error != DX_OK)
	  {
	      goto end_function_unlock;
	  }
  }
  
end_function_unlock:

  /* lock access to the SEP */
  SEPDriver_Unlock();
   
end_function:
   
  return Error;
   

  #endif /* CRYS_NO_DES_SUPPORT */
   
}/* END OF CRYS_DES */   

