/*
*  Object %CE2_UTIL_RSA_SCHEMES.c    : %
*  State           :  %state%
*  Creation date   :  %date%
*  Last modified   :  %modify_time%
*/
/** @file
*  \brief This module defines the API that supports PKCS#1 v1.5 and PKCS#1 v2.1 schemes
*
*  \version CE2_UTIL_RSA_SCHEMES.c#1:incl:1
*  \author ronys ohads
*  \remarks Copyright (C) 2001-2007 by Discretix Technologies Ltd. All Rights reserved.
*/

#include "CE2_public.h"
#include "CE2_UTIL_RSA_SCHEMES.h"
#include "LLF_RSA_Common.h"
#include "LLF_ECPKI_Common.h"
#include "LLF_RSA_SCHEMES.h"

/************************ Defines *****************************/
/************************ Enums *******************************/
/************************ Typedefs ****************************/
/************************ Global Data *************************/
/************************ Private function prototype **********/
/************************ Private Functions *******************/
/* The function changes the hash_descriptor values of the TomCrypt */
/* hashFunc - hash mode											   */
/* pHashIndex - return the hash index in the hash_descriptor       */
/* Function returns error code									   */

CE2Error_t UTILS_RegisterOldHashDx(int hashFunc, int *pHashIndex)							 
{
	int error_code = CE2_OK;

	/* Register hash */
	switch (hashFunc)
	{
	case CE2_RSA_After_HASH_NOT_KNOWN_mode: /* For PKCS1 v1.5 */
		/* If PKCS1_ver is CE2_PKCS1_VER15, then
		the value CE2_RSA_After_HASH_NOT_KNOWN_mode will allow
		the signature data to determine the hash function to be used.*/
		/* this operations are a little lower */
		break;
	case CE2_RSA_HASH_SHA1_mode:
	case CE2_RSA_After_SHA1_mode: /* For PKCS1 v1.5 */
		if (register_hash(&sha1_descDx) == -1)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}
		*pHashIndex = find_hash("sha1Dx");
		break;
	case CE2_RSA_HASH_SHA224_mode:
	case CE2_RSA_After_SHA224_mode: /* For PKCS1 v1.5 */
		if (register_hash(&sha224_descDx) == -1)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}
		*pHashIndex = find_hash("sha224Dx");
		break;
	case CE2_RSA_HASH_SHA256_mode:
	case CE2_RSA_After_SHA256_mode: /* For PKCS1 v1.5 */
		if (register_hash(&sha256_descDx) == -1)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}
		*pHashIndex = find_hash("sha256Dx");
		break;
	case CE2_RSA_HASH_SHA384_mode:
	case CE2_RSA_After_SHA384_mode: /* For PKCS1 v1.5 */
		if (register_hash(&sha384_descDx) == -1)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}
		*pHashIndex = find_hash("sha384Dx");
		break;
	case CE2_RSA_HASH_SHA512_mode:
	case CE2_RSA_After_SHA512_mode: /* For PKCS1 v1.5 */
		if (register_hash(&sha512_descDx) == -1)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}
		*pHashIndex = find_hash("sha512Dx");
		break;
	case CE2_RSA_HASH_MD5_mode:
	case CE2_RSA_After_MD5_mode:
		/*if (PKCS1_ver == CE2_PKCS1_VER21)
		{
		error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
		break;
		}*/
		if (register_hash(&md5_descDx) == -1)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}
		*pHashIndex = find_hash("md5Dx");
		break;
		/*	for v2.1 MD5 is not supported, since
		according to the PKCS#1 ver2.1 it is not recommended*/
	default:
		error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
	}

exit_label:
	return error_code;
}

