
/*
   *  Object %name    : SEPDriver.h
   *  State           :  %state%
   *  Creation date   :  Wed Nov 17 17:39:24 2004
   *  Last modified   :  %modify_time%
   */
  /** @file
   *  \brief  Key Management h file (API and structures )
   *
   *  \version 
   *  \author yevgenys
   *  \remarks Copyright (C) 2004 by Discretix Technologies Ltd.
   *           All Rights reserved
   */

#include "DX_VOS_BaseTypes.h"
#include "error.h"
#include "SEPDriver.h"
#include "CRYS_AES.h"
#include "CRYS_DES.h"
#include "CRYS_HASH.h"
#include "CRYS_FLOW.h"
#include "CRYS_FLOW_error.h"
#include "flow_host_op_code.h"
#include "CRYS_AES_error.h"
#include "CRYS_DES_error.h"
#include "CRYS_HMAC_error.h"
#include "CRYS_HASH_error.h"
#include "CRYS_RC4_error.h"
#include "CRYS_RC4.h"
#include "host_op_code.h"
#include "FVOS_Config.h"




/*------------------------------
    DEFINES
--------------------------------*/



/*--------------------------------------
  PROTOTYPES
---------------------------------------*/


/*--------------------------------------
   GLOBAL variables
---------------------------------------*/
/* data for flows */
extern FVOS_FlowContext_t  g_FlowsContexts[FVOS_NUM_FLOWS];


/* Data for handling AddBuffer input params validity */
/* will be initialize in any Init operation */
CRYS_FLOW_DataBase_t  g_FlowsDb[FVOS_NUM_FLOWS];


/*------------------------------------------------
    PRIVATE FUNCTIONS PROTOTYPE
--------------------------------------------------*/
/**
 * @brief       This function checks:
 *    1) total out size equal total in size (for dout_to_mem operations only) 
 *    2) Static flow: check that all in buffer and all out buffer sizes are equal
 *       (NOTE: there can be diffrent number of arrays in/out but internal sizes must be equal)
 *    3) Hash: buffers must be %64
 * 
 * @param[in] flowParams_ptr - flow parameters for the operation.
 * @param[in] flowType - type of flow, static or dynamic
 * @param[in] opMode - mode type for Hash or AES
 * @param[in] opType - operation type. 
 *
 * @return DXError_t - On success DX_OK is returned, on failure a
 *                        value MODULE_* CRYS_FLOW_error.h
 */

static DxError_t CRYS_FLOW_CheckValidInOutBufferSizes(CRYS_FLOW_Params_t* flowParams_ptr,
                                                      CRYS_FLOW_Type_t    flowType,
                                                      DxUint32_t          opMode,
                                                      CRYS_FLOW_Op_t      opType);
/*------------------------------------------------
    PUBLIC FUNCTIONS
--------------------------------------------------*/

/**
 * @brief       This function initializes the AES flow 
 *
 *    NOTE: 1) Static requests same buffer sizes for in and out (number of input buffers can be different from number of output buffers)
 *          2) In/Out buffer sizes must be modulus 16.
 * 
 * @param[in] flowType - type of flow, static or dynamic
 * @param[in] flowParams_ptr - flow parameters for the operation.
 * @param[in] aesData_ptr - aes data parameters
 * @param[out] flowId_ptr - the id of the created flow
 *
 * @return DXError_t - On success DX_OK is returned, on failure a
 *                        value MODULE_* CRYS_FLOW_error.h
 */
