/*
* Creation date : Fri Mar 09 17:09:09 2007
* Last modified : %modify_time%
*/
/** @file
* \brief This file contains implementation of 
* CE2_RSA_SCHEMES functions.
*
* \version CE2_RSA_SCHEMES.c#1:csrc:1
* \author Pavel Sasunkevich
* \remarks Copyright (C) 2007 by Discretix Technologies Ltd.
* All Rights reserved
*/

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

#include "CE2_RSA_SCHEMES.h"
#include "LLF_RSA_SCHEMES.h"
#include "LLF_RSA_Common.h"

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

/**
****************************************************************
* Function Name: 
*  CE2_DX_RSA_SCHEMES_Encrypt
*
* Inputs:
*  @param UserPubKey_ptr [in] - A pointer to the public key data structure of the User;
*  @param hashFunc       [in] - The hash function to be used;
*  @param L              [in] - The label input;
*  @param Llen           [in] - The label length;
*  @param MGF            [in] - The mask generation function. PKCS#1 v2.1 defines MGF1, 
*         so the only value allowed here is CE2_PKCS1_MGF1;
*  @param DataIn_ptr     [in] - A pointer to the data to encrypt;
*  @param DataInSize       [in] - The size, in bytes, of the data to encrypt;
*  @param Output_ptr     [out] - A pointer to the encrypted data;
*  @param PKCS1_ver      [in] - Ver 1.5 or 2.1, according to the functionality required.
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code:
*     - CE2_BAD_PARAM,
*     - CE2_OUT_OF_RANGE.
*
* \brief \b
* Description:
*  This function implements the Encrypt algorithm as defined in
*  PKCS#1 v2.1 and PKCS#1 v1.5.
*  The actual macro that will be used by the user is:
*   CE2_RSA_OAEP_Encrypt 		- for v2.1;
*   CE2_RSA_PKCS1v15_Encrypt	- for v1.5.
*
* \b
* Algorithm:
*  -# Verify input parameters for validity;
*  -# Call low level function LLF_DX_RSA_SCHEMES_Encrypt
*     to encrypt data using public key, hash function and mask
*     generation functuion with using LibTomCrypt.
***************************************************************/
CE2CIMPORT_C CE2Error_t CE2_DX_RSA_SCHEMES_Encrypt(
                        CE2_RSAUserPubKey_t *UserPubKey_ptr,/* in */
                        CE2_RSA_HASH_OpMode_t hashFunc,	/* in */
                        DxUint8_t      *L,				/* in */
                        DxUint16_t      Llen,			/* in */
                        CE2_PKCS1_MGF_t MGF,			/* in */
                        DxUint8_t       *DataIn_ptr,	/* in */
                        DxUint16_t      DataInSize,		/* in */
                        DxUint8_t       *Output_ptr,	/* out */
                        CE2_PKCS1_version PKCS1_ver)	/* in */
{
	if (UserPubKey_ptr == NULL)
		return CE2_RSA_SCHEMES_ENCRYPT_INVALID_PUBKEY_PTR_ERROR;

	if (0 > hashFunc || hashFunc >= CE2_RSA_HASH_NumOfModes )
		return CE2_RSA_SCHEMES_ENCRYPT_INVALID_HASHMODE_ERROR;

	/* for PKCS1 v1.5 */
	if (PKCS1_ver == CE2_PKCS1_VER15)
	{
		/* hash functions check for v1.5 */
	}else
	/* for PKCS1 v2.1 */
	if (PKCS1_ver == CE2_PKCS1_VER21)
	{
		/* hash functions check for v2.1 */
		if (hashFunc != CE2_RSA_HASH_MD5_mode &&
			hashFunc != CE2_RSA_HASH_SHA1_mode &&
			hashFunc != CE2_RSA_HASH_SHA224_mode &&
			hashFunc != CE2_RSA_HASH_SHA256_mode &&
			hashFunc != CE2_RSA_HASH_SHA384_mode &&
			hashFunc != CE2_RSA_HASH_SHA512_mode)
			return CE2_RSA_SCHEMES_ENCRYPT_INVALID_HASHMODE_ERROR;
		/*The other hash functions recommended 
		by PKCS#1 v2.1 are SHA-256/284/512.*/

		if (MGF != CE2_PKCS1_MGF1)
			return CE2_RSA_SCHEMES_ENCRYPT_INVALID_MGF_MODE_ERROR;
	} else
		return CE2_RSA_SCHEMES_ENCRYPT_INVALID_PKCS_VERSION_ERROR;

	/* L ignored */
	/*
	if (L == NULL)
		return CE2_BAD_PARAM;
	*/

	if (DataIn_ptr == NULL && DataInSize != 0)
		return CE2_RSA_SCHEMES_ENCRYPT_INVALID_DATAIN_PTR_ERROR;

	if (Output_ptr == NULL)
		return CE2_RSA_SCHEMES_ENCRYPT_INVALID_DATAOUT_PTR_ERROR;

	return LLF_DX_RSA_SCHEMES_Encrypt(UserPubKey_ptr, hashFunc,
		L, Llen, MGF, DataIn_ptr, DataInSize, Output_ptr, PKCS1_ver);
} /* End of CE2_DX_RSA_SCHEMES_Encrypt */