CE2Error_t UTILS_LLF_RSA_HASH(CE2_RSA_HASH_OpMode_t HashMode,
						DxUint8_t             *DataIn_ptr,
						DxUint32_t            DataInSize,
						DxUint8_t             *DataOut_ptr,
						DxUint32_t            *DataOutSize_ptr)
{
	int hash_index = -1, make_hash = 1;
	int error_code = CRYPT_OK;
	DxUint8_t empty_buffer;

	switch(HashMode)
	{
	case CE2_RSA_HASH_MD5_mode:
	case CE2_RSA_HASH_SHA1_mode:
	case CE2_RSA_HASH_SHA224_mode:
	case CE2_RSA_HASH_SHA256_mode:
	case CE2_RSA_HASH_SHA384_mode:
	case CE2_RSA_HASH_SHA512_mode:
		make_hash = 1;
		break;
	case CE2_RSA_After_MD5_mode:
		*DataOutSize_ptr = CE2_HASH_MD5_DIGEST_SIZE_IN_BYTES;
		make_hash = 0;
		break;
	case CE2_RSA_After_SHA1_mode:
		*DataOutSize_ptr = CE2_HASH_SHA1_DIGEST_SIZE_IN_BYTES;
		make_hash = 0;
		break;
	case CE2_RSA_After_SHA224_mode:
		*DataOutSize_ptr = CE2_HASH_SHA224_DIGEST_SIZE_IN_BYTES;
		make_hash = 0;
		break;
	case CE2_RSA_After_SHA256_mode:
		*DataOutSize_ptr = CE2_HASH_SHA256_DIGEST_SIZE_IN_BYTES;
		make_hash = 0;
		break;
	case CE2_RSA_After_SHA384_mode:
		*DataOutSize_ptr = CE2_HASH_SHA384_DIGEST_SIZE_IN_BYTES;
		make_hash = 0;
		break;
	case CE2_RSA_After_SHA512_mode:
		*DataOutSize_ptr = CE2_HASH_SHA512_DIGEST_SIZE_IN_BYTES;
		make_hash = 0;
		break;
	default:
		return CE2_LLF_HASH_MODULE_ERROR_BASE;
	}

	if (make_hash) {
		UTILS_RegisterOldHashDx(HashMode, &hash_index);	
		if (hash_index == -1)
			return CE2_LLF_HASH_MODULE_ERROR_BASE;

		/* Case of input message is absent */
		if (DataIn_ptr == NULL) {
			DataInSize = 0;
			DataIn_ptr = &empty_buffer;
		}

		/* Perform hash operation. */
		error_code = hash_memory(hash_index, DataIn_ptr, DataInSize,
			DataOut_ptr, DataOutSize_ptr);
		if (error_code != CRYPT_OK)
			return CE2_LLF_HASH_MODULE_ERROR_BASE;
	} else {
		if (DataIn_ptr != NULL) {
			memset(DataOut_ptr, 0, *DataOutSize_ptr);
			memcpy(DataOut_ptr, DataIn_ptr, min(*DataOutSize_ptr, DataInSize));
		} else {
			*DataOutSize_ptr = 0;
		}
	}

	return CE2_OK;
} /* End of LLF_RSA_HASH */