DxError_t CRYS_FLOW_AESInit(CRYS_FLOW_Type_t            flowType,
                            CRYS_FLOW_Params_t*         flowParams_ptr,
                            CRYS_FLOW_AESEngineData_t*  aesData_ptr,
                            DxUint32_t*                 flowId_ptr)
{
  /* error */
  DxError_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 each of the first tables */
  DxUint32_t    numEntriesInInputTable;
  
  /* number of entries in each of the first tables */
  DxUint32_t    numEntriesInOutputTable;
   
  /* size of data in the first input table */
  DxUint32_t    inputTableSize;
  
  /* size of data in the first output table */
  DxUint32_t    outputTableSize;
  
  /* key size in bytes */
  DxUint32_t    keySizeInBytes;
  
  /* swap input flag */
  DxUint32_t    swapInputFlag;
  
  /* swap input flag */
  DxUint32_t    swapOutputFlag;
   
  /* sram offset */
  DxUint32_t    sramOffset;
  
  /* message parameters */
  DxUint32_t    messageParam[15];
  
  /*------------------------
      CODE
  ----------------------------*/
  
  /* check the input paramaters */
  
  /* check input pointer */
  if((flowId_ptr == DX_NULL) ||
  	 (flowParams_ptr == DX_NULL) ||
     (aesData_ptr == DX_NULL)
  	)	
  {
    error = CRYS_FLOW_ARG_NULL_PTR_ERROR;
    goto end_function;
  }
  
  /* check that total out size equal total in size */
  error = CRYS_FLOW_CheckValidInOutBufferSizes(flowParams_ptr, flowType, aesData_ptr->OperationMode, FLOW_AES_InitOperation);
  if(error != DX_OK)
  {
      goto end_function;
  }
  	
    /* If the operation mode is legal return an error */
    if( aesData_ptr->OperationMode >= CRYS_AES_NumOfModes )
    {
        error = CRYS_AES_ILLEGAL_OPERATION_MODE_ERROR;
        goto end_function;
    }

	/* If key size is not valid return an error */
	if( aesData_ptr->KeySize >= CRYS_AES_KeySizeNumOfOptions )  
	{
	    error = CRYS_AES_ILLEGAL_KEY_SIZE_ERROR;
	    goto end_function;
	}

	/* Check the key size for all modes besides XTS */
	if( aesData_ptr->OperationMode != CRYS_AES_XTS_mode && 
		aesData_ptr->KeySize > CRYS_AES_Key256BitSize ) 
	{
	    error = CRYS_AES_ILLEGAL_KEY_SIZE_ERROR;
	    goto end_function;
	}

	/* Check in XTS mode key size */
	if( aesData_ptr->OperationMode == CRYS_AES_XTS_mode )
	{
		if( aesData_ptr->KeySize != CRYS_AES_Key256BitSize && aesData_ptr->KeySize != CRYS_AES_Key512BitSize )
		{
		    error = CRYS_AES_ILLEGAL_KEY_SIZE_ERROR;
		    goto end_function;
		}
		
	}

	/* On XCBC mode enable only key size 128 bit, else - return an error */
	if( aesData_ptr->OperationMode == CRYS_AES_XCBC_MAC_mode && 
		aesData_ptr->KeySize != CRYS_AES_Key128BitSize  )
	{
	    error = CRYS_AES_NOT_ALLOWED_KEY_TYPE_ON_THIS_MODE;
	    goto end_function;
	}

	/* If Encrypt / Decrypt flag invalid - return an error */
	if( aesData_ptr->EncryptDecryptFlag >= CRYS_AES_EncryptNumOfOptions )
	{
	    error = CRYS_AES_INVALID_ENCRYPT_MODE_ERROR;
	    goto end_function;
	}

	/* In mode CTR enable only the encrypt mode */
	if( aesData_ptr->OperationMode == CRYS_AES_CTR_mode && aesData_ptr->EncryptDecryptFlag != CRYS_AES_Encrypt )
	{
	    error = CRYS_AES_DECRYPT_MODE_NOT_ALLOWED_ON_CTR_MODE;
	    goto end_function;
	}

	/* In XCBC and CMAC modes enable only:  encrypt mode  */
	if( (aesData_ptr->OperationMode == CRYS_AES_XCBC_MAC_mode || 
		aesData_ptr->OperationMode == CRYS_AES_CMAC_mode )    && 
		aesData_ptr->EncryptDecryptFlag != CRYS_AES_Encrypt )
	{
	    error = CRYS_AES_DECRYPTION_NOT_ALLOWED_ON_THIS_MODE;	
	    goto end_function;
	}

  /* lock access to the SEP */	    
  error = SEPDriver_Lock();
  
  if(error != DX_OK)
  {
      goto end_function;
  }
  
  /* prepare the input tables for the flows */
  error = SEPDriver_PrepareFlowDMATables(flowType,
                                         (SEP_FLOW_BufferData_t*)flowParams_ptr->inputBuffersArrays,
                                         flowParams_ptr->inputBuffersArraySize,
                                         SEP_DRIVER_InputBuffer,
                                         &firstInputLLITableAddr,
                                         &numEntriesInInputTable,
                                         &inputTableSize);                                      
  if(error != DX_OK)
  {
    /* NOTE: function will release flow resources internally */
    goto end_function_unlock;
  }
  
  /* prepare the output tables for the flows */
  error = SEPDriver_PrepareFlowDMATables(flowType,
                                         (SEP_FLOW_BufferData_t*)flowParams_ptr->outputBuffersArrays,
                                         flowParams_ptr->outputBuffersArraySize,
                                         SEP_DRIVER_OutputBuffer,
                                         &firstOutputLLITableAddr,
                                         &numEntriesInOutputTable,
                                         &outputTableSize);                                      
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }
  
  /* calculate swap for input and output */
  swapInputFlag = swapOutputFlag = DX_FALSE;
  if(flowParams_ptr->wordsBuffersOrderFlag)
  {
    if(flowParams_ptr->inputBigEndianOrderFlag)
    {
      swapInputFlag = DX_TRUE;
    }
    if(flowParams_ptr->outputBigEndianOrderFlag)
    {
      swapOutputFlag = DX_TRUE;
    }
  }
  
  /* prepare protocol */
  sramOffset = 0;
   
  /* start the message */
  SEPDriver_StartMessage(&sramOffset);
  
  /* prepare message */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_FLOW_INIT_AES_OP_CODE;
  messageParam[1] = flowParams_ptr->inputInterruptId;
  messageParam[2] = flowParams_ptr->outputInterruptId;
  messageParam[3] = swapInputFlag;
  messageParam[4] = swapOutputFlag;
  messageParam[5] = flowType;
  messageParam[6] = firstInputLLITableAddr;
  messageParam[7] = inputTableSize;
  messageParam[8] = numEntriesInInputTable;
  messageParam[9] = firstOutputLLITableAddr;
  messageParam[10] = outputTableSize;
  messageParam[11] = numEntriesInOutputTable;
  messageParam[12] = aesData_ptr->KeySize;
  messageParam[13] = aesData_ptr->EncryptDecryptFlag;
  messageParam[14] = aesData_ptr->OperationMode;
  
  /* send paramaters */
  error = SEPDriver_WriteParamater((DxUint32_t)messageParam,
                                    sizeof(DxUint32_t) * 12,
                                    sizeof(DxUint32_t) * 12,
                                    &sramOffset, 
                                    DX_FALSE);
  
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }
  
  /* send IV/CTR */
  error = SEPDriver_WriteParamater((DxUint32_t)aesData_ptr->IVCounter_ptr , 
                                   sizeof(CRYS_AES_IvCounter_t) ,
                                   sizeof(DxUint32_t) * 4, 
                                   &sramOffset , 
                                   DX_FALSE);
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }
  
  /* send key */
  switch(aesData_ptr->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)aesData_ptr->Key_ptr , 
                                    keySizeInBytes ,
                                    16 * sizeof(DxUint32_t) , 
                                    &sramOffset , 
                                    DX_TRUE);
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }
  
  /* send paramaters */
  error = SEPDriver_WriteParamater((DxUint32_t)&messageParam[12],
                                    sizeof(DxUint32_t) * 3,
                                    sizeof(DxUint32_t) * 3,
                                    &sramOffset, 
                                    DX_FALSE);
  
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }
  
  /* end message */
  SEPDriver_EndMessage(sramOffset);
            
  /* wait for the response */
  error = SEPDriver_POLL_FOR_REPONSE();
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }
   
  /*-------------------
      start reading message from the SEP 
  ---------------------*/
   
  /* start the message */
  error = SEPDriver_StartIncomingMessage(&sramOffset);
  if(error)
  {
    goto end_function_unlock_release_flow_resource;
  }
   
  /* 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_release_flow_resource;
  }
   
  /* check the opcode */
  if(messageParam[0] != DX_SEP_HOST_SEP_PROTOCOL_HOST_FLOW_INIT_AES_OP_CODE)
  {
    error = DX_WRONG_OPCODE_FROM_SEP_ERR;
    goto end_function_unlock_release_flow_resource;
  }
   
  /* check status */
  if(messageParam[1] != DX_OK)
  {
    error = messageParam[1];
    goto end_function_unlock_release_flow_resource;
  }
  
  /* read the flow id */
  error = SEPDriver_ReadParamater((DxUint32_t)flowId_ptr,
                                  sizeof(DxUint32_t),
                                  sizeof(DxUint32_t),
                                  &sramOffset ,
                                  DX_FALSE);
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }
  
  /* now set the id of the newly created tables */
  SEPDriver_SetFlowId(*flowId_ptr);
  
  
  /* Init general Flow data base parameters */
  g_FlowsDb[*flowId_ptr].opType = FLOW_AES_InitOperation;
  g_FlowsDb[*flowId_ptr].opMode = aesData_ptr->OperationMode;
  g_FlowsDb[*flowId_ptr].flowType = flowType;
  goto end_function_unlock;
  
  /* --------------------- End Operation --------------------------*/
end_function_unlock_release_flow_resource:
  /* free all SEP tables resources */
  SEPDriver_FreeFlowResources(FVOS_DEFAULT_FLOW_ID);

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

end_function:
  return error;
}

/**
 * @brief       This function initializes the AES flow 
 *
 *    NOTE: Static requests same buffer sizes for in and out (number of input buffers can be different from number of output buffers)
 * 
 * @param[in] flowType - type of flow, static or dynamic
 * @param[in] flowParams_ptr - flow parameters for the operation.
 * @param[in] desData_ptr - des data parameters
 * @param[out] flowId_ptr - the id of the created flow
 *
 * @return DXError_t - On success DX_OK is returned, on failure a
 *                        value MODULE_* CRYS_FLOW_error.h
 */
