
  /*
   *  Object %name    : %
   *  State           :  %state%
   *  Creation date   :  Thu Jan 06 15:21:09 2005
   *  Last modified   :  %modify_time%
   */
  /** @file
   *  \brief A brief description of this module
   *
   *  \version CRYS_RSA_PSS_Sign.c#1:csrc:1
   *  \author ohads
   *  \remarks Copyright (C) 2004 by Discretix Technologies Ltd.
   *           All Rights reserved
   */



/************* Include Files ****************/
#include "DX_VOS_Mem.h"
#include "DX_VOS_Memmap.h"
#include "CRYS_RSA_error.h"
#include "CRYS_RSA_Types.h"
#include "crys_host_op_code.h"
#include "error.h"
#include "SEPDriver.h"
#include "gen.h"

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


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


/************************ Typedefs ******************************/


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


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


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


/**********************************************************************************************************/
/**
   \brief RSA_SignInit initializes the Signing
   multi-call algorithm as defined in PKCS#1 v1.5 and 2.1

	The actual macro that will be used by the user is:
	CRYS_RSA_PSS_SignInit		 - for v2.1
	CRYS_RSA_PKCS1v15_SignInit	 - for v1.5

   This function does not do cryptographic processing. Rather, it
   prepares a context that is used by the Update
   and Finish functions.
   
   @param[in,out] UserContext_ptr - A pointer to a Context. The value
                                returned here must be passed to
                                the Update and Finish functions.
   @param[in] UserPrivKey_ptr - A pointer to the private key data
                            structure. \note The representation
                            (pair or quintuple) and hence the
                            algorithm (CRT or not) is determined
                            by the Private Key data
                            structure -using CRYS_Build_PrivKey
                            or CRYS_Build_PrivKeyCRT determines
                            which algorithm will be used.
   @param[in] hashFunc - The hash function to be used. Currently
                         only CRYS_PKCS1_SHA1 is supported. The
                         other hash functions recommended by PKCS#1
                         v2.1 are SHA-256/284/512.
   @param[in] MGF - The mask generation function. PKCS#1 v2.1
                    defines MGF1, so the only value allowed here is CRYS_PKCS1_MGF1.
   @param[in] SaltLen - The Length of the Salt buffer. relevant for PKCS#1 Ver 2.1 Only
   						Typical lengths are 0 and hLen (20 for SHA1)
   						The maximum length allowed is NSize - hLen - 2                    
   @param[in] PKCS1_ver - Ver 1.5 or 2.1, according to the functionality required
                       
   @return CRYSError_t - CRYS_OK, CRYS_BAD_PARAM
*/