int pkcs_1_oaep_wrong_encode(const unsigned char *msg,    unsigned long msglen,
					   const unsigned char *lparam, unsigned long lparamlen,
					   unsigned long modulus_bitlen, prng_state *prng,
					   int           prng_idx,         int  hash_idx,
					   unsigned char *out,    unsigned long *outlen,
					   DxUint32_t errorSchemetype )
{
	unsigned char *DB, *seed, *mask;
	unsigned long hLen, x, y, modulus_len;
	int           err;

	LTC_ARGCHK(msg    != NULL);
	LTC_ARGCHK(out    != NULL);
	LTC_ARGCHK(outlen != NULL);

	/* test valid hash */
	if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { 
		return err;
	}

	/* valid prng */
	if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) {
		return err;
	}

	hLen        = hash_descriptor[hash_idx].hashsize;
	modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0);

	/* test message size */
	if ((2*hLen >= (modulus_len - 2)) || (msglen > (modulus_len - 2*hLen - 2))) {
		return CRYPT_PK_INVALID_SIZE;
	}

	/* allocate ram for DB/mask/salt of size modulus_len */
	DB   = XMALLOC(modulus_len);
	mask = XMALLOC(modulus_len);
	seed = XMALLOC(hLen);
	if (DB == NULL || mask == NULL || seed == NULL) {
		if (DB != NULL) {
			XFREE(DB);
		}
		if (mask != NULL) {
			XFREE(mask);
		}
		if (seed != NULL) {
			XFREE(seed);
		}
		return CRYPT_MEM;
	}

	/* get lhash */
	/* DB == lhash || PS || 0x01 || M, PS == k - mlen - 2hlen - 2 zeroes */
	x = modulus_len;
	if (lparam != NULL) {
		if ((err = hash_memory(hash_idx, lparam, lparamlen, DB, &x)) != CRYPT_OK) {
			goto LBL_ERR;
		}
	} else {
		/* can't pass hash_memory a NULL so use DB with zero length */
		if ((err = hash_memory(hash_idx, DB, 0, DB, &x)) != CRYPT_OK) {
			goto LBL_ERR;
		}
	}

	/* append PS then 0x01 (to lhash)  */
	if (errorSchemetype & ~PKCS1_V21_EncodeErrorDisableAppendPSToLhash){
		x = hLen;
		y = modulus_len - msglen - 2*hLen - 2;
		XMEMSET(DB+x, 0, y);
		x += y;
	}
	
	/* 0x01 byte */
	if ( errorSchemetype & ~PKCS1_V21_EncodeErrorDontAdd0x01ToLhash ){
		DB[x++] = 0x01;
	}

	/* message (length = msglen) */
	XMEMCPY(DB+x, msg, msglen);
	x += msglen;

	/* now choose a random seed */
	if (prng_descriptor[prng_idx].read(seed, hLen, prng) != hLen) {
		err = CRYPT_ERROR_READPRNG;
		goto LBL_ERR;
	}

	/* compute MGF1 of seed (k - hlen - 1) */
	if ( errorSchemetype & ~PKCS1_V21_EncodeErrorDisableRandomGenerator ){
		if ((err = pkcs_1_mgf1(hash_idx, seed, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
			goto LBL_ERR;
		}
	}

	/* xor against DB */
	for (y = 0; y < (modulus_len - hLen - 1); y++) {
		DB[y] ^= mask[y]; 
	}

	/* compute MGF1 of maskedDB (hLen) */ 
	if ((err = pkcs_1_mgf1(hash_idx, DB, modulus_len - hLen - 1, mask, hLen)) != CRYPT_OK) {
		goto LBL_ERR;
	}

	/* XOR against seed */
	if (errorSchemetype & ~PKCS1_V21_EncodeErrorDisableXORagainstSeed){
		for (y = 0; y < hLen; y++) {
			seed[y] ^= mask[y];
		}
	}

	/* create string of length modulus_len */
	if (*outlen < modulus_len) {
		*outlen = modulus_len;
		err = CRYPT_BUFFER_OVERFLOW;
		goto LBL_ERR;
	}

	/* start output which is 0x00 || maskedSeed || maskedDB */
	x = 0;
	out[x++] = 0x00;
	XMEMCPY(out+x, seed, hLen);
	x += hLen;
	XMEMCPY(out+x, DB, modulus_len - hLen - 1);
	x += modulus_len - hLen - 1;

	*outlen = x;

	err = CRYPT_OK;
LBL_ERR:
#ifdef LTC_CLEAN_STACK
	zeromem(DB,   modulus_len);
	zeromem(seed, hLen);
	zeromem(mask, modulus_len);
#endif

	XFREE(seed);
	XFREE(mask);
	XFREE(DB);

	return err;
}
int pkcs_1_v15_sa_wrongencode(const unsigned char *msghash,  unsigned long msghashlen,
						 int            hash_idx, unsigned long modulus_bitlen,
						 unsigned char *out,      unsigned long *outlen,
						 DxUint32_t errorSchemetype )
{
	unsigned long OIDlen, modulus_bytelen, x, y;
	int err;

	LTC_ARGCHK(msghash != NULL)
		LTC_ARGCHK(out     != NULL);
	LTC_ARGCHK(outlen  != NULL);

	if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
		return err;
	}

	/* hack, to detect any hash without a DER OID */
	if (hash_descriptor[hash_idx].OIDlen == 0) {
		return CRYPT_INVALID_ARG; 
	}

	/* get modulus len */
	modulus_bytelen = (modulus_bitlen>>3) + (modulus_bitlen & 7 ? 1 : 0);

	/* get der len ok?  Forgive my lame German accent.... */
	OIDlen = hash_descriptor[hash_idx].OIDlen;

	/* valid sizes? */
	if (msghashlen + 3 + OIDlen > modulus_bytelen) {
		return CRYPT_PK_INVALID_SIZE;
	}

	if (*outlen < modulus_bytelen) {
		return CRYPT_BUFFER_OVERFLOW;
	}

	/* packet is 0x00 0x01 PS 0x00 T, where PS == 0xFF repeated modulus_bytelen - 3 - OIDlen - msghashlen times, T == DER || hash */
	x = 0;
	if ( errorSchemetype& ~PKCS1_V15_SaEncodeErrorDontAdd0AtTheBegining ){
		out[x++] = 0x00;
	}
	if ( errorSchemetype& ~PKCS1_V15_SaEncodeErrorDontAdd1AtTheBegining ){
		out[x++] = 0x01;
	}
	for (y = 0; y < (modulus_bytelen - 3 - OIDlen - msghashlen); y++) {
		out[x++] = 0xFF;
	}
	out[x++] = 0x00;
	if ( errorSchemetype& ~PKCS1_V15_SaEncodeErrorDontAddHAshDescriptor ){
		for (y = 0; y < OIDlen; y++){
			out[x++] = (char)hash_descriptor[hash_idx].OID[y];
		}
	}
	for (y = 0; y < msghashlen; y++) {
		out[x++] = msghash[y];
	}

	*outlen = modulus_bytelen;
	return CRYPT_OK;
}
int pkcs_1_pss_wrongencode(const unsigned char *msghash, unsigned long msghashlen,
					  unsigned long saltlen,  prng_state   *prng,     
					  int           prng_idx, int           hash_idx,
					  unsigned long modulus_bitlen,
					  unsigned char *out,     unsigned long *outlen,
					  DxUint32_t errorSchemetype )
{
	unsigned char *DB, *mask, *salt, *hash;
	unsigned long x, y, hLen, modulus_len;
	int           err;
	hash_state    md;

	LTC_ARGCHK(msghash != NULL);
	LTC_ARGCHK(out     != NULL);
	LTC_ARGCHK(outlen  != NULL);

	/* ensure hash and PRNG are valid */
	if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
		return err;
	}
	if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) {
		return err;
	}

	hLen        = hash_descriptor[hash_idx].hashsize;
	modulus_len = (modulus_bitlen>>3) + (modulus_bitlen & 7 ? 1 : 0);

	/* check sizes */
	if ((saltlen > modulus_len) || (modulus_len < hLen + saltlen + 2)) {
		return CRYPT_PK_INVALID_SIZE;
	}

	/* allocate ram for DB/mask/salt/hash of size modulus_len */
	DB   = XMALLOC(modulus_len);
	mask = XMALLOC(modulus_len);
	salt = XMALLOC(modulus_len);
	hash = XMALLOC(modulus_len);
	if (DB == NULL || mask == NULL || salt == NULL || hash == NULL) {
		if (DB != NULL) {
			XFREE(DB);
		}
		if (mask != NULL) {
			XFREE(mask);
		}
		if (salt != NULL) {
			XFREE(salt);
		}
		if (hash != NULL) {
			XFREE(hash);
		}
		return CRYPT_MEM;
	}


	/* generate random salt */
	if (saltlen > 0) {
		if (prng_descriptor[prng_idx].read(salt, saltlen, prng) != saltlen) {
			err = CRYPT_ERROR_READPRNG;
			goto LBL_ERR;
		}
	}

	/* M = (eight) 0x00 || msghash || salt, hash = H(M) */
	if ((err = hash_descriptor[hash_idx].init(&md)) != CRYPT_OK) {
		goto LBL_ERR;
	}
	if ( errorSchemetype & ~PKCS1_V21_SaEncodeErrorDontAddEight0x00AtTheBegining){
		zeromem(DB, 8);
	}
	if ((err = hash_descriptor[hash_idx].process(&md, DB, 8)) != CRYPT_OK) {
		goto LBL_ERR;
	}
	if ( errorSchemetype & ~PKCS1_V21_SaEncodeErrorDontAddMsgHash ){
		if ((err = hash_descriptor[hash_idx].process(&md, msghash, msghashlen)) != CRYPT_OK) {
			goto LBL_ERR;
		}
	}
	if ((err = hash_descriptor[hash_idx].process(&md, salt, saltlen)) != CRYPT_OK) {
		goto LBL_ERR;
	}
	if ( errorSchemetype & ~PKCS1_V21_SaEncodeErrorDontAddHash ){
		if ((err = hash_descriptor[hash_idx].done(&md, hash)) != CRYPT_OK) {
			goto LBL_ERR;
		}
	}

	/* generate DB = PS || 0x01 || salt, PS == modulus_len - saltlen - hLen - 2 zero bytes */
	x = 0;
	XMEMSET(DB + x, 0, modulus_len - saltlen - hLen - 2);
	x += modulus_len - saltlen - hLen - 2;
	DB[x++] = 0x01;
	XMEMCPY(DB + x, salt, saltlen);
	x += saltlen;

	/* generate mask of length modulus_len - hLen - 1 from hash */
	if ((err = pkcs_1_mgf1(hash_idx, hash, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
		goto LBL_ERR;
	}

	/* xor against DB */
	for (y = 0; y < (modulus_len - hLen - 1); y++) {
		DB[y] ^= mask[y];
	}

	/* output is DB || hash || 0xBC */
	if (*outlen < modulus_len) {
		*outlen = modulus_len;
		err = CRYPT_BUFFER_OVERFLOW;
		goto LBL_ERR;
	}

	/* DB len = modulus_len - hLen - 1 */
	y = 0;
	XMEMCPY(out + y, DB, modulus_len - hLen - 1);
	y += modulus_len - hLen - 1;

	/* hash */
	XMEMCPY(out + y, hash, hLen);
	y += hLen;

	/* 0xBC */
	out[y] = 0xBC;

	/* now clear the 8*modulus_len - modulus_bitlen most significant bits */
	out[0] &= 0xFF >> ((modulus_len<<3) - (modulus_bitlen-1));

	/* store output size */
	*outlen = modulus_len;
	err = CRYPT_OK;
LBL_ERR:
#ifdef LTC_CLEAN_STACK
	zeromem(DB,   modulus_len);   
	zeromem(mask, modulus_len);   
	zeromem(salt, modulus_len);   
	zeromem(hash, modulus_len);   
#endif

	XFREE(hash);
	XFREE(salt);
	XFREE(mask);
	XFREE(DB);

	return err;
}

CE2Error_t LLF_RSA_PKCS1_V15_WrongEncode(DxUint8_t *DataIn_ptr,    
									DxUint32_t DataInSize,
									DxUint32_t ModulusSizeInBits, 
									DxUint8_t *DataOut_ptr,    
									DxUint32_t *DataOutSize_ptr,
									DxUint32_t errorSchemetype)
{
	CE2Error_t error, result = CE2_OK;
	prng_state prng; 
	int wprng;
	DxUint32_t modulusSize, size, was_read, j, i;

	if(DataIn_ptr == DX_NULL || DataOut_ptr == DX_NULL || 
		DataOutSize_ptr == DX_NULL)
		return CE2_LLF_RSA_MODULE_ERROR_BASE;

	/* Create and initialize Pseudo-Random Number Generators. */
	/* It needs for pkcs1 v15 encoding.                       */
	if ( errorSchemetype & PKCS1_V15_EncodeErrorDisableRandomGenerator ){
		wprng = 0;
	}else{
		error =  LLF_ECPKI_PRNG_Init(&prng, &wprng);
		if (error != CE2_OK) {
			fortuna_done(&prng);
			return CE2_LLF_RSA_MODULE_ERROR_BASE;
		}
	}

	/* Get modulus size (in bytes) */
	modulusSize = BITS2BYTES(ModulusSizeInBits);
	if (modulusSize < 12) {
		result = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto error_case;
	}

	/* Verify input and output data size */
	if (DataInSize > (modulusSize - 11) || *DataOutSize_ptr < modulusSize) {
		result = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto error_case;
	}

	/* 0x00 0x02 PS 0x00 M */
	i = 0;
	if ( ~errorSchemetype & PKCS1_V15_EncodeErrorDontAdd0AtTheBegining ){
		DataOut_ptr[i++] = 0x00;
	}
	if ( ~errorSchemetype & PKCS1_V15_EncodeErrorDontAdd2AtTheBegining ){
		DataOut_ptr[i++] = 0x02;
	}
	size = modulusSize - DataInSize - 3;
	was_read = prng_descriptor[wprng].read(DataOut_ptr + i, size, &prng);
	if (was_read != size) {
		result = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto error_case;
	}
	/* Remove zeros */ 
	if ( ~errorSchemetype & PKCS1_V15_EncodeErrorDisableRemoveZeros ){
		for(j = 0; j < size; j++) {
			if (DataOut_ptr[i + j] == 0)
				DataOut_ptr[i + j] = 1;
		}
	}
	i += size;
	DataOut_ptr[i++] = 0x00;
	memcpy(DataOut_ptr + i, DataIn_ptr, DataInSize);
	*DataOutSize_ptr = modulusSize;

error_case:
	fortuna_done(&prng);
	return result;
} /* End of LLF_RSA_PKCS1_V15_Encode */

CE2Error_t LLF_DX_RSA_SCHEMES_WrongEncrypt(
									  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 */
									  DxUint32_t errorSchemetype,
									  CE2_PKCS1_version PKCS1_ver)	/* in */
{
	CE2RSAPubKey_t * pubKey = (CE2RSAPubKey_t *)UserPubKey_ptr->PublicKeyDbBuff;
	char null_value = 0x00;//Remove NULL ptr
	prng_state yarrow_prng;
	//unsigned long e = 0;
	unsigned long outlen = 0;
	unsigned long x;
	int error_code = -1;
	int hash_idx = 0;
	int prng_idx = 0;
	rsa_key key = { 0 };
	CE2Error_t error;

	/* register prng */
	if (register_prng(&yarrow_desc) == -1)
	{
		error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* register a math library (in this case TomFastMath) */
	ltc_mp = ltm_desc;

	/* Register hash: only SHA1 supported */
	/* The other hash functions recommended 
	by PKCS#1 v2.1 are SHA-256/284/512. */
	switch (hashFunc)
	{
	case CE2_RSA_HASH_NO_HASH_mode:
		break;
	case CE2_RSA_HASH_MD5_mode:
		if (register_hash(&md5_desc) == -1)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}
		hash_idx = find_hash("md5");
		break;
	case CE2_RSA_HASH_SHA1_mode:
		if (register_hash(&sha1_desc) == -1)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}
		hash_idx = find_hash("sha1");
		break;
	case CE2_RSA_HASH_SHA224_mode:
		if (register_hash(&sha224_desc) == -1)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}
		hash_idx = find_hash("sha224");
		break;
	case CE2_RSA_HASH_SHA256_mode:
		if (register_hash(&sha256_desc) == -1)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}
		hash_idx = find_hash("sha256");
		break;
	case CE2_RSA_HASH_SHA384_mode:
		if (register_hash(&sha384_desc) == -1)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}
		hash_idx = find_hash("sha384");
		break;
	case CE2_RSA_HASH_SHA512_mode:
		if (register_hash(&sha512_desc) == -1)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}
		hash_idx = find_hash("sha512");
		break;
	default:
		error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto exit_label;
	}

	if (PKCS1_ver == CE2_PKCS1_VER21)
	{
		if (MGF != CE2_PKCS1_MGF1)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}

		/* DataInSize Must be <= (modulus_size - 2*Hash_output_length - 2). */
		error_code = (DataInSize >
			(BITS2BYTES(pubKey->nSizeInBits) - 2*hash_descriptor[hash_idx].hashsize-2));

		if (error_code != CRYPT_OK)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}
	}

	prng_idx = find_prng("yarrow");

	error_code = rng_make_prng(128, prng_idx, &yarrow_prng, 0);
	if (error_code != CRYPT_OK)
	{
		error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto exit_label;
	}

	if (hash_idx == -1 || prng_idx == -1)
	{
		error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto exit_label;
	}

	error_code = LLF_RSA_UserPubKey_TO_rsakey(UserPubKey_ptr, &key);
	if (error_code != CRYPT_OK)
	{
		error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* take outlen like modulus size */
	outlen = BITS2BYTES(pubKey->nSizeInBits);

	/* master encrypt code starts */

	x = outlen;

	//Remove NULL pointers
	if (DataIn_ptr == NULL){
		DataIn_ptr = &null_value;
		DataInSize = 1;
	}

	if (PKCS1_ver == CE2_PKCS1_VER15)
	{
		/* pad it */
		error = LLF_RSA_PKCS1_V15_WrongEncode(DataIn_ptr, DataInSize,
			pubKey->nSizeInBits, Output_ptr, &x, errorSchemetype); 
		if (error != CE2_OK) {
			error_code = error;
			goto exit_label;
		}

		//error_code = pkcs_1_v15_es_encode(
		//	DataIn_ptr, DataInSize, pubKey->nSizeInBits,
		//	&yarrow_prng, prng_idx, Output_ptr, &x);
		//if (error_code != CRYPT_OK)
		//{
		//	error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
		//	goto exit_label;
		//}

		/* encrypt it */
		error_code = rsa_exptmod(Output_ptr, x, Output_ptr, &outlen, PK_PUBLIC, &key);
		if (error_code != CRYPT_OK)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}
	}
	else
		if (PKCS1_ver == CE2_PKCS1_VER21 )
		{
			/* OAEP pad the key */
			// need to recode: MGF inside
			/* if MGF1 is single call pkcs_1_oaep_encode, othervise recode */
			error_code = pkcs_1_oaep_wrong_encode(
				DataIn_ptr, DataInSize, L, 
				Llen, pubKey->nSizeInBits, &yarrow_prng, prng_idx, hash_idx,
				Output_ptr, &x, errorSchemetype);
			if (error_code != CRYPT_OK)
			{
				error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
				goto exit_label;
			}

			/* rsa exptmod the OAEP pad */
			error_code = ltc_mp.rsa_me(Output_ptr, x, Output_ptr, &outlen, PK_PUBLIC, &key);
			if (error_code != CRYPT_OK)
			{
				error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
				goto exit_label;
			}
		}

		/* end of master code  */