DxError_t CRYS_FLOW_DESInit(CRYS_FLOW_Type_t            flowType,
                            CRYS_FLOW_Params_t*         flowParams_ptr,
                            CRYS_FLOW_DESEngineData_t*  desData_ptr,
                            DxUint32_t*                 flowId_ptr)
{
  /* error */
  DxError_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 each of the first tables */
  DxUint32_t    numEntriesInInputTable;
  
  /* number of entries in each of the first tables */
  DxUint32_t    numEntriesInOutputTable;
   
  /* size of data in the first input table */
  DxUint32_t    inputTableSize;
  
  /* size of data in the first output table */
  DxUint32_t    outputTableSize;
  
  /* swap input flag */
  DxUint32_t    swapInputFlag;
  
  /* swap input flag */
  DxUint32_t    swapOutputFlag;
   
  /* sram offset */
  DxUint32_t    sramOffset;
  
  /* message parameters */
  DxUint32_t    messageParam[15];
  
  
  /*------------------------
      CODE
  ----------------------------*/
  
  /* check the input paramaters */
  
  /* check input pointer */
  if((flowId_ptr == DX_NULL) ||
  	 (flowParams_ptr == DX_NULL) ||
     (desData_ptr == DX_NULL)
  	)	
  {
    error = CRYS_FLOW_ARG_NULL_PTR_ERROR;
    goto end_function;
  }

  /* check that total out size equal total in size */
  error = CRYS_FLOW_CheckValidInOutBufferSizes(flowParams_ptr, flowType, desData_ptr->OperationMode , FLOW_DES_InitOperation);
  if(error != DX_OK)
  {
      goto end_function;
  }
  

    /* check if the operation mode is legal */
    if( desData_ptr->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( desData_ptr->OperationMode == CRYS_DES_CBC_mode && desData_ptr->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( desData_ptr->NumOfKeys >= CRYS_DES_NumOfKeysOptions || desData_ptr->NumOfKeys == 0 )  
	{   
		error = CRYS_DES_ILLEGAL_NUM_OF_KEYS_ERROR;
		goto end_function;
	}   

	/*check the valisity of the key pointer */
	if( desData_ptr->Key_ptr == DX_NULL )
	{
		error = CRYS_DES_INVALID_KEY_POINTER_ERROR;
		goto end_function;
	}   

	/* Check the Encrypt / Decrypt flag validity */
	if( desData_ptr->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;
   }
  
  /* prepare the input tables for the flows */
  error = SEPDriver_PrepareFlowDMATables(flowType,
                                         (SEP_FLOW_BufferData_t*)flowParams_ptr->inputBuffersArrays,
                                         flowParams_ptr->inputBuffersArraySize,
                                         SEP_DRIVER_InputBuffer,
                                         &firstInputLLITableAddr,
                                         &numEntriesInInputTable,
                                         &inputTableSize);                                      
  if(error != DX_OK)
  {
    /* NOTE: function will release flow resources internally */
    goto end_function_unlock;
  }
  
  /* prepare the output tables for the flows */
  error = SEPDriver_PrepareFlowDMATables(flowType,
                                         (SEP_FLOW_BufferData_t*)flowParams_ptr->outputBuffersArrays,
                                         flowParams_ptr->outputBuffersArraySize,
                                         SEP_DRIVER_OutputBuffer,
                                         &firstOutputLLITableAddr,
                                         &numEntriesInOutputTable,
                                         &outputTableSize);                                      
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }
  
  /* calculate swap for input and output */
  swapInputFlag = swapOutputFlag = DX_FALSE;
  if(flowParams_ptr->wordsBuffersOrderFlag)
  {
    if(flowParams_ptr->inputBigEndianOrderFlag)
    {
      swapInputFlag = DX_TRUE;
    }
    if(flowParams_ptr->outputBigEndianOrderFlag)
    {
      swapOutputFlag = DX_TRUE;
    }
  }
  
  /* prepare protocol */
  sramOffset = 0;
   
  /* start the message */
  SEPDriver_StartMessage(&sramOffset);
  
  /* prepare message */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_FLOW_INIT_DES_OP_CODE;
  messageParam[1] = flowParams_ptr->inputInterruptId;
  messageParam[2] = flowParams_ptr->outputInterruptId; 
  messageParam[3] = swapInputFlag;
  messageParam[4] = swapOutputFlag;
  messageParam[5] = flowType;
  messageParam[6] = firstInputLLITableAddr;
  messageParam[7] = inputTableSize;
  messageParam[8] = numEntriesInInputTable;
  messageParam[9] = firstOutputLLITableAddr;
  messageParam[10] = outputTableSize;
  messageParam[11] = numEntriesInOutputTable;
  messageParam[12] = desData_ptr->NumOfKeys;
  messageParam[13] = desData_ptr->EncryptDecryptFlag;
  messageParam[14] = desData_ptr->OperationMode;
 
  /* send paramaters */
  error = SEPDriver_WriteParamater((DxUint32_t)messageParam,
                                    sizeof(DxUint32_t) * 12,
                                    sizeof(DxUint32_t) * 12,
                                    &sramOffset, 
                                    DX_FALSE);
  
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }
  
  /* send IV/CTR */
  error = SEPDriver_WriteParamater((DxUint32_t)desData_ptr->IV_ptr , 
                                   sizeof(CRYS_DES_Iv_t) ,
                                   sizeof(DxUint32_t) * 4, 
                                   &sramOffset , 
                                   DX_FALSE);
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }
   
  error = SEPDriver_WriteParamater((DxUint32_t)desData_ptr->Key_ptr , 
                                    8 * sizeof(DxUint32_t) ,
                                    8 * sizeof(DxUint32_t) , 
                                    &sramOffset , 
                                    DX_TRUE);
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }
  
  /* send paramaters */
  error = SEPDriver_WriteParamater((DxUint32_t)&messageParam[12],
                                    sizeof(DxUint32_t) * 3,
                                    sizeof(DxUint32_t) * 3,
                                    &sramOffset, 
                                    DX_FALSE);
  
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }
  
  /* end message */
  SEPDriver_EndMessage(sramOffset);
            
  /* wait for the response */
  error = SEPDriver_POLL_FOR_REPONSE();
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }
   
  /*-------------------
      start reading message from the SEP 
  ---------------------*/
   
  /* start the message */
  error = SEPDriver_StartIncomingMessage(&sramOffset);
  if(error)
  {
    goto end_function_unlock_release_flow_resource;
  }
   
  /* 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_release_flow_resource;
  }
   
  /* check the opcode */
  if(messageParam[0] != DX_SEP_HOST_SEP_PROTOCOL_HOST_FLOW_INIT_DES_OP_CODE)
  {
    error = DX_WRONG_OPCODE_FROM_SEP_ERR;
    goto end_function_unlock_release_flow_resource;
  }
   
  /* check status */
  if(messageParam[1] != DX_OK)
  {
    error = messageParam[1];
    goto end_function_unlock_release_flow_resource;
  }
  
  /* read the flow id */
  error = SEPDriver_ReadParamater((DxUint32_t)flowId_ptr,
                                  sizeof(DxUint32_t),
                                  sizeof(DxUint32_t),
                                  &sramOffset ,
                                  DX_FALSE);
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }
  
  /* now set the id of the newly created tables */
  SEPDriver_SetFlowId(*flowId_ptr);
  
  /* Init general Flow data base parameters */
  g_FlowsDb[*flowId_ptr].opType = FLOW_DES_InitOperation;
  g_FlowsDb[*flowId_ptr].opMode = desData_ptr->OperationMode;
  g_FlowsDb[*flowId_ptr].flowType = flowType;
  goto end_function_unlock;

  /* --------------------- End Operation --------------------------*/
end_function_unlock_release_flow_resource:
  /* free all SEP tables resources */
  SEPDriver_FreeFlowResources(FVOS_DEFAULT_FLOW_ID);

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

end_function:
  return error;
}

/**
 * @brief      This function initializes the Hash flow 
 *
 *    NOTE: 1) buffer size must be modulus 64 or modulus 128 (in SHA384|SHA512) HW smallest HASH input. 
 *          2) Static requests same buffer sizes for in and out (number of input buffers can be different from number of output buffers)
 * 
 * @param[in] flowType - type of flow, static or dynamic
 * @param[in] flowParams_ptr - flow parameters for the operation.
 * @param[in] hashData_ptr - hash data parameters
 * @param[out] flowId_ptr - the id of the created flow
 *
 * @return DXError_t - On success DX_OK is returned, on failure a
 *                        value MODULE_* CRYS_FLOW_error.h
 */