/**
****************************************************************
* Function Name: 
*  CE2_DX_RSA_SCHEMES_Decrypt
*
* Inputs:
*  @param UserPrivKey_ptr [in] - A pointer to the private key data structure;
*  @param hashFunc        [in] - The hash function to be used;
*  @param L               [in] - The label input;
*  @param Llen            [in] - The label length;
*  @param MGF             [in] - The mask generation function. PKCS#1 v2.1 defines MGF1, 
          so the only value allowed here is CE2_PKCS1_MGF1.
*  @param Data_ptr        [in] - A pointer to the data to decrypt;
*  @param DataSize        [in] - The size, in bytes, of the data to decrypt;
*  @param Output_ptr      [out] - Pointer to the decrypted data;
*  @param OutputSize_ptr  [in/out] - The size of the Output_buffer ptr  [bytes];
*  @param PKCS1_ver       [in] - Ver 1.5 or 2.1, according to the functionality required.
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code:
*     - CE2_BAD_PARAM,
*     - CE2_OUT_OF_RANGE.
*
* \brief \b
* Description:
*  This function implements the Decrypt algorithm as defined
*  in PKCS#1 v2.1 and PKCS#1 v1.5.
*   The actual macro that will be used by the user is:
*   CE2_RSA_OAEP_Decrypt		- for v2.1;
*   CE2_RSA_PKCS1v15_Decrypt	- for v1.5.
*
* \b
* Algorithm:
*  -# Verify input parameters for validity;
*  -# Call low level function LLF_DX_RSA_SCHEMES_Decrypt
*     to decrypt data using private key, hash function and mask
*     generation functuion with using LibTomCrypt.
***************************************************************/
CE2CIMPORT_C CE2Error_t CE2_DX_RSA_SCHEMES_Decrypt(
                        CE2_RSAUserPrivKey_t *UserPrivKey_ptr,/* in */
                        CE2_RSA_HASH_OpMode_t hashFunc,	/* in */
                        DxUint8_t       *L,				/* in */
                        DxUint16_t      Llen,			/* in */
                        CE2_PKCS1_MGF_t MGF,			/* in */
                        DxUint8_t       *Data_ptr,		/* in */
                        DxUint16_t      DataSize,		/* in */
                        DxUint8_t       *Output_ptr,	/* out */
                        DxUint16_t      *OutputSize_ptr,/* in, out */
                        CE2_PKCS1_version PKCS1_ver)	/* in */
{
	CE2RSAPrivKey_t * privKey = (CE2RSAPrivKey_t *)UserPrivKey_ptr->PrivateKeyDbBuff;

	/* L ignored */
	/*
	if (L == NULL)
		return CE2_BAD_PARAM;
	*/

	if (Data_ptr == NULL)
		return CE2_RSA_SCHEMES_DECRYPT_INVALID_DATA_PTR_ERROR;

	/* Must be <= the size of the modulus. */
	if (DataSize > BITS2BYTES(privKey->nSizeInBits))
		return CE2_RSA_SCHEMES_DECRYPT_INVALID_DATASIZE_ERROR;

	if (Output_ptr == NULL)
		return CE2_RSA_SCHEMES_DECRYPT_INVALID_OUTPUT_PTR_ERROR;

	if (PKCS1_ver == CE2_PKCS1_VER15)
	{
		/*
		for PKCS1 v1.5 *OutputSize_ptr contains
		length of real message
		*/
		/* hash functions check for v1.5 */
	} else
	if (PKCS1_ver == CE2_PKCS1_VER21)
	{
		/* Must be >= the size of the modulus. */
		if (*OutputSize_ptr < BITS2BYTES(privKey->nSizeInBits))
			return CE2_RSA_SCHEMES_DECRYPT_INVALID_OUTPUT_SIZE_PTR_ERROR;

		/* hash functions check for v2.1 */
		if (hashFunc != CE2_RSA_HASH_MD5_mode &&
			hashFunc != CE2_RSA_HASH_SHA1_mode &&
			hashFunc != CE2_RSA_HASH_SHA224_mode &&
			hashFunc != CE2_RSA_HASH_SHA256_mode &&
			hashFunc != CE2_RSA_HASH_SHA384_mode &&
			hashFunc != CE2_RSA_HASH_SHA512_mode)
			return CE2_RSA_SCHEMES_DECRYPT_INVALID_HASH_MODE_ERROR;
		/*The other hash functions recommended 
		by PKCS#1 v2.1 are SHA-256/284/512.*/

		if (MGF != CE2_PKCS1_MGF1)
			return CE2_RSA_SCHEMES_DECRYPT_INVALID_MGF_MODE_ERROR;
	}
	else
		return CE2_RSA_SCHEMES_DECRYPT_INVALID_PKCS_MODE_ERROR;

	return LLF_DX_RSA_SCHEMES_Decrypt(UserPrivKey_ptr, hashFunc,
		L, Llen, MGF, Data_ptr, DataSize, Output_ptr, OutputSize_ptr,
		PKCS1_ver);
} /* End of CE2_DX_RSA_SCHEMES_Decrypt */

