
  /*
   *  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_AES.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 "DX_VOS_Sem.h"
#include "error.h"
#include "CRYS_AES_error.h"
#include "CRYS_AES.h"
#include "CRYS_COMMON.h"
#include "SEPDriver.h" 
#include "crys_host_op_code.h"
#include "gen.h"
/************************ Defines ******************************/



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

/* this macro is required to remove compilers warnings if the AES is not supported */

#ifdef CRYS_NO_AES_SUPPORT
#define RETURN_IF_AES_UNSUPPORTED( a , b , c , d , e , f , g , h , i , j ) \
  (a)=0;(b)=0;(c)=0;(d)=0;(e)=0;(f)=0;(g)=0;(h)=0;(i)=0;(j)=0; \
  return CRYS_AES_IS_NOT_SUPPORTED
#else  /* !CRYS_NO_AES_SUPPORT */
#define RETURN_IF_AES_UNSUPPORTED( a , b , c , d , e , f , g , h , i , j ) 
#endif /* !CRYS_NO_AES_SUPPORT */
  

/************************ 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 AES machine.
 *        In order to operate the AES machine the first function that should be
 *        called is this function.
 *
 *        The actual macros that will be used by the users are:
 *
 *        CRYS_AES_Init - initializing with a key from the user.
 *        CRYS_AES_InitSecretKey - initializing with the secret key.
 *
 *        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 one of the modes that is selected are CBC , MAC or CTR.
 *           - verifying that the pointer to the key buffer is not DX_NULL 
 *             if the secret key is not enabled.
 *           - verifying the values of the key size 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.
 *
 *      NOTE: In XCBC and CMAC modes: IVCounter_ptr = DX_NULL, EncryptDecrypt mode = Encrypt, 
 *                                    is_secret_key = DX_FALSE. The parameters checking in 
 *                                    thse modesis performed ccordingly.      
 *
 * @param[in] ContextID_ptr - a pointer to the AES context buffer allocated by the user that
 *                       is used for the AES machine operation.
 *
 * @param[in,out] IVCounter_ptr - This parameter is the buffer of the IV or counters on mode CTR.
 *                          In ECB, XCBC, CMAC mode this parameter is not used.
 *                          In CBC and MAC modes this parameter should contain the IV values.
 *                          In CTR mode this value should contain the init counter.
 *                          In XCBC and CMAC modes it may be NULL
 *
 * @param[in] Key_ptr -  A pointer to the user's key buffer.
 *
 * @param[in] KeySize - The size of the KEY used by the AES: 128, 192, or 256 bits, as defined in the enum.
 *
 * @param[in] EncryptDecryptFlag - A flag specifying whether the AES should perform an Encrypt operation (0) 
 *                           or a Decrypt operation (1). In XCBC and CMAC modes it must be 0.
 *
 * @param[in] OperationMode - The operation mode: ECB, CBC, MAC, CTR, XCBC (PRF and 96), CMAC.
 *
 * @param[in] is_secret_key - A parameter specifying whether to use a secret key (1) 
 *                           or to use a key defined by the user (0). 
 *
 * @return CRYSError_t - On success CRYS_OK is returned, on failure a
 *                        value MODULE_* CRYS_AES_error.h
 */