DxError_t CRYS_FLOW_HASHInit(CRYS_FLOW_Type_t               flowType,
                             CRYS_FLOW_Params_t*            flowParams_ptr,
                             CRYS_FLOW_HASHEngine_Data_t*   hashData_ptr,
                             DxUint32_t*                    flowId_ptr)
{
  /* error */
  DxError_t     error;
   
  /* address of the first table in the input list */
  DxUint32_t    firstInputLLITableAddr;
   
  /* number of entries in each of the first tables */
  DxUint32_t    numEntriesInInputTable;
   
  /* size of data in the first input table */
  DxUint32_t    inputTableSize;
  
  /* swap input flag */
  DxUint32_t    swapInputFlag;
  
  /* sram offset */
  DxUint32_t    sramOffset;
  
  /* message parameters */
  DxUint32_t    messageParam[10];
  
  /*------------------------
      CODE
  ----------------------------*/
  
  /* check the input paramaters */
  
  /* check input pointer */
  if((flowId_ptr == DX_NULL) ||
  	 (flowParams_ptr == DX_NULL) ||
     (hashData_ptr == DX_NULL)
  	)	
  {
    error = CRYS_FLOW_ARG_NULL_PTR_ERROR;
    goto end_function;
  }
  
  /* check that total out size equal total in size */
  error = CRYS_FLOW_CheckValidInOutBufferSizes(flowParams_ptr, flowType, hashData_ptr->opMode , FLOW_HASH_InitOperation);
  if(error != DX_OK)
  {
      goto end_function;
  }
  
  /* check if the operation mode is legal */
  if( hashData_ptr->opMode >= CRYS_HASH_NumOfModes )
  {
    error = CRYS_HASH_ILLEGAL_OPERATION_MODE_ERROR;
    goto end_function;
  }
    
  
  /* lock access to the SEP */	    
  error = SEPDriver_Lock();
   
  if(error != DX_OK)
  {
      goto end_function;
  }
  
  /* prepare the input tables for the flows */
  error = SEPDriver_PrepareFlowDMATables(flowType,
                                         (SEP_FLOW_BufferData_t*)flowParams_ptr->inputBuffersArrays,
                                         flowParams_ptr->inputBuffersArraySize,
                                         SEP_DRIVER_InputBuffer,
                                         &firstInputLLITableAddr,
                                         &numEntriesInInputTable,
                                         &inputTableSize);                                      
  if(error != DX_OK)
  {
    /* NOTE: function will release flow resources internally */
    goto end_function_unlock;
  } 
  
  /* calculate swap for input and output */
  swapInputFlag = DX_FALSE;
  if(flowParams_ptr->wordsBuffersOrderFlag && flowParams_ptr->inputBigEndianOrderFlag)
  {
    swapInputFlag = DX_TRUE;
  }
  
  /* prepare protocol */
  sramOffset = 0;
   
  /* start the message */
  SEPDriver_StartMessage(&sramOffset);
  
  /* prepare message */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_FLOW_INIT_HASH_OP_CODE;
  messageParam[1] = flowParams_ptr->inputInterruptId;
  messageParam[2] = flowParams_ptr->outputInterruptId;
  messageParam[3] = swapInputFlag;
  messageParam[4] = 0;
  messageParam[5] = flowType;
  messageParam[6] = firstInputLLITableAddr;
  messageParam[7] = inputTableSize;
  messageParam[8] = numEntriesInInputTable;
  messageParam[9] = hashData_ptr->opMode;
  
  /* send paramaters */
  error = SEPDriver_WriteParamater((DxUint32_t)messageParam,
                                    sizeof(DxUint32_t) * 10,
                                    sizeof(DxUint32_t) * 10,
                                    &sramOffset, 
                                    DX_FALSE);
  
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }
  
  /* end message */
  SEPDriver_EndMessage(sramOffset);
            
  /* wait for the response */
  error = SEPDriver_POLL_FOR_REPONSE();
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }
   
  /*-------------------
      start reading message from the SEP 
  ---------------------*/
   
  /* start the message */
  error = SEPDriver_StartIncomingMessage(&sramOffset);
  if(error)
  {
    goto end_function_unlock_release_flow_resource;
  }
   
  /* 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_release_flow_resource;
  }
   
  /* check the opcode */
  if(messageParam[0] != DX_SEP_HOST_SEP_PROTOCOL_HOST_FLOW_INIT_HASH_OP_CODE)
  {
    error = DX_WRONG_OPCODE_FROM_SEP_ERR;
    goto end_function_unlock_release_flow_resource;
  }
   
  /* check status */
  if(messageParam[1] != DX_OK)
  {
    error = messageParam[1];
    goto end_function_unlock_release_flow_resource;
  }
  
  /* read the flow id */
  error = SEPDriver_ReadParamater((DxUint32_t)flowId_ptr,
                                  sizeof(DxUint32_t),
                                  sizeof(DxUint32_t),
                                  &sramOffset ,
                                  DX_FALSE);
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }
  
  /* now set the id of the newly created tables */
  SEPDriver_SetFlowId(*flowId_ptr);
  
  /* Init general Flow data base parameters */
  g_FlowsDb[*flowId_ptr].opType = FLOW_HASH_InitOperation;
  g_FlowsDb[*flowId_ptr].opMode = hashData_ptr->opMode ;
  g_FlowsDb[*flowId_ptr].flowType = flowType;
  goto end_function_unlock;

  /* --------------------- End Operation --------------------------*/
end_function_unlock_release_flow_resource:
  /* free all SEP tables resources */
  SEPDriver_FreeFlowResources(FVOS_DEFAULT_FLOW_ID);

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

end_function:
  return error;
}

/**
 * @brief       This function initializes the Hmac flow 
 *
 *    NOTE: 1) Static requests same buffer sizes for in and out (number of input buffers can be different from number of output buffers)
 *          2) Key size is limited to be <= 64 bytes
 * 
 * @param[in] flowType - type of flow, static or dynamic
 * @param[in] flowParams_ptr - flow parameters for the operation.
 * @param[in] hmacData_ptr - hmac data parameters
 * @param[out] flowId_ptr - the id of the created flow
 *
 * @return DXError_t - On success DX_OK is returned, on failure a
 *                        value MODULE_* CRYS_FLOW_error.h
 */
DxError_t CRYS_FLOW_HMACInit(CRYS_FLOW_Type_t               flowType,
                             CRYS_FLOW_Params_t*            flowParams_ptr,
                             CRYS_FLOW_HMACEngine_Data_t*   hmacData_ptr,
                             DxUint32_t*                    flowId_ptr)
{
  /* error */
  DxError_t     error;

  /* address of the first table in the input list */
  DxUint32_t    firstInputLLITableAddr;
   
  /* number of entries in each of the first tables */
  DxUint32_t    numEntriesInInputTable;
   
  /* size of data in the first input table */
  DxUint32_t    inputTableSize;
  
  /* swap input flag */
  DxUint32_t    swapInputFlag;
  
  /* sram offset */
  DxUint32_t    sramOffset;
  
  
  /* message parameters */
  DxUint32_t    messageParam[11];
  
  /*------------------------
      CODE
  ----------------------------*/
  
  /* check the input paramaters */
  
  /* check input pointer */
  if((flowId_ptr == DX_NULL) ||
  	 (flowParams_ptr == DX_NULL) ||
     (hmacData_ptr == DX_NULL)
  	)	
  {
    error = CRYS_FLOW_ARG_NULL_PTR_ERROR;
    goto end_function;
  }
  
  /*  HMAC doesn't support 512, 384 modes */
  if ((hmacData_ptr->opMode == CRYS_HASH_SHA384_mode) ||
      (hmacData_ptr->opMode == CRYS_HASH_SHA512_mode))
      return CRYS_HMAC_ILLEGAL_OPERATION_MODE_ERROR;
  
  /* check that total out size equal total in size */
  error = CRYS_FLOW_CheckValidInOutBufferSizes(flowParams_ptr, flowType, hmacData_ptr->opMode , FLOW_HMAC_InitOperation);
  if(error != DX_OK)
  {
      goto end_function;
  }
  
    /* check if the operation mode is legal */
	if( hmacData_ptr->opMode >= CRYS_HASH_NumOfModes )
	{
	    error = CRYS_HMAC_ILLEGAL_OPERATION_MODE_ERROR;
	    goto end_function;
	}

	/* check if the key pointer is valid */
	if( hmacData_ptr->Key_ptr == DX_NULL )
	{
	    error = CRYS_HMAC_INVALID_KEY_POINTER_ERROR;
	    goto end_function;
	}


	/* check if the key size is valid */
	if( hmacData_ptr->KeySize == 0 )
	{
	    error = CRYS_HMAC_UNVALID_KEY_SIZE_ERROR;
	    goto end_function;
	}
  
  /* lock access to the SEP */	    
  error = SEPDriver_Lock();
   
  if(error != DX_OK)
  {
      goto end_function;
  }
  
  /* prepare the input tables for the flows */
  error = SEPDriver_PrepareFlowDMATables(flowType,
                                         (SEP_FLOW_BufferData_t*)flowParams_ptr->inputBuffersArrays,
                                         flowParams_ptr->inputBuffersArraySize,
                                         SEP_DRIVER_InputBuffer,
                                         &firstInputLLITableAddr,
                                         &numEntriesInInputTable,
                                         &inputTableSize);                                      
  if(error != DX_OK)
  {
    /* NOTE: function will release flow resources internally */
    goto end_function_unlock;
  } 
  
  /* calculate swap for input and output */
  swapInputFlag = DX_FALSE;
  if(flowParams_ptr->wordsBuffersOrderFlag && flowParams_ptr->inputBigEndianOrderFlag)
  {
    swapInputFlag = DX_TRUE;
  }
  
  /* prepare protocol */
  sramOffset = 0;
   
  /* start the message */
  SEPDriver_StartMessage(&sramOffset);
  
  /* prepare message */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_FLOW_INIT_HMAC_OP_CODE;
  messageParam[1] = flowParams_ptr->inputInterruptId;
  messageParam[2] = flowParams_ptr->outputInterruptId;
  messageParam[3] = swapInputFlag;
  messageParam[4] = 0;
  messageParam[5] = flowType;
  messageParam[6] = firstInputLLITableAddr;
  messageParam[7] = inputTableSize;
  messageParam[8] = numEntriesInInputTable;
  messageParam[9] = hmacData_ptr->opMode;
  messageParam[10] = hmacData_ptr->KeySize;
  
  /* send paramaters */
  error = SEPDriver_WriteParamater((DxUint32_t)messageParam,
                                    sizeof(DxUint32_t) * 10,
                                    sizeof(DxUint32_t) * 10,
                                    &sramOffset, 
                                    DX_FALSE);
  
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }
  
  /* send key params */ 
  error = SEPDriver_WriteParamater((DxUint32_t)hmacData_ptr->Key_ptr , 
                                    hmacData_ptr->KeySize ,
                                    16 * sizeof(DxUint32_t) , 
                                    &sramOffset , 
                                    DX_TRUE);
                                    
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }

  /* send rest of message parameter */  
  error = SEPDriver_WriteParamater((DxUint32_t)(DxUint32_t)&messageParam[10], 
                                    sizeof(DxUint32_t) ,
                                    sizeof(DxUint32_t) , 
                                    &sramOffset , 
                                    DX_FALSE);
                                    
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }
  
  
  /* end message */
  SEPDriver_EndMessage(sramOffset);
            
  /* wait for the response */
  error = SEPDriver_POLL_FOR_REPONSE();
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }
   
  /*-------------------
      start reading message from the SEP 
  ---------------------*/
   
  /* start the message */
  error = SEPDriver_StartIncomingMessage(&sramOffset);
  if(error)
  {
    goto end_function_unlock_release_flow_resource;
  }
   
  /* 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_release_flow_resource;
  }
   
  /* check the opcode */
  if(messageParam[0] != DX_SEP_HOST_SEP_PROTOCOL_HOST_FLOW_INIT_HMAC_OP_CODE)
  {
    error = DX_WRONG_OPCODE_FROM_SEP_ERR;
    goto end_function_unlock_release_flow_resource;
  }
   
  /* check status */
  if(messageParam[1] != DX_OK)
  {
    error = messageParam[1];
    goto end_function_unlock_release_flow_resource;
  }
  
  /* read the flow id */
  error = SEPDriver_ReadParamater((DxUint32_t)flowId_ptr,
                                  sizeof(DxUint32_t),
                                  sizeof(DxUint32_t),
                                  &sramOffset ,
                                  DX_FALSE);
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }
  
  /* now set the id of the newly created tables */
  SEPDriver_SetFlowId(*flowId_ptr);
  
  /* Init general Flow data base parameters */
  g_FlowsDb[*flowId_ptr].opType = FLOW_HMAC_InitOperation;
  g_FlowsDb[*flowId_ptr].opMode = hmacData_ptr->opMode;
  g_FlowsDb[*flowId_ptr].flowType = flowType;
  goto end_function_unlock;

  /* --------------------- End Operation --------------------------*/