CEXPORT_C CRYSError_t _DX_RSA_SignInit(CRYS_RSAPrivUserContext_t*   UserContext_ptr,
                                       CRYS_RSAUserPrivKey_t*       UserPrivKey_ptr,
                                       CRYS_RSA_HASH_OpMode_t       hashFunc,
                                       CRYS_PKCS1_MGF_t             MGF,
                                       DxUint16_t                   SaltLen,				  				  
                                       CRYS_PKCS1_version           PKCS1_ver)
{
  /* The return error identifier */
  CRYSError_t Error;
  
  /* offset */
  DxUint32_t  sramOffset;
  
  /* param read */
  DxUint32_t  messageParam[5];
  
  /* max length */
  DxUint32_t  maxLength;
   
  /*------------------------
      CODE
  --------------------------*/
   
  Error = CRYS_OK;

  #ifndef CRYS_NO_HASH_SUPPORT                                      
  #ifndef CRYS_NO_PKI_SUPPORT                                      
      
  /* ............... checking the parameters validity ................... */
   
  /* if the users context ID pointer is DX_NULL return an error */
  if( UserContext_ptr == DX_NULL )
  {
    Error = CRYS_RSA_INVALID_USER_CONTEXT_POINTER_ERROR;
    goto end_function;
  }
   
  /*if the private key object is DX_NULL return an error*/   
  if (UserPrivKey_ptr == DX_NULL)
  {
    Error = CRYS_RSA_INVALID_PRIV_KEY_STRUCT_POINTER_ERROR;
    goto end_function;
  }
   	  
  /* check if the hash operation mode is legal */
  if( hashFunc >= CRYS_RSA_HASH_NumOfModes)
  {
    Error = CRYS_RSA_HASH_ILLEGAL_OPERATION_MODE_ERROR;
    goto end_function;
  }
     
  /* check if the MGF operation mode is legal */   
  if(MGF >= CRYS_RSA_NumOfMGFFunctions)
  {
    Error = CRYS_RSA_MGF_ILLEGAL_ARG_ERROR;
    goto end_function;
  }
    
  /* check that the PKCS1 version argument is legal*/
  if(PKCS1_ver >= CRYS_RSA_NumOf_PKCS1_versions)
  {
    Error = CRYS_RSA_PKCS1_VER_ARG_ERROR;
    goto end_function;
  }

  /*According to the PKCS1 ver 2.1 standart it is not recommended to use MD5 hash
  therefore we do not support it */
  if(PKCS1_ver == CRYS_PKCS1_VER21 && hashFunc == CRYS_RSA_HASH_MD5_mode)
  {
    Error = CRYS_RSA_HASH_ILLEGAL_OPERATION_MODE_ERROR;
    goto end_function;
  }
  
   /* lock access to the SEP */
   Error = SEPDriver_Lock();
   
   if(Error != DX_OK)
   {
       goto end_function;
   }
  
  /*----------------------------
      start sending message to SEP 
  -----------------------------*/
  sramOffset = 0;
   
  /* start the message */
  SEPDriver_StartMessage(&sramOffset);
  
  /* prepare message */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_RSA_SIGN_INIT_OP_CODE;
  messageParam[1] = hashFunc;
  messageParam[2] = MGF;
  messageParam[3] = SaltLen;
  messageParam[4] = PKCS1_ver;
  
  /* 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 private key */
  maxLength = ((sizeof(CRYS_RSAUserPrivKey_t) + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t); 
  Error = SEPDriver_WriteParamater((DxUint32_t)UserPrivKey_ptr ,
                            sizeof(CRYS_RSAUserPrivKey_t),
                            maxLength,
                            &sramOffset,
                            DX_TRUE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
  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_RSA_SIGN_INIT_OP_CODE)
  {
    Error = DX_WRONG_OPCODE_FROM_SEP_ERR;
    goto end_function_unlock;
  }
   
  /* check the status */
  if(messageParam[1] != CRYS_OK)
  {
    Error = messageParam[1];
    goto end_function_unlock;
  }
   
  /* read the context */
  maxLength = ((sizeof(CRYS_RSAPrivUserContext_t) + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t); 
  Error = SEPDriver_ReadParamater((DxUint32_t)UserContext_ptr,
                                           sizeof(CRYS_RSAPrivUserContext_t),
                                           maxLength,
                                           &sramOffset,
                                           DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                                           
  /* ...................... end of function ................................ */   

end_function_unlock:   

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

  return Error;

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

}/* _DX_RSA_SignInit */
				  
/**********************************************************************************************************/
/**
   \brief CRYS_RSA_PSS_SignUpdate processes the data to be signed
   in a given context.

   \note RSA_PSS_SignUpdate can be called multiple times
   with data 
   
	The actual macro that will be used by the users is (one of):
	CRYS_RSA_PSS_SignUpdate
	CRYS_RSA_PKCS1v15_SignUpdate

   \note CRYS_RSA_PSS_SignUpdate can be called multiple times
   with data 

   @param[in] UserContext_ptr - A pointer to a valid context,
                            as returned by CRYS_RSA_PSS_SignInit.
   @param[in] DataIn_ptr - A pointer to the data to sign.
   @param[in] DataInSize - The size, in bytes, of the data to sign.

   @return CRYSError_t - CRYS_OK, CRYS_BAD_PARAM
*/

CEXPORT_C CRYSError_t _DX_RSA_SignUpdate(CRYS_RSAPrivUserContext_t*   UserContext_ptr,
                                         DxUint8_t*                   DataIn_ptr,
                                         DxUint32_t                   DataInSize)
{
  /* The return error identifier */
  CRYSError_t         Error;
   
  /* address of the first table in the input list */
  DxUint32_t          inputLLITableAddr;
   
  /* number of entries in each of the first tables */
  DxUint32_t          numEntriesInTable;
  
  /* first table data size */
  DxUint32_t          firstTableDataSize;
  
  /* offset */
  DxUint32_t          sramOffset;
  
  /* read parameter */
  DxUint32_t          messageParam[4]; 
  
  /* max length */
  DxUint32_t          maxLength;      
  
  /* hash mode */
  CRYS_RSA_HASH_OpMode_t  hashOperationMode;
  
  /* temp user context pointer */
  CRYS_HASHUserContext_t	 *hashUserContext_ptr;
  
  /* number of bytes to upate */
  DxUint32_t 		numBytesToUpdate;
  
  /* number of into the message from the start of user buffer */
  DxUint32_t              numBytesFromStart;
  
  /* number of into the message from the start of user buffer */
  DxUint32_t              numBytesFromEnd;
  
  /* block size */
  DxUint32_t              blockSize;      

  /*-------------------
    CODE
  --------------------*/
  
  Error = CRYS_OK;      

                       
  #ifndef CRYS_NO_HASH_SUPPORT                                      
  #ifndef CRYS_NO_PKI_SUPPORT                                      
   
  /* ............... checking the parameters validity ................... */
   
  /* if the users context pointer is DX_NULL return an error */
  if( UserContext_ptr == DX_NULL )
  {
    Error = CRYS_RSA_INVALID_USER_CONTEXT_POINTER_ERROR;
    goto end_function;
  }
   
  /* if the users Data In pointer is illegal return an error */
  if( DataIn_ptr == DX_NULL && DataInSize )
  {
    Error = CRYS_RSA_DATA_POINTER_INVALID_ERROR;
    goto end_function;
  }
    
  /* if the data size is larger then 2^29 (to prevant an overflow on the transition to bits ) 
     return error */
  if( DataInSize >= (1 << 29) )
  {
    Error = CRYS_RSA_INVALID_MESSAGE_DATA_SIZE;
    goto end_function;
  }
  
  /* lock access to the SEP */
  Error = SEPDriver_Lock();
   
  if(Error != DX_OK)
  {
    goto end_function;
  }
  
  /* get the hash operation mode */
  hashOperationMode = ((RSAPrivContext_t *)UserContext_ptr->context_buff)->HashOperationMode;
  
  /* get the hash user context */
  hashUserContext_ptr = &((RSAPrivContext_t *)UserContext_ptr->context_buff)->HashUserContext;
  
  /* get the number of bytes to update */ 
  numBytesToUpdate = ((HASHContext_t *)hashUserContext_ptr->context_buff)->NumOfBytesOnThePreviousUpdateBuff;
   
  /* get block size */
  switch (hashOperationMode)
  {
  	case CRYS_RSA_HASH_SHA1_mode:
  	case CRYS_RSA_HASH_SHA224_mode:
  	case CRYS_RSA_HASH_SHA256_mode:
  	case CRYS_RSA_HASH_MD5_mode:
  		blockSize = CRYS_HASH_BLOCK_SIZE_IN_BYTES;
  		break;
  	case CRYS_RSA_HASH_SHA384_mode:
  	case CRYS_RSA_HASH_SHA512_mode:
  		blockSize = CRYS_HASH_SHA2_BLOCK_SIZE_IN_BYTES;
  		break;
  	case CRYS_RSA_After_MD5_mode:
  		blockSize = CRYS_HASH_MD5_DIGEST_SIZE_IN_BYTES;
  		break;
  	case CRYS_RSA_After_SHA1_mode:
  		blockSize = CRYS_HASH_SHA1_DIGEST_SIZE_IN_BYTES;
  		break;
  	case CRYS_RSA_After_SHA224_mode:
  		blockSize = CRYS_HASH_SHA224_DIGEST_SIZE_IN_BYTES;
  		break;
  	case CRYS_RSA_After_SHA256_mode:
  		blockSize = CRYS_HASH_SHA256_DIGEST_SIZE_IN_BYTES;
  		break;
  	case CRYS_RSA_After_SHA384_mode:
  		blockSize = CRYS_HASH_SHA384_DIGEST_SIZE_IN_BYTES;
  		break;
  	case CRYS_RSA_After_SHA512_mode:
  		blockSize = CRYS_HASH_SHA512_DIGEST_SIZE_IN_BYTES;
  		break;
  	default:
  		return CRYS_RSA_HASH_ILLEGAL_OPERATION_MODE_ERROR;
  }
  
  
  /* check if we're in after hash mode. if not - calculate numBytesFromStart, DMA tables and numBytesFromEnd */
  if (hashOperationMode >= CRYS_RSA_HASH_MD5_mode && hashOperationMode  <= CRYS_RSA_HASH_SHA512_mode)
  {
    /* get the number of bytes from the beginning of the user buffer into the message */
    numBytesFromStart = (blockSize - numBytesToUpdate) % blockSize;
    if(DataInSize < numBytesFromStart)
    {
      numBytesFromStart = DataInSize;
    }

    /* get the number of bytes from the beginning of the user buffer into the message */
    numBytesFromEnd = (DataInSize - numBytesFromStart) % blockSize;

  }
  else /* After hash mode */
  {
  	numBytesFromEnd = 0;
  	
  	/* set data size to the first block */
  	numBytesFromStart = DataInSize;  	
  }
  
  /* prepare tables for the input only */
  Error = SEPDriver_PREPARE_INPUT_SYM_DMA_TABLE((DxUint32_t)(DataIn_ptr + numBytesFromStart), 
                                                            DataInSize - (numBytesFromStart + numBytesFromEnd),
                                                            blockSize,
                                                            &inputLLITableAddr, 
                                                            &numEntriesInTable,
                                                            &firstTableDataSize ) ; 
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
  
  /*----------------------------
      start sending message to SEP 
  -----------------------------*/
  sramOffset = 0;
   
  /* start the message */
  SEPDriver_StartMessage(&sramOffset);
  
  /* prepare message */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_RSA_SIGN_UPDATE_OP_CODE;
  messageParam[1] = inputLLITableAddr;
  messageParam[2] = numEntriesInTable;
  messageParam[3] = firstTableDataSize;
  
  /* 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 the size of the first part of the input buffer */
  Error = SEPDriver_WriteParamater((DxUint32_t)&numBytesFromStart,
                                   sizeof(DxUint32_t),
                                   sizeof(DxUint32_t),
                                   &sramOffset , 
                                   DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
  
  /* send the first part of the input buffer */
  Error = SEPDriver_WriteParamater((DxUint32_t)DataIn_ptr,
                                   numBytesFromStart,
                                   sizeof(DxUint32_t) * 32,
                                   &sramOffset , 
                                   DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
  
  /* send the size of the last part of the input buffer */
  Error = SEPDriver_WriteParamater((DxUint32_t)&numBytesFromEnd,
                                   sizeof(DxUint32_t),
                                   sizeof(DxUint32_t),
                                   &sramOffset , 
                                   DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
  
  /* send the last part of the input buffer */
  Error = SEPDriver_WriteParamater((DxUint32_t)(DataIn_ptr + DataInSize - numBytesFromEnd),
                                   numBytesFromEnd,
                                   sizeof(DxUint32_t) * 32,
                                   &sramOffset , 
                                   DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
  
  /* send context */
  maxLength = ((sizeof(CRYS_RSAPrivUserContext_t) + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t); 
  Error = SEPDriver_WriteParamater((DxUint32_t)UserContext_ptr , 
                            sizeof(CRYS_RSAPrivUserContext_t) ,
                            maxLength, 
                            &sramOffset , 
                            DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
  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 
  ---------------------*/
  
  /* free allocated tables */
  Error = SEPDriver_FreeDMATables();
  if(Error != DX_OK)
  {
  	goto end_function_unlock;
  }
   
  /* start the message */
  Error = SEPDriver_StartIncomingMessage(&sramOffset);
  if(Error != DX_OK)
  {
  	goto end_function_unlock;
  }
   
  /* read opcode + status */
  Error = SEPDriver_ReadParamater((DxUint32_t)messageParam ,
                          sizeof(DxUint32_t) * 2,
                          sizeof(DxUint32_t) * 2,
                          &sramOffset , 
                          DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
  /* check the opcode */
  if(messageParam[0] != DX_SEP_HOST_SEP_PROTOCOL_HOST_RSA_SIGN_UPDATE_OP_CODE)
  {
    Error = DX_WRONG_OPCODE_FROM_SEP_ERR;
    goto end_function_unlock;
  }
   
  /* check the status */
  if(messageParam[1] != CRYS_OK)
  {
    Error = messageParam[1];
    goto end_function_unlock;
  }
   
  /* read the context */
  maxLength = ((sizeof(CRYS_RSAPrivUserContext_t) + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t);  
  Error = SEPDriver_ReadParamater((DxUint32_t)UserContext_ptr,
                           sizeof(CRYS_RSAPrivUserContext_t),
                           maxLength,
                           &sramOffset,
                           DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }

                                          
end_function_unlock:

  /* unlock access to the SEP */
  SEPDriver_Unlock();                                          
                                                 
end_function:

  return Error;

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

}/* _DX_RSA_SignUpdate */


/**********************************************************************************************************/
/**
   \brief _DX_RSA_SignFinish calculates the signature on the
   data passed to one or more calls to CRYS_RSA_PSS_SignUpdate,
   and releases the context.

	The actual macro that will be used by the user is:
	CRYS_RSA_PSS_SignFinish			- for v2.1
	CRYS_RSA_PKCS1v15_SignFinish	- for v1.5
	
   @param[in,out] UserContext_ptr - A pointer to the Context
                                initialized by the SignInit function 
                                and used by the SignUpdate function
   @param[out] Output_ptr - A pointer to the signature. 
                            The buffer must be at least PrivKey_ptr->N.len bytes long 
                            (that is, the size of the modulus, in bytes).
   @param[in,out] OutputSize_ptr - A pointer to the Signature Size value - the input value
                                   is the signature buffer size allocated, the output value is 
                                   the signature size used.
                                   The buffer must be at least PrivKey_ptr->N.len bytes long 
                                   (that is, the size of the modulus, in bytes).

   @return CRYSError_t - CRYS_OK,
                         CRYS_RSA_INVALID_USER_CONTEXT_POINTER_ERROR,
                         CRYS_RSA_USER_CONTEXT_VALIDATION_TAG_ERROR,
                         CRYS_RSA_INVALID_OUTPUT_POINTER_ERROR,
                         CRYS_RSA_INVALID_SIGNATURE_BUFFER_SIZE,
                         CRYS_RSA_HASH_ILLEGAL_OPERATION_MODE_ERROR,
                         CRYS_RSA_PKCS1_VER_ARG_ERROR
*/

CEXPORT_C CRYSError_t _DX_RSA_SignFinish(CRYS_RSAPrivUserContext_t*   UserContext_ptr,
                                         DxUint8_t*                   Output_ptr,
                                         DxUint16_t*                  OutputSize_ptr)  
{
  /* The return error identifier */
  CRYSError_t Error;
  
   /* offset */
  DxUint32_t  sramOffset;
  
  /* read parameter */
  DxUint32_t  messageParam[2]; 
  
  /* max length */
  DxUint32_t  maxLength;    

  /*-----------------------
      CODE
  ------------------------*/
   
  Error = CRYS_OK;      

  #ifndef CRYS_NO_HASH_SUPPORT                                      
  #ifndef CRYS_NO_PKI_SUPPORT                                      
   
  /* ............... checking the parameters validity ................... */
   
  /* if the users context pointer is DX_NULL return an error */
  if( UserContext_ptr == DX_NULL )
  {
    Error = CRYS_RSA_INVALID_USER_CONTEXT_POINTER_ERROR;
    goto end_function;
  }
      
  /*If the output pointer is DX_NULL return Error*/   
  if(Output_ptr == DX_NULL)
  {
    Error = CRYS_RSA_INVALID_OUTPUT_POINTER_ERROR;
    goto end_function;
  }
   	     	        
  /*If the output Size pointer is DX_NULL return Error*/   
  if(OutputSize_ptr == DX_NULL)
  {
    Error = CRYS_RSA_INVALID_OUTPUT_SIZE_POINTER_ERROR;
    goto end_function;
  }
   	  
   /* lock access to the SEP */
   Error = SEPDriver_Lock();
   
   if(Error != DX_OK)
   {
       goto end_function;
   }
  
  /*----------------------------
      start sending message to SEP 
  -----------------------------*/
  sramOffset = 0;
  
  /* start the message */
  SEPDriver_StartMessage(&sramOffset);
  
  /* send opcode */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_RSA_SIGN_FINISH_OP_CODE;
  Error = SEPDriver_WriteParamater((DxUint32_t)messageParam , 
                           sizeof(DxUint32_t),
                           sizeof(DxUint32_t),
                           &sramOffset , 
                           DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
  
  /* send context */
  maxLength = ((sizeof(CRYS_RSAPrivUserContext_t) + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t); 
  Error = SEPDriver_WriteParamater((DxUint32_t)UserContext_ptr , 
                            sizeof(CRYS_RSAPrivUserContext_t) , 
                            maxLength,
                            &sramOffset , 
                            DX_FALSE); 
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
  
  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_RSA_SIGN_FINISH_OP_CODE)
  {
    Error = DX_WRONG_OPCODE_FROM_SEP_ERR;
    goto end_function_unlock;
  }
   
  /* check the status */
  if(messageParam[1] != CRYS_OK)
  {
    Error = messageParam[1];
    goto end_function_unlock;
  }
  
  /* read size out data */
  
  Error = SEPDriver_ReadParamater((DxUint32_t)messageParam , 
                          sizeof(DxUint32_t),
                          sizeof(DxUint32_t),
                          &sramOffset , 
                          DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
  
  if (*OutputSize_ptr < (DxUint16_t)messageParam[0])
  {
    Error = CRYS_RSA_INVALID_SIGNATURE_BUFFER_SIZE;
    goto end_function_unlock;
  }
  
  /* set output paramater */
  *OutputSize_ptr =  (DxUint16_t)messageParam[0];                       
  
  
  /* read the result */
  maxLength = ((*OutputSize_ptr + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t); 
  Error = SEPDriver_ReadParamater((DxUint32_t)Output_ptr,
                           *OutputSize_ptr,
                           maxLength,
                           &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:

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

/**********************************************************************************************************/
/**
   @brief
   RSA_Sign implements the Signing algorithm as defined
   in PKCS#1 v1.5 or v2.1, using a single function

   The actual macros that will be used by the user are:
   CRYS_RSA_PKCS1v15_Sign		- for v1.5
   CRYS_RSA_PKCS1v15_SHA1_Sign	- for v1.5 data is hashed with SHA1
   CRYS_RSA_PKCS1v15_MD5_Sign	- for v1.5 data is hashed with MD5
   CRYS_RSA_PSS_Sign			- for v2.1
   CRYS_RSA_PSS_SHA1_Sign		- for v2.1 data is hashed with SHA1
					- for v2.1 MD5 is not supported, since 
					according to the PKCS#1 ver2.1 it is not recommended
   
   @param[in] UserContext_ptr - A pointer to a Context. For the use of the 
   								function as a space to work on.
   @param[in] UserPrivKey_ptr - A pointer to the private key data
                            structure of the user. \note The representation
                            (pair or quintuple) and hence the
                            algorithm (CRT or not) is determined
                            by the Private Key data
                            structure - using CRYS_Build_PrivKey
                            or CRYS_Build_PrivKeyCRT determines
                            which algorithm will be used.
   @param[in] hashFunc - The hash function to be used. Currently
                         only CRYS_PKCS1_SHA1 and CRYS_PKCS1_MD5
                         are supported. 
   @param[in] MGF - The mask generation function. Only for PKCS#1 v2.1
                    defines MGF1, so the only value allowed for v2.1 
                    is CRYS_PKCS1_MGF1. 
   @param[in] SaltLen - The Length of the Salt buffer. relevant for PKCS#1 Ver 2.1 Only
   						Typical lengths are 0 and hLen (20 for SHA1)
   						The maximum length allowed is NSize - hLen - 2                                                                                       
   @param[in] DataIn_ptr - A pointer to the data to sign.
   @param[in] DataInSize - The size, in bytes, of the data to sign.
   @param[out] Output_ptr - A pointer to the signature. 
                            The buffer must be at least PrivKey_ptr->N.len bytes long 
                            (that is, the size of the modulus in bytes).
   @param[in,out] OutputSize_ptr - A pointer to the Signature Size value - the input value
                            is the signature buffer size allocated, the output value is 
                            the signature size actually used.
                            The buffer must be at least PrivKey_ptr->N.len bytes long 
                            (that is, the size of the modulus in bytes).
   @param[in] PKCS1_ver - Ver 1.5 or 2.1, according to the functionality required
      
   @return CRYSError_t - CRYS_OK,
                         CRYS_RSA_INVALID_USER_CONTEXT_POINTER_ERROR,
                         CRYS_RSA_INVALID_PRIV_KEY_STRUCT_POINTER_ERROR,
                         CRYS_RSA_PRIV_KEY_VALIDATION_TAG_ERROR,
                         CRYS_RSA_HASH_ILLEGAL_OPERATION_MODE_ERROR,
                         CRYS_RSA_MGF_ILLEGAL_ARG_ERROR,
                         CRYS_RSA_PKCS1_VER_ARG_ERROR,
                         CRYS_RSA_INVALID_MESSAGE_DATA_SIZE,
                         CRYS_RSA_INVALID_OUTPUT_POINTER_ERROR,
                         CRYS_RSA_INVALID_SIGNATURE_BUFFER_SIZE
*/


CEXPORT_C CRYSError_t _DX_RSA_Sign(CRYS_RSAPrivUserContext_t*   UserContext_ptr,
                                   CRYS_RSAUserPrivKey_t*       UserPrivKey_ptr,
                                   CRYS_RSA_HASH_OpMode_t       hashFunc,
                                   CRYS_PKCS1_MGF_t             MGF,
                                   DxUint16_t                   SaltLen,				  				  			      
                                   DxUint8_t*                   DataIn_ptr,
                                   DxUint32_t                   DataInSize,
                                   DxUint8_t*                   Output_ptr,
                                   DxUint16_t*                  OutputSize_ptr,
                                   CRYS_PKCS1_version           PKCS1_ver)

{
  /* The return error identifier */
  CRYSError_t         Error;
   
  /* address of the first table in the input list */
  DxUint32_t          inputLLITableAddr;
   
  /* number of entries in each of the first tables */
  DxUint32_t          numEntriesInTable;
  
  /* first table data size */
  DxUint32_t          firstTableDataSize;
  
  /* offset */
  DxUint32_t          sramOffset;
  
  /* read parameter */
  DxUint32_t          messageParam[8]; 
  
  /* max length */
  DxUint32_t          maxLength;
  
  /* number of into the message from the start of user buffer */
  DxUint32_t          numBytesFromStart;
  
  /* number of into the message from the start of user buffer */
  DxUint32_t          numBytesFromEnd;
  
  /* block size */
  DxUint32_t          blockSize; 
  
  

  /*----------------------
      CODE
  ------------------------*/
  
  UserContext_ptr=UserContext_ptr;
  
  Error = CRYS_OK;      
                   
  #ifndef CRYS_NO_HASH_SUPPORT                                      
  #ifndef CRYS_NO_PKI_SUPPORT 
  
  /* if the users context ID pointer is DX_NULL return an error */
  if( UserContext_ptr == DX_NULL )
  {
    Error = CRYS_RSA_INVALID_USER_CONTEXT_POINTER_ERROR;
    goto end_function;
  }
  /*if the private key object is DX_NULL return an error*/   
  if (UserPrivKey_ptr == DX_NULL)
  {
    Error = CRYS_RSA_INVALID_PRIV_KEY_STRUCT_POINTER_ERROR;
    goto end_function;
  }
   	  
  /* check if the hash operation mode is legal */
  if( hashFunc >= CRYS_RSA_HASH_NumOfModes)
  {
    Error = CRYS_RSA_HASH_ILLEGAL_OPERATION_MODE_ERROR;
    goto end_function;
  }
     
  /* check if the MGF operation mode is legal */   
  if(MGF >= CRYS_RSA_NumOfMGFFunctions)
  {
    Error = CRYS_RSA_MGF_ILLEGAL_ARG_ERROR;
    goto end_function;
  }
    
  /* check that the PKCS1 version argument is legal*/
  if(PKCS1_ver >= CRYS_RSA_NumOf_PKCS1_versions)
  {
    Error = CRYS_RSA_PKCS1_VER_ARG_ERROR;
    goto end_function;
  }

  /*According to the PKCS1 ver 2.1 standart it is not recommended to use MD5 hash
  therefore we do not support it */
  if(PKCS1_ver == CRYS_PKCS1_VER21 && hashFunc == CRYS_RSA_HASH_MD5_mode)
  {
    Error = CRYS_RSA_HASH_ILLEGAL_OPERATION_MODE_ERROR;
    goto end_function;
  }
  
  /* if the users Data In pointer is illegal return an error */
  if( DataIn_ptr == DX_NULL && DataInSize )
  {
    Error = CRYS_RSA_DATA_POINTER_INVALID_ERROR;
    goto end_function;
  }
    
  /* if the data size is larger then 2^29 (to prevant an overflow on the transition to bits ) 
     return error */
  if( DataInSize >= (1 << 29) )
  {
    Error = CRYS_RSA_INVALID_MESSAGE_DATA_SIZE;
    goto end_function;
  } 
  
  /*If the output pointer is DX_NULL return Error*/   
  if(Output_ptr == DX_NULL)
  {
    Error = CRYS_RSA_INVALID_OUTPUT_POINTER_ERROR;
    goto end_function;
  }
   	     	        
  /*If the output Size pointer is DX_NULL return Error*/   
  if(OutputSize_ptr == DX_NULL)
  {
    Error = CRYS_RSA_INVALID_OUTPUT_SIZE_POINTER_ERROR;
    goto end_function;
  }
  
  /* lock access to the SEP */
  Error = SEPDriver_Lock();
   
  if(Error != DX_OK)
  {
     goto end_function;
  }
  
  /* get block size */
  switch (hashFunc)
  {
  	case CRYS_RSA_HASH_SHA1_mode:
  	case CRYS_RSA_HASH_SHA224_mode:
  	case CRYS_RSA_HASH_SHA256_mode:
  	case CRYS_RSA_HASH_MD5_mode:
  		blockSize = CRYS_HASH_BLOCK_SIZE_IN_BYTES;
  		break;
  	case CRYS_RSA_HASH_SHA384_mode:
  	case CRYS_RSA_HASH_SHA512_mode:
  		blockSize = CRYS_HASH_SHA2_BLOCK_SIZE_IN_BYTES;
  		break;
  	case CRYS_RSA_After_MD5_mode:
  		blockSize = CRYS_HASH_MD5_DIGEST_SIZE_IN_BYTES;
  		break;
  	case CRYS_RSA_After_SHA1_mode:
  		blockSize = CRYS_HASH_SHA1_DIGEST_SIZE_IN_BYTES;
  		break;
  	case CRYS_RSA_After_SHA224_mode:
  		blockSize = CRYS_HASH_SHA224_DIGEST_SIZE_IN_BYTES;
  		break;
  	case CRYS_RSA_After_SHA256_mode:
  		blockSize = CRYS_HASH_SHA256_DIGEST_SIZE_IN_BYTES;
  		break;
  	case CRYS_RSA_After_SHA384_mode:
  		blockSize = CRYS_HASH_SHA384_DIGEST_SIZE_IN_BYTES;
  		break;
  	case CRYS_RSA_After_SHA512_mode:
  		blockSize = CRYS_HASH_SHA512_DIGEST_SIZE_IN_BYTES;
  		break;
  	default:
  		return CRYS_RSA_HASH_ILLEGAL_OPERATION_MODE_ERROR;
  }
  
  if (DataInSize <= blockSize)
  {
    /* set start input as data in size */
    numBytesFromStart = DataInSize;
    
    /* set end part to zero */
    numBytesFromEnd = 0;
    
  }
  else
  {
    /* set start part to zero */
    numBytesFromStart = 0;
  
    /* get the number of bytes from the end of the user buffer into the message */
    numBytesFromEnd = DataInSize % blockSize;
  }
  
  /* prepare tables for the input only */
  Error = SEPDriver_PREPARE_INPUT_SYM_DMA_TABLE((DxUint32_t)(DataIn_ptr + numBytesFromStart),
                                                            DataInSize - (numBytesFromStart + numBytesFromEnd),
                                                            blockSize,
                                                            &inputLLITableAddr,
                                                            &numEntriesInTable,
                                                            &firstTableDataSize ) ; 
     
  if(Error != DX_OK)
  {
    goto end_function_unlock;
  }                                    

  /*----------------------------
      start sending message to SEP 
  -----------------------------*/
  sramOffset = 0;
   
  /* start the message */
  SEPDriver_StartMessage(&sramOffset);
  
  /* prepare message */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_RSA_SIGN_OP_CODE;
  messageParam[1] = hashFunc;
  messageParam[2] = MGF;
  messageParam[3] = SaltLen;
  messageParam[4] = PKCS1_ver;
  messageParam[5] = inputLLITableAddr;
  messageParam[6] = numEntriesInTable;
  messageParam[7] = firstTableDataSize;
  
  /* send params */
  Error = SEPDriver_WriteParamater((DxUint32_t)messageParam , 
                           sizeof(DxUint32_t) * 8,
                           sizeof(DxUint32_t) * 8,
                           &sramOffset , 
                           DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
  
  /* send the size of the first part of the input buffer */
  Error = SEPDriver_WriteParamater((DxUint32_t)&numBytesFromStart,
                                   sizeof(DxUint32_t),
                                   sizeof(DxUint32_t),
                                   &sramOffset , 
                                   DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
  
  /* send the first part of the input buffer */
  Error = SEPDriver_WriteParamater((DxUint32_t)DataIn_ptr,
                                   numBytesFromStart,
                                   sizeof(DxUint32_t) * 32,
                                   &sramOffset , 
                                   DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
  
  /* send the size of the last part of the input buffer */
  Error = SEPDriver_WriteParamater((DxUint32_t)&numBytesFromEnd,
                                   sizeof(DxUint32_t),
                                   sizeof(DxUint32_t),
                                   &sramOffset , 
                                   DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
  
  /* send the last part of the input buffer */
  Error = SEPDriver_WriteParamater((DxUint32_t)(DataIn_ptr + DataInSize - numBytesFromEnd),
                                   numBytesFromEnd,
                                   sizeof(DxUint32_t) * 32,
                                   &sramOffset , 
                                   DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
  /* send private key */
  maxLength = ((sizeof(CRYS_RSAUserPrivKey_t) + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t); 
  Error = SEPDriver_WriteParamater((DxUint32_t)UserPrivKey_ptr ,
                            sizeof(CRYS_RSAUserPrivKey_t),
                            maxLength,
                            &sramOffset,
                            DX_TRUE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                                            
  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 
  ---------------------*/
  
  /* free allocated tables */
  Error = SEPDriver_FreeDMATables();
  if(Error != DX_OK)
  {
  	goto end_function_unlock;
  }

  /* start the message */
  Error = SEPDriver_StartIncomingMessage(&sramOffset);
  if(Error != DX_OK)
  {
  	goto end_function_unlock;
  }
   
  /* read opcode + status  */
  Error = SEPDriver_ReadParamater((DxUint32_t)messageParam,
                          sizeof(DxUint32_t) * 2,
                          sizeof(DxUint32_t) * 2,
                          &sramOffset , 
                          DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
   
  /* check the opcode */
  if(messageParam[0] != DX_SEP_HOST_SEP_PROTOCOL_HOST_RSA_SIGN_OP_CODE)
  {
    Error = DX_WRONG_OPCODE_FROM_SEP_ERR;
    goto end_function_unlock;
  }
   
  /* check the status */
  if(messageParam[1] != CRYS_OK)
  {
    Error = messageParam[1];
    goto end_function_unlock;
  }
   
   /* read size out data */
  Error = SEPDriver_ReadParamater((DxUint32_t)messageParam , 
                          sizeof(DxUint32_t),
                          sizeof(DxUint32_t),
                          &sramOffset , 
                          DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                          
  if (*OutputSize_ptr < (DxUint16_t)messageParam[0])
  {
    Error = CRYS_RSA_INVALID_SIGNATURE_BUFFER_SIZE;
    goto end_function_unlock;
  }
    
  *OutputSize_ptr = (DxUint16_t)messageParam[0];
  
  /* read the result */
  maxLength = ((*OutputSize_ptr + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t); 
  Error = SEPDriver_ReadParamater((DxUint32_t)Output_ptr,
                           *OutputSize_ptr,
                            maxLength,
                            &sramOffset,
                            DX_TRUE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                                           
end_function_unlock:

  /* unlock access to the SEP */
  SEPDriver_Unlock();                                          
                                                 
end_function:

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

}/* END OF _DX_RSA_Sign */