exit_label:
		rsa_free(&key);
		return error_code;
} /* End of LLF_DX_RSA_SCHEMES_Encrypt */

CE2Error_t LLF_DX_RSA_WrongSign(
						   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 */
						   DxUint32_t errorSchemetype,
						   CE2_PKCS1_version PKCS1_ver)	/* in */
{
	CE2RSAPrivKey_t * privKey = (CE2RSAPrivKey_t *)UserPrivKey_ptr->PrivateKeyDbBuff;

	prng_state yarrow_prng;
	//unsigned long e = 0;
	unsigned long outlen = 0;
	unsigned long x;
	int error_code;
	int hash_idx = 0;
	int prng_idx = 0;
	hash_state hs = { 0 };
	DxUint8_t hash[MAXBLOCKSIZE] = { 0 };
	DxUint32_t hashSize = MAXBLOCKSIZE;
	rsa_key key = { 0 };

	/* register prng */
	if (register_prng(&yarrow_desc) == -1)
	{
		error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* register a math library (in this case TomFastMath) */
	ltc_mp = ltm_desc;

	/* Anna 6/8/2007 fix bug of TomCrypt that has wrong DER encoding T */
	/* of the DigestInfo values */
	/* for back word computability */
	/* The function changes the hash_descriptor values of the TomCrypt */
	error_code = UTILS_RegisterOldHashDx(hashFunc, &hash_idx);
	if (error_code != CE2_OK)
		goto exit_label;

	if (PKCS1_ver == CE2_PKCS1_VER21)
	{
		if (MGF != CE2_PKCS1_MGF1)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}
	}

	prng_idx = find_prng("yarrow");

	error_code = rng_make_prng(128, prng_idx, &yarrow_prng, 0);
	if (error_code != CRYPT_OK)
	{
		error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto exit_label;
	}

	if (hash_idx == -1 || prng_idx == -1)
	{
		error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto exit_label;
	}

	error_code = LLF_RSA_UserPrivKey_TO_rsakey(UserPrivKey_ptr, &key);
	if (error_code != CRYPT_OK)
	{
		error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* take outlen like modulus size */
	outlen = BITS2BYTES(privKey->nSizeInBits);

	/* master sign code starts */

	/* OAEP pad the key */
	x = outlen;
	error_code = UTILS_LLF_RSA_HASH(hashFunc, DataIn_ptr, DataInSize,
		hash, &hashSize);
	if (error_code != CRYPT_OK) {
		error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto exit_label;
	}

	if (PKCS1_ver == CE2_PKCS1_VER15)
	{
		/* pad it */
		error_code = pkcs_1_v15_sa_wrongencode(
			hash, hash_descriptor[hash_idx].hashsize, hash_idx,
			privKey->nSizeInBits, Output_ptr, &x, errorSchemetype);
		if (error_code != CRYPT_OK)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}
	} else if (PKCS1_ver == CE2_PKCS1_VER21) {
		// need to recode: MGF inside
		/* if MGF1 is single call pkcs_1_pss_encode, othervise recode */
		/* PSS pad the key */
		error_code = pkcs_1_pss_wrongencode(
			hash, hash_descriptor[hash_idx].hashsize,
			SaltLen, &yarrow_prng, prng_idx, hash_idx,
			privKey->nSizeInBits, Output_ptr, &x, errorSchemetype);
		if (error_code != CRYPT_OK)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}
	}

	/* RSA encode it */
	error_code = LLF_RSA_EXPTMOD(Output_ptr, x, Output_ptr, &outlen, &key, PKCS1_ver);
	if (error_code != CRYPT_OK)
	{
		error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto exit_label;
	}

	*OutputSize_ptr = (DxUint16_t)(outlen);
	/* end of master code  */