end_function_unlock_release_flow_resource:
  /* free all SEP tables resources */
  SEPDriver_FreeFlowResources(FVOS_DEFAULT_FLOW_ID);

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

end_function:
  return error;

}/*CRYS_FLOW_HMACInit*/


/**
 * @brief       This function initializes the RC4 flow 
 *
 *    NOTE: 1) Static requests same buffer sizes for in and out (number of input buffers can be different from number of output buffers)
 *          2) Key size is limited to 4-16 bytes.
 *          3) In/Out buffers size must be modulus 8.
 * 
 * @param[in] flowType - type of flow, static or dynamic
 * @param[in] flowParams_ptr - flow parameters for the operation.
 * @param[in] rc4Data_ptr - rc4 data parameters
 * @param[out] flowId_ptr - the id of the created flow
 *
 * @return DXError_t - On success DX_OK is returned, on failure a
 *                        value MODULE_* CRYS_FLOW_error.h
 */
DxError_t CRYS_FLOW_RC4Init(CRYS_FLOW_Type_t               flowType,
                            CRYS_FLOW_Params_t*            flowParams_ptr,
                            CRYS_FLOW_RC4Engine_Data_t*    rc4Data_ptr,
                            DxUint32_t*                    flowId_ptr)
{
  /* error */
  DxError_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 each of the first tables */
  DxUint32_t    numEntriesInInputTable;
  
  /* number of entries in each of the first tables */
  DxUint32_t    numEntriesInOutputTable;
   
  /* size of data in the first input table */
  DxUint32_t    inputTableSize;
  
  /* size of data in the first output table */
  DxUint32_t    outputTableSize;
  
  /* swap input flag */
  DxUint32_t    swapInputFlag;
  
  /* swap input flag */
  DxUint32_t    swapOutputFlag;
   
  /* sram offset */
  DxUint32_t    sramOffset;
  

  /* message parameters */
  DxUint32_t    messageParam[13];
  
  /*------------------------
      CODE
  ----------------------------*/
  
  /* check the input paramaters */
  
  /* check input pointer */
  if((flowId_ptr == DX_NULL) ||
  	 (flowParams_ptr == DX_NULL) ||
     (rc4Data_ptr == DX_NULL)
  	)	
  {
    error = CRYS_FLOW_ARG_NULL_PTR_ERROR;
    goto end_function;
  }
  
  /* check that total out size equal total in size */
  error = CRYS_FLOW_CheckValidInOutBufferSizes(flowParams_ptr, flowType, 0 , FLOW_RC4_InitOperation);
  if(error != DX_OK)
  {
      goto end_function;
  }
  
    /* If the Keys size is invalid return an error */
	if( rc4Data_ptr->KeySize == 0 || rc4Data_ptr->KeySize > CRYS_RC4_MAX_KEY_SIZE_IN_BYTES)  
	{
	    error = CRYS_RC4_ILLEGAL_KEY_SIZE_ERROR;
	    goto end_function;
	}
	
	/* If the the key pointer is not validity */
    if( rc4Data_ptr->Key_ptr == DX_NULL )
    {
        error = CRYS_RC4_INVALID_KEY_POINTER_ERROR;
        goto end_function;
    }

  /* lock access to the SEP */	    
  error = SEPDriver_Lock();
  
  if(error != DX_OK)
  {
      goto end_function;
  }
  
  /* prepare the input tables for the flows */
  error = SEPDriver_PrepareFlowDMATables(flowType,
                                         (SEP_FLOW_BufferData_t*)flowParams_ptr->inputBuffersArrays,
                                         flowParams_ptr->inputBuffersArraySize,
                                         SEP_DRIVER_InputBuffer,
                                         &firstInputLLITableAddr,
                                         &numEntriesInInputTable,
                                         &inputTableSize);                                      
  if(error != DX_OK)
  {
    /* NOTE: function will release flow resources internally */
    goto end_function_unlock;
  }
  
  /* prepare the output tables for the flows */
  error = SEPDriver_PrepareFlowDMATables(flowType,
                                         (SEP_FLOW_BufferData_t*)flowParams_ptr->outputBuffersArrays,
                                         flowParams_ptr->outputBuffersArraySize,
                                         SEP_DRIVER_OutputBuffer,
                                         &firstOutputLLITableAddr,
                                         &numEntriesInOutputTable,
                                         &outputTableSize);                                      
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }
  
  /* calculate swap for input and output */
  swapInputFlag = swapOutputFlag = DX_FALSE;
  if(flowParams_ptr->wordsBuffersOrderFlag)
  {
    if(flowParams_ptr->inputBigEndianOrderFlag)
    {
      swapInputFlag = DX_TRUE;
    }
    if(flowParams_ptr->outputBigEndianOrderFlag)
    {
      swapOutputFlag = DX_TRUE;
    }
  }
  
  /* prepare protocol */
  sramOffset = 0;
   
  /* start the message */
  SEPDriver_StartMessage(&sramOffset);
  
  /* prepare message */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_FLOW_INIT_RC4_OP_CODE;
  messageParam[1] = flowParams_ptr->inputInterruptId;
  messageParam[2] = flowParams_ptr->outputInterruptId;
  messageParam[3] = swapInputFlag;
  messageParam[4] = swapOutputFlag;
  messageParam[5] = flowType;
  messageParam[6] = firstInputLLITableAddr;
  messageParam[7] = inputTableSize;
  messageParam[8] = numEntriesInInputTable;
  messageParam[9] = firstOutputLLITableAddr;
  messageParam[10] = outputTableSize;
  messageParam[11] = numEntriesInOutputTable;
  messageParam[12] = rc4Data_ptr->KeySize;

  /* send paramaters */
  error = SEPDriver_WriteParamater((DxUint32_t)messageParam,
                                    sizeof(DxUint32_t) * 13,
                                    sizeof(DxUint32_t) * 13,
                                    &sramOffset, 
                                    DX_FALSE);
  
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }

  /* send key params */  
  error = SEPDriver_WriteParamater((DxUint32_t)rc4Data_ptr->Key_ptr , 
                                    rc4Data_ptr->KeySize ,
                                    16 * sizeof(DxUint32_t) , 
                                    &sramOffset , 
                                    DX_TRUE);
                                    
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }


  /* end message */
  SEPDriver_EndMessage(sramOffset);
            
  /* wait for the response */
  error = SEPDriver_POLL_FOR_REPONSE();
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }
   
  /*-------------------
      start reading message from the SEP 
  ---------------------*/
   
  /* start the message */
  error = SEPDriver_StartIncomingMessage(&sramOffset);
  if(error)
  {
    goto end_function_unlock_release_flow_resource;
  }
   
  /* 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_release_flow_resource;
  }
   
  /* check the opcode */
  if(messageParam[0] != DX_SEP_HOST_SEP_PROTOCOL_HOST_FLOW_INIT_RC4_OP_CODE)
  {
    error = DX_WRONG_OPCODE_FROM_SEP_ERR;
    goto end_function_unlock_release_flow_resource;
  }
   
  /* check status */
  if(messageParam[1] != DX_OK)
  {
    error = messageParam[1];
    goto end_function_unlock_release_flow_resource;
  }
  
  /* read the flow id */
  error = SEPDriver_ReadParamater((DxUint32_t)flowId_ptr,
                                  sizeof(DxUint32_t),
                                  sizeof(DxUint32_t),
                                  &sramOffset ,
                                  DX_FALSE);
  if(error != DX_OK)
  {
    goto end_function_unlock_release_flow_resource;
  }
  
  /* now set the id of the newly created tables */
  SEPDriver_SetFlowId(*flowId_ptr);
  
  /* Init general Flow data base parameters */
  g_FlowsDb[*flowId_ptr].opType = FLOW_RC4_InitOperation;
  g_FlowsDb[*flowId_ptr].opMode = 0;
  g_FlowsDb[*flowId_ptr].flowType = flowType;

  goto end_function_unlock;

  /* --------------------- End Operation --------------------------*/
