/*
* Creation date : Tues Mar 03 09:00:00 2007
* Last modified : %modify_time%
*/
/** @file
* \brief This file contains implementation of Elgamal  algorithm.
*
* \version CE2_ECPKI_ELGAMAL.c#1:csrc:1
* \author Yermalayeu Ihar
* \remarks Copyright (C) 2007 by Discretix Technologies Ltd.
* All Rights reserved
*/

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

#include "CE2_ECPKI_ELGAMAL.h"
#include "LLF_ECPKI_Common.h"
#include "LLF_ECPKI_ELGAMAL.h"

/************************ Defines *****************************/
/************************ Enums *******************************/
/************************ Typedefs ****************************/
/************************ Global Data *************************/
/************************ Private function prototype **********/
/************************ Private Functions *******************/
/************************ Public Functions ********************/

/**
****************************************************************
* Function Name: 
*  CE2_DX_ECPKI_ELGAMAL_Encrypt
*
* Inputs:
* @param ReceiverUserPublKey_ptr [in] - A pointer to receiver public key 
*                           (key in little endian)
* @param MessageIn_ptr [in] - A pointer to message to be encrypted (message in big endian).
* @param MessageInSizeBytes [in] - A size of incoming message in bytes. The size must be
*                       MessageInSizeBytes =< ModulusSizeInBytes -  1.
*                       Note: in case CE2_ECPKI_DomainID_secp521r1 
*                       MessageInSizeBytes =< ModulusSizeInBytes -  2.
* @param EncrMessageOut_ptr [out] - A pointer to buffer for encrypted message.
* @param EncrMessageOutSize_ptr [in\out] - A pointer to output message size.
* @param IsEphemerKeyInternal [in] - A parameter defining whether ephemeral 
*                         key internal or external
* @param EphemerPrivKeyIn_ptr [in] - A pointer to ephemeral private key.
* @param EphemerPrivKeySizeBytes [in] - A size (in bytes) of sender's ephemeral 
*                            private key data.
*
* Outputs:
* @returns \b CE2Error_t 
*  - CE2_OK - on success
*  - Otherwise - error code:
*   - CE2_EC_ELGAMAL_ENCR_INVALID_RECEIVER_PUBL_KEY_PTR_ERROR
*   - CE2_EC_ELGAMAL_ENCR_INVALID_MESSAGE_IN_PTR_ERROR
*   - CE2_EC_ELGAMAL_ENCR_INVALID_MESSAGE_OUT_PTR_ERROR
*   - CE2_EC_ELGAMAL_ENCR_INVALID_MESSAGE_OUT_SIZE_PTR_ERROR
*   - CE2_EC_ELGAMAL_ENCR_INVALID_EPHEMERAL_KEY_IN_ERROR
*   - CE2_EC_ELGAMAL_ENCR_INVALID_MESSAGE_IN_SIZE_ERROR
*   - CE2_EC_ELGAMAL_ENCR_INVALID_MESSAGE_OUT_SIZE_ERROR
*
* \brief \b 
* Description:
*  This function make Elgamal encryption.
*
* \b 
* Algorithm:
*  -# Verify input parameters for validity;
*  -# Call low level function LLF_ECPKI_ELGAMAL_Encrypt
*     for making of Elgamal encryption with using LibTomCrypt.
***************************************************************/
CE2CIMPORT_C CE2Error_t  CE2_DX_ECPKI_ELGAMAL_Encrypt (
					CE2_ECPKI_UserPublKey_t        *ReceiverUserPublKey_ptr, /*in*/
					DxUint8_t                      *MessageIn_ptr,           /*in*/
					DxUint32_t                      MessageInSizeBytes,      /*in*/
					DxUint8_t   				   *EncrMessageOut_ptr,      /*out*/
					DxUint32_t                     *EncrMessageOutSize_ptr,  /*in/out*/
					DxInt8_t                        IsEphemerKeyInternal,    /*in*/
					DxUint8_t                      *EphemerPrivKeyIn_ptr,    /*in*/ 
					DxUint32_t                      EphemerPrivKeySizeBytes /*in*/)
{
  DxUint_t size, maxMessageSize, modulusSize;

  if (ReceiverUserPublKey_ptr == DX_NULL)
    return CE2_EC_ELGAMAL_ENCR_INVALID_RECEIVER_PUBL_KEY_PTR_ERROR;

  modulusSize = LLF_ECPKI_DomainIdToModulusSize(ReceiverUserPublKey_ptr->DomainID);
  size = 4*modulusSize;
  if (ReceiverUserPublKey_ptr->DomainID == CE2_ECPKI_DomainID_secp521r1)
    maxMessageSize = modulusSize - 2;
  else 
    maxMessageSize = modulusSize - 1;

  if (MessageIn_ptr == DX_NULL) 
    return CE2_EC_ELGAMAL_ENCR_INVALID_MESSAGE_IN_PTR_ERROR;

  if (EncrMessageOut_ptr == DX_NULL)
    return CE2_EC_ELGAMAL_ENCR_INVALID_MESSAGE_OUT_PTR_ERROR;

  if (EncrMessageOutSize_ptr == DX_NULL)
    return CE2_EC_ELGAMAL_ENCR_INVALID_MESSAGE_OUT_SIZE_PTR_ERROR;

  if (IsEphemerKeyInternal != TRUE && EphemerPrivKeyIn_ptr == DX_NULL)
    return CE2_EC_ELGAMAL_ENCR_INVALID_EPHEMERAL_KEY_IN_ERROR;

  if (IsEphemerKeyInternal == TRUE && EphemerPrivKeyIn_ptr != DX_NULL)
    return CE2_EC_ELGAMAL_ENCR_INVALID_EPHEMERAL_KEY_IN_ERROR;

  if (MessageInSizeBytes > maxMessageSize)
    return CE2_EC_ELGAMAL_ENCR_INVALID_MESSAGE_IN_SIZE_ERROR;

  if (*EncrMessageOutSize_ptr < size) {
    *EncrMessageOutSize_ptr = size;
    return CE2_EC_ELGAMAL_ENCR_INVALID_MESSAGE_OUT_SIZE_ERROR;
  }
  *EncrMessageOutSize_ptr = size;

  return LLF_ECPKI_ELGAMAL_Encrypt(ReceiverUserPublKey_ptr, MessageIn_ptr, 
    MessageInSizeBytes, EncrMessageOut_ptr,
    IsEphemerKeyInternal, EphemerPrivKeyIn_ptr, EphemerPrivKeySizeBytes);
} /* End of CE2_DX_ECPKI_ELGAMAL_Encrypt */