CEXPORT_C CRYSError_t  _DX_AES_Init( CRYS_AESUserContext_t    *ContextID_ptr,
                                     CRYS_AES_IvCounter_t     IVCounter_ptr,
                                     CRYS_AES_Key_t           Key_ptr,
                                     CRYS_AES_KeySize_t       KeySize,
                                     CRYS_AES_EncryptMode_t   EncryptDecryptFlag,
                                     CRYS_AES_OperationMode_t OperationMode,
                                     DxUint8_t                is_secret_key )
{
   /* offset into SRAM */
   DxUint32_t   sramOffset;
   
   /* read param */
   DxUint32_t   messageParam[5];
   
   /* max length */
   DxUint32_t   maxLength;
   
   /* key size in bytes */
   DxUint32_t   keySizeInBytes;
 
   /* The return error identifier */
   CRYSError_t  Error;
   
     
   /* FUNCTION LOGIC */
   
   /* ............... local initializations .............................. */
   /* -------------------------------------------------------------------- */
   
   /* initializing the Error to O.K */
   Error = CRYS_OK;
      
   /* ............... if not supported exit .............................. */
   /* -------------------------------------------------------------------- */   
      
   RETURN_IF_AES_UNSUPPORTED( ContextID_ptr , IVCounter_ptr , Key_ptr , 
                              KeySize , EncryptDecryptFlag , OperationMode , 
                              is_secret_key , ccmWorkingContext_ptr , is_secret_key , is_secret_key );
                              
   #ifndef CRYS_NO_AES_SUPPORT                              
      
   /* ............... checking the parameters validity ................... */
   /* -------------------------------------------------------------------- */
   
   /* if the users context ID pointer is DX_NULL return an error */
   if( ContextID_ptr == DX_NULL )
   {
      Error = CRYS_AES_INVALID_USER_CONTEXT_POINTER_ERROR;
      goto end_function;
   }   

   /* check if the operation mode is legal */
   if( OperationMode >= CRYS_AES_NumOfModes )
   {
      Error = CRYS_AES_ILLEGAL_OPERATION_MODE_ERROR;
      goto end_function;
   }       
      
#ifndef DX_NO_NULL_POINTER_CHECKING
   /* if the operation mode selected is CBC , MAC or CTR then check the validity of
      the IV counter pointer */    
   if( OperationMode != CRYS_AES_ECB_mode      &&
       OperationMode != CRYS_AES_XCBC_MAC_mode &&
       OperationMode != CRYS_AES_CMAC_mode     && 
       IVCounter_ptr == DX_NULL )
   {
      Error = CRYS_AES_INVALID_IV_OR_TWEAK_PTR_ERROR;
      goto end_function;
   }   
#endif  
   
   /* If illegal secret key mode return an error */
   if( is_secret_key != 0 && is_secret_key != 1)
   {   
      Error = CRYS_AES_ILLEGAL_SECRET_KEY_MODE;
      goto end_function;
   }      
   
   /* If the Keys size is invalid return an error */
   if( KeySize >= CRYS_AES_KeySizeNumOfOptions )  
   {   
      Error = CRYS_AES_ILLEGAL_KEY_SIZE_ERROR;
      goto end_function;
   }   
     
   /* If the secret key mode is not sellected then check the validity of the key pointer */
   if( is_secret_key == DX_FALSE && Key_ptr == DX_NULL )
   {
      Error = CRYS_AES_INVALID_KEY_POINTER_ERROR;
      goto end_function;
   }   
      
   /* Check the Encrypt / Decrypt flag validity */
   if( EncryptDecryptFlag >= CRYS_AES_EncryptNumOfOptions )
   {
      Error = CRYS_AES_INVALID_ENCRYPT_MODE_ERROR;
      goto end_function;
   }
   
   /* in mode CTR enable only the encrypt mode */
   if( OperationMode == CRYS_AES_CTR_mode && EncryptDecryptFlag == CRYS_AES_Decrypt )
   {
      Error = CRYS_AES_DECRYPT_MODE_NOT_ALLOWED_ON_CTR_MODE;
      goto end_function;
   }
    
   /* in MAC,XCBC,CMAC modes enable only:  encrypt mode  */
   if( (OperationMode == CRYS_AES_XCBC_MAC_mode || OperationMode == CRYS_AES_CMAC_mode || OperationMode == CRYS_AES_MAC_mode) && 
         EncryptDecryptFlag != CRYS_AES_Encrypt )
   {
      Error = CRYS_AES_DECRYPTION_NOT_ALLOWED_ON_THIS_MODE;
      goto end_function;
   }
   
      /* in XCBC mode enable only key size = 128 bit */
   if(   OperationMode == CRYS_AES_XCBC_MAC_mode && 
         KeySize != CRYS_AES_Key128BitSize)
   {
      Error = CRYS_AES_NOT_ALLOWED_KEY_TYPE_ON_THIS_MODE;
      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 message */
   messageParam[0] = DX_SEP_HOST_SEP_PROTOCL_HOST_AES_INIT_OP_CODE;
   messageParam[1] = KeySize;
   messageParam[2] = EncryptDecryptFlag;
   messageParam[3] = OperationMode;
   messageParam[4] = is_secret_key;
   
   /* send opcode */
   Error = SEPDriver_WriteParamater((DxUint32_t)messageParam,
                            sizeof(DxUint32_t),
                            sizeof(DxUint32_t),
                            &sramOffset,
                            DX_FALSE);
   if(Error != DX_OK)
   {
       goto end_function_unlock;
   }
   
   /* send IV */
   maxLength = ((sizeof(CRYS_AES_IvCounter_t) + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t);
   Error = SEPDriver_WriteParamater((DxUint32_t)IVCounter_ptr , 
                             sizeof(CRYS_AES_IvCounter_t) ,
                             maxLength, 
                             &sramOffset , 
                             DX_FALSE);
   if(Error != DX_OK)
   {
       goto end_function_unlock;
   }
   
   /* send key */
   switch(KeySize)
   {
    case CRYS_AES_Key128BitSize:
      keySizeInBytes = 16;
      break;
      
    case CRYS_AES_Key192BitSize:
      keySizeInBytes = 24;
      break;
      
    case CRYS_AES_Key256BitSize:
      keySizeInBytes = 32;
      break;
      
    default:
      keySizeInBytes = 0;
      break;
   }
   
   Error = SEPDriver_WriteParamater((DxUint32_t)Key_ptr , 
                             keySizeInBytes ,
                             64 , 
                             &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) * 4,
                            sizeof(DxUint32_t) * 4,
                            &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)
   {
      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_PROTOCL_HOST_AES_INIT_OP_CODE)
   {
      Error = DX_WRONG_OPCODE_FROM_SEP_ERR;
      goto end_function_unlock;
   }
   
   /* check status */
   if(messageParam[1] != CRYS_OK)
   {
      Error = messageParam[1];
      goto end_function_unlock;
   }
   
   /* read the context */
   maxLength = ((sizeof(CRYS_AESUserContext_t) + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t);
   Error = SEPDriver_ReadParamater((DxUint32_t)ContextID_ptr,
                            sizeof(CRYS_AESUserContext_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_AES_SUPPORT */
   
}/* END OF _DX_AES_Init */   
                         

/****************************************************************************************************/
/** 
 * @brief This function is used to operate a block on the AES machine.
 *        This function should be called after the CRYS_AES_Init or CRYS_AES_InitSecretKey functions
 *        were 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.
 *          - in all modes besides XCBC and CMAC:  
 *              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.Executes the AES operation on the hardware by calling the 
 *          low level AES function LLF_AES_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 AES context buffer allocated by the user that
 *                       is used for the AES 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 AES. 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 16 bytes, 
 *                         besides XCBC and CMAC.
 *
 * @param[in/out] DataOut_ptr - The pointer to the buffer of the output data from the AES. The pointer 
 *                        does not need to be aligned to 32 bits. In XCBC and CMAC modes it may be NULL 
 *
 * @return CRYSError_t - On success CRYS_OK is returned, on failure a
 *                        value MODULE_* CRYS_AES_error.h
 */
 CEXPORT_C CRYSError_t  CRYS_AES_Block( CRYS_AESUserContext_t   *ContextID_ptr,   
                                        DxUint8_t               *DataIn_ptr,     
                                        DxUint32_t               DataInSize,     
                                        DxUint8_t               *DataOut_ptr )
 {                              
   /* 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 pitput tables */
   DxUint32_t         numOutTableEntries;
   
   /* size of data in the first table */
   DxUint32_t         firstTableSize;
   
   /* sram offset */
   DxUint32_t         sramOffset;
  
   /* message parameters */
   DxUint32_t         messageParam[7];
   
   /* max length */
   DxUint32_t         maxLength;
   
   /* remaining Data size for specail AES modes*/
   DxUint32_t         remainingDataSize;
   DxUint32_t         dataForDma;
  
   /*-----------------------
      CODE
   --------------------------*/
    
   /* initializing the Error to O.K  and DataOutSize to 0 */
   Error = CRYS_OK;                                              
    
   /* ............... checking the parameters validity ................... */
   /* -------------------------------------------------------------------- */

  //DataInSize = 48;
   /* if the users context ID pointer is DX_NULL return an error */
   if( ContextID_ptr == DX_NULL )
   {
      Error = CRYS_AES_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_AES_DATA_IN_POINTER_INVALID_ERROR;
      goto end_function;
   }
   
   if(ContextID_ptr->OperationMode == CRYS_AES_MAC_mode && DataOut_ptr == DX_NULL)
   {
      Error = CRYS_AES_DATA_IN_POINTER_INVALID_ERROR;
      goto end_function;
   }
   
   /* for the CRYS_AES_ECB_mode,CRYS_AES_CBC_mode,CRYS_AES_CTR_mode check that there is no overlapping between the input buffers */
   if(ContextID_ptr->OperationMode == CRYS_AES_ECB_mode ||
      ContextID_ptr->OperationMode == CRYS_AES_CBC_mode ||
      ContextID_ptr->OperationMode == CRYS_AES_CTR_mode)
   {
      if(DataOut_ptr == DX_NULL)
      {
        Error = CRYS_AES_DATA_IN_POINTER_INVALID_ERROR;
        goto end_function;
      }
   
      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_AES_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_AES_DATA_OUT_DATA_IN_OVERLAP_ERROR;
            goto end_function;
          }   
        }/* end of DataOut_ptr > DataIn_ptr */   
      }
   }

   /* lock access to the SEP */
   Error = SEPDriver_Lock();
   
   if(Error != DX_OK)
   {
      goto end_function;
   }
   
   dataForDma = DataInSize;
   if((ContextID_ptr->OperationMode == CRYS_AES_XCBC_MAC_mode)
      ||(ContextID_ptr->OperationMode == CRYS_AES_CMAC_mode))
   {
   	  remainingDataSize = DataInSize % CRYS_AES_BLOCK_SIZE_IN_BYTES;
	  /*if data is aligned to 16bytes need to copy the whole last block but still send if for encryption*/
   	  if(DataInSize && !remainingDataSize)
   	  {
   	  	remainingDataSize = CRYS_AES_BLOCK_SIZE_IN_BYTES;	
   	  }
	  /*if data is not aligned to 16 bytes, the remainig siez will be copied and only aligned data will be send to DMA*/
   	  dataForDma = DataInSize - (remainingDataSize & 0xF); 	
   }
   else
   {
   	  remainingDataSize = 0x0;
   }

   if(ContextID_ptr->OperationMode == CRYS_AES_MAC_mode ||
      ContextID_ptr->OperationMode == CRYS_AES_XCBC_MAC_mode ||
      ContextID_ptr->OperationMode == CRYS_AES_CMAC_mode)
   {
      Error = SEPDriver_PREPARE_INPUT_SYM_DMA_TABLE((DxUint32_t)DataIn_ptr,
                                                     dataForDma,
                                                     CRYS_AES_BLOCK_SIZE_IN_BYTES,
                                                     &firstInputLLITableAddr,
                                                     &numInTableEntries,
                                                     &firstTableSize); 
    
   }
   else
   {
     /* prepare DMA tables */      
     Error = SEPDriver_PrepareSymDMATables((DxUint32_t)DataIn_ptr,
                                           (DxUint32_t)DataOut_ptr,
                                           dataForDma,
                                           CRYS_AES_BLOCK_SIZE_IN_BYTES,
                                           &firstInputLLITableAddr,
                                           &firstOutputLLITableAddr,
                                           &numInTableEntries,
                                           &numOutTableEntries,
                                           &firstTableSize); 
   }
                                    
   if(Error != DX_OK)
   {
      goto end_function_unlock;
   }
   
   /* send the message to SEP */
   sramOffset = 0;
   
   /* start the message */
   SEPDriver_StartMessage(&sramOffset);
  
   /* prepare message */
   messageParam[0] = DX_SEP_HOST_SEP_PROTOCL_HOST_AES_BLOCK_CODE;
   messageParam[1] = firstInputLLITableAddr;
   messageParam[2] = numInTableEntries;
   messageParam[3] = firstOutputLLITableAddr;
   messageParam[4] = numOutTableEntries;
   messageParam[5] = firstTableSize;
   messageParam[6] = remainingDataSize;
   
   /* send message */
   Error = SEPDriver_WriteParamater((DxUint32_t)messageParam,
                            sizeof(DxUint32_t) * 7,
                            sizeof(DxUint32_t) * 7,
                            &sramOffset, 
                            DX_FALSE);
   if(Error != DX_OK)
   {
       goto end_function_unlock;
   }
   
   /* send remainf data size */
   Error = SEPDriver_WriteParamater((DxUint32_t)(DataIn_ptr + DataInSize - remainingDataSize),
                            remainingDataSize,
                            CRYS_AES_BLOCK_SIZE_IN_BYTES,
                            &sramOffset, 
                            DX_TRUE);
   if(Error != DX_OK)
   {
       goto end_function_unlock;
   }
   /* send context */
   maxLength = ((sizeof(CRYS_AESUserContext_t) + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t);
   Error = SEPDriver_WriteParamater((DxUint32_t)ContextID_ptr , 
                            sizeof(CRYS_AESUserContext_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 
   ---------------------*/ 
   
   /* free the tables */
   Error = SEPDriver_FreeDMATables();
   if(Error)
   {
      goto end_function_unlock;
   }
   
   /* start the message */
   Error = SEPDriver_StartIncomingMessage(&sramOffset);
   if(Error)
   {
    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_PROTOCL_HOST_AES_BLOCK_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(ContextID_ptr->OperationMode == CRYS_AES_MAC_mode)
   {
      Error = SEPDriver_ReadParamater((DxUint32_t)DataOut_ptr,
                               4 * sizeof(DxUint32_t),
                               4 * sizeof(DxUint32_t),
                               &sramOffset,
                               DX_FALSE);
      if(Error != DX_OK)
      {
          goto end_function_unlock;
      }
   }
   else
   {
      /* skip MAC */
      sramOffset += 4 * sizeof(DxUint32_t);
   }
   
   
   /* read the context */
   maxLength = ((sizeof(CRYS_AESUserContext_t) + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t);
   Error = SEPDriver_ReadParamater((DxUint32_t)ContextID_ptr,
                           sizeof(CRYS_AESUserContext_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;
 
}/* END OF CRYS_AES_Block */ 


/****************************************************************************************************/
/** 
 * @brief This function is used as finish operation of AES on special modes.
 *
 *        The function must be called after all AES_Block operations on 
 *        CRYS_AES_XCBC_MAC_mode, CRYS_AES_CMAC_mode only.
 *
 *        The function performs specific operations for last block of data and 
 *        outputs result authentication value: 
 *        
 *        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.
 *        2. If AES operation mode is not one of XCBC or CMAC goto step 5. 
 *        3. Decrypts the received context to the working context  by calling the 
 *           CRYS_CCM_GetContext function.
 *        4. If operation mode is XCBC or CMAC then the function calls the LLF_AES_Finish function.
 *        5. Calls the CRYS_AES_Free function for cleaning working context.
 *        6. Exits   
 *      
 *
 * @param[in] ContextID_ptr - a pointer to the AES context buffer allocated by the user that
 *                            should be the same context that was used on the previous call
 *                            of this session.
 * @param[in] DataOut_ptr - The pointer to the buffer for output MAC data from the AES. 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_AES_error.h
 */
 CEXPORT_C CRYSError_t  _DX_AES_Finish( CRYS_AESUserContext_t   *ContextID_ptr,                                       
                                        CRYS_AES_MAX_MAC_RESULT_t DataOut_ptr )
 {                              
   /* FUNCTION DECLERATIONS */

   /* The return error identifier */
   CRYSError_t  Error;
   
   /* sram offset */
   DxUint32_t   sramOffset;
   
   /* read parameter */
   DxUint32_t   messageParam[2];
   
   /* max length */
   DxUint32_t   maxLength;
  
   /*-----------------------
      CODE
   ------------------------*/
  
   /* initializing the Error to O.K */
   Error = CRYS_OK;                             
   
   /* ............... checking the parameters validity ................... */
   /* -------------------------------------------------------------------- */

   /* if the users context ID pointer is DX_NULL return an error */
   if( ContextID_ptr == DX_NULL )
   {
      Error = CRYS_AES_INVALID_USER_CONTEXT_POINTER_ERROR;
      goto end_function;
   }
   
   
   /* lock access to the SEP */
   Error = SEPDriver_Lock();
   
   if(Error != DX_OK)
   {
       goto end_function;
   }
   
   sramOffset = 0;
   
   /* start the message */
   SEPDriver_StartMessage(&sramOffset);
  
   /* prepare message  */
   messageParam[0] = DX_SEP_HOST_SEP_PROTOCL_HOST_AES_FINISH_OP_CODE;
   
   /* send message */
   Error = SEPDriver_WriteParamater((DxUint32_t)messageParam,
                            sizeof(DxUint32_t),
                            sizeof(DxUint32_t),
                            &sramOffset, 
                            DX_FALSE);
   if(Error != DX_OK)
   {
       goto end_function_unlock;
   }
   
   /* send context */
   maxLength = ((sizeof(CRYS_AESUserContext_t) + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t);
   Error = SEPDriver_WriteParamater((DxUint32_t)ContextID_ptr , 
                             sizeof(CRYS_AESUserContext_t) , 
                             maxLength,
                             &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)
   {
    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_PROTOCL_HOST_AES_FINISH_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 result if needed */ 
   if( ContextID_ptr->OperationMode == CRYS_AES_MAC_mode      ||
	   ContextID_ptr->OperationMode == CRYS_AES_XCBC_MAC_mode ||
	   ContextID_ptr->OperationMode == CRYS_AES_CMAC_mode )
   {
      /* check the DataOut pointer, excluding MAC_mode */
      if( DataOut_ptr == DX_NULL && ContextID_ptr->OperationMode != CRYS_AES_MAC_mode )
      {
	      Error = CRYS_AES_DATA_OUT_POINTER_INVALID_ERROR;
	      goto end_function_unlock;
      }
      
      if( DataOut_ptr != DX_NULL )
      {
	      Error = SEPDriver_ReadParamater((DxUint32_t)DataOut_ptr,
	                               4 * sizeof(DxUint32_t),
	                               4 * sizeof(DxUint32_t),
	                               &sramOffset,
	                               DX_FALSE);
     
	      if(Error != DX_OK)
	      {
	          goto end_function_unlock;
	      }
      }
   }
  
end_function_unlock:
          
   /* lock access to the SEP */
   SEPDriver_Unlock();
      
   /* ................. end of function ..................................... */
   /* ----------------------------------------------------------------------- */
end_function:
  
   return Error;
 
}/* END OF _DX_AES_Finish */ 


/****************************************************************************************************/
/**
 * @brief This function is used to end the AES operation session.
 *        It is the last function called on the AES 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 AES context buffer allocated by the user that
 *                       is used for the AES 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_AES_error.h
 */
CEXPORT_C CRYSError_t  CRYS_AES_Free(CRYS_AESUserContext_t  *ContextID_ptr )
{
   /* FUNCTION DECLERATIONS */

   /* The return error identifier */
   CRYSError_t Error;

   /* FUNCTION LOGIC */
 
   /* ............... local initializations .............................. */
   /* -------------------------------------------------------------------- */
   
   /* initializing the Error to O.K */
   Error = CRYS_OK;                           
  
   /* ............... checking the parameters validity ................... */
   /* -------------------------------------------------------------------- */

   /* if the users context ID pointer is DX_NULL return an error */
   if( ContextID_ptr == DX_NULL )
   {
      Error = CRYS_AES_INVALID_USER_CONTEXT_POINTER_ERROR;
      goto End;
   } 
   
   /* .............. clearing the users context .......................... */
   /* -------------------------------------------------------------------- */
   
   DX_VOS_MemSet( ContextID_ptr , 0 , sizeof(CRYS_AESUserContext_t) );   

   /* ................. end of function ..................................... */
   /* ----------------------------------------------------------------------- */
    
   End:
   
   return Error;                             
 
}/* END OF CRYS_AES_Free */

/****************************************************************************************************/
/**
 * @brief This function is used to operate the AES machine in one integrated operation.
 *
 *        The actual macros that will be used by the users are:
 *
 *        CRYS_AES_ - Operating the integrated AES with a key from the user.
 *        CRYS_AES_SecretKey - Operating the AES with the secret key.
 *      
 *
 * @param[in,out] IVCounter_ptr - this parameter is the buffer of the IV or counters on mode CTR.
 *                          In ECB mode this parameter has no use.
 *                          In CBC and MAC modes this parameter should containe the IV values.
 *                          in CTR mode this value shuld contain the init counter.
 *
 * @param[in] Key_ptr - a pointer to the users key buffer.
 *
 * @param[in] KeySize - The size of the KEY used on the AES : 128 , 196 or 256 bits as defined in the enum.
 *
 * @param[in] EncryptDecryptFlag - This flag determains if the AES shall perform an Encrypt operation [0] or a
 *                           Decrypt operation [1].
 *
 * @param[in] OperationMode - The operation mode : ECB , CBC , MAC or CTR.
 *
 * @param[in] is_secret_key - This paramrter defines do we use a secret key [1] or a key defined from the user [0].    
 *
 * @param[in] DataIn_ptr - The pointer to the buffer of the input data to the AES. 
 *                   The pointer's value 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 16 bytes).
 *
 * @param[in,out] DataOut_ptr - The pointer to the buffer of the output data from the AES. 
 *                        The pointer's value does not need to be word-aligned.  
 *
 * @return CRYSError_t - On success CRYS_OK is returned, on failure a
 *                        value MODULE_* CRYS_AES_error.h
 */
CEXPORT_C CRYSError_t  _DX_AES( CRYS_AES_IvCounter_t       IVCounter_ptr,       
		                        CRYS_AES_Key_t             Key_ptr,                 
		                        CRYS_AES_KeySize_t         KeySize,            
		                        CRYS_AES_EncryptMode_t     EncryptDecryptFlag, 
		                        CRYS_AES_OperationMode_t   OperationMode ,      
		                        DxUint8_t                  is_secret_key,       
		                        DxUint8_t                  *DataIn_ptr,        
		                        DxUint32_t                 DataInSize,         
		                        DxUint8_t                  *DataOut_ptr )
{    
   /* FUNCTION DECLERATIONS */

   /* 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;
  
   /* message parameter */
   DxUint32_t             messageParam[11];
   
    /* max length */
   DxUint32_t             maxLength;
   
   /* key size in bytes */
   DxUint32_t             keySizeInBytes;
   
   /* size of unaligned data */
   DxUint32_t             remainingDataSize;
   DxUint32_t             dataForDma;

   /*---------------------------
      CODE
   -----------------------------*/
    
   /* ............... local initializations .............................. */
   /* -------------------------------------------------------------------- */
   
   /* initializing the Error to O.K */
   Error = CRYS_OK;

   #ifndef CRYS_NO_AES_SUPPORT  
   
   /* if the users Data In pointer is illegal return an error */
   if( DataIn_ptr == DX_NULL )
   {
      Error = CRYS_AES_DATA_IN_POINTER_INVALID_ERROR;
      goto end_function;
   }
   
   /* check if the operation mode validity */
   if( OperationMode >= CRYS_AES_NumOfModes )
      return  CRYS_AES_ILLEGAL_OPERATION_MODE_ERROR;
   
      /* Check the Encrypt / Decrypt flag validity */
   if( EncryptDecryptFlag >= CRYS_AES_EncryptNumOfOptions )
      return  CRYS_AES_INVALID_ENCRYPT_MODE_ERROR;
   
   /* check DataOut pointer */
   if(OperationMode == CRYS_AES_MAC_mode && DataOut_ptr == DX_NULL)
   {
      Error = CRYS_AES_DATA_IN_POINTER_INVALID_ERROR;
      goto end_function;
   }
   
   /* for the CRYS_AES_ECB_mode,CRYS_AES_CBC_mode,CRYS_AES_CTR_mode check that there is no overlapping between the input buffers */
   if(OperationMode == CRYS_AES_ECB_mode ||
      OperationMode == CRYS_AES_CBC_mode ||
      OperationMode == CRYS_AES_CTR_mode)
   {
      if(DataOut_ptr == DX_NULL)
      {
        Error = CRYS_AES_DATA_IN_POINTER_INVALID_ERROR;
        goto end_function;
      }
   
      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_AES_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_AES_DATA_OUT_DATA_IN_OVERLAP_ERROR;
            goto end_function;
          }   
        }/* end of DataOut_ptr > DataIn_ptr */   
      }
   }                               
  
   /* ............... calling the CRYS init function ...................... */
   /* --------------------------------------------------------------------- */
 
   /* lock access to the SEP */
   Error = SEPDriver_Lock();
   
   if(Error != DX_OK)
   {
       goto end_function_no_unlock;
   }

   dataForDma = DataInSize;
   if((OperationMode == CRYS_AES_XCBC_MAC_mode)
      ||(OperationMode == CRYS_AES_CMAC_mode))
   {
   	  remainingDataSize = DataInSize % CRYS_AES_BLOCK_SIZE_IN_BYTES;
	  /*if data is aligned to 16bytes need to copy the whole last block but still send if for encryption*/
   	  if(DataInSize && !remainingDataSize)
   	  {
   	  	remainingDataSize = CRYS_AES_BLOCK_SIZE_IN_BYTES;	
   	  }
	  
	  /*if data is not aligned to 16 bytes, the remainig size will be copied and only aligned data will be send to DMA*/
   	  dataForDma = DataInSize - (remainingDataSize & 0xF); 	
   }
   else
   {
   	  remainingDataSize = 0x0;
   }
   
   
   if(OperationMode == CRYS_AES_MAC_mode ||
      OperationMode == CRYS_AES_XCBC_MAC_mode ||
      OperationMode == CRYS_AES_CMAC_mode)
   {
      Error = SEPDriver_PREPARE_INPUT_SYM_DMA_TABLE((DxUint32_t)DataIn_ptr,
                                                    dataForDma,
                                                    CRYS_AES_BLOCK_SIZE_IN_BYTES,
                                                    &firstInputLLITableAddr,
                                                    &numInTableEntries,
                                                    &firstTableSize);
   }
   else
   {
     /* prepare LLI table */
     Error = SEPDriver_PrepareSymDMATables((DxUint32_t)DataIn_ptr,
                                           (DxUint32_t)DataOut_ptr,
                                           dataForDma,
                                           CRYS_AES_BLOCK_SIZE_IN_BYTES,
                                           &firstInputLLITableAddr,
                                           &firstOutputLLITableAddr,
                                           &numInTableEntries,
                                           &numOutTableEntries,
                                           &firstTableSize);
   }
   if(Error != DX_OK)
   {
       goto end_function;
   }                                    
                                   
   /* send the message to SEP */
   sramOffset = 0;
   
   /* start the message */
   SEPDriver_StartMessage(&sramOffset);
  
   /* prepare message */
   messageParam[0] = DX_SEP_HOST_SEP_PROTOCL_HOST_AES_OP_CODE;
   messageParam[1] = KeySize;
   messageParam[2] = EncryptDecryptFlag;
   messageParam[3] = OperationMode;
   messageParam[4] = is_secret_key;
   messageParam[5] = firstInputLLITableAddr;
   messageParam[6] = numInTableEntries;
   messageParam[7] = firstOutputLLITableAddr;
   messageParam[8] = numOutTableEntries;
   messageParam[9] = firstTableSize;
   messageParam[10] = remainingDataSize;
  
   /* send message param */
   Error = SEPDriver_WriteParamater((DxUint32_t)messageParam , 
                            sizeof(DxUint32_t),
                            sizeof(DxUint32_t),
                            &sramOffset , 
                            DX_FALSE);
   if(Error != DX_OK)
   {
       goto end_function;
   }
   
   /* send IV */
   Error = SEPDriver_WriteParamater((DxUint32_t)IVCounter_ptr , 
                             sizeof(CRYS_AES_IvCounter_t) , 
                             4 * 4,
                             &sramOffset , 
                             DX_FALSE);
   if(Error != DX_OK)
   {
       goto end_function;
   }
   
   /* send key */
   switch(KeySize)
   {
    case CRYS_AES_Key128BitSize:
      keySizeInBytes = 16;
      break;
      
    case CRYS_AES_Key192BitSize:
      keySizeInBytes = 24;
      break;
      
    case CRYS_AES_Key256BitSize:
      keySizeInBytes = 32;
      break;
      
    default:
      keySizeInBytes = 0;
      break;
   }
   Error = SEPDriver_WriteParamater((DxUint32_t)Key_ptr ,
                                        keySizeInBytes, 
                                        8 * 8 , 
                                        &sramOffset , 
                                        DX_TRUE);
   if(Error != DX_OK)
   {
       goto end_function;
   }
   
   /* send rest of params */
   Error = SEPDriver_WriteParamater((DxUint32_t)&messageParam[1],
                            sizeof(DxUint32_t) * 10,
                            sizeof(DxUint32_t) * 10, 
                            &sramOffset , 
                            DX_FALSE);
   if(Error != DX_OK)
   {
       goto end_function;
   }
   
   /* send the tail data */
   Error = SEPDriver_WriteParamater((DxUint32_t)(DataIn_ptr + DataInSize - remainingDataSize) ,
                            remainingDataSize,
                            CRYS_AES_BLOCK_SIZE_IN_BYTES, 
                            &sramOffset , 
                            DX_TRUE);
   if(Error != DX_OK)
   {
       goto end_function;
   }
   /* 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;
   }
   
   /*-------------------
      start reading message from the SEP 
   ---------------------*/ 
   
   /* free the tables */
   Error = SEPDriver_FreeDMATables();
   if(Error)
   {
     goto end_function;
   }
   
   /* start the message */
   Error = SEPDriver_StartIncomingMessage(&sramOffset);
   if(Error)
   {
     goto end_function;
   }
   
   /* 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;
   }
   
   /* check the opcode */
   if(messageParam[0] != DX_SEP_HOST_SEP_PROTOCL_HOST_AES_OP_CODE)
   {
      Error = DX_WRONG_OPCODE_FROM_SEP_ERR;
      goto end_function;
   }
   
   /* check the status */
   if(messageParam[1] != CRYS_OK)
   {
      Error = messageParam[1];
      goto end_function;
   }
   
   if(OperationMode == CRYS_AES_MAC_mode ||
		  OperationMode == CRYS_AES_XCBC_MAC_mode ||
		  OperationMode == CRYS_AES_CMAC_mode)
   {
      maxLength = ((sizeof(CRYS_AES_MAX_MAC_RESULT_t) + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t);
      Error = SEPDriver_ReadParamater((DxUint32_t)DataOut_ptr ,  
                               sizeof(CRYS_AES_MAX_MAC_RESULT_t),
                               maxLength,
                               &sramOffset ,
                               DX_FALSE);
      if(Error != DX_OK)
      {
          goto end_function;
      }
   }
           
   /* ................. end of function ..................................... */
   /* ----------------------------------------------------------------------- */
   
end_function:
   
   /* lock access to the SEP */
   SEPDriver_Unlock();

end_function_no_unlock:
      
   return Error;
  
   #endif /* !CRYS_NO_AES_SUPPORT  */
   
}/* END OF _DX_AES */   


/**
   @brief  The CRYS_AES_Wrap function implements the following algorithm 
           (rfc3394, Sept. 2002):  
   
   Inputs:  Plaintext DataIn, n 64-bit values {P1, P2, ..., Pn}, 
            KeyData, K (the KEK).                
   Outputs: Ciphertext, WrapDataOut (n+1) 64-bit values {C0, C1, ..., Cn}.
  

  @param[in]  DataIn_ptr - A pointer to plain text data to be wrapped
                            NOTE: Overlapping between the data input and data output buffer
                                  is not allowed, except the inplace case that is legal . 			
   @param[in]  DataInLen  - Length of data in bytes. DataLen must be multiple of 
                            8 bytes and  must be in range [16,  2^28].
   @param[in]  KeyData	  - A pointer to  key data (key encryption key - KEK). 
   @param[in]  KeySize	  - Enumerator variable, defines length of key.
   @param[out] WrapDataOut_ptr -	A pointer to buffer for output of wrapped data.
   @param[in/out] WrapDataLen_ptr - A pointer to a buffer for input of size of 
                                    user passed buffer and for output actual 
                                    size of unwrapped data in bytes. Buffer size must 
                                    be not less than DataLen+CRYS_AES_WRAP_BLOCK_SIZE_IN_BYTES.                         
   @return CRYSError_t - CRYS_OK, or error message                         
                         CRYS_AES_WRAP_ILLEGAL_DATA_PTR_ERROR            
                         CRYS_AES_WRAP_DATA_LENGTH_ERROR                 
                         CRYS_AES_WRAP_ILLEGAL_KEY_PTR_ERROR             
                         CRYS_AES_WRAP_KEY_LENGTH_ERROR                  
                         CRYS_AES_WRAP_ILLEGAL_WRAP_DATA_PTR_ERROR      
                         CRYS_AES_WRAP_ILLEGAL_WRAP_DATA_LEN_PTR_ERROR  
                         CRYS_AES_WRAP_ILLEGAL_WRAP_DATA_LENGTH_ERROR
						 CRYS_AES_WRAP_DATA_OUT_DATA_IN_OVERLAP_ERROR 

     NOTE:  On error exiting from function the output buffer may be zeroed by the function.
*/
CIMPORT_C  CRYSError_t CRYS_AES_Wrap (DxUint8_t            *DataIn_ptr,      /*in*/   
                                      DxUint32_t            DataInLen,       /*in*/
                                      CRYS_AES_Key_t        KeyData,         /*in*/
                                      CRYS_AES_KeySize_t    KeySize,         /*in*/
      							                  DxInt8_t              isSecretKey,     /*in*/
                                      DxUint8_t            *WrapDataOut_ptr, /*out*/
                                      DxUint32_t           *WrapDataLen_ptr  /*in/out*/ ) 
{
  
   /*****************  LOCAL DECLARATIONS  ********************************/
	
   CRYSError_t 	Error = CRYS_OK;

   /* offset */
   DxUint32_t	  sramOffset;
   
   /* param read */
   DxUint32_t   messageParam[4]; 
   
   /* max length */
   DxUint32_t   maxLength;
   
   /* key size in bytes */
   DxUint32_t   keySizeInBytes;  
   
                       
#ifndef CRYS_NO_AES_SUPPORT  
                               

   /*----------------------------------------------------------------------*/
   /*            Check input parameters                                    */ 
   /*----------------------------------------------------------------------*/
   
   /* Check input pointers */
   
   if(DataIn_ptr == DX_NULL)
   {
      Error = CRYS_AES_WRAP_ILLEGAL_DATA_PTR_ERROR;
      goto end_function;
   }
   
   /* Check isSecretKey value */
   if( isSecretKey != DX_FALSE && isSecretKey != DX_TRUE )
      return CRYS_AES_WRAP_IS_SECRET_KEY_FLAG_ILLEGAL_ERROR;
   
   if(KeyData == DX_NULL)
   {
      Error = CRYS_AES_WRAP_ILLEGAL_KEY_PTR_ERROR;
      goto end_function;
   }
   
   if(WrapDataOut_ptr == DX_NULL)
   {
      Error = CRYS_AES_WRAP_ILLEGAL_WRAP_DATA_PTR_ERROR;
      goto end_function;
   }
      
   if(WrapDataLen_ptr == DX_NULL)
   {
      Error = CRYS_AES_WRAP_ILLEGAL_WRAP_DATA_LEN_PTR_ERROR;
      goto end_function;
   }
      
   /* Check length of input parameters */
   if(DataInLen % CRYS_AES_WRAP_BLOCK_SIZE_IN_BYTES)
   {
      Error = CRYS_AES_WRAP_DATA_LENGTH_ERROR;
      goto end_function;
   }
      
   if(DataInLen < CRYS_AES_WRAP_DATA_MIN_SIZE_IN_BYTES)
   {
      Error = CRYS_AES_WRAP_DATA_LENGTH_ERROR;
      goto end_function;
   }
     
   if(DataInLen > CRYS_AES_WRAP_DATA_MAX_SIZE_IN_BYTES)
   {
      Error = CRYS_AES_WRAP_DATA_LENGTH_ERROR;
      goto end_function;
   }
      
   if(KeySize >= CRYS_AES_KeySizeNumOfOptions)
   {
      Error = CRYS_AES_WRAP_KEY_LENGTH_ERROR;
      goto end_function;
   }
      
   
   /* Check wrapped data buffer length */
   if( *WrapDataLen_ptr < DataInLen + CRYS_AES_WRAP_BLOCK_SIZE_IN_BYTES)
   {
      Error = CRYS_AES_WRAP_ILLEGAL_WRAP_DATA_LENGTH_ERROR; 
      goto end_function;
   }
      
   /* Check that there is no overlapping between the data input and data output buffer
      except the inplace case that is legal */
   if ( DataIn_ptr > WrapDataOut_ptr && 
	    DataIn_ptr < WrapDataOut_ptr + DataInLen + CRYS_AES_WRAP_BLOCK_SIZE_IN_BYTES )
   {
      Error = CRYS_AES_WRAP_DATA_OUT_DATA_IN_OVERLAP_ERROR; 
      goto end_function;
   }
            
   if ( DataIn_ptr < WrapDataOut_ptr && 
	    DataIn_ptr > WrapDataOut_ptr - DataInLen )
   {
      Error = CRYS_AES_WRAP_DATA_OUT_DATA_IN_OVERLAP_ERROR; 
      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_PROTOCL_HOST_AES_WRAP_OP_CODE;
   messageParam[1] = KeySize;
   messageParam[2] = isSecretKey;
   messageParam[3] = DataInLen;
   
   Error = SEPDriver_WriteParamater((DxUint32_t)messageParam,
                            sizeof(DxUint32_t) * 2,
                            sizeof(DxUint32_t) * 2,
                            &sramOffset ,
                            DX_FALSE);
   if(Error != DX_OK)
   {
       goto end_function_unlock;
   }
   
   /* send key */
   switch(KeySize)
   {
    case CRYS_AES_Key128BitSize:
      keySizeInBytes = 16;
      break;
      
    case CRYS_AES_Key192BitSize:
      keySizeInBytes = 24;
      break;
      
    case CRYS_AES_Key256BitSize:
      keySizeInBytes = 32;
      break;
      
    default:
      Error = CRYS_AES_WRAP_KEY_LENGTH_ERROR;
      goto end_function;
      
   }
   Error = SEPDriver_WriteParamater((DxUint32_t)KeyData , 
                             keySizeInBytes,
                             32 , 
                             &sramOffset , 
                             DX_TRUE);
   if(Error != DX_OK)
   {
       goto end_function_unlock;
   }
   
   /* send rest of param  */
   Error = SEPDriver_WriteParamater((DxUint32_t)&messageParam[2],
                            sizeof(DxUint32_t) * 2,
                            sizeof(DxUint32_t) * 2,
                            &sramOffset ,
                            DX_FALSE);
   if(Error != DX_OK)
   {
       goto end_function_unlock;
   }
   
   /* send data in */
   maxLength = ((DataInLen + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t);
   Error = SEPDriver_WriteParamater((DxUint32_t)DataIn_ptr , 
                             DataInLen , 
                             maxLength,
                             &sramOffset , 
                             DX_TRUE);
   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;
   }         
        
   /* read response */
    
   /* start the message */
   Error = SEPDriver_StartIncomingMessage(&sramOffset);
   if(Error)
   {
    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_PROTOCL_HOST_AES_WRAP_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 data out length */
   Error = SEPDriver_ReadParamater((DxUint32_t)WrapDataLen_ptr , 
                           sizeof(DxUint32_t),
                           sizeof(DxUint32_t),
                           &sramOffset , 
                           DX_FALSE);
   if(Error != DX_OK)
   {
       goto end_function_unlock;
   }
   
   /* read wrapped data */
   maxLength = ((*WrapDataLen_ptr + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t);
   Error = SEPDriver_ReadParamater((DxUint32_t)WrapDataOut_ptr , 
                           *WrapDataLen_ptr ,
                           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 /* End of CRYS_NO_AES_SUPPORT */ 
 
}/* End of CRYS_AES_Wrap */


/**
   @brief  The CRYS_AES_Unwrap function performs inverse AES_Wrap transformation 
           and implements the following algorithm (rfc3394, Sept. 2002):  

   Inputs:  Ciphertext, (n+1) 64-bit values {C0, C1, ..., Cn}, and
            K  - key (the KEK).
  
   Outputs: Plaintext, n 64-bit values {P1, P2, ..., Pn}.
   
		       
   @param[in]  WrapDataIn_ptr - A pointer to wrapped data to be unwrapped 
                                NOTE: Overlapping between the data input and data output buffer
                                      is not allowed, except the inplace case that is legal . 			
   @param[in]  WrapDataInLen  - Length of wrapped data in bytes. DataLen must be multiple of 
                                8 bytes and  must be in range [24, 2^29].
   @param[in]  KeyData        - A pointer to  key data (key encryption key - KEK). 
   @param[in]  KeySize        - Enumerator variable, defines length of key.
   @param[in]  isSecretKey - Variable, defining is secret key used (1) or not (0).
   @param[out] DataOut_ptr     - A pointer to buffer for output of unwrapped data.
   @param[in/out]  DataOutLen_ptr - A pointer to a buffer for input of size of user passed 
                              buffer and for output of actual size of unwrapped data in bytes.
                              DataOutLen must be multiple of 8 bytes and must be not less
                              than WrapDataInLen - CRYS_AES_WRAP_BLOCK_SIZE_IN_BYTES.
                           
   @return CRYSError_t - CRYS_OK, or error message 
                         CRYS_AES_UNWRAP_WRAP_DATA_LENGTH_ERROR          
                         CRYS_AES_UNWRAP_ILLEGAL_KEY_PTR_ERROR           
                         CRYS_AES_UNWRAP_KEY_LEN_ERROR                   
                         CRYS_AES_UNWRAP_ILLEGAL_DATA_PTR_ERROR          
                         CRYS_AES_UNWRAP_ILLEGAL_DATA_LEN_PTR_ERROR      
                         CRYS_AES_UNWRAP_ILLEGAL_DATA_LENGTH_ERROR       
                         CRYS_AES_UNWRAP_FUNCTION_FAILED_ERROR 
						 CRYS_AES_UNWRAP_DATA_OUT_DATA_IN_OVERLAP_ERROR 
						 CRYS_AES_UNWRAP_IS_SECRET_KEY_FLAG_ILLEGAL_ERROR

    NOTE:  On error exiting from function the output buffer may be zeroed by the function.
                         
*/                               
CIMPORT_C  CRYSError_t CRYS_AES_Unwrap(DxUint8_t            *WrapDataIn_ptr, /*in*/   
                                       DxUint32_t            WrapDataInLen,    /*in*/
                                       CRYS_AES_Key_t        KeyData,        /*in*/
                                       CRYS_AES_KeySize_t    KeySize,        /*in*/ 
    								   DxInt8_t              isSecretKey,     /*in*/
                                       DxUint8_t            *DataOut_ptr,    /*out*/
                                       DxUint32_t           *DataOutLen_ptr     /*in/out*/ )
{
  
  /* error */
  CRYSError_t     Error = CRYS_OK;
  
  /* offset */
   DxUint32_t	    sramOffset;
   
   /* message param */
   DxUint32_t     messageParam[4];
   
   /* max length */
   DxUint32_t     maxLength;
   
   /* key size in bytes */
   DxUint32_t    keySizeInBytes;
  
  /*----------------------------
      CODE
  -------------------------------*/
  
  if(WrapDataIn_ptr == DX_NULL)
  {
    Error = CRYS_AES_UNWRAP_ILLEGAL_WRAP_DATA_PTR_ERROR;
    goto end_function;
  }
  
  /* Check isSecretKey value */
   if( isSecretKey != DX_FALSE && isSecretKey != DX_TRUE )
        return CRYS_AES_UNWRAP_IS_SECRET_KEY_FLAG_ILLEGAL_ERROR;

   /* Check key pointer */
   if(KeyData == DX_NULL && isSecretKey == DX_FALSE)
      return CRYS_AES_UNWRAP_ILLEGAL_KEY_PTR_ERROR;
      
  
  if(DataOut_ptr == DX_NULL)
  {
    Error = CRYS_AES_UNWRAP_ILLEGAL_DATA_PTR_ERROR;
    goto end_function;
  }
   
  if(DataOutLen_ptr == DX_NULL)
  {
    Error = CRYS_AES_UNWRAP_ILLEGAL_DATA_LEN_PTR_ERROR;
    goto end_function;
  }
      	
  /* Check length of input parameters */
  if(WrapDataInLen % CRYS_AES_WRAP_BLOCK_SIZE_IN_BYTES)
  {
    Error = CRYS_AES_UNWRAP_WRAP_DATA_LENGTH_ERROR;
    goto end_function;
  }
     
  if(WrapDataInLen < (CRYS_AES_WRAP_DATA_MIN_SIZE_IN_BYTES + CRYS_AES_WRAP_BLOCK_SIZE_IN_BYTES))
  {
    Error = CRYS_AES_UNWRAP_WRAP_DATA_LENGTH_ERROR;
    goto end_function;
  }
     
  if(WrapDataInLen > (CRYS_AES_WRAP_DATA_MAX_SIZE_IN_BYTES + CRYS_AES_WRAP_BLOCK_SIZE_IN_BYTES))
  {
    Error = CRYS_AES_UNWRAP_WRAP_DATA_LENGTH_ERROR;
    goto end_function;
  }
      
  if(KeySize >= CRYS_AES_KeySizeNumOfOptions)
  {
    Error = CRYS_AES_UNWRAP_KEY_LEN_ERROR;
    goto end_function;
  }
    
  /* Check unwrapped data buffer length */
  if( *DataOutLen_ptr < WrapDataInLen - CRYS_AES_WRAP_BLOCK_SIZE_IN_BYTES)
  {
    Error = CRYS_AES_UNWRAP_ILLEGAL_DATA_LENGTH_ERROR;
    goto end_function;
  }
 
  /* Check that there is no overlapping between the data input and data output buffer
     except the inplace case that is legal */
  if ( WrapDataIn_ptr > DataOut_ptr && 
	     WrapDataIn_ptr < DataOut_ptr + WrapDataInLen )
  {
    Error = CRYS_AES_UNWRAP_DATA_OUT_DATA_IN_OVERLAP_ERROR;
    goto end_function;
  }
    
  if ( WrapDataIn_ptr < DataOut_ptr && 
	     WrapDataIn_ptr > DataOut_ptr - WrapDataInLen )
  {
    Error = CRYS_AES_UNWRAP_DATA_OUT_DATA_IN_OVERLAP_ERROR;
    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 message */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCL_HOST_AES_UNWRAP_OP_CODE;
  messageParam[1] = KeySize;
  messageParam[2] = isSecretKey;
  messageParam[3] = WrapDataInLen;
  
  /* send message */
  Error = SEPDriver_WriteParamater((DxUint32_t)messageParam,
                           sizeof(DxUint32_t) * 2,
                           sizeof(DxUint32_t) * 2,
                           &sramOffset , 
                           DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
  /* send key */
  switch(KeySize)
   {
    case CRYS_AES_Key128BitSize:
      keySizeInBytes = 16;
      break;
      
    case CRYS_AES_Key192BitSize:
      keySizeInBytes = 24;
      break;
      
    case CRYS_AES_Key256BitSize:
      keySizeInBytes = 32;
      break;
      
    default:
      Error = CRYS_AES_WRAP_KEY_LENGTH_ERROR;
      goto end_function_unlock;
   }
  Error = SEPDriver_WriteParamater((DxUint32_t)KeyData , 
                            keySizeInBytes,
                            32 , 
                            &sramOffset , 
                            DX_TRUE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
  /* send the rest of params  */
  Error = SEPDriver_WriteParamater((DxUint32_t)&messageParam[2] , 
                           sizeof(DxUint32_t) * 2,
                           sizeof(DxUint32_t) * 2,
                           &sramOffset , 
                           DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
  /* send data in */
  maxLength = ((WrapDataInLen + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t);
  Error = SEPDriver_WriteParamater((DxUint32_t)WrapDataIn_ptr , 
                            WrapDataInLen , 
                            maxLength,
                            &sramOffset , 
                            DX_TRUE);
  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;
  }    
        
  /* read response */
    
  /* start the message */
  Error = SEPDriver_StartIncomingMessage(&sramOffset);
  if(Error)
   {
    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_PROTOCL_HOST_AES_UNWRAP_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 data out length */
  Error = SEPDriver_ReadParamater((DxUint32_t)DataOutLen_ptr , 
                          sizeof(DxUint32_t),
                          sizeof(DxUint32_t),
                          &sramOffset , 
                          DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
  /* read unwrapped data */
  maxLength = (*(DxUint32_t*)DataOutLen_ptr + 3) / sizeof(DxUint32_t) * sizeof(DxUint32_t);
  Error = SEPDriver_ReadParamater((DxUint32_t)DataOut_ptr , 
                          *DataOutLen_ptr ,
                          maxLength,
                          &sramOffset , 
                          DX_TRUE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }

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

end_function:
   
  return Error; 
  
}