/**
****************************************************************
* Function Name: 
*  CE2_DX_RSA_Sign
*
* Inputs:
*  @param UserPrivKey_ptr [in] - A pointer to the private key data
*         structure of the user;
*  @param hashFunc        [in] - The hash function to be used;
*  @param MGF             [in] - The mask generation function;
*  @param SaltLen         [in] - The Length of the Salt buffer;
*  @param DataIn_ptr      [in] - A pointer to the data to sign;
*  @param DataInSize      [in] - The size, in bytes, of the data to sign;
*  @param Output_ptr      [out] - A pointer to the signature;
*  @param OutputSize_ptr  [in/out] - A pointer to the Signature Size value;
*  @param PKCS1_ver       [in] - Ver 1.5 or 2.1, according to the functionality required.
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code:
*     - CE2_RSA_INVALID_PRIV_KEY_STRUCT_POINTER_ERROR,
*     - CE2_RSA_PRIV_KEY_VALIDATION_TAG_ERROR,
*     - CE2_RSA_HASH_ILLEGAL_OPERATION_MODE_ERROR,
*     - CE2_RSA_MGF_ILLEGAL_ARG_ERROR,
*     - CE2_RSA_PKCS1_VER_ARG_ERROR,
*     - CE2_RSA_INVALID_MESSAGE_DATA_SIZE,
*     - CE2_RSA_INVALID_OUTPUT_POINTER_ERROR,
*     - CE2_RSA_INVALID_SIGNATURE_BUFFER_SIZE.
*
* \brief \b
* Description:
*  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:
*   CE2_RSA_PKCS1v15_Sign		- for v1.5;
*   CE2_RSA_PSS_Sign			- for v2.1.
*								- for v2.1 MD5 is not supported, since 
*                 according to the PKCS#1 ver2.1 it is not recommended.
*
* \b
* Algorithm:
*  -# Verify input parameters for validity;
*  -# Call low level function LLF_DX_RSA_Sign
*     to sign data using private key, hash function and mask
*     generation functuion with using LibTomCrypt.
***************************************************************/
CE2CIMPORT_C CE2Error_t CE2_DX_RSA_Sign(
                        CE2_RSAUserPrivKey_t *UserPrivKey_ptr,/* in */
                        CE2_RSA_HASH_OpMode_t hashFunc,	/* in */
                        CE2_PKCS1_MGF_t MGF,			/* in */
                        DxUint16_t    SaltLen,			/* in */
                        DxUint8_t     *DataIn_ptr,		/* in */
                        DxUint32_t     DataInSize,		/* in */
                        DxUint8_t     *Output_ptr,		/* out */
                        DxUint16_t    *OutputSize_ptr,	/* in, out */
                        CE2_PKCS1_version PKCS1_ver)	/* in */
{
	if (UserPrivKey_ptr == NULL)
		return CE2_RSA_SCHEMES_SIGN_INVALID_PRIVKEY_PTR_ERROR;

	if (UserPrivKey_ptr->valid_tag != sizeof(CE2_RSAUserPrivKey_t))
		return CE2_RSA_SCHEMES_SIGN_PRIVKEY_VALIDATION_TAG_ERROR;

	if (0 > hashFunc || hashFunc >= CE2_RSA_HASH_NumOfModes)
			return CE2_RSA_SCHEMES_SIGN_ILLEGAL_HASH_MODE_ERROR;

	if (PKCS1_ver == CE2_PKCS1_VER15)
	{
		/* hash functions check for v1.5 */
	} else
	if (PKCS1_ver == CE2_PKCS1_VER21)
	{
		/* hash functions check for v2.1 */
		/* for v2.1 MD5 is not supported, since 
			according to the PKCS#1 ver2.1 it is not recommended */
		//if (hashFunc == CE2_RSA_HASH_MD5_mode)
		//	return CE2_RSA_SCHEMES_SIGN_ILLEGAL_HASH_MODE_ERROR;

		/* MGF functions check */
		if (MGF != CE2_PKCS1_MGF1)
			return CE2_RSA_SCHEMES_SIGN_ILLEGAL_MGF_ERROR;
	}
	else
		return CE2_RSA_SCHEMES_SIGN_ILLEGAL_PKCS_VERSION_ERROR;

	if (DataIn_ptr == NULL && DataInSize != 0)
		return CE2_RSA_SCHEMES_SIGN_INVALID_DATA_PTR_ERROR;

	/* CE2_RSA_INVALID_MESSAGE_DATA_SIZE */

	if (Output_ptr == NULL)
		return CE2_RSA_SCHEMES_SIGN_INVALID_OUTPUT_PTR_ERROR;

	/* CE2_RSA_INVALID_SIGNATURE_BUFFER_SIZE */

	return LLF_DX_RSA_Sign(UserPrivKey_ptr, hashFunc, MGF, SaltLen,
		DataIn_ptr, DataInSize, Output_ptr, OutputSize_ptr, PKCS1_ver);
} /* End of CE2_DX_RSA_Sign */