end_function_unlock_release_flow_resource:
  /* free all SEP tables resources */
  SEPDriver_FreeFlowResources(FVOS_DEFAULT_FLOW_ID);

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

end_function:
  return error;
  
}/*CRYS_FLOW_RC4Init*/


/**
 * @brief       This function allos to add buffers to a dynamic flow
 * 
 *    NOTE: Add buffer should be only after all input buffers of the Init function were executed. (in no OS environment)
 *      
 * @param[in] flowId - id of the flow to add buffers to
 * @param[in] inputBuffersArray_ptr - array of input buffers. If no input buffers to add, the this parameter shoud be NULL
 * @param[in] inputBuffersArraySize - number of entries in the array of input buffers to add. If no input buffers to add, the this parameter shoud be 0
 * @param[in] outputBuffersArray_ptr - array of output buffers. If no output buffers to add, the this parameter shoud be NULL
 * @param[in] outputBuffersArraySize - number of entries in the array of output buffers to add. If no output buffers to add, the this parameter shoud be 0
 *
 * @return DXError_t - On success DX_OK is returned, on failure a
 *                        value MODULE_* CRYS_FLOW_error.h
 */
DxError_t CRYS_FLOW_AddBuffers(DxUint32_t               flowId,
                               CRYS_FLOW_BufferData_t*  inputBuffersArray_ptr,
                               DxUint32_t               inputBuffersArraySize,
                               CRYS_FLOW_BufferData_t*  outputBuffersArray_ptr,
                               DxUint32_t               outputBuffersArraySize)
{
  /* error */
  DxError_t     error = DX_OK;
   
  /* 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 each of the first tables */
  DxUint32_t    numEntriesInInputTable;
  
  /* number of entries in each of the first tables */
  DxUint32_t    numEntriesInOutputTable;
   
  /* size of data in the first input table */
  DxUint32_t    inputTableSize;
  
  /* size of data in the first output table */
  DxUint32_t    outputTableSize;
 
  /* message parameters */
  DxUint32_t    messageParam[8];
  
  CRYS_FLOW_Params_t  flowParams;
  DxUint32_t          loop;

  /*--------------------
      CODE
  -----------------------*/
  
  error = DX_OK;
  
  /* set flow params */
  flowParams.inputBuffersArrays = inputBuffersArray_ptr;
  flowParams.inputBuffersArraySize = inputBuffersArraySize;
  flowParams.outputBuffersArrays = outputBuffersArray_ptr;
  flowParams.outputBuffersArraySize = outputBuffersArraySize;
  /* check if flowid exists */
  for(loop = 0; loop < FVOS_NUM_FLOWS; loop++)
  {
    if(g_FlowsContexts[loop].flowId == flowId)
    {
      break;
    }
  }
  
  if(loop >= FVOS_NUM_FLOWS)
  {
  	error = CRYS_FLOW_ADDBUFFER_NO_ACTIVE_FLOWID_ERROR;
  	goto end_function;
  }


  /* validate that this is a dynamic flow */
  if(g_FlowsDb[flowId].flowType == CRYS_FLOW_TypeStatic)
  {
  	error = CRYS_FLOW_ADD_BUFFER_NOT_DYNAMIC_ERROR;
  	goto end_function;
  }
 
  /* check that total out size equal total in size */
  error = CRYS_FLOW_CheckValidInOutBufferSizes(&flowParams, CRYS_FLOW_TypeDynamic, g_FlowsDb[flowId].opMode ,g_FlowsDb[flowId].opType);
  if(error != DX_OK)
  {
      goto end_function;
  }
  
   /* lock access to the SEP */	  
   error = SEPDriver_Lock();
   
   if(error != DX_OK)
   {
       goto end_function;
   }
   
  
  error = SEPDriver_AddFlowBuffers(flowId,
                                   0, 
                                   (SEP_FLOW_BufferData_t*)inputBuffersArray_ptr, 
                                   inputBuffersArraySize,
                                   &firstInputLLITableAddr,
                                   &numEntriesInInputTable,
                                   &inputTableSize);
                                   
  if(error != DX_OK)
  {
    /* NOTE: function will release flow resources internally */
    goto end_function_unlock;
  }
  
  if(outputBuffersArray_ptr != DX_NULL)
  {
    error = SEPDriver_AddFlowBuffers(flowId,
                                     1,
                                     (SEP_FLOW_BufferData_t*)outputBuffersArray_ptr,
                                     outputBuffersArraySize,
                                     &firstOutputLLITableAddr,
                                     &numEntriesInOutputTable,
                                     &outputTableSize);
    if(error != DX_OK)
    {
      goto end_function_unlock_release_flow_resource;
    }
  }
  
  /* prepare message */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_FLOW_ADD_OP_CODE;
  messageParam[1] = flowId;
  messageParam[2] = firstInputLLITableAddr;
  messageParam[3] = inputTableSize;
  messageParam[4] = numEntriesInInputTable;
  if(outputBuffersArray_ptr != DX_NULL)
  {
    messageParam[5] = firstOutputLLITableAddr;
    messageParam[6] = outputTableSize;
    messageParam[7] = numEntriesInOutputTable;
  }
  else
  {
    messageParam[5] = 0;
    messageParam[6] = 0;
    messageParam[7] = 0;
  }
  
  /* add message */
  SEPDriver_AddBufferMessage(flowId,
                             &messageParam[0],
                             8);  
  
  
  goto end_function_unlock;

  /* --------------------- End Operation --------------------------*/
end_function_unlock_release_flow_resource:
  /* free all SEP tables resources */
  SEPDriver_FreeFlowResources(FVOS_DEFAULT_FLOW_ID);

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

end_function:
  return error;
}
                          

/**
 * @brief       This function finishes the flow. It sends (if needed), the last data for symmetric operation, and recieves the output (HASH,AES-MAC ), and the current state of the engine (IV/CTR) 
 * 
 * Notes: 1) After finish is done any additional input interrupt causes unexpectable behavior.
 *           It is user responsibilty.
 *
 * @param[in] flowId - id of the flow to add buffers to
 * @param[in] dataInSize - size of the last data.Should be 0, if no data is needed to be passed
 *
 * @return DXError_t - On success DX_OK is returned, on failure a
 *                        value MODULE_* CRYS_FLOW_error.h
 */