/**
****************************************************************
* Function Name: 
*  CE2_ECPKI_ELGAMAL_Decrypt
*
* Inputs:
* @param ReceiverUserPrivKey_ptr [in] - A pointer to a receiver private key 
*                            structure (in affine coordinates).    				
* @param EncrMessageIn_ptr [in] - The user passed pointer to the encrypted 
*                      message buffer.
* @param EncrMessageSizeInBytes [in] - The size of input encrypted message. 
*                           Must be equal to 4*(EC modulus size in bytes)   
* @param DecrMessageOut_ptr [out] - The user passed pointer to buffer for output of  
*                       decrypted message.
* @param DecrMessageOutSize_ptr [in\out] - A pointer to size of uzer passed buffer 
*                          for decrypted message (in) and actual size 
*                          of decrypted message (out).
*                          Input value must be *DecrMessageOutSize_ptr >= 
*                         (EC modulus size in bytes) - 1. 
*                         Note: in case CE2_ECPKI_DomainID_secp521r1 input value must be 
*                         *DecrMessageOutSize_ptr >= (EC modulus size in bytes) - 2.
*
* Outputs:
* @returns \b CE2Error_t 
*  - CE2_OK - on success
*  - Otherwise - error code:
*   - CE2_EC_ELGAMAL_DECR_INVALID_RECEIVER_PRIV_KEY_PTR_ERROR
*   - CE2_EC_ELGAMAL_DECR_INVALID_ENCR_MESSAGE_IN_PTR_ERROR
*   - CE2_EC_ELGAMAL_DECR_INVALID_DECR_MESSAGE_OUT_PTR_ERROR
*   - CE2_EC_ELGAMAL_DECR_INVALID_DECR_MESSAGE_OUT_SIZE_PTR_ERROR
*   - CE2_EC_ELGAMAL_DECR_INVALID_ENCR_MESSAGE_IN_SIZE_ERROR
*   - CE2_EC_ELGAMAL_DECR_INVALID_ENCR_MESSAGE_OUT_SIZE_ERROR
*
* \brief \b 
* Description:
*  This function make Elgamal decryption.
*
* \b 
* Algorithm:
*  -# Verify input parameters for validity;
*  -# Call low level function LLF_ECPKI_ELGAMAL_Decrypt
*     for making of Elgamal decryption with using LibTomCrypt.
***************************************************************/
CE2CIMPORT_C CE2Error_t  CE2_ECPKI_ELGAMAL_Decrypt (			      
				CE2_ECPKI_UserPrivKey_t    *ReceiverUserPrivKey_ptr,  /*in*/	
			  DxUint8_t   		           *EncrMessageIn_ptr,        /*in*/
				DxUint32_t                  EncrMessageSizeInBytes,   /*in*/
			  DxUint8_t		               *DecrMessageOut_ptr,       /*out*/
				DxUint32_t                 *DecrMessageOutSize_ptr   /*in\out*/)
{
  DxUint_t size, maxMessageSize, modulusSize;

  if (ReceiverUserPrivKey_ptr == DX_NULL)
    return CE2_EC_ELGAMAL_DECR_INVALID_RECEIVER_PRIV_KEY_PTR_ERROR;

  modulusSize = LLF_ECPKI_DomainIdToModulusSize(ReceiverUserPrivKey_ptr->DomainID);
  size = 4*modulusSize;
  if (ReceiverUserPrivKey_ptr->DomainID == CE2_ECPKI_DomainID_secp521r1)
    maxMessageSize = modulusSize - 2;
  else 
    maxMessageSize = modulusSize - 1;

  if (EncrMessageIn_ptr == DX_NULL)
    return CE2_EC_ELGAMAL_DECR_INVALID_ENCR_MESSAGE_IN_PTR_ERROR;

  if (DecrMessageOut_ptr == DX_NULL)
    return CE2_EC_ELGAMAL_DECR_INVALID_DECR_MESSAGE_OUT_PTR_ERROR;

  if (DecrMessageOutSize_ptr == DX_NULL)
    return CE2_EC_ELGAMAL_DECR_INVALID_DECR_MESSAGE_OUT_SIZE_PTR_ERROR;

  if (EncrMessageSizeInBytes < size)
    return CE2_EC_ELGAMAL_DECR_INVALID_ENCR_MESSAGE_IN_SIZE_ERROR;

  if (*DecrMessageOutSize_ptr > maxMessageSize) {
    *DecrMessageOutSize_ptr = maxMessageSize;
    return CE2_EC_ELGAMAL_DECR_INVALID_ENCR_MESSAGE_OUT_SIZE_ERROR;
  }
  //*DecrMessageOutSize_ptr = maxMessageSize;

  return LLF_ECPKI_ELGAMAL_Decrypt(ReceiverUserPrivKey_ptr, EncrMessageIn_ptr,
    DecrMessageOut_ptr, DecrMessageOutSize_ptr);
} /* CE2_ECPKI_ELGAMAL_Decrypt */