/**
****************************************************************
* Function Name: 
*  CE2_DX_RSA_Verify
*
* Inputs:
*  @param UserPubKey_ptr [in] - A pointer to the public key data structure of the user;
*  @param hashFunc       [in] - The hash function to be used. 
*  @param MGF            [in] - The mask generation function;
*  @param SaltLen        [in] - The Length of the Salt buffer;
*  @param DataIn_ptr     [in] - A pointer to the data whose signature is to be verified;
*  @param DataInSize     [in] - The size, in bytes, of the data whose signature is to be verified;
*  @param Sig_ptr        [in] - A pointer to the signature to be verified;
*  @param PKCS1_ver      [in] - Ver 1.5 or 2.1, according to the functionality required;
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code:
*     - CE2_INVALID_SIGNATURE,
*     - CE2_BAD_PARAM,
*     - CE2_OUT_OF_RANGE.
*
* \brief \b
* Description:
*  _DX_RSA_Verify implements the RSASSA-PKCS1v15 algorithm
*  in a single function, as defined in PKCS#1 v1.5 and v2.1
*  The actual macro that will be used by the users is:
*   CE2_RSA_PKCS1v15_Verify			- for v1.5;
*   CE2_RSA_PSS_Verify				- for v2.1;
*									- for v2.1 MD5 is not supported, since
*					according to the PKCS#1 ver2.1 it is not recommended.
*
* \b
* Algorithm:
*  -# Verify input parameters for validity;
*  -# Call low level function LLF_DX_RSA_Verify
*     to verify data using public key, hash function, mask
*     generation functuion and sign of data with using LibTomCrypt.
***************************************************************/
CE2CIMPORT_C CE2Error_t CE2_DX_RSA_Verify(
                        CE2_RSAUserPubKey_t *UserPubKey_ptr,/* in */
                        CE2_RSA_HASH_OpMode_t hashFunc,	/* in */
                        CE2_PKCS1_MGF_t MGF,		/* in */
                        DxUint16_t      SaltLen,	/* in */
                        DxUint8_t       *DataIn_ptr,/* in */
                        DxUint32_t      DataInSize,	/* in */
                        DxUint8_t       *Sig_ptr,	/* in */
                        CE2_PKCS1_version PKCS1_ver)/* in */
{
	//CE2RSAPubKey_t * pubKey = (CE2RSAPubKey_t *)UserPubKey_ptr->PublicKeyDbBuff;

	if (UserPubKey_ptr == NULL)
		return CE2_RSA_SCHEMES_VERIFY_INVALID_PUBKEY_PTR_ERROR;

	if (UserPubKey_ptr->valid_tag != sizeof(CE2_RSAUserPubKey_t))
		return CE2_RSA_SCHEMES_VERIFY_PUBKEY_VALIDATION_TAG_ERROR;

	if (PKCS1_ver == CE2_PKCS1_VER15)
	{
		/* hash functions check for v1.5 */
	} else
	if (PKCS1_ver == CE2_PKCS1_VER21)
	{
		/* hash functions check for v2.1 */
		/* for v2.1 MD5 is not supported, since 
			according to the PKCS#1 ver2.1 it is not recommended */
		//if (hashFunc == CE2_RSA_HASH_MD5_mode)
		//	return CE2_RSA_SCHEMES_VERIFY_ILLEGAL_HASH_MODE_ERROR;

		/* MGF functions check */
		if (MGF != CE2_PKCS1_MGF1)
			return CE2_RSA_SCHEMES_VERIFY_ILLEGAL_MGF_ERROR;
	}
	else
		return CE2_RSA_SCHEMES_VERIFY_ILLEGAL_PKCS_VERSION_ERROR;

	if (DataIn_ptr == NULL && DataInSize != 0)
		return CE2_RSA_SCHEMES_VERIFY_INVALID_DATAIN_PTR_ERROR;

	return LLF_DX_RSA_Verify(UserPubKey_ptr, hashFunc, MGF, SaltLen,
		DataIn_ptr, DataInSize, Sig_ptr, PKCS1_ver);
} /* End of CE2_DX_RSA_Verify */