DxError_t CRYS_FLOW_Finish(DxUint32_t   flowId,
                           DxUint32_t   dataInSize)
{
  /* error */
  DxError_t     error = DX_OK;
  
  /* sram offset */
  DxUint32_t    sramOffset;
 
  /* message parameters */
  DxUint32_t    messageParam[3];
  
  DxUint32_t    loop;

  /*--------------------
      CODE
  -----------------------*/
  
  /* check if flowid exists */
  for(loop = 0; loop < FVOS_NUM_FLOWS; loop++)
  {
    if(g_FlowsContexts[loop].flowId == flowId)
    {
      break;
    }
  }
  
  if(loop >= FVOS_NUM_FLOWS)
  {
  	error = CRYS_FLOW_FINISH_NO_ACTIVE_FLOWID_ERROR;
  	goto end_function_no_unlock;
  }


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

  
  /* start the message */
  SEPDriver_StartMessage(&sramOffset);
  
  /* prepare message */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_FLOW_FINISH_OP_CODE;
  messageParam[1] = flowId;
  messageParam[2] = dataInSize;
  
  /* send paramaters */
  error = SEPDriver_WriteParamater((DxUint32_t)messageParam,
                                    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)
  {
    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_FLOW_FINISH_OP_CODE)
  {
    error = DX_WRONG_OPCODE_FROM_SEP_ERR;
    goto end_function_unlock;
  }
   
  /* check status */
  if(messageParam[1] != DX_OK)
  {
    error = messageParam[1];
    goto end_function_unlock;
  }
  
end_function_unlock:

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

end_function_no_unlock:

  return error;
}
                           
/**
 * @brief       This function receives the output of the flow, if needed (HASH, AES_MAC). If the results are not ready
 *              yet - appropriate error code will be returned
 * 
 * @param[in] flowId - id of the flow to add buffers to
 * @param[in] outputBuffer_ptr - address of the buffer , to where the result will be written
 * @param[in] outputBufferSize - size of the input buffer
 *
 * @return DXError_t - On success DX_OK is returned, on failure a
 *                        value MODULE_* CRYS_FLOW_error.h
 */
DxError_t CRYS_FLOW_GetResults(DxUint32_t   flowId,
                               DxUint8_t*   outputBuffer_ptr,
                               DxUint32_t   outputBufferSize)
{
  /* error */
  DxError_t     error = DX_OK;
  
  /* sram offset */
  DxUint32_t    sramOffset;
  
  /* maximum length */
  DxUint32_t    maxLength;
 
  /* message parameters */
  DxUint32_t    messageParam[3];

  DxUint32_t    loop;
  
  DxBool_t      is_mem_to_din_op;
  
 
  /*--------------------
      CODE
  -----------------------*/
  /* check if flowid exists */
  for(loop = 0; loop < FVOS_NUM_FLOWS; loop++)
  {
    if(g_FlowsContexts[loop].flowId == flowId)
    {
      break;
    }
  }
  
  if(loop >= FVOS_NUM_FLOWS)
  {
  	error = CRYS_FLOW_GETRESUALT_NO_ACTIVE_FLOWID_ERROR;
  	goto end_function;
  }
  
  /* Mark if the operation is mem_to_din interrupts (Hash, AES_MAC) */
  /* -------------------------------------------------------------- */
  is_mem_to_din_op = DX_FALSE;
  
  if( (g_FlowsDb[flowId].opType == FLOW_HASH_InitOperation)     || 
      (g_FlowsDb[flowId].opType == FLOW_HMAC_InitOperation)     ||
      ( (g_FlowsDb[flowId].opType == FLOW_AES_InitOperation)    && 
        ( (g_FlowsDb[flowId].opMode == 	CRYS_AES_MAC_mode)      ||
		  (g_FlowsDb[flowId].opMode == 	CRYS_AES_XCBC_MAC_mode) ||
		  (g_FlowsDb[flowId].opMode == 	CRYS_AES_CMAC_mode)		  	
        )
      ) 
    )
  {
  	is_mem_to_din_op = DX_TRUE; 
  }
  
  /* if engine is HASH/HMAC/AES MAC */
  if ((is_mem_to_din_op == DX_TRUE) &&
	  (outputBuffer_ptr == DX_NULL))
    return CRYS_FLOW_OUTPUT_BUFFER_IS_NULL_ERROR;
  
  /* lock access to the SEP */	  
  error = SEPDriver_Lock();
   
  if(error != DX_OK)
  {
    goto end_function;
  }

  
  /* start the message */
  SEPDriver_StartMessage(&sramOffset);
  
  /* prepare message */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_FLOW_GET_RESULTS_OP_CODE;
  messageParam[1] = flowId;
  
  /* send paramaters */
  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;
  }
  
  /* 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_PROTOCOL_HOST_FLOW_GET_RESULTS_OP_CODE)
  {
    error = DX_WRONG_OPCODE_FROM_SEP_ERR;
    goto end_function_unlock;
  }
   
  /* check status */
  if(messageParam[1] != DX_OK)
  {
    error = messageParam[1];
    goto end_function_unlock;
  }
  
  /* get the size of the result */
  error = SEPDriver_ReadParamater((DxUint32_t)messageParam,
                                  sizeof(DxUint32_t),
                                  sizeof(DxUint32_t),
                                  &sramOffset ,
                                  DX_FALSE);
  if(error != DX_OK)
  {
    goto end_function_unlock;
  }
  
  /* if return result size is 0 */
  if(messageParam[0] == 0)
  {
    goto end_function_unlock;
  }
  
  /* check that we have sufficient memory allocated for result */
  if(messageParam[0] > outputBufferSize)
  {
    error = CRYS_FLOW_UNSUFFICIENT_MEMORY_ALLOC_ERROR;
    goto end_function_unlock; 
  }
  
  /* copy the data into output parameter */
  maxLength = ((messageParam[0] + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t); 
  error = SEPDriver_ReadParamater((DxUint32_t)outputBuffer_ptr,
                                  messageParam[0],
                                  maxLength,
                                  &sramOffset ,
                                  DX_FALSE);
  
end_function_unlock:

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

end_function:

  return error;
}
                               
/**
 * @brief       This function terminates the flow immediatly
 * 
 * @param[in] flowId - id of the flow to add buffers to
 *
 * @return DXError_t - On success DX_OK is returned, on failure a
 *                        value MODULE_* CRYS_FLOW_error.h
 */
DxError_t CRYS_FLOW_Terminate(DxUint32_t  flowId)
{
  /* error */
  DxError_t     error = DX_OK;
  
  /* sram offset */
  DxUint32_t    sramOffset;
 
  /* message parameters */
  DxUint32_t    messageParam[2];

  DxUint32_t    loop;

  /*--------------------
      CODE
  -----------------------*/
  
  /* check if flowid exists */
  for(loop = 0; loop < FVOS_NUM_FLOWS; loop++)
  {
    if(g_FlowsContexts[loop].flowId == flowId)
    {
      break;
    }
  }
  
  if(loop >= FVOS_NUM_FLOWS)
  {
  	error = CRYS_FLOW_TERMINATE_NO_ACTIVE_FLOWID_ERROR;
  	goto end_function_no_unlock;
  }
  
  /* lock access to the SEP */	  
  error = SEPDriver_Lock();  
  if(error != DX_OK)
  {
    goto end_function_no_unlock;
  }
  
  /* start the message */
  SEPDriver_StartMessage(&sramOffset);
     
  /* prepare message */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_FLOW_TERMINATE_OP_CODE;
  messageParam[1] = flowId;
  
  /* send paramaters */
  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;
  }
  
  /* end message */
  SEPDriver_EndMessage(sramOffset);
            
  /* wait for the response */
  error = SEPDriver_POLL_FOR_REPONSE();
  if(error != DX_OK)
  {
    goto end_function_unlock;
  }
   
  /* free all SEP tables resources */
  SEPDriver_FreeFlowResources(flowId);

  /*-------------------
      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_PROTOCOL_HOST_FLOW_TERMINATE_OP_CODE)
  {
    error = DX_WRONG_OPCODE_FROM_SEP_ERR;
    goto end_function_unlock;
  }
   
  /* check status */
  if(messageParam[1] != DX_OK)
  {
    error = messageParam[1];
    goto end_function_unlock;
  }
  
  /* deallocate all the FLOW DMA tables */
  
end_function_unlock:

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

end_function_no_unlock:

  return error;
}

/*------------------------------------------------
    PRIVATE FUNCTIONS
--------------------------------------------------*/

