
  /*
   *  Object %name    : %
   *  State           :  %state%
   *  Creation date   :  Tue Feb 01 17:15:04 2005
   *  Last modified   :  %modify_time%
   */
  /** @file
   *  \brief A brief description of this module
   *
   *  \version CRYS_DH.c#1:csrc:8
   *  \author ohads
   *  \remarks Copyright (C) 2004 by Discretix Technologies Ltd.
   *           All Rights reserved
   */



/************* Include Files ****************/
#include "DX_VOS_Mem.h"
#include "CRYS_DH_errors.h"
#include "CRYS_RSA_Types.h"
#include "CRYS_RSA_BUILD.h"
#include "CRYS_DH.h"
#include "CRYS_RSA_PRIM.h"
#include "CRYS_RND.h"
#include "PLAT_SystemDep.h"
#include "SEPDriver.h"
#include "crys_host_op_code.h"
#include "error.h"

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

/* canceling the lint warning:
   Use of goto is deprecated */
/*lint --e{801} */

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

/************************ macros ********************************/

/* this macro is required to remove compilers warnings if the HASH or PKI is not supported */

#if defined(CRYS_NO_HASH_SUPPORT) || defined(CRYS_NO_PKI_SUPPORT)
#define RETURN_IF_DH_UNSUPPORTED( a , b , c , d , e , f , g , h , i , j , k , l , a1 , b1 , c1 , d1 , e1 , f1 , g1 , h1 , i1 , j1) \
  (a)=0;(b)=0;(c)=0;(d)=0;(e)=0;(f)=0;(g)=0;(h)=0;(i)=0;(j)=0;(k)=0;(l)=0; \
  (a1)=0;(b1)=0;(c1)=0;(d1)=0;(e1)=0;(f1)=0;(g1)=0;(h1)=0;(i1)=0;(j1)=0; \
  (a)=(a);(b)=(b);(c)=(c);(d)=(d);(e)=(e);(f)=(f);(g)=(g);(h)=(h);(i)=(i);(j)=(j);(k)=(k);(l)=(l); \
  (a1)=(a1);(b1)=(b1);(c1)=(c1);(d1)=(d1);(e1)=(e1);(f1)=(f1);(g1)=(g1);(h1)=(h1);(i1)=(i1);(j1)=(j1); \
  return CRYS_DH_IS_NOT_SUPPORTED
#else  /* !CRYS_NO_HASH_SUPPORT && ! CRYS_NO_PKI_SUPPORT */
#define RETURN_IF_DH_UNSUPPORTED( a , b , c , d , e , f , g , h , i , j , k , l , a1 , b1 , c1 , d1 , e1 , f1 , g1 , h1 , i1 , j1) 
#endif /* !CRYS_NO_HASH_SUPPORT && ! CRYS_NO_PKI_SUPPORT */

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

/**
 * @brief 
 	_DX_DH_GeneratePubPrv has 2 functionalities:
 	1. randomly generates the Client private key 
 	2. compute the Client public key which is 
 		ClientPub = Generator ^ Prv mod Prime 
 		
 	Note: All buffers arguments are represented in Big-Endian
 	
  @param[in] Generator_ptr 		- Pointer to the Generator octet string
  @param[in] GeneratorSize 		- Size of the Generator String (in bytes)
  @param[in] Prime_ptr 			- Pointer to the Prime octet string
  @param[in] PrimeSize 			- Size of the Prime string (in bytes)
  @param[in] L 					- Relevant only for PKCS#3, the private value length in bits
  								  If L != 0 then - force the private key to be 2^(L-1) <= Prv < 2^l
  				 					if L 0 then: 0< Prv < P-1
  				 				  In ANSI X9.42 L is irrelevant  
  @param[in] Q_ptr 				- Relevant only for ANSI X9.42 - Pointer to the Q octet string
  									1<= Prv <= q-1   or   1< Prv < q-1
  @param[in] QSize	 			- Relevant only for ANSI X9.42 - Size of the Q string (in bytes)  				 				  
  @param[in] DH_mode			- enum declaring weather this is PKCS#3 or ANSI X9.42
  
  @param[in] UserPubKey_ptr		- a pointer to the publick key structure. used for the Exp operation function
  									the struct doesn't need to be initialized
  @param[in] PrimeData_ptr 		- a pointer to a structure containing internal buffers  
                                    the struct doesn't need to be initialized
  @param[out] ClientPrvKey_ptr  - Pointer to the Private key octet string - 
  							  	  In PKCS#3 This buffer should be at least the following size
	  							  	  2^L - 1 - if L is provided
	  							  	  P-1	  - if L is DX_NULL
  @param[in/out] ClientPrvKeySize_ptr - The user should provide the size of the buffer indicated by ClientPrvKey_ptr
                                        The function returns the actual size in bytes of the Private key Size
  @param[out] ClientPub_ptr 	- Pointer to the Public key octet string
  						  		  This Buffer should be at least PrimeSize bytes
  							  
  @param[in/out] ClientPubSize_ptr -    The user should provide the size of the buffer indicated by ClientPub_ptr
                                        The function returns the actual size in bytes of the client public buffer
 
  @return CRYSError_t - On success CRYS_OK is returned, on failure an ERROR as defined CRYS_DH_error.h
                         
 */

