
  /*
   *  Object %name    : %
   *  State           :  %state%
   *  Creation date   :  Thu Jan 13 14:18:07 2005
   *  Last modified   :  %modify_time%
   */
  /** @file
   *  \brief This file holds the c code of the OAEP functions as described 
   *	in the specs of PKCS#1 Ver 1.5 and 2.1
   *
   *  \version CRYS_RSA_OAEP.c#1:csrc:2
   *  \author ohads
   *  \remarks Copyright (C) 2004 by Discretix Technologies Ltd.
   *           All Rights reserved
   */



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

#include <linux/module.h>
#include "CRYS_RSA_error.h"
#include "CRYS_RND_error.h"
#include "CRYS_HASH_error.h"
#include "CRYS_RND.h"
#include "CRYS_RSA_Types.h"
#include "CRYS_RSA_PRIM.h"
#include "CRYS_HASH.h"
#include "error.h"
#include "host_op_code.h"
#include "SEPDriver.h"

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


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


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


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






/**********************************************************************************************************/

/**
   @brief
   RSA_SCHEMES_Encrypt implements the RSAES-OAEP algorithm as defined
   in PKCS#1 v2.1 8.1 and in PKCS#1 v1.5 8.1

   This function combines the RSA encryption primitive and the
   EME-OAEP encoding method, to provide an RSA-based encryption
   method that is semantically secure against adaptive
   chosen-ciphertext attacks. For more details, please refere to
   the PKCS#1 standard.

   @param[in] PubKey_ptr - Pointer to the public key data structure.
   @param[in] PrimeData_ptr - Pointer to a CRYS_RSAPrimeData_t which is used for the 
   							Encryption operation
   @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] L - The label input. relevant for PKCS#1 Ver2.1
                  Version 2.1 of the standard defines the default value for L as the empty string, 
   @param[in] Llen - The label length. relevant for PKCS#1 Ver2.1
                  Version 2.1 of the standard defines the default value for Llen as zero, 
   @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] Data_ptr - Pointer to the data to encrypt.
   @param[in] DataSize - The size, in bytes, of the data to
                         encrypt. \note Must be <= (modulus_size - 2*Hash_output_length - 2).

   @param[out] Output_ptr - Pointer to the encrypted data, the buffer
                            must be at least PubKey_ptr->N.len
                            bytes long (that is, the size of the
                            modulus, in bytes).

   @return CRYSError_t - CRYS_OK, CRYS_BAD_PARAM, CRYS_OUT_OF_RANGE
*/

CEXPORT_C CRYSError_t _DX_RSA_SCHEMES_Encrypt(CRYS_RSAUserPubKey_t*   UserPubKey_ptr,
                                              CRYS_RSAPrimeData_t*    PrimeData_ptr,
                                              CRYS_RSA_HASH_OpMode_t  hashFunc,
                                              DxUint8_t*              L,
                                              DxUint16_t              Llen,
                                              CRYS_PKCS1_MGF_t        MGF,
                                              DxUint8_t*              DataIn_ptr,
                                              DxUint16_t              DataInSize,
                                              DxUint8_t*              Output_ptr,
                                              CRYS_PKCS1_version      PKCS1_ver)
				  