exit_label:
	rsa_free(&key);
	return error_code;
} /* End of LLF_DX_RSA_Sign */

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

////////////////////////////////////////////////////////////////////////
//CE2_DX_RSA_SCHEMES_WrongEncrypt
CE2Error_t CE2_DX_RSA_SCHEMES_WrongEncrypt(CE2_RSAUserPubKey_t *UserPubKey_ptr,
										   CE2_RSA_HASH_OpMode_t hashFunc,
										   DxUint8_t *L,
										   DxUint16_t Llen,
										   CE2_PKCS1_MGF_t MGF,
										   DxUint8_t *DataIn_ptr,
										   DxUint16_t DataInSize,
										   DxUint8_t *Output_ptr,
										   DxUint32_t errorSchemetype,
										   CE2_PKCS1_version PKCS1_ver)
{
	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_WrongEncrypt(UserPubKey_ptr, hashFunc,
		L, Llen, MGF, DataIn_ptr, DataInSize, Output_ptr, errorSchemetype, PKCS1_ver);

} /* End of CE2_DX_RSA_SCHEMES_Encrypt */

////////////////////////////////////////////////////////////////////////
//CE2_DX_RSA_WrongSign

CE2Error_t CE2_DX_RSA_WrongSign(CE2_RSAUserPrivKey_t *UserPrivKey_ptr,
								CE2_RSA_HASH_OpMode_t hashFunc,
								CE2_PKCS1_MGF_t MGF,
								DxUint16_t SaltLen,				  			      
								DxUint8_t *DataIn_ptr,
								DxUint32_t DataInSize,
								DxUint8_t *Output_ptr,
								DxUint16_t *OutputSize_ptr,
								DxUint32_t errorSchemetype,
								CE2_PKCS1_version PKCS1_ver)
{
	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_WrongSign(UserPrivKey_ptr, hashFunc, MGF, SaltLen,
		DataIn_ptr, DataInSize, Output_ptr, OutputSize_ptr, errorSchemetype, PKCS1_ver);
}