CEXPORT_C CRYSError_t _DX_DH_GeneratePubPrv(DxUint8_t *Generator_ptr,
                                            DxUint16_t GeneratorSize,
                                            DxUint8_t *Prime_ptr,
                                            DxUint16_t PrimeSize,
                                            DxUint16_t L,
                                            DxUint8_t *Q_ptr,
                                            DxUint16_t QSize,
                                            CRYS_DH_OpMode_t DH_mode,
                                            CRYS_DHUserPubKey_t *UserPubKey_ptr,
                                            CRYS_DHPrimeData_t  *PrimeData_ptr,
                                            DxUint8_t *ClientPrvKey_ptr,
                                            DxUint16_t *ClientPrvKeySize_ptr,
                                            DxUint8_t *ClientPub1_ptr,
                                            DxUint16_t *ClientPubSize_ptr)

{
  /* The return error identifier */
  CRYSError_t       Error;

  /* sram offset */
  DxUint32_t        sramOffset;
  
  /* message parameters */
  DxUint32_t        messageParam[7];

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

  /* ............... if not supported exit .............................. */
  /* -------------------------------------------------------------------- */   

  RETURN_IF_DH_UNSUPPORTED( Generator_ptr , GeneratorSize , Prime_ptr , 
                             PrimeSize , L , Q_ptr , QSize , 
                             DH_mode , UserPubKey_ptr , PrimeData_ptr , ClientPrvKey_ptr ,
                             ClientPrvKeySize_ptr , ClientPub1_ptr , ClientPubSize_ptr,
                             tmp_byte , tmp_vectorSize , Compared , i , Error , Error , Error , Error); 
                              
  #ifndef CRYS_NO_HASH_SUPPORT                                      
  #ifndef CRYS_NO_PKI_SUPPORT                                      
   
  /* ............... checking the parameters validity ................... */
  /* -------------------------------------------------------------------- */


  /* if an argument pointer is DX_NULL return an error */
  if( Generator_ptr == DX_NULL || Prime_ptr == DX_NULL || 
      ClientPrvKey_ptr == DX_NULL || ClientPub1_ptr == DX_NULL ||
      ClientPrvKeySize_ptr == DX_NULL || ClientPubSize_ptr == DX_NULL ||
      UserPubKey_ptr == DX_NULL || PrimeData_ptr == DX_NULL)
   	   
       return CRYS_DH_INVALID_ARGUMENT_POINTER_ERROR;      
       
  /*If an argument buffer size is zero return an error*/
  if( GeneratorSize == 0 || PrimeSize == 0 || *ClientPrvKeySize_ptr == 0 || *ClientPubSize_ptr < PrimeSize)   
    return CRYS_DH_INVALID_ARGUMENT_SIZE_ERROR;
   
  if(DH_mode > CRYS_DH_NumOfModes)
    return CRYS_DH_INVALID_ARGUMENT_OPERATION_MODE_ERROR;
   
  if(DH_mode == CRYS_DH_ANSI_X942_mode && Q_ptr == DX_NULL)
    return CRYS_DH_INVALID_ARGUMENT_POINTER_ERROR;      
       
  if(DH_mode == CRYS_DH_ANSI_X942_mode && QSize == 0)       
    return CRYS_DH_INVALID_ARGUMENT_SIZE_ERROR;
   		

   /* lock access to the SEP */
   Error = SEPDriver_Lock();
   
   if(Error != DX_OK)
   {
       goto end_function_no_unlock;
   }
   
  /*----------------------------
    start sending message to SEP 
  -----------------------------*/
  
  sramOffset = 0;
   
  /* start the message */
  SEPDriver_StartMessage(&sramOffset);
  
  /* prepare message */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_DH_GEN_PUB_PRV_OP_CODE;
  messageParam[1] = DH_mode;
  messageParam[2] = L;
  messageParam[3] = GeneratorSize;
  messageParam[4] = PrimeSize;
  messageParam[5] = QSize;
  
  /* send params */
  Error = SEPDriver_WriteParamater((DxUint32_t)messageParam,
                            sizeof(DxUint32_t) * 4,
                            sizeof(DxUint32_t) * 4,
                            &sramOffset,
                            DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                            
  /* send Generator */
  Error = SEPDriver_WriteParamater((DxUint32_t)Generator_ptr , 
                             GeneratorSize ,
                             64 * 4, 
                             &sramOffset , 
                             DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                             
  /* send params */
  Error = SEPDriver_WriteParamater((DxUint32_t)&messageParam[4],
                            sizeof(DxUint32_t),
                            sizeof(DxUint32_t),
                            &sramOffset,
                            DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                             
  /* send prime */
  Error = SEPDriver_WriteParamater((DxUint32_t)Prime_ptr , 
                             PrimeSize ,
                             64 * 4, 
                             &sramOffset , 
                             DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
  
  
  
  /* send Q size */
  Error = SEPDriver_WriteParamater((DxUint32_t)&messageParam[5],
                            sizeof(DxUint32_t),
                            sizeof(DxUint32_t),
                            &sramOffset,
                            DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                            
  /* send Q */
  Error = SEPDriver_WriteParamater((DxUint32_t)Q_ptr , 
                             QSize ,
                             64 * 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 != DX_OK)
  {
  	goto end_function_unlock;
  }
   
  /* read opcode + status  */
  Error = SEPDriver_ReadParamater((DxUint32_t)messageParam,
                            sizeof(DxUint32_t) * 2,
                            sizeof(DxUint32_t) * 2,
                            &sramOffset ,
                            DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
  /* check the opcode */
  if(messageParam[0] != DX_SEP_HOST_SEP_PROTOCOL_HOST_DH_GEN_PUB_PRV_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 private key size */
  Error = SEPDriver_ReadParamater((DxUint32_t)messageParam,
                            sizeof(DxUint32_t),
                            sizeof(DxUint32_t),
                            &sramOffset,
                            DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                        
  if (*ClientPrvKeySize_ptr < (DxUint16_t)messageParam[0])
  {
    Error = CRYS_DH_ARGUMENT_PRV_SIZE_ERROR;
    goto end_function_unlock;    
  }
  
  *ClientPrvKeySize_ptr = (DxUint16_t)messageParam[0];                          
  
  /* read private key */
  Error = SEPDriver_ReadParamater((DxUint32_t)ClientPrvKey_ptr,
                           *ClientPrvKeySize_ptr,
                           64 * 4,
                           &sramOffset,
                           DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                             
  /* read public key size */
  Error = SEPDriver_ReadParamater((DxUint32_t)messageParam,
                            sizeof(DxUint32_t),
                            sizeof(DxUint32_t),
                            &sramOffset,
                            DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                            
  if (*ClientPubSize_ptr < (DxUint16_t)messageParam[0])
  {
    Error = CRYS_DH_INVALID_ARGUMENT_SIZE_ERROR;
    goto end_function_unlock;    
  }
  
  *ClientPubSize_ptr = (DxUint16_t)messageParam[0];
                            
  /* read public key */
  Error = SEPDriver_ReadParamater((DxUint32_t)ClientPub1_ptr,
                           *ClientPubSize_ptr,
                           64 * 4,
                           &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_no_unlock:

  return Error;  

#endif /*CRYS_NO_HASH_SUPPORT*/
#endif /*CRYS_NO_PKI_SUPPORT*/

}/* END OF _DX_DH_GeneratePubPrv */				                    




/****************************************************************/
/**
 * @brief CRYS_DH_PKCS3_GetSecretKey computes the shared secret key in the following computation:
 	SecretKey = ServerPubKey ^ ClientPrvKey mod Prime
 
  	Note: All buffers arguments are represented in Big-Endian
 
  @param[in] ClientPrvKey_ptr 	- Pointer to the Private key octet string - 
  @param[in] ClientPrvKeySize  	- The Private key Size (in bytes)
  @param[in] ServerPubKey_ptr   - Pointer to the Server public key octet string - 
  @param[in] ServerPubKeySize   - The Server Public key Size (in bytes)
  @param[in] Prime_ptr 			- Pointer to the Prime octet string
  @param[in] PrimeSize 			- Size of the Prime string
  @param[in] UserPubKey_ptr		- a pointer to the publick key structure. used for the Exp operation function
                                  the struct doesn't need to be initialized
  @param[in] PrimeData_ptr 		- a pointer to a structure containing internal buffers
                                  the struct doesn't need to be initialized    
  @param[out] SecretKey_ptr 	- Pointer to the secret key octet string.
  							  	  This buffer should be at least PrimeSize Bytes
  							  
  @param[in/out] SecretKeySize_ptr - The user should provide the actual size in bytes of the buffer indicated by SecretKey_ptr
                                    The function will return the actual size in bytes of the output secret key

  @return CRYSError_t - On success CRYS_OK is returned, on failure an ERROR as defined CRYS_DH_error.h
*/

CEXPORT_C CRYSError_t CRYS_DH_PKCS3_GetSecretKey(DxUint8_t*           ClientPrvKey_ptr,
                      				                   DxUint16_t           ClientPrvKeySize,
                       				                   DxUint8_t*           ServerPubKey_ptr,
                      				                   DxUint16_t           ServerPubKeySize,				                    
                      				                   DxUint8_t*           Prime_ptr,
                      				                   DxUint16_t           PrimeSize,
                                                 CRYS_DHUserPubKey_t* UserPubKey_ptr,
                                                 CRYS_DHPrimeData_t*  PrimeData_ptr, 				                    
                                                 DxUint8_t*           SecretKey_ptr,
                                                 DxUint16_t*          SecretKeySize_ptr)			                    
{
  /* The return error identifier */
  CRYSError_t       Error;
   
  /* sram offset */
  DxUint32_t        sramOffset;
  
  /* message parameters */
  DxUint32_t        messageParam[4];
  
  /*-------------------------
      CODE
  -----------------------------*/
   
  
  /* initializing the Error to O.K */
  Error = CRYS_OK;
   
  /* ............... if not supported exit .............................. */
  /* -------------------------------------------------------------------- */   

  RETURN_IF_DH_UNSUPPORTED( ClientPrvKey_ptr , ClientPrvKeySize , ServerPubKey_ptr , 
                             ServerPubKeySize , Prime_ptr , PrimeSize , UserPubKey_ptr , 
                             PrimeData_ptr , SecretKey_ptr , 
                             SecretKeySize_ptr , index , Error , Error ,
                             Error,Error,Error,Error,Error,Error,Error,Error,Error); 
                              
  #ifndef CRYS_NO_HASH_SUPPORT                                      
  #ifndef CRYS_NO_PKI_SUPPORT                                      
   
  /* ............... checking the parameters validity ................... */
  /* -------------------------------------------------------------------- */


  /* if an argument pointer is DX_NULL return an error */
  if( ClientPrvKey_ptr == DX_NULL || ServerPubKey_ptr == DX_NULL || 
   	   Prime_ptr == DX_NULL || UserPubKey_ptr == DX_NULL ||
   	   PrimeData_ptr == DX_NULL || SecretKey_ptr == DX_NULL || SecretKeySize_ptr == DX_NULL)
   	   
    return CRYS_DH_INVALID_ARGUMENT_POINTER_ERROR;      
       
  /*If an argument buffer size is zero return an error*/
  if( ClientPrvKeySize == 0 || ServerPubKeySize == 0 || PrimeSize == 0 || *SecretKeySize_ptr < PrimeSize)   
    return CRYS_DH_INVALID_ARGUMENT_SIZE_ERROR;
  
   /* lock access to the SEP */
   Error = SEPDriver_Lock();
   
   if(Error != DX_OK)
   {
       goto end_function_no_unlock;
   }

  /*----------------------------
    start sending message to SEP 
  -----------------------------*/
  
  sramOffset = 0;
   
  /* start the message */
  SEPDriver_StartMessage(&sramOffset);
  
  /* prepare message */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_DH_GET_SEC_KEY_OP_CODE;
  messageParam[1] = ClientPrvKeySize;
  messageParam[2] = ServerPubKeySize;
  messageParam[3] = PrimeSize;
  
  /* send params */
  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 private key */
  Error = SEPDriver_WriteParamater((DxUint32_t)ClientPrvKey_ptr,
                            ClientPrvKeySize,
                            64 * 4,
                            &sramOffset,
                            DX_FALSE);                          
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
   
  /* send server key size */
  Error = SEPDriver_WriteParamater((DxUint32_t)&messageParam[2],
                            sizeof(DxUint32_t),
                            sizeof(DxUint32_t),
                            &sramOffset,
                            DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
  
  /* send server key */
  Error = SEPDriver_WriteParamater((DxUint32_t)ServerPubKey_ptr,
                            ServerPubKeySize,
                            64 * 4,
                            &sramOffset,
                            DX_FALSE); 
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
  /* send prime size */
  Error = SEPDriver_WriteParamater((DxUint32_t)&messageParam[3],
                            sizeof(DxUint32_t),
                            sizeof(DxUint32_t),
                            &sramOffset,
                            DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
  
  /* send prime */
  Error = SEPDriver_WriteParamater((DxUint32_t)Prime_ptr,
                            PrimeSize,
                            64 * 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 != DX_OK)
  {
  	goto end_function_unlock;
  }
   
  /* read opcode + status  */
  Error = SEPDriver_ReadParamater((DxUint32_t)messageParam,
                            sizeof(DxUint32_t) * 2,
                            sizeof(DxUint32_t) * 2,
                            &sramOffset ,
                            DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
  /* check the opcode */
  if(messageParam[0] != DX_SEP_HOST_SEP_PROTOCOL_HOST_DH_GET_SEC_KEY_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 secret key size */
  Error = SEPDriver_ReadParamater((DxUint32_t)messageParam,
                            sizeof(DxUint32_t),
                            sizeof(DxUint32_t),
                            &sramOffset,
                            DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                            
  *SecretKeySize_ptr = (DxUint16_t)messageParam[0];
                            
  /* read secret key */
  Error = SEPDriver_ReadParamater((DxUint32_t)SecretKey_ptr,
                           *SecretKeySize_ptr,
                           64 * 4,
                           &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_no_unlock:

  return Error; 
  
  #endif /*CRYS_NO_HASH_SUPPORT*/
  #endif /*CRYS_NO_PKI_SUPPORT*/

}

/****************************************************************/
/**
 * @brief _DX_DH_KeyDerivationFunc specifies the key derivation function, either based on ASN.1 DER encoding
 			or based on the concatanation of fields as specified in ANSI X9.42-2001.
 			The purpose of this function is to derive a key data from the shared secret value.
 			
	The actual APIs that will be used by the user are:
		CRYS_DH_ASN1_KeyDerivation_SHA1Func 			
		CRYS_DH_Concat_KeyDerivation_SHA1Func
 			
  \note The length in Bytes of the hash result buffer is denoted by "hashlen".
  \note The standard states that optional "other info" may be passed as input to
        the derivation function. This implementation does not support this option.
  \note All buffers arguments are represented in Big-Endian format.
 
  @param[in] ZZSecret_ptr 	- A pointer to shared secret key octet string 
  @param[in] ZZSecretSize  	- The shared secret key Size, in bytes
  @param[in] hashFunc 		- The hash function to be used. The hash function output must be at least 160 bits.
  @param[in] KeyLenInBits	- The size in Bits of the keying data to be generated - 
  								KeyLenInBits < hashlen*(2^32-1) - in our implementation the size should not 
  								be larger than the maximum input size to the Hash function
  @param[in] derivation_mode - Specifies whether we use an ASN.1-based derivation function 
                               or a derivation based on concatenation.
  @param[out] KeyingData_ptr - A pointer to the keying data derived from the secret key, of length KeyLenInBits
  							  
  @return CRYSError_t - On success the value CRYS_OK is returned, 
			and on failure an ERROR as defined in CRYS_DH_error.h
*/

CEXPORT_C CRYSError_t _DX_DH_KeyDerivationFunc(DxUint8_t*                   ZZSecret_ptr,
                                               DxUint16_t                   ZZSecretSize,
                                               CRYS_DH_HASH_OpMode_t        hashFunc,				                    
                                               DxUint32_t                   KeyLenInBits,				                    
                                               DxUint8_t*                   KeyingData_ptr,
                                               CRYS_DH_DerivationFunc_Mode  derivation_mode)
{
  /* The return error identifier */
  CRYSError_t       Error;
  
  /* sram offset */
  DxUint32_t        sramOffset;
  
  /* message parameters */
  DxUint32_t        messageParam[4];
   
  /*------------------------------------------- 
      CODE
  ----------------------------------------------*/    

  /* initializing the Error to O.K */
  Error = CRYS_OK;

  /* ............... if not supported exit .............................. */
  /* -------------------------------------------------------------------- */   

  RETURN_IF_DH_UNSUPPORTED( ZZSecret_ptr , ZZSecretSize , hashFunc , 
                             KeyLenInBits , KeyingData_ptr , derivation_mode , Error , 
                             HashOutputSizeBytes , HashOutputSizeBits , 
                             D_param , i , Counter , HashContext.valid_tag ,
                             curResult_index,HashResultBuff[0],DHhash_mode,Error,Error,Error,Error,Error,Error); 
                              
  #ifndef CRYS_NO_HASH_SUPPORT                                      
  #ifndef CRYS_NO_PKI_SUPPORT                                      
      
  /* ............... checking the parameters validity ................... */
  /* -------------------------------------------------------------------- */

  /* if an argument pointer is DX_NULL return an error */
  if(ZZSecret_ptr == DX_NULL || KeyingData_ptr == DX_NULL)
		return CRYS_DH_INVALID_ARGUMENT_POINTER_ERROR;
	
  if(ZZSecretSize == 0 )
   		return CRYS_DH_INVALID_ARGUMENT_SIZE_ERROR;
   	

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


	/*----------------------------
    start sending message to SEP 
  -----------------------------*/
  
  sramOffset = 0;
   
  /* start the message */
  SEPDriver_StartMessage(&sramOffset);
  
  /* prepare message */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_DH_DER_KEY_OP_CODE;
  messageParam[1] = KeyLenInBits;
  messageParam[2] = hashFunc;
  messageParam[3] = derivation_mode;
  
  /* send params */
  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 */
  Error = SEPDriver_WriteParamater((DxUint32_t)KeyingData_ptr,
                            KeyLenInBits/8,
                            64,
                            &sramOffset,
                            DX_FALSE);                          
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
   
  /* send hash mode and derivation */
  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;
  }
  
  sramOffset += 65 * sizeof(DxUint32_t);  
   
  /* end message */
  SEPDriver_EndMessage(sramOffset);
            
  /* wait for the response */
  Error = SEPDriver_POLL_FOR_REPONSE();
  if(Error != DX_OK)
  {
  	goto end_function_unlock;
  }
   
  /*-------------------
    start reading message from the SEP 
  ---------------------*/
   
  /* start the message */
  Error = SEPDriver_StartIncomingMessage(&sramOffset);
  if(Error != DX_OK)
  {
  	goto end_function_unlock;
  }
   
  /* read opcode + status  */
  Error = SEPDriver_ReadParamater((DxUint32_t)messageParam,
                            sizeof(DxUint32_t) * 2,
                            sizeof(DxUint32_t) * 2,
                            &sramOffset ,
                            DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
  /* check the opcode */
  if(messageParam[0] != DX_SEP_HOST_SEP_PROTOCOL_HOST_DH_DER_KEY_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 secret key */
  Error = SEPDriver_ReadParamater((DxUint32_t)ZZSecret_ptr,
                           ZZSecretSize,
                           64,
                           &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_no_unlock:

  return Error; 

  #endif /*CRYS_NO_HASH_SUPPORT*/
  #endif /*CRYS_NO_PKI_SUPPORT*/

}/* END OF _DX_DH_KeyDerivationFunc */				                    


/****************************************************************/
/**
 * @brief _DX_DH_X942_GetSecretData computes the shared secret key as follows:
 		1. OPTIONAL - validate the correctness of the argument keys
 		2. SecretKey = ServerPubKey ^ ClientPrvKey mod Prime
 		3. Use of Derivation function to derive a data key from the secret key 
 
 	The actual APIs that will be used by the user are:
 	CRYS_DH_X942_GetSecret_ASN1_2_Data
 	CRYS_DH_X942_GetSecret_Concat_2_Data
 
  	Note: All buffers arguments are represented in Big-Endian format

  @param[in] UserPubKey_ptr		- A pointer to the public key data structure. Not initialized.
  @param[in] PrimeData_ptr 		- A pointer to a CRYS_RSAPrimeData_t structure 
   								  that is used for the Exp operation
  @param[in] hashFunc			- The hash function to be used
  @param[in] ClientPrvKey_ptr 	- A pointer to the Private key octet string 
  @param[in] ClientPrvKeySize  	- The Private key size, in bytes
  @param[in] ServerPubKey_ptr   - A pointer to the Server public key octet string - 
  @param[in] ServerPubKeySize   - The Server Public key size, in bytes
  @param[in] Prime_ptr 			- A pointer to the Prime octet string
  @param[in] PrimeSize 			- The size of the Prime string
  @param[in] DerFunc_mode 		- The type of function to derive the secret key to the key data.
  								  We use ASN.1-based function or Hash concatenation function mode.
  @param[out] SecretKeyData_ptr	- A pointer to the secret key octet string. 
				  				  This buffer should be at least PrimeSize bytes.
  @param[in] SecretKeyDataSizeBitsNeeded - Specifies the derived Secret Key data size needed in Bits. This value converted to bytes 
                                  cannot be larger than PrimeSize

  @return CRYSError_t - On success a value of CRYS_OK is returned, on failure an ERROR as defined in CRYS_DH_error.h
*/
CIMPORT_C CRYSError_t _DX_DH_X942_GetSecretData(CRYS_DHUserPubKey_t*        UserPubKey_ptr,
                               					CRYS_DHPrimeData_t*         PrimeData_ptr, 
                              				  	CRYS_DH_HASH_OpMode_t       hashFunc,		
                              					DxUint8_t*                  ClientPrvKey_ptr,
                              				    DxUint16_t                  ClientPrvKeySize,
                               				    DxUint8_t*                  ServerPubKey_ptr,
                              				    DxUint16_t                  ServerPubKeySize,				                    
                              				    DxUint8_t*                  Prime_ptr,
                              				    DxUint16_t                  PrimeSize,
                              				    CRYS_DH_DerivationFunc_Mode DerFunc_mode,
                              				    DxUint8_t*                  SecretKeyData_ptr,
                              				    DxUint16_t                  SecretKeyDataSizeBitsNeeded)
{
  /* The return error identifier */
  CRYSError_t       Error;
  
  /* sram offset */
  DxUint32_t        sramOffset;
  
  /* message parameters */
  DxUint32_t        messageParam[7];

  /*-------------------------
      CODE
  ---------------------------*/
   
  /* ............... local initializations .............................. */
  /* -------------------------------------------------------------------- */
  PrimeData_ptr=PrimeData_ptr;
  UserPubKey_ptr=UserPubKey_ptr; 
  
  /* initializing the Error to O.K */
  Error = CRYS_OK;
 
                         
  #ifndef CRYS_NO_HASH_SUPPORT                                      
  #ifndef CRYS_NO_PKI_SUPPORT                                      
     
  /* ............... checking the parameters validity ................... */
  /* -------------------------------------------------------------------- */
   
  /*check that the derived secret key needed is not zero*/
  if(SecretKeyDataSizeBitsNeeded == 0)
    return CRYS_DH_SECRET_KEY_SIZE_NEEDED_ERROR;

  /*check that the derived secret key needed is smaller than PrimeSize*/
  if(SecretKeyDataSizeBitsNeeded > PrimeSize*8)
    return CRYS_DH_SECRET_KEY_SIZE_NEEDED_BIGGER_THAN_PRIME_SIZE;
  
  /* if an argument pointer is DX_NULL return an error */
	if( ClientPrvKey_ptr  == DX_NULL || 
		ServerPubKey_ptr  == DX_NULL || 
		Prime_ptr         == DX_NULL ||
		UserPubKey_ptr    == DX_NULL ||
		PrimeData_ptr     == DX_NULL || 
		SecretKeyData_ptr     == DX_NULL)
		return CRYS_DH_INVALID_ARGUMENT_POINTER_ERROR; 
		
		

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

	/*----------------------------
    start sending message to SEP 
  -----------------------------*/
  
  sramOffset = 0;
   
  /* start the message */
  SEPDriver_StartMessage(&sramOffset);
  
  /* prepare message */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_DH_X942_GET_SEC_DATA_OP_CODE;
  messageParam[1] = hashFunc;
  messageParam[2] = DerFunc_mode;
  messageParam[3] = SecretKeyDataSizeBitsNeeded;
  messageParam[4] = ClientPrvKeySize;
  messageParam[5] = ServerPubKeySize;
  messageParam[6] = PrimeSize;
  
  /* send params */
  Error = SEPDriver_WriteParamater((DxUint32_t)messageParam,
                            sizeof(DxUint32_t) * 5,
                            sizeof(DxUint32_t) * 5,
                            &sramOffset,
                            DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
  
  /* send client priv key */
  Error = SEPDriver_WriteParamater((DxUint32_t)ClientPrvKey_ptr,
                            ClientPrvKeySize,
                            sizeof(DxUint32_t) * 64,
                            &sramOffset,
                            DX_TRUE);                          
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
   
  /* send param */
  Error = SEPDriver_WriteParamater((DxUint32_t)&messageParam[5],
                            sizeof(DxUint32_t),
                            sizeof(DxUint32_t),
                            &sramOffset,
                            DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                            
  /* send server pub key */
  Error = SEPDriver_WriteParamater((DxUint32_t)ServerPubKey_ptr,
                            ServerPubKeySize,
                            sizeof(DxUint32_t) * 64,
                            &sramOffset,
                            DX_TRUE); 
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                            
  /* send param */
  Error = SEPDriver_WriteParamater((DxUint32_t)&messageParam[6],
                            sizeof(DxUint32_t),
                            sizeof(DxUint32_t),
                            &sramOffset,
                            DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                            
  /* send prime data  */
  Error = SEPDriver_WriteParamater((DxUint32_t)Prime_ptr,
                            PrimeSize,
                            sizeof(DxUint32_t) * 64,
                            &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;
  }
   
  /*-------------------
    start reading message from the SEP 
  ---------------------*/
   
  /* start the message */
  Error = SEPDriver_StartIncomingMessage(&sramOffset);
  if(Error != DX_OK)
  {
  	goto end_function_unlock;
  }
   
  /* read opcode + status  */
  Error = SEPDriver_ReadParamater((DxUint32_t)messageParam,
                            sizeof(DxUint32_t) * 2,
                            sizeof(DxUint32_t) * 2,
                            &sramOffset ,
                            DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
  /* check the opcode */
  if(messageParam[0] != DX_SEP_HOST_SEP_PROTOCOL_HOST_DH_X942_GET_SEC_DATA_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 secret key */
  Error = SEPDriver_ReadParamater((DxUint32_t)SecretKeyData_ptr,
                           (SecretKeyDataSizeBitsNeeded + 7) / 8,
                           sizeof(DxUint32_t) * 64,
                           &sramOffset,
                           DX_TRUE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                             
  
                                 
   /* ...................... end of function ................................ */   

end_function_unlock:   

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

end_function_no_unlock:

  return Error; 
  
  #endif /*CRYS_NO_HASH_SUPPORT*/
  #endif /*CRYS_NO_PKI_SUPPORT*/
}

/****************************************************************/
/**
 * @brief _DX_DH_X942_Hybrid_GetSecretData computes the shared secret key as follows:
 		1. OPTIONAL - validate the correctness of the argument keys
 		2. SecretKey1 = ServerPubKey1 ^ ClientPrvKey1 mod Prime
 		3. SecretKey2 = ServerPubKey2 ^ ClientPrvKey2 mod Prime
 		3. Use of Derivation function to derive a data key from the 2 secret keys 
 
 	The actual APIs that will be used by the user are:
 	CRYS_DH_X942_Hybrid_GetSecret_ASN1_2_Data
 	CRYS_DH_X942_Hybrid_GetSecret_Concat_2_Data
 
  	Note: All buffers arguments are represented in Big-Endian format.
 
  @param[in] UserPubKey_ptr		- A pointer to the public key data structure. Not initialized.
  @param[in] PrimeData_ptr 		- A pointer to a CRYS_RSAPrimeData_t structure 
                                  that is used for the Exp operation
  @param[in] hashFunc			- The hash function to be used
  @param[in] ClientPrvKey_ptr1 	- A pointer to the First Private key octet string number 
  @param[in] ClientPrvKeySize1 	- The First Private key Size, in bytes
  @param[in] ClientPrvKey_ptr2 	- A pointer to the Second Private key octet string
  @param[in] ClientPrvKeySize2 	- The Second Private key Size, in bytes
  @param[in] ServerPubKey_ptr1  - A pointer to the First Server public key octet string
  @param[in] ServerPubKeySize1  - The First Server Public key Size, in bytes
  @param[in] ServerPubKey_ptr2  - A pointer to the Second Server public key octet string
  @param[in] ServerPubKeySize2  - The Second Server Public key Size, in bytes
  @param[in] Prime_ptr 			- A pointer to the Prime octet string
  @param[in] PrimeSize 			- The size of the Prime string
  @param[in] DerFunc_mode 		- The type of function to derive the secret key to the key data.
                                  We use an ASN.1-based function or a Hash concatenation function mode.
  @param[out] SecretKeyData_ptr - A pointer to the secret key octet string.
			  	                  This buffer should be at least 2*PrimeSize bytes.
  							  
  @param[in] SecretKeyDataSizeBitsNeeded - Specifies the derived Secret Key data size needed in Bits. This value converted to bytes 
                                  cannot be larger than PrimeSize

  @return CRYSError_t - On success the value CRYS_OK is returned, 
			and on failure an ERROR as defined in CRYS_DH_error.h
*/
CEXPORT_C CRYSError_t _DX_DH_X942_Hybrid_GetSecretData(CRYS_DHUserPubKey_t*         UserPubKey_ptr,
                                                       CRYS_DHPrimeData_t*          PrimeData_ptr, 
                                                       CRYS_DH_HASH_OpMode_t        hashFunc,		
                                                       DxUint8_t*                   ClientPrvKey_ptr1,
                                                       DxUint16_t                   ClientPrvKeySize1,
                                                       DxUint8_t*                   ClientPrvKey_ptr2,
                                                       DxUint16_t                   ClientPrvKeySize2,				                    
                                                       DxUint8_t*                   ServerPubKey_ptr1,
                                                       DxUint16_t                   ServerPubKeySize1,
                                                       DxUint8_t*                   ServerPubKey_ptr2,
                                                       DxUint16_t                   ServerPubKeySize2,				                    				                    
                                                       DxUint8_t*                   Prime_ptr,
                                                       DxUint16_t                   PrimeSize,
                                                       CRYS_DH_DerivationFunc_Mode  DerFunc_mode,
                                                       DxUint8_t*                   SecretKeyData_ptr,
                                                       DxUint16_t                   SecretKeyDataSizeBitsNeeded)

{
  /* The return error identifier */
  CRYSError_t       Error;
  
  /* sram offset */
  DxUint32_t        sramOffset;
  
  /* message parameters */
  DxUint32_t        messageParam[9];
  
   
  /*-----------------------------
      CODE
  --------------------------------*/
  PrimeData_ptr=PrimeData_ptr;
  UserPubKey_ptr=UserPubKey_ptr;
 
  /* initializing the Error to O.K */
  Error = CRYS_OK;


  #ifndef CRYS_NO_HASH_SUPPORT                                      
  #ifndef CRYS_NO_PKI_SUPPORT                                      
      
  /* ............... checking the parameters validity ................... */
  /* -------------------------------------------------------------------- */

  /*check that the derived secret key needed is not zero*/
  if(SecretKeyDataSizeBitsNeeded == 0)
    return CRYS_DH_SECRET_KEY_SIZE_NEEDED_ERROR;

  /*check that the derived secret key needed is smaller than PrimeSize*/
  if(SecretKeyDataSizeBitsNeeded > PrimeSize*8)
    return CRYS_DH_SECRET_KEY_SIZE_NEEDED_BIGGER_THAN_PRIME_SIZE;
  
  /* if an argument pointer is DX_NULL return an error */
  if( ClientPrvKey_ptr1  == DX_NULL || 
		ServerPubKey_ptr1  == DX_NULL || 
		Prime_ptr         == DX_NULL ||
		UserPubKey_ptr    == DX_NULL ||
		PrimeData_ptr     == DX_NULL || 
		SecretKeyData_ptr     == DX_NULL)
        return CRYS_DH_INVALID_ARGUMENT_POINTER_ERROR; 
        
    /* if an argument pointer is DX_NULL return an error */
  if( ClientPrvKey_ptr2  == DX_NULL || 
		ServerPubKey_ptr2  == DX_NULL || 
		Prime_ptr         == DX_NULL ||
		UserPubKey_ptr    == DX_NULL ||
		PrimeData_ptr     == DX_NULL || 
		SecretKeyData_ptr     == DX_NULL)
        return CRYS_DH_INVALID_ARGUMENT_POINTER_ERROR; 
        

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

	/*----------------------------
    start sending message to SEP 
  -----------------------------*/
  
  sramOffset = 0;
   
  /* start the message */
  SEPDriver_StartMessage(&sramOffset);
  
  /* prepare message */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_DH_X942_GET_HYBRID_SEC_DATA_OP_CODE;
  messageParam[1] = hashFunc;
  messageParam[2] = DerFunc_mode;
  messageParam[3] = SecretKeyDataSizeBitsNeeded;
  messageParam[4] = ClientPrvKeySize1;
  messageParam[5] = ClientPrvKeySize2;
  messageParam[6] = ServerPubKeySize1;
  messageParam[7] = ServerPubKeySize2;
  messageParam[8] = PrimeSize;
  
  /* send params */
  Error = SEPDriver_WriteParamater((DxUint32_t)messageParam,
                            sizeof(DxUint32_t) * 5,
                            sizeof(DxUint32_t) * 5,
                            &sramOffset,
                            DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
  
  /* send client priv key 1 */
  Error = SEPDriver_WriteParamater((DxUint32_t)ClientPrvKey_ptr1,
                            ClientPrvKeySize1,
                            sizeof(DxUint32_t) * 64,
                            &sramOffset,
                            DX_TRUE);                          
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
   
  /* send param */
  Error = SEPDriver_WriteParamater((DxUint32_t)&messageParam[5],
                            sizeof(DxUint32_t),
                            sizeof(DxUint32_t),
                            &sramOffset,
                            DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                            
  /* send client priv key 2 */
  Error = SEPDriver_WriteParamater((DxUint32_t)ClientPrvKey_ptr2,
                            ClientPrvKeySize2,
                            sizeof(DxUint32_t) * 64,
                            &sramOffset,
                            DX_TRUE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                            
  /* send param */
  Error = SEPDriver_WriteParamater((DxUint32_t)&messageParam[6],
                            sizeof(DxUint32_t),
                            sizeof(DxUint32_t),
                            &sramOffset,
                            DX_FALSE); 
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                            
  /* send server pub key 1 */
  Error = SEPDriver_WriteParamater((DxUint32_t)ServerPubKey_ptr1,
                            ServerPubKeySize1,
                            sizeof(DxUint32_t) * 64,
                            &sramOffset,
                            DX_TRUE); 
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                            
  /* send param */
  Error = SEPDriver_WriteParamater((DxUint32_t)&messageParam[7],
                            sizeof(DxUint32_t),
                            sizeof(DxUint32_t),
                            &sramOffset,
                            DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                            
  /* send server pub key 2 */
  Error = SEPDriver_WriteParamater((DxUint32_t)ServerPubKey_ptr2,
                            ServerPubKeySize2,
                            sizeof(DxUint32_t) * 64,
                            &sramOffset,
                            DX_TRUE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                            
  /* send param */
  Error = SEPDriver_WriteParamater((DxUint32_t)&messageParam[8],
                            sizeof(DxUint32_t),
                            sizeof(DxUint32_t),
                            &sramOffset,
                            DX_FALSE); 
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                            
  /* send prime data  */
  Error = SEPDriver_WriteParamater((DxUint32_t)Prime_ptr,
                            PrimeSize,
                            sizeof(DxUint32_t) * 64,
                            &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;
  }
   
  /*-------------------
    start reading message from the SEP 
  ---------------------*/
   
  /* start the message */
  Error = SEPDriver_StartIncomingMessage(&sramOffset);
  if(Error != DX_OK)
  {
  	goto end_function_unlock;
  }
   
  /* read opcode + status  */
  Error = SEPDriver_ReadParamater((DxUint32_t)messageParam,
                            sizeof(DxUint32_t) * 2,
                            sizeof(DxUint32_t) * 2,
                            &sramOffset ,
                            DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
  /* check the opcode */
  if(messageParam[0] != DX_SEP_HOST_SEP_PROTOCOL_HOST_DH_X942_GET_HYBRID_SEC_DATA_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 secret key */
  Error = SEPDriver_ReadParamater((DxUint32_t)SecretKeyData_ptr,
                           (SecretKeyDataSizeBitsNeeded + 7) / 8,
                           sizeof(DxUint32_t) * 64,
                           &sramOffset,
                           DX_TRUE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                             
  
                                 
   /* ...................... end of function ................................ */   

end_function_unlock:   

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

end_function_no_unlock:

  return Error; 
 
  #endif /*CRYS_NO_HASH_SUPPORT*/
  #endif /*CRYS_NO_PKI_SUPPORT*/
 
}
				                    