{
  /* The return error identifier */
  CRYSError_t   Error;
  
  /* offset */
  DxUint32_t    sramOffset;
  
  /* read parameter */
  DxUint32_t    messageParam[6];
  
  /* maximum parameter 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( UserPubKey_ptr == DX_NULL )
  {
    Error = CRYS_RSA_INVALID_PUB_KEY_STRUCT_POINTER_ERROR;
    goto end_function;
  }
      
  /* checking the Prime Data pointer */
  if( PrimeData_ptr == DX_NULL )
  {
    Error = CRYS_RSA_PRIM_DATA_STRUCT_POINTER_INVALID;
    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;
  }
   
  /* if the users Data In pointer is illegal return an error */
  /* note - it is allowed to encrypt a message of size zero ; only on this case a NULL is allowed */
  if( DataIn_ptr == DX_NULL && DataInSize != 0)
  {
    Error = CRYS_RSA_DATA_POINTER_INVALID_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;
  }
   
   /* lock access to the SEP */
   Error = SEPDriver_Lock();
   
   if(Error != DX_OK)
   {
       goto end_function;
   }
  
  /*----------------------------
      start sending message to SEP 
  -----------------------------*/
  sramOffset = 0;
   
  /* start the message */
  SEPDriver_StartMessage(&sramOffset);
  
  /* prepare params */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_RSA_ENC_OP_CODE;
  messageParam[1] = hashFunc;
  messageParam[2] = MGF;
  messageParam[3] = PKCS1_ver;
  messageParam[4] = Llen;
  messageParam[5] = DataInSize;
  
  /* 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;
  }
  
  /* write L */
  Error = SEPDriver_WriteParamater((DxUint32_t)L,
                                       Llen,
                                       64 * 4,
                                       &sramOffset,
                                       DX_TRUE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                                           
  /* send params   */
  Error = SEPDriver_WriteParamater((DxUint32_t)&messageParam[5] , 
                           sizeof(DxUint32_t),
                           sizeof(DxUint32_t),
                           &sramOffset , 
                           DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
  
  /* write data in  */
  Error = SEPDriver_WriteParamater((DxUint32_t)DataIn_ptr,
                                      DataInSize,
                                      64 * 4,
                                      &sramOffset,
                                      DX_TRUE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
  
  /* write public key */
  maxLength = ((sizeof(CRYS_RSAUserPubKey_t) + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t);
  Error = SEPDriver_WriteParamater((DxUint32_t)UserPubKey_ptr,
                                       sizeof(CRYS_RSAUserPubKey_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_ENC_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 data out  */
  Error = SEPDriver_ReadParamater((DxUint32_t)Output_ptr,
                                      64 * 4,
                                      64 * 4,
                                      &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 */
	  	
}/* END OF _DX_RSA_SCHEMES_Encrypt */


EXPORT_SYMBOL(_DX_RSA_SCHEMES_Encrypt);				  

/**********************************************************************************************************/
/**
   @brief
   RSA_SCHEMES_Decrypt implements the RSAES-OAEP algorithm as defined
   in PKCS#1 v2.1 8.1 and in PKCS#1 v1.5

   This function combines the RSA decryption primitive and the
   EME-OAEP encoding method, to provide an RSA-based decryption
   method that is semantically secure against adaptive
   chosen-ciphertext attacks. For more details, please refere to
   the PKCS#1 standard.

   @param[in] UserPrivKey_ptr - Pointer to the private key data
                            structure. \note The representation
                            (pair or quintiple) 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] PrimeData_ptr - Pointer to a CRYS_RSAPrimeData_t which is used for the 
   							Encryption operation
   							                            
   @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/384/512.
   @param[in] L - The label input. relevant for PKCS#1 Ver2.1
                  Version 2.1 of the standard defines the default value for L as the empty string, 
   @param[in] Llen - The label length. relevant for PKCS#1 Ver2.1
                  Version 2.1 of the standard defines the default value for Llen as zero, 
   @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] Data_ptr - Pointer to the data to decrypt.
   @param[in] DataSize - The size, in bytes, of the data to
                         decrypt. \note Must be <= the size of the modulus.

   @param[out] Output_ptr - Pointer to the decrypted data, 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 - The size of the Output_ptr buffer [bytes].
                                   The input size value must be at least the size of the modulus 
                                   This value is updated with the actual number 
                                   of bytes that are loaded to Output_ptr buffer

   @return CRYSError_t - CRYS_OK, CRYS_BAD_PARAM, CRYS_OUT_OF_RANGE
*/

CEXPORT_C CRYSError_t _DX_RSA_SCHEMES_Decrypt(CRYS_RSAUserPrivKey_t*  UserPrivKey_ptr,
                                              CRYS_RSAPrimeData_t*    PrimeData_ptr,
                                              CRYS_RSA_HASH_OpMode_t  hashFunc,
                                              DxUint8_t*              L,
                                              DxUint16_t              Llen,
                                              CRYS_PKCS1_MGF_t        MGF,
                                              DxUint8_t*              DataIn_ptr,
                                              DxUint16_t              DataInSize,
                                              DxUint8_t*              Output_ptr,
                                              DxUint16_t*             OutputSize_ptr,
                                              CRYS_PKCS1_version      PKCS1_ver)
{
  /* The return error identifier */
  CRYSError_t   Error;
  
  /* offset */
  DxUint32_t    sramOffset;
  
  /* read parameter */
  DxUint32_t    messageParam[6];
  
  /* maximum parameter length */
  DxUint32_t    maxLength;

	/*--------------------------------------
	    CODE
	---------------------------------------*/
	
  #ifndef CRYS_NO_HASH_SUPPORT                                      
  #ifndef CRYS_NO_PKI_SUPPORT                                      
 
  Error = CRYS_OK;
   
  /* ............... checking the parameters validity ................... */
   
  /* if the users context pointer is DX_NULL return an error */
  if( UserPrivKey_ptr == DX_NULL )
  {
    Error = CRYS_RSA_INVALID_PRIV_KEY_STRUCT_POINTER_ERROR;
    goto end_function;
  }
      
  if(PrimeData_ptr == DX_NULL)
  {
    Error = CRYS_RSA_PRIM_DATA_STRUCT_POINTER_INVALID;
    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;
  }
   	 
  /* if the users Data In pointer is illegal return an error */
  if( DataIn_ptr == DX_NULL )
  {
    Error = CRYS_RSA_DATA_POINTER_INVALID_ERROR;
    goto end_function;
  }
      
  /* if the data size is zero or larger then 2^29 (to prevant an overflow on the transition to bits ) 
    return error */
  if( DataInSize == 0 )
  {
    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_DECRYPT_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);
  
  /* prepare params */
  messageParam[0] = DX_SEP_HOST_SEP_PROTOCOL_HOST_RSA_DEC_OP_CODE;
  messageParam[1] = hashFunc;
  messageParam[2] = MGF;
  messageParam[3] = PKCS1_ver;
  messageParam[4] = Llen;
  messageParam[5] = DataInSize;
  
  /* 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;
  }
   
  /* write L */
  Error = SEPDriver_WriteParamater((DxUint32_t)L,
                                       Llen,
                                       64 * 4,
                                       &sramOffset,
                                       DX_TRUE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                                           
  /* send params */
  Error = SEPDriver_WriteParamater((DxUint32_t)&messageParam[5] , 
                           sizeof(DxUint32_t),
                           sizeof(DxUint32_t),
                           &sramOffset , 
                           DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
  
  /* write data in  */
  Error = SEPDriver_WriteParamater((DxUint32_t)DataIn_ptr,
                                       DataInSize,
                                       64 * 4,
                                       &sramOffset,
                                       DX_TRUE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
  
  /* write 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_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_DEC_OP_CODE)
  {
    Error = DX_WRONG_OPCODE_FROM_SEP_ERR;
    goto end_function_unlock;
  }
   
  /* check the status */
  if(messageParam[1] != CRYS_OK)
  {
    Error = messageParam[1];
    goto end_function_unlock;
  }
  
  /* read data out size */
  Error = SEPDriver_ReadParamater((DxUint32_t)messageParam , 
                          sizeof(DxUint32_t),
                          sizeof(DxUint32_t),
                          &sramOffset , 
                          DX_FALSE);
  if(Error != DX_OK)
  {
      goto end_function_unlock;
  }
                          
  *OutputSize_ptr = (DxUint16_t)messageParam[0];
                          
  /* read the data out  */
  maxLength = ((*OutputSize_ptr + 3) / sizeof(DxUint32_t)) * sizeof(DxUint32_t);
  Error = SEPDriver_ReadParamater((DxUint32_t)Output_ptr,
                                      *OutputSize_ptr,
                                       64 * 4,
                                       &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 */         
   
}/* END OF _DX_RSA_SCHEMES_Decrypt */

EXPORT_SYMBOL(_DX_RSA_SCHEMES_Decrypt);