/**
 * @brief       This function checks:
 *    1) total out size equal total in size (for dout_to_mem operations only) 
 *    2) Static flow: check that all in buffer and all out buffer sizes are equal
 *       (NOTE: there can be diffrent number of arrays in/out but internal sizes must be equal)
 *    3) Hash: buffers must be %64
 * 
 * @param[in] flowParams_ptr - flow parameters for the operation.
 * @param[in] flowType - type of flow, static or dynamic
 * @param[in] opMode - mode type for Hash or AES
 * @param[in] opType - operation type. 
 *
 * @return DXError_t - On success DX_OK is returned, on failure a
 *                        value MODULE_* CRYS_FLOW_error.h
 */

static DxError_t CRYS_FLOW_CheckValidInOutBufferSizes(CRYS_FLOW_Params_t* flowParams_ptr,
                                                      CRYS_FLOW_Type_t    flowType,
                                                      DxUint32_t          opMode,
                                                      CRYS_FLOW_Op_t      opType)
{
  DxUint32_t    loop;
  DxUint32_t    TotalInSize;
  DxBool_t      is_mem_to_din_op;
  DxUint32_t    TotalOutSize;
  DxUint32_t    PrevBuffSize;

  /*--------------------
      CODE
  -----------------------*/

 
  if (flowType > CRYS_FLOW_TypeDynamic)
		return CRYS_FLOW_ILLEGALTYPE_ERROR;
  
  /* Mark if the operation is mem_to_din interrupts (Hash, AES_MAC) */
  /* -------------------------------------------------------------- */
  is_mem_to_din_op = DX_FALSE;
  if( (opType == FLOW_HASH_InitOperation) || 
      (opType == FLOW_HMAC_InitOperation) ||
      ( (opType == FLOW_AES_InitOperation) && 
        ( (opMode == 	CRYS_AES_MAC_mode) ||
		  (opMode == 	CRYS_AES_XCBC_MAC_mode) ||
		  (opMode == 	CRYS_AES_CMAC_mode)		  	
        )
      ) 
    )
  {
  	is_mem_to_din_op = DX_TRUE;  
  	/* no output flow data => set outputBuffersArraySize to */ 
  	/*zero to prevent enterig en endless loop */
  	flowParams_ptr->outputBuffersArraySize = 0;
  }
  
  /* check that input/output buffer exists */
  /* ------------------------------------- */	
  if(flowParams_ptr->inputBuffersArrays == DX_NULL)
  {
  	return CRYS_FLOW_INPUT_BUFFER_IS_NULL_ERROR;
  }
  if((is_mem_to_din_op == DX_FALSE) && (flowParams_ptr->outputBuffersArrays == DX_NULL))
  {
  	return CRYS_FLOW_OUTPUT_BUFFER_IS_NULL_ERROR;
  }
  
    
  /* calculate Total Data in size & Total Data out size*/
  /* -------------------------------------------------- */
  PrevBuffSize = 0;
  TotalInSize = 0;
  TotalOutSize = 0;
  for(loop=0; loop<flowParams_ptr->inputBuffersArraySize; loop++)
  {
    TotalInSize += flowParams_ptr->inputBuffersArrays[loop].bufferSize;
  }
  for(loop=0; loop<flowParams_ptr->outputBuffersArraySize; loop++)
  {
    TotalOutSize += flowParams_ptr->outputBuffersArrays[loop].bufferSize;
  }
  
  /* check that operation NOT mem_to_din interrupts (Hash,Hmac, AES_MAC) */
  if ((is_mem_to_din_op == DX_FALSE) &&
      (TotalInSize != TotalOutSize))
  {
    return CRYS_FLOW_TOTAL_INSIZE_NOT_EQUAL_OUTSIZE_ERROR;
  }
  
  /* for static flow check if all in/out buffer sizes are equal */
  /* ----------------------------------------------------------- */
  if(flowType == CRYS_FLOW_TypeStatic)
  {
    for(loop=0; loop<flowParams_ptr->inputBuffersArraySize; loop++)
    {
      if(loop == 0)
        PrevBuffSize = flowParams_ptr->inputBuffersArrays[loop].bufferSize;
      else
      {
        if(PrevBuffSize != flowParams_ptr->inputBuffersArrays[loop].bufferSize)
          return CRYS_FLOW_STATIC_INBUFF_SIZES_NOT_EQUAL_ERROR;
        else
          PrevBuffSize = flowParams_ptr->inputBuffersArrays[loop].bufferSize;          
      }      
    }
    
    /* check output buffer only for dout_to_mem operations */
    if(is_mem_to_din_op == DX_FALSE)
    {
      for(loop=0; loop<flowParams_ptr->outputBuffersArraySize; loop++)
      {
        if(loop == 0)
          PrevBuffSize = flowParams_ptr->outputBuffersArrays[loop].bufferSize;
        else
        {
          if(PrevBuffSize != flowParams_ptr->outputBuffersArrays[loop].bufferSize)
            return CRYS_FLOW_STATIC_OUTBUFF_SIZES_NOT_EQUAL_ERROR;
          else
            PrevBuffSize = flowParams_ptr->outputBuffersArrays[loop].bufferSize;          
        }      
      }
    }
  }
  
  /* for all modes: */
  /*check that input/output array sizes are according to HW speciffications*/	
  /* ---------------------------------------------------------------------- */
  if(opType == FLOW_HASH_InitOperation || opType == FLOW_HMAC_InitOperation)
  {
      if(opMode == CRYS_HASH_SHA384_mode || opMode == CRYS_HASH_SHA512_mode)
      {
        /* hash => check only input buffers */
        for(loop=0; loop<flowParams_ptr->inputBuffersArraySize; loop++)
        {
          if((flowParams_ptr->inputBuffersArrays[loop].bufferSize % 128) != 0)
            return CRYS_FLOW_HASH_OP_BUFF_NOT_MOD_128_ERROR;
        }
      }
      else
      {
        /* hash => check only input buffers */
        for(loop=0; loop<flowParams_ptr->inputBuffersArraySize; loop++)
        {
          if((flowParams_ptr->inputBuffersArrays[loop].bufferSize % 64) != 0)
            return CRYS_FLOW_HASH_OP_BUFF_NOT_MOD_64_ERROR;
        }
      }
  }
  if(opType == FLOW_RC4_InitOperation)
  {
     for(loop=0; loop<flowParams_ptr->inputBuffersArraySize; loop++)
     {
       if((flowParams_ptr->inputBuffersArrays[loop].bufferSize % 8) != 0)
         return CRYS_FLOW_RC4_OP_IN_BUFF_NOT_MOD_8_ERROR;
     }

     for(loop=0; loop<flowParams_ptr->outputBuffersArraySize; loop++)
     {
       if((flowParams_ptr->outputBuffersArrays[loop].bufferSize % 8) != 0)
         return CRYS_FLOW_RC4_OP_OUT_BUFF_NOT_MOD_8_ERROR;
     }
  }
  if(opType == FLOW_DES_InitOperation)
  {
     for(loop=0; loop<flowParams_ptr->inputBuffersArraySize; loop++)
     {
       if((flowParams_ptr->inputBuffersArrays[loop].bufferSize % 8) != 0)
         return CRYS_FLOW_DES_OP_IN_BUFF_NOT_MOD_8_ERROR;
     }

     for(loop=0; loop<flowParams_ptr->outputBuffersArraySize; loop++)
     {
       if((flowParams_ptr->outputBuffersArrays[loop].bufferSize % 8) != 0)
         return CRYS_FLOW_DES_OP_OUT_BUFF_NOT_MOD_8_ERROR;
     }
  }
  if(opType == FLOW_AES_InitOperation)
  {
     for(loop=0; loop<flowParams_ptr->inputBuffersArraySize; loop++)
     {
       if((flowParams_ptr->inputBuffersArrays[loop].bufferSize % 16) != 0)
         return CRYS_FLOW_AES_OP_IN_BUFF_NOT_MOD_16_ERROR;
     }

     for(loop=0; loop<flowParams_ptr->outputBuffersArraySize; loop++)
     {
       if((flowParams_ptr->outputBuffersArrays[loop].bufferSize % 16) != 0)
         return CRYS_FLOW_AES_OP_OUT_BUFF_NOT_MOD_16_ERROR;
     }
  }  

END:  
  return DX_OK;
}
