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

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

#include "LLF_RSA_Common.h"
#include "LLF_ECPKI_Common.h"
#include "tommath.h"

/************************ Defines *****************************/
/************************ Enums *******************************/
/************************ Typedefs ****************************/
/************************ Global Data *************************/

const struct ltc_hash_descriptor sha1_descDx =
{
  "sha1Dx",
  2,
  20,
  64,

  /* DER identifier */
  { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 
  0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14 },
  15,

  &sha1_init,
  &sha1_process,
  &sha1_done,
  &sha1_test,
  NULL
};


const struct ltc_hash_descriptor md5_descDx =
{
  "md5Dx",
  3,
  16,
  64,

  /* DER identifier */
  { 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 
  0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 
  0x04, 0x10 },
  18,

  &md5_init,
  &md5_process,
  &md5_done,
  &md5_test,
  NULL
};

const struct ltc_hash_descriptor sha512_descDx =
{
  "sha512Dx",
  5,
  64,
  128,

  // DER identifier 
  { 0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 
  0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 
  0x00, 0x04, 0x40 },
  19,

  &sha512_init,
  &sha512_process,
  &sha512_done,
  &sha512_test,
  NULL
};

const struct ltc_hash_descriptor sha384_descDx =
{
  "sha384Dx",
  4,
  48,
  128,

  // DER identifier 
  { 0x30, 0x41, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 
  0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 
  0x00, 0x04, 0x30 },
  19,

  &sha384_init,
  &sha512_process,
  &sha384_done,
  &sha384_test,
  NULL
};

const struct ltc_hash_descriptor sha256_descDx =
{
  "sha256Dx",
  0,
  32,
  64,

  // DER identifier 
  { 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 
  0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 
  0x00, 0x04, 0x20 },
  19,

  &sha256_init,
  &sha256_process,
  &sha256_done,
  &sha256_test,
  NULL
};

const struct ltc_hash_descriptor sha224_descDx =
{
  "sha224Dx",
  10,
  28,
  64,

  // DER identifier 
  { 0x30, 0x2D, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 
  0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 
  0x00, 0x04, 0x1C },
  19,

  &sha224_init,
  &sha256_process,
  &sha224_done,
  &sha224_test,
  NULL
};

/************************ Private function prototype **********/
/************************ Private Functions *******************/
/************************ Public Functions ********************/

/**
****************************************************************
* Function Name: 
*  LLF_RSA_UserPubKey_TO_rsakey
*
* Inputs:
*  @param UserPubKey_ptr [in] - A pointer to the user public key structure;
*  @param key [out] - A pointer to the public key structure.
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code.
*
* \brief \b
* Description:
*  LLF_RSA_UserPubKey_TO_rsakey exports public key data from
*  UserPubKey_ptr to rsa_key.
*
* \b
* Algorithm:
*  -# Convert from unsigned bin variables of user public key to
*     mp_int variables into the public rsa_key.
***************************************************************/
CE2Error_t LLF_RSA_UserPubKey_TO_rsakey(
                        CE2_RSAUserPubKey_t * UserPubKey_ptr,	/* in */
                        rsa_key *key)							/* out */
{
	CE2RSAPubKey_t * pubKey = (CE2RSAPubKey_t *)UserPubKey_ptr->PublicKeyDbBuff;
	int error_code;

	/* Inicialization needed */
	rsa_free(key);

	ltc_init_multi(&(key->e), &(key->N), 0);

	/* Put public exponent (e) from inputted buffer into our big number e. */
	error_code = mp_read_unsigned_bin(
		key->e, (unsigned char*)pubKey->e, BITS2BYTES(pubKey->eSizeInBits));
	if (error_code != CRYPT_OK)
	{
		error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* Put modulus exponent (N) from inputted buffer into our big number N. */
	error_code = mp_read_unsigned_bin(
		key->N, (unsigned char *)pubKey->n, BITS2BYTES(pubKey->nSizeInBits));
	if (error_code != CRYPT_OK)
	{
		error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* Set key as PUBLIC. */
	key->type = PK_PUBLIC;

exit_label:
	return error_code;
} /* End of LLF_RSA_UserPubKey_TO_rsakey */

/**
****************************************************************
* Function Name: 
*  LLF_RSA_UserPrivKey_TO_rsakey
*
* Inputs:
*  @param UserPrivKey_ptr [in] - A pointer to the user private key structure;
*  @param key [out] - A pointer to the public key structure.
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code.
*
* \brief \b
* Description:
*  LLF_RSA_UserPrivKey_TO_rsakey exports private key data from
*  UserPubKey_ptr to rsa_key.
*
* \b
* Algorithm:
*  -# Convert from unsigned bin variables of user private key to
*     mp_int variables into the private rsa_key.
***************************************************************/
CE2Error_t LLF_RSA_UserPrivKey_TO_rsakey(
                        CE2_RSAUserPrivKey_t * UserPrivKey_ptr,	/* in */
                        rsa_key *key)							/* out */
{
	CE2RSAPrivKey_t * privKey = (CE2RSAPrivKey_t *)UserPrivKey_ptr->PrivateKeyDbBuff;
	int error_code;

	/* Inicialization needed */
	rsa_free(key);

	ltc_init_multi(&(key->e), &(key->N), &(key->d),
		&(key->p), &(key->q), &(key->dP), &(key->dQ), &(key->qP), 0);

	/* Put public exponent (e) from inputted buffer into our big number e. */
	error_code = mp_read_unsigned_bin(
		key->e, (unsigned char*)privKey->e, BITS2BYTES(privKey->eSizeInBits));
	if (error_code != CRYPT_OK)
	{
		error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* Put modulus exponent (N) from inputted buffer into our big number N. */
	error_code = mp_read_unsigned_bin(
		key->N, (unsigned char *)privKey->n, BITS2BYTES(privKey->nSizeInBits));
	if (error_code != CRYPT_OK)
	{
		error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* Put private exponent (d) from inputted buffer into our big number d. */
	error_code = mp_read_unsigned_bin(
		key->d, (unsigned char*)privKey->d, BITS2BYTES(privKey->dSizeInBits));
	if (error_code != CRYPT_OK)
	{
		error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* Set type key as PRIVATE / PUBLIC. */
	key->type = (privKey->mode == CE2_RSA_PRIVATE_KEY_CRT_MODE) ?
		(PK_PRIVATE) : (PK_PUBLIC);

	/* If private key is in CRT mode then get CRT values. */
	if (key->type == PK_PRIVATE)
	{
		/* Put p factor of N (p) from inputted buffer into our big number p. */
		error_code = mp_read_unsigned_bin(
			key->p, (unsigned char*)privKey->p, BITS2BYTES(privKey->pSizeInBits));
		if (error_code != CRYPT_OK)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}

		/* Put q factor of N (q) from inputted buffer into our big number q. */
		error_code = mp_read_unsigned_bin(
			key->q, (unsigned char *)privKey->q, BITS2BYTES(privKey->qSizeInBits));
		if (error_code != CRYPT_OK)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}

		/* Put d mod (p - 1) CRT param (dP) from inputted buffer into our big number dP. */
		error_code = mp_read_unsigned_bin(
			key->dP, (unsigned char *)privKey->dP, BITS2BYTES(privKey->dPSizeInBits));
		if (error_code != CRYPT_OK)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}

		/* Put d mod (q - 1) CRT param (dQ) from inputted buffer into our big number dQ. */
		error_code = mp_read_unsigned_bin(
			key->dQ, (unsigned char *)privKey->dQ, BITS2BYTES(privKey->dQSizeInBits));
		if (error_code != CRYPT_OK)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}

		/* Put 1/q mod p CRT param (qP) from inputted buffer into our big number qP. */
		error_code = mp_read_unsigned_bin(
			key->qP, (unsigned char *)privKey->qP, BITS2BYTES(privKey->qPSizeInBits));
		if (error_code != CRYPT_OK)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}
	}

	/* It's a private key */
	/*key->type = PK_PRIVATE;*/

exit_label:
	return error_code;
} /* End of LLF_RSA_UserPrivKey_TO_rsakey */

/**
****************************************************************
* Function Name: 
*  LLF_RSA_rsakey_TO_UserPubKey
*
* Inputs:
*  @param key [in] - A pointer to the public key structure;
*  @param UserPubKey_ptr [out] - A pointer to the user public key structure.

* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code.
*
* \brief \b
* Description:
*  LLF_RSA_rsakey_TO_UserPubKey exports private key data from
*  UserPubKey_ptr to rsa_key.
*
* \b
* Algorithm:
*  -# Convert from mp_int variables into the public rsa_key to 
*     unsigned bin variables of user public key.
***************************************************************/
CE2Error_t LLF_RSA_rsakey_TO_UserPubKey(
                        rsa_key *key,							/* in */
                        CE2_RSAUserPubKey_t * UserPubKey_ptr)	/* out */
{
	CE2RSAPubKey_t * pubKey = (CE2RSAPubKey_t *)UserPubKey_ptr->PublicKeyDbBuff;
	int error_code;

	/* Get modulus exponent (N) from created key and it size. */
	error_code = mp_to_unsigned_bin(key->N, (unsigned char *)pubKey->n);
	if (error_code != CRYPT_OK)
	{
		error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* Get modulus exponent (e) from created key and it size. */
	error_code = mp_to_unsigned_bin(key->e, (unsigned char *)pubKey->e);
	if (error_code != CRYPT_OK)
	{
		error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* initialize size of bufferr, in bits*/
	pubKey->eSizeInBits = mp_count_bits(key->e);
	pubKey->nSizeInBits = mp_count_bits(key->N);

	/* set valid tag */
	UserPubKey_ptr->valid_tag = sizeof(CE2_RSAUserPubKey_t);

exit_label:
	return error_code;
} /* End of LLF_RSA_rsakey_TO_UserPubKey */

/**
****************************************************************
* Function Name: 
*  LLF_RSA_rsakey_TO_UserPrivKey
*
* Inputs:
*  @param key [in] - A pointer to the private key structure;
*  @param UserPrivKey_ptr [out] - A pointer to the user private key structure;
*  @param mode [in] - defines if CRT parameters should be transfered.
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code.
*
* \brief \b
* Description:
*  LLF_RSA_rsakey_TO_UserPrivKey exports private key data
*  with/without CRT parameters from rsa_key to UserPrivKey_ptr.
*
* \b
* Algorithm:
*  -# Convert from mp_int variables into the private rsa_key to 
*     unsigned bin variables of user private key with/without
*     CRT parameters.
***************************************************************/
CE2Error_t LLF_RSA_rsakey_TO_UserPrivKey(
                        rsa_key *key,							/* in */
                        CE2_RSAUserPrivKey_t * UserPrivKey_ptr, /* out */
                        DxUint16_t mode)						/* in */
{
	CE2RSAPrivKey_t * privKey = (CE2RSAPrivKey_t *)UserPrivKey_ptr->PrivateKeyDbBuff;
	int error_code;

	privKey->mode = mode;

	/* Get modulus exponent (N) from created key and it size. */
	error_code = mp_to_unsigned_bin(key->N, (unsigned char *)privKey->n);
	if (error_code != CRYPT_OK)
	{
		error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* Get modulus exponent (e) from created key and it size. */
	error_code = mp_to_unsigned_bin(key->e, (unsigned char *)privKey->e);
	if (error_code != CRYPT_OK)
	{
		error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* Get private exponent (d) from created key and it size. */
	error_code = mp_to_unsigned_bin(key->d, (unsigned char *)privKey->d);
	if (error_code != CRYPT_OK)
	{
		error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto exit_label;
	}

	/* initialize size of bufferr, in bits*/
	privKey->eSizeInBits = mp_count_bits(key->e);
	privKey->nSizeInBits = mp_count_bits(key->N);
	privKey->dSizeInBits = mp_count_bits(key->d);

	/* export CRT parameters */
	if (privKey->mode == CE2_RSA_PRIVATE_KEY_CRT_MODE)
	{
		/* Get p factor of N (p) from imported key and it size. */
		error_code = mp_to_unsigned_bin(key->p, (unsigned char *)privKey->p);
		if (error_code != CRYPT_OK)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}

		/* Get q factor of N (q) from imported key and it size. */
		error_code = mp_to_unsigned_bin(key->q, (unsigned char *)privKey->q);
		if (error_code != CRYPT_OK)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}

		/* Get d mod (p - 1) CRT param (dP) from imported key and it size. */
		error_code = mp_to_unsigned_bin(key->dP, (unsigned char *)privKey->dP);
		if (error_code != CRYPT_OK)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}

		/* Get d mod (q - 1) CRT param (dQ) from imported key and it size. */
		error_code = mp_to_unsigned_bin(key->dQ, (unsigned char *)privKey->dQ);
		if (error_code != CRYPT_OK)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}

		/* Get 1/q mod p CRT param (qP) from imported key and it size. */
		error_code = mp_to_unsigned_bin(key->qP, (unsigned char *)privKey->qP);
		if (error_code != CRYPT_OK)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}

		/* initialize size of bufferr, in bits*/
		privKey->dPSizeInBits = mp_count_bits(key->dP);
		privKey->dQSizeInBits = mp_count_bits(key->dQ);
		privKey->qPSizeInBits = mp_count_bits(key->qP);
		privKey->pSizeInBits = mp_count_bits(key->p);
		privKey->qSizeInBits = mp_count_bits(key->q);
	}

	/* set valid tag */
	UserPrivKey_ptr->valid_tag = sizeof(CE2_RSAUserPrivKey_t);

exit_label:
	return error_code;
} /* End of LLF_RSA_rsakey_TO_UserPrivKey */

/**
****************************************************************
* Function Name: 
*  LLF_RSA_EXPTMOD
*
* Inputs:
*  @param in    [in] - A pointer to the input data (Big-Endian format);
*  @param inlen [in] - The size of the input data, in bytes;
*  @param out   [out] - A pointer to the output data (Big-Endian format);
*  @param outlen[out] - The size of the Output_buffer ptr [bytes].
*         This value is updated with the actual number 
*         of bytes that are loaded to out buffer;
*  @param key [in] - Private user key;
*  @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.
*
* \brief \b
* Description:
*  LLF_RSA_EXPTMOD loads the bignum from “in”, raises it to either
*  “e” or “d” and stores the result in “out” and the size of the result
*  in “outlen”.
*  If private key mode is set to CE2_RSA_PRIVATE_KEY_NON_CRT_MODE
*  to use “d” as the exponent (i.e. for decrypting/signing), and 
*  If private key mode is set to CE2_RSA_PRIVATE_KEY_CRT_MODE
*  to use CRT parameters of private user key to calculate exponent.
*
* \b
* Algorithm:
*  -# If we are not using CRT mode: calculate out = in**d mod N;
*  -# If we are using CRT mode: calculate out using rsa_exptmod or 
*     ltc_mp.rsa_me depending on PKCS1_ver.
***************************************************************/
CE2Error_t LLF_RSA_EXPTMOD(
                        DxUint8_t * in,		/* in */
                        DxUint32_t inlen,	/* in */
                        DxUint8_t * out,	/* out */
                        DxUint32_t * outlen,/* in,out */
                        rsa_key * key,		/* in */
                        CE2_PKCS1_version PKCS1_ver) /* in */
{
	int error_code = CRYPT_OK;
	void * data = 0;	// mp_int used for "in" number
	unsigned long x;
	int ModulusSizeinBytes;

	/* rsa decode the packet */

	/* if we are not using CRT mode */
	if (key->type != PK_PRIVATE)
	{
		/*
		if key is not int CRT mode, then we must calculate
		decoded = C**d mod N, (C - cyphertext - Data_ptr)
		*/

		/* initialization */
		x = *outlen;
		ModulusSizeinBytes = mp_unsigned_bin_size(key->N);

		ltc_init_multi(&data, 0);

		/* Data_ptr -> data */
		error_code = mp_read_unsigned_bin(data, in, inlen);
		if (error_code != CRYPT_OK)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}

		/* data = data**e mod N */
    if (key->d == 0) {
      error_code = mp_exptmod(data, key->e, key->N, data);
      if (error_code != CRYPT_OK)
      {
        error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
        goto exit_label;
      }
    } else {
      error_code = mp_exptmod(data, key->d, key->N, data);
      if (error_code != CRYPT_OK)
      {
        error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
        goto exit_label;
      }
    }

		/* sizeof(data) -> x */
		x = (unsigned long)mp_unsigned_bin_size(data);

		/* check data size */
		if (x > *outlen) {
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}

		/* data -> out */
		zeromem(out, x);
		error_code = mp_to_unsigned_bin(data, out+(ModulusSizeinBytes-x));
		if (error_code != CRYPT_OK)
		{
			error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
			goto exit_label;
		}

		x = ModulusSizeinBytes;

		ltc_deinit_multi(data, 0);
	}
	else
	/* use CRT optimized mode if possible */
	//if (key->type == PK_PRIVATE)
	{
		x = inlen;

		/* rsa decode the packet */
		if (PKCS1_ver == CE2_PKCS1_VER15)
		{
			error_code = rsa_exptmod(in, inlen, out, &x, PK_PRIVATE, key);
			if (error_code != CRYPT_OK)
			{
				error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
				goto exit_label;
			}
		}
		else
		if (PKCS1_ver == CE2_PKCS1_VER21)
		{
			error_code = ltc_mp.rsa_me(in, inlen, out, &x, PK_PRIVATE, key);
			if (error_code != CRYPT_OK)
			{
				error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
				goto exit_label;
			}
		}
	}

	*outlen = x;

exit_label:
	return error_code;
} /* End of LLF_RSA_EXPTMOD */

/**
****************************************************************
* Function Name: 
*  LLF_RSA_register_available_hash_modes
*
* Inputs:
*  None
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code.
*
* \brief \b
* Description:
*  LLF_RSA_register_available_hash_modes function register hash
*  modes that used in LLF_RSA_pkcs_v15_sa_get_sig_hash_mode to
*  determine hash idx
*
* \b
* Algorithm:
*  -# Register following modes: SHA1, SHA224, SHA256, SHA384,
*     SHA512, MD5;
***************************************************************/
CE2Error_t LLF_RSA_register_available_hash_modes(void)
{
	int i;

#if 0
	const struct ltc_hash_descriptor * modes[] =
	{
		&sha1_desc,		/* CE2_HASH_SHA1_mode */
		&sha224_desc,	/* CE2_HASH_SHA224_mode */
		&sha256_desc,	/* CE2_HASH_SHA256_mode */
		&sha384_desc,	/* CE2_HASH_SHA384_mode */
		&sha512_desc,	/* CE2_HASH_SHA512_mode */
		&md5_desc		/* CE2_HASH_MD5_mode */
	};
#else
  const struct ltc_hash_descriptor * modes[] =
  {
    &sha1_descDx,		/* CE2_HASH_SHA1_mode */
    &sha224_descDx,	/* CE2_HASH_SHA224_mode */
    &sha256_descDx,	/* CE2_HASH_SHA256_mode */
    &sha384_descDx,	/* CE2_HASH_SHA384_mode */
    &sha512_descDx,	/* CE2_HASH_SHA512_mode */
    &md5_descDx		/* CE2_HASH_MD5_mode */
  };
#endif

	/* register available modes:
	SHA1, SHA224, SHA256, SHA384, SHA512, MD5.*/
	for (i = 0; i < (int)(sizeof(modes)/sizeof(modes[0])); ++i)
		register_hash(modes[i]);

	return CE2_OK;
} /* LLF_RSA_register_available_hash_modes */

/**
****************************************************************
* Function Name: 
*  LLF_RSA_pkcs_v15_sa_get_sig_hash_mode
*
* Inputs:
*  @param sig [in] - A pointer to the signature;
*  @param siglen [in] - Length of signature (usually == modulus_bytelen);
*  @param modulus_bytelen [in] - Size of modulus in bytes;
*  @param hash_idx [out] - Founded hash idx or -1 if unknown.
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code.
*
* \brief \b
* Description:
*  LLF_RSA_pkcs_v15_sa_get_sig_hash_mode determines the hash
*  functions that was used when sign was created.
*
* \b
* Algorithm:
*  -# Register used hashes using LLF_RSA_register_available_hash_modes;
*  -# Validate sign structure;
*  -# Seek at the begining of the ASN.1 OID;
*  -# Compare OID in sign with the available OIDs and their len
*     to find equal OID.
***************************************************************/
CE2Error_t LLF_RSA_pkcs_v15_sa_get_sig_hash_mode(
                        DxUint8_t * sig,		/* in */
						DxUint32_t siglen,		/* in */
                        DxUint32_t modulus_bytelen,	/* in */
						DxInt_t *hash_idx)		/* out */
{
	int error_code = CRYPT_OK;
	unsigned long i, x, y, OIDlen;
	unsigned int msghashlen = 0;
	unsigned int OIDbegin;
	short OIDunused[TAB_SIZE] = { 0 };

	if (sig == NULL)
	{
		error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto exit_label;
	}

	if (hash_idx == NULL)
	{
		error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto exit_label;
	}

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

	LLF_RSA_register_available_hash_modes();

	/* default to invalid */
	*hash_idx = -1;
	OIDlen = 0;

	/*
	packet is 0x00 0x01 PS 0x00 T,
	where PS == 0xFF repeated modulus_bytelen - 3 - OIDlen - msghashlen times,
	T == DER || hash
	*/
	x = 0;
	if ((sig[x++] != 0x00 || sig[x++] != 0x01))
	{
		error_code = CE2_OK;
		goto exit_label;
	}

	/* now follows (modulus_bytelen - 3 - OIDlen - msghashlen) 0xFF bytes */
	for (i = 0; i < (modulus_bytelen - 3 - OIDlen - msghashlen); i++)
	{
		/* found end of 0xFF array: i == OIDlen of hash in sign */
		if (sig[x] == 0x00) break;

		/* expected 0xFF */
		if (sig[x++] != 0xFF)
		{
			error_code = CRYPT_OK;
			goto exit_label;
		}
	}

	/* is invalid end of 0xFF array */
	if (sig[x++] != 0x00)
	{
		error_code = CRYPT_OK;
		goto exit_label;
	}

	/* get max possible OIDlen */
	/* thru all hashes */
	LTC_MUTEX_LOCK(&ltc_hash_mutex);
	for (i = 0; i < TAB_SIZE; ++i)
	{
		/* skip unnamed */
		if (hash_descriptor[i].name == NULL)
		{
			OIDunused[i] = 1;
			continue;
		}

		/* get max OIDlen */
		OIDlen = MAX(hash_descriptor[i].OIDlen, OIDlen);
	}
	LTC_MUTEX_UNLOCK(&ltc_hash_mutex);

	/* start of OID */
	OIDbegin = x;

	/* check  */
	LTC_MUTEX_LOCK(&ltc_hash_mutex);

	/* get current OID */
	for (y = 0; x < (modulus_bytelen - 3); ++x, ++y)
	{
		for (i = 0; i < TAB_SIZE; ++i)
		{
			/* use only available */
			if (OIDunused[i] == 1) continue;

			/* typecast (unsigned char) added */
			if (sig[x] != (unsigned char)hash_descriptor[i].OID[y])
			{
				OIDunused[i] = 1;
				continue;
			}

			/* check size, maybe found */
			if (x - OIDbegin +1 == hash_descriptor[i].OIDlen &&
				modulus_bytelen ==
				OIDbegin + hash_descriptor[i].OIDlen + hash_descriptor[i].hashsize)
			{
				/* found */
				*hash_idx = i;
				goto exit_label;
			}
		}
	}
	LTC_MUTEX_UNLOCK(&ltc_hash_mutex);

exit_label:
	return error_code;
} /* End of LLF_RSA_pkcs_v15_sa_get_sig_hash_mode */

/**
*************************************************************
* Function Name: 
*  LLF_RSA_pkcs_1_v15_sa_decode
*
* Inputs:
*  @param msghash    [in] - The hash that was signed;
*  @param msghashlen [in] - The length of the hash;
*  @param sig        [in] - The signature [padded data];
*  @param siglen     [in] - The length of the signature;
*  @param hash_idx   [in] - The index of the hash used;
*  @param modulus_bitlen [in] - The bit length of the RSA modulus;
*  @param res        [out] - Result of comparison, 1==valid, 0==invalid.
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK, CRYPT_OK - On success
*  - Otherwise - error code.
*
* \brief \b
* Description:
*  LLF_RSA_pkcs_1_v15_sa_decode perform PKCS #1 v1.5 Signature Decoding.
*
* \b
* Algorithm:
*  -# Identical pkcs_1_v15_sa_decode but used typecast on IOD
*     validation;
*  -# Validate hash;
*  -# Validate sizes;
*  -# Validate OID;
*  -# Compare sign hashes.
***************************************************************/
CE2Error_t LLF_RSA_pkcs_1_v15_sa_decode(
                        const unsigned char *msghash,	/* in */
                        unsigned long        msghashlen,/* in */
                        const unsigned char *sig,		/* in */
                        unsigned long        siglen,	/* in */
                        int                  hash_idx,	/* in */
                        unsigned long        modulus_bitlen, /* in */
                        int                 *res)		/* out */
{
   unsigned long x, y, modulus_bytelen, OIDlen;
   int err;
   
   /* default to invalid */
   *res = 0;

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

   /* get OIDlen */
   OIDlen = hash_descriptor[hash_idx].OIDlen;

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

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

   /* packet is 0x00 0x01 PS 0x00 T, where PS == 0xFF repeated modulus_bytelen - 3 - OIDlen - msghashlen times, T == DER || hash */
   x = 0;
   if (sig[x++] != 0x00 || sig[x++] != 0x01) {
      return CRYPT_OK;
   }

   /* now follows (modulus_bytelen - 3 - OIDlen - msghashlen) 0xFF bytes */
   for (y = 0; y < (modulus_bytelen - 3 - OIDlen - msghashlen); y++) {
     if (sig[x++] != 0xFF) {
        return CRYPT_OK;
     }
   }

   if (sig[x++] != 0x00) {
      return CRYPT_OK;
   }

   /* typecast (unsigned char) added */
   for (y = 0; y < OIDlen; y++) {
      if (sig[x++] != (unsigned char)hash_descriptor[hash_idx].OID[y]) {
         return CRYPT_OK;
      }
   }

   if (memcmp(msghash, sig+x, msghashlen) == 0) {
      *res = 1;
   }
   return CRYPT_OK;
} /* End of LLF_RSA_pkcs_1_v15_sa_decode */

/**
*************************************************************
* Function Name: 
*  LLF_RSA_pkcs_1_oaep_encode
*
* Inputs:
* @param msg       [in]  - The data to encode;
* @param msglen    [in]  - The length of the data to encode (octets);
* @param lparam    [in]  - A session or system parameter (can be NULL);
* @param lparamlen [in]  - The length of the lparam data;
* @param modulus_bitlen [in] - The bit length of the RSA modulus;
* @param prng      [in]  - An active PRNG state;
* @param prng_idx  [in]  - The index of the PRNG desired;
* @param hash_idx  [in]  - The index of the hash desired;
* @param out       [out] - The destination for the encoded data;
* @param outlen    [in/out] - The max size and resulting size of the encoded data.
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK, CRYPT_OK - On success
*  - Otherwise - error code.
*
* \brief \b
* Description:
*  LLF_RSA_pkcs_1_oaep_encode perform PKCS #1 v2.1 Encoding.
*
* \b
* Algorithm:
*  -# Identical pkcs_1_oaep_encode but null pointer is valid
*     entire data;
*  -# Validate hash;
*  -# Validate sizes;
*  -# Validate OID;
*  -# Compare sign hashes.
***************************************************************/
CE2Error_t LLF_RSA_pkcs_1_oaep_encode(
						const unsigned char	*msg,		/* in */
						unsigned long		msglen,		/* in */
						const unsigned char	*lparam,	/* in */
						unsigned long		lparamlen,	/* in */
						unsigned long		modulus_bitlen,	/* in */
						prng_state			*prng,		/* in */
						int					prng_idx,	/* in */
						int					hash_idx,	/* in */
						unsigned char		*out,		/* out */
						unsigned long		*outlen)	/* in/out */
{
   unsigned char *DB, *seed, *mask;
   unsigned long hLen, x, y, modulus_len;
   int           err;

   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)  */
   x = hLen;
   y = modulus_len - msglen - 2*hLen - 2;
   XMEMSET(DB+x, 0, y);
   x += y;

   /* 0x01 byte */
   DB[x++] = 0x01;

   /* message (length = msglen) */
   if (msg != NULL) {
	  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 ((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 */
   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;
} /* End of LLF_RSA_pkcs_1_oaep_encode */

/**
****************************************************************
* Function Name: 
*  LLF_RSA_pss_get_sig_salt_len
*
* Inputs:
*  @param sig [in] - A pointer to the signature;
*  @param siglen [in] - Length of signature (usually == modulus_bytelen);
*  @param modulus_bytelen [in] - Size of modulus in bytes;
*  @param hash_idx [int] - hash idx;
*  @param saltlen [out] - Founded saltlen;
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code.
*
* \brief \b
* Description:
*  LLF_RSA_pss_get_sig_salt_len determines the salt len
*  parameter that was used when sign was created.
*
* \b
* Algorithm:
*  -# Register used hashes using LLF_RSA_register_available_hash_modes;
*  -# Validate sign structure;
*  -# Seek at the begining of the ASN.1 OID;
*  -# Calculate salt len of the sign.
***************************************************************/
CE2Error_t LLF_RSA_pss_get_sig_salt_len(
                        DxUint8_t * sig,		/* in */
						DxUint32_t siglen,		/* in */
                        DxUint32_t modulus_bitlen,/* in */
						DxInt_t hash_idx,		/* in */
						DxUint16_t* saltlen)	/* out */
{
	int error_code = CE2_LLF_RSA_MODULE_ERROR_BASE;

	unsigned char *DB, *mask,*hash;
	unsigned long x, y, hLen, modulus_len;

	if (sig == NULL)				goto exit_label;
	if (saltlen == NULL)			goto exit_label;
	modulus_len	= BITS2BYTES(modulus_bitlen);
	if (siglen != modulus_len)	goto exit_label;

	LLF_RSA_register_available_hash_modes();

	/* default to invalid */
	*saltlen = 0;

	/* allocate ram for DB/mask/salt/hash of size modulus_len */
	DB		= XMALLOC(modulus_len);
	mask	= XMALLOC(modulus_len);
	hash	= XMALLOC(modulus_len);

	if (DB == NULL || mask == NULL ||hash == NULL)
	{
		if (DB != NULL)		XFREE(DB);
		if (mask != NULL)	XFREE(mask);
		if (hash != NULL)	XFREE(hash);

		goto exit_label;
	}

	/* ensure hash is valid */
	if (hash_is_valid(hash_idx) != CRYPT_OK)
	{
		goto exit_label;
	}

	hLen = hash_descriptor[hash_idx].hashsize;

	/* ensure the 0xBC byte */
	if (sig[siglen - 1] != 0xBC)
	{
		goto exit_label;
	}

	/* copy out the DB */
	x = 0;
	XMEMCPY(DB, sig + x, modulus_len - hLen - 1);
	x += modulus_len - hLen - 1;

	/* copy out the hash */
	XMEMCPY(hash, sig + x, hLen);
	x += hLen;

	/* check the MSB */
	if ((sig[0] & ~(0xFF >> ((modulus_len<<3) - (modulus_bitlen-1)))) != 0)
	{
		goto exit_label;
	}

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

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

	/* now clear the first byte [make sure smaller than modulus] */
	DB[0] &= 0xFF >> ((modulus_len<<3) - (modulus_bitlen-1));

	/* DB = PS || 0x01 || salt, PS == modulus_len - saltlen - hLen - 2 zero bytes */

	/* check for zeroes and 0x01 */
	for (x = 0; x < modulus_len - hLen - 2; ++x)
	{
		if (DB[x] != 0x00)
		{
			break;
		}
	}

	/* check for the 0x01 */
	if (DB[x] != 0x01)
	{
		goto exit_label;
	}

	*saltlen = (DxUint16_t)(modulus_len - hLen - 2 - x);

	error_code = CRYPT_OK;

#ifdef LTC_CLEAN_STACK
	zeromem(DB,		modulus_len);
	zeromem(mask,	modulus_len);
	zeromem(hash,	modulus_len);
#endif

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

exit_label:
	return error_code;
} /* End of LLF_RSA_pss_get_sig_salt_len */


/**
****************************************************************
* Function Name: 
*  LLF_RSA_Encrypt
*
* Inputs:
*  @param in    [in] - A pointer to the input data (Big-Endian format);
*  @param inlen [in] - The size of the input data, in bytes;
*  @param out   [out] - A pointer to the output data (Big-Endian format);
*  @param outlen[out] - The size of the Output_buffer ptr [bytes].
*         This value is updated with the actual number 
*         of bytes that are loaded to out buffer;
*  @param UserPublKey [in] - User public RSA key;
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code.
*
* \brief \b
* Description:
*  LLF_RSA_Encrypt - Make RSA encryption (modular exponentiation).
*
* \b
* Algorithm:
*  -# Initialize LibTomCrypt variables.
*  -# Verify if in < modulus.
*  -# Encrypt input message with using exptmod() function;
*  -# Convert encrypted message in output big-endian format;
***************************************************************/
CE2Error_t LLF_RSA_Encrypt(DxUint8_t * in,		/* in */
                          DxUint32_t inlen,	/* in */
                          DxUint8_t * out,	/* out */
                          DxUint32_t * outlen,/* in,out */
                          CE2_RSAUserPubKey_t *UserPublKey) /* in */
{
  CE2RSAPubKey_t *pubKey = (CE2RSAPubKey_t *)UserPublKey->PublicKeyDbBuff;
  CE2Error_t result = CE2_OK;
  void *n, *m, *e, *c;
  int error_code, cmp_result;
  DxUint32_t c_size, n_size;

  /* Init LibTomCrypt variables */
  ltc_mp = ltm_desc;
  error_code = ltc_init_multi(&n, &m, &e, &c, NULL);
  if (error_code != CRYPT_OK) {
    return CE2_LLF_RSA_MODULE_ERROR_BASE;
  }
  /* Set m */
  if (in != NULL) {
    error_code = ltc_mp.unsigned_read(m, in, inlen);
    if (error_code != CRYPT_OK) {
      result = CE2_LLF_RSA_MODULE_ERROR_BASE;
      goto error_case; 
    }
  } else {
	error_code = ltc_mp.set_int(m, 0);
	if (error_code != CRYPT_OK) {
		result = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto error_case; 
	}
  }
  /* Set n */
  error_code = ltc_mp.unsigned_read(n, (unsigned char*)pubKey->n, 
    BITS2BYTES(pubKey->nSizeInBits));
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_RSA_MODULE_ERROR_BASE;
    goto error_case; 
  }
  /* Set e (public exponent) */
  error_code = ltc_mp.unsigned_read(e, (unsigned char*)pubKey->e, 
    BITS2BYTES(pubKey->eSizeInBits));
  if (error_code != CRYPT_OK) {
    result = CE2_LLF_RSA_MODULE_ERROR_BASE;
    goto error_case; 
  }

  /* Verify if the integer representative of m is not strictly */
  /* less than the RSA modulus.                                */
  /* Compare m and n */
  cmp_result = ltc_mp.compare(m, n);
  if (cmp_result != LTC_MP_LT) {
    result = CE2_CMLA_RSA_ENCRYPT_MESSAGE_INTEGER_TOO_LONG_ERROR;
    goto error_case; 
  }

  /* Encrypt m under device public key UserPublKey with RSA encryption */
  /* c = m^e mod N */
  error_code = ltc_mp.exptmod(m, e, n, c);
  if (error_code != CRYPT_OK)
  {
    result = CE2_LLF_RSA_MODULE_ERROR_BASE;
    goto error_case; 
  }

  /* Convert c to big-endian number out */
	c_size = ltc_mp.unsigned_size(c);
	n_size = ltc_mp.unsigned_size(n);
	if (n_size > *outlen)
	{
		*outlen = n_size;
		result = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto error_case; 
	}
	*outlen = n_size;
	zeromem(out, n_size - c_size);
	error_code = ltc_mp.unsigned_write(c, out + (n_size - c_size));
	if (error_code != CRYPT_OK) {
		result = CE2_LLF_RSA_MODULE_ERROR_BASE;
		goto error_case; 
	}
  
error_case:
  ltc_deinit_multi(m, n, e, c, NULL);
  return result;
} /* End of LLF_RSA_Encrypt */

/**
****************************************************************
* Function Name: 
*  LLF_RSA_Decrypt
*
* Inputs:
*  @param in    [in] - A pointer to the input data (Big-Endian format);
*  @param inlen [in] - The size of the input data, in bytes;
*  @param out   [out] - A pointer to the output data (Big-Endian format);
*  @param outlen[out] - The size of the Output_buffer ptr [bytes].
*         This value is updated with the actual number 
*         of bytes that are loaded to out buffer;
*  @param UserPrivKey [in] - User private RSA key;
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code.
*
* \brief \b
* Description:
*  LLF_RSA_Decrypt - Make RSA decryption (modular exponentiation).
*
* \b
* Algorithm:
*  -# Initialize LibTomCrypt variables.
*  -# Decrypt input message 
*    a) with using exptmod() function (in NON_CRT_MODE);
*    b) with using rsa_me() function (in CRT_MODE);
*  -# Convert decrypted message in output big-endian format;
***************************************************************/
CE2Error_t LLF_RSA_Decrypt(DxUint8_t * in,		/* in */
                           DxUint32_t inlen,	/* in */
                           DxUint8_t * out,	/* out */
                           DxUint32_t * outlen,/* in,out */
                           CE2_RSAUserPrivKey_t *UserPrivKey) /* in */
{
  CE2RSAPrivKey_t *privKey = (CE2RSAPrivKey_t *)UserPrivKey->PrivateKeyDbBuff;
  CE2Error_t result = CE2_OK;
  DxUint32_t m_size, n_size;
  rsa_key key = {0};
  void *c, *m;
  int error_code;

  /* Initialize LibTomCrypt variables */
  ltc_mp = ltm_desc;
  error_code = ltc_init_multi(&(key.e), &(key.N), &(key.d), &(key.p), 
    &(key.q), &(key.dP), &(key.dQ), &(key.qP), &c, &m, NULL);
  if (error_code != CRYPT_OK) 
    return CE2_LLF_RSA_MODULE_ERROR_BASE;

  /* Decrypt input message */
  if (privKey->mode == CE2_RSA_PRIVATE_KEY_CRT_MODE) {
    /* Set p */
    error_code = ltc_mp.unsigned_read(key.p, (unsigned char*)privKey->p, 
      BITS2BYTES(privKey->pSizeInBits));
    if (error_code != CRYPT_OK) {
      result = CE2_LLF_RSA_MODULE_ERROR_BASE;
      goto error_case; 
    }
    /* Set q */
    error_code = ltc_mp.unsigned_read(key.q, (unsigned char*)privKey->q, 
      BITS2BYTES(privKey->qSizeInBits));
    if (error_code != CRYPT_OK) {
      result = CE2_LLF_RSA_MODULE_ERROR_BASE;
      goto error_case; 
    }
    /* Set dP */
    error_code = ltc_mp.unsigned_read(key.dP, (unsigned char*)privKey->dP, 
      BITS2BYTES(privKey->dPSizeInBits));
    if (error_code != CRYPT_OK) {
      result = CE2_LLF_RSA_MODULE_ERROR_BASE;
      goto error_case; 
    }
    /* Set dQ */
    error_code = ltc_mp.unsigned_read(key.dQ, (unsigned char*)privKey->dQ, 
      BITS2BYTES(privKey->dQSizeInBits));
    if (error_code != CRYPT_OK) {
      result = CE2_LLF_RSA_MODULE_ERROR_BASE;
      goto error_case; 
    }
    /* Set qP */
    error_code = ltc_mp.unsigned_read(key.qP, (unsigned char*)privKey->qP, 
      BITS2BYTES(privKey->qPSizeInBits));
    if (error_code != CRYPT_OK) {
      result = CE2_LLF_RSA_MODULE_ERROR_BASE;
      goto error_case; 
    }
    /* N = q*p */
    error_code = ltc_mp.mul(key.p, key.q, key.N);
    if (error_code != CRYPT_OK) {
      result = CE2_LLF_RSA_MODULE_ERROR_BASE;
      goto error_case; 
    }
    key.type = PK_PRIVATE;
    /* Optimized RSA decryption */
    error_code = ltc_mp.rsa_me(in, inlen, 
      out, outlen, PK_PRIVATE, &key);
    if (error_code != CRYPT_OK) {
      result = CE2_LLF_RSA_MODULE_ERROR_BASE;
      goto error_case; 
    }
  } else {
    /* Set c */
    error_code = ltc_mp.unsigned_read(c, in, inlen);
    if (error_code != CRYPT_OK) {
      result = CE2_LLF_RSA_MODULE_ERROR_BASE;
      goto error_case; 
    }
    /* Set N */
    error_code = ltc_mp.unsigned_read(key.N, (unsigned char*)privKey->n, 
      BITS2BYTES(privKey->nSizeInBits));
    if (error_code != CRYPT_OK) {
      result = CE2_LLF_RSA_MODULE_ERROR_BASE;
      goto error_case; 
    }
    /* Set private exponent */
    error_code = ltc_mp.unsigned_read(key.d, (unsigned char*)privKey->d, 
      BITS2BYTES(privKey->dSizeInBits));
    if (error_code != CRYPT_OK) {
      result = CE2_LLF_RSA_MODULE_ERROR_BASE;
      goto error_case; 
    }
    /* m = c^d mod N */
    error_code = ltc_mp.exptmod(c, key.d, key.N, m);
    if (error_code != CRYPT_OK)
    {
      result = CE2_LLF_RSA_MODULE_ERROR_BASE;
      goto error_case; 
    }
    /* Convert m to big-endian number out */
    m_size = ltc_mp.unsigned_size(m);
		n_size = ltc_mp.unsigned_size(key.N);
    if (n_size > *outlen)
    {
      *outlen = n_size;
      result = CE2_LLF_RSA_MODULE_ERROR_BASE;
      goto error_case; 
    }
    *outlen = n_size;
		zeromem(out, n_size - m_size);
    error_code = ltc_mp.unsigned_write(m, out + (n_size - m_size));
    if (error_code != CRYPT_OK) {
      result = CE2_LLF_RSA_MODULE_ERROR_BASE;
      goto error_case; 
    }
  }

error_case:
  ltc_deinit_multi(key.e, key.d, key.N, key.dQ, key.dP, key.qP, key.p, 
    key.q, m, c, NULL);
  return result;
} /* End of LLF_RSA_Decrypt */

/**
****************************************************************
* Function Name: 
*  LLF_RSA_PKCS1_V15_Encode
*
* Inputs:
*  @param DataIn_ptr [in] - A pointer to input data.
*  @param DataInSize [in] - Size of input data.
*                           Note: DataInSize <=  ModulusSize - 11; 
*  @param ModulusSizeInBits [in] - Size of modulus (in bits). 
*  @param DataOut_ptr [out] - A pointer to output data.    
*  @param DataOutSize_ptr [in/out] - A pointer to actual size of output data.
*                                    Note: *DataOutSize_ptr >= ModulusSize; 
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code.
*
* \brief \b
* Description:
*  LLF_RSA_PKCS1_V15_Encode - Make pkcs1 v15 encoding.
*
* \b
* Algorithm:
*  -# 
***************************************************************/
CE2Error_t LLF_RSA_PKCS1_V15_Encode(DxUint8_t *DataIn_ptr,    
																		DxUint32_t DataInSize,
																		DxUint32_t ModulusSizeInBits, 
																		DxUint8_t *DataOut_ptr,    
																		DxUint32_t *DataOutSize_ptr)
{
	CE2Error_t error, result = CE2_OK;
	prng_state prng; 
	int wprng;
	DxUint32_t modulusSize, size, was_read, j, i;

	if((DataIn_ptr == DX_NULL && DataInSize != 0) || 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.                       */
	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;
	DataOut_ptr[i++] = 0x00;
	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 */ 
	for(j = 0; j < size; j++) {
		if (DataOut_ptr[i + j] == 0)
			DataOut_ptr[i + j] = 1;
	}
	i += size;
	DataOut_ptr[i++] = 0x00;
	if (DataIn_ptr != DX_NULL)
		memcpy(DataOut_ptr + i, DataIn_ptr, DataInSize);
	*DataOutSize_ptr = modulusSize;

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

/**
****************************************************************
* Function Name: 
*  LLF_RSA_PKCS1_V15_Decode
*
* Inputs:
*  @param DataIn_ptr [in] - A pointer to input data.
*  @param DataInSize [in] - Size of input data.
*                           Note: DataInSize == ModulusSize; 
*  @param ModulusSizeInBits [in] - Size of modulus (in bits). 
*  @param DataOut_ptr [out] - A pointer to output data.    
*  @param DataOutSize_ptr [in/out] - A pointer to actual size of output data.
*                                    Note: *DataOutSize_ptr >= ModulusSize - 11; 
*
* Outputs: @returns \b
*  CE2Error_t  
*  - CE2_OK - On success
*  - Otherwise - error code.
*
* \brief \b
* Description:
*  LLF_RSA_PKCS1_V15_Decode - Make pkcs1 v15 decoding.
*
* \b
* Algorithm:
*  -# 
***************************************************************/
CE2Error_t LLF_RSA_PKCS1_V15_Decode(DxUint8_t *DataIn_ptr,    
																		DxUint32_t DataInSize,
																		DxUint32_t ModulusSizeInBits, 
																		DxUint8_t *DataOut_ptr,    
																		DxUint32_t *DataOutSize_ptr)
{
	DxUint32_t modulusSize, i;

	if(DataIn_ptr == DX_NULL || DataOut_ptr == DX_NULL || 
		DataOutSize_ptr == DX_NULL)
		return CE2_LLF_RSA_MODULE_ERROR_BASE;
	
	if (*DataOutSize_ptr == 0){
		return CE2_OK;
	}

	/* Get modulus size (in bytes) */
	modulusSize = BITS2BYTES(ModulusSizeInBits);
	if (modulusSize < 12) 
		return CE2_LLF_RSA_MODULE_ERROR_BASE;

	/* Verify input data size */
	if (DataInSize != modulusSize)
		return CE2_LLF_RSA_MODULE_ERROR_BASE;


	/* Should start with 0x00 0x02 */
	if (DataIn_ptr[0] != 0x00 || DataIn_ptr[1] != 0x02) 
		return CE2_LLF_RSA_MODULE_ERROR_BASE;

	/* PS must has at least 8 bytes size */
	for(i = 10; i < DataInSize; i++) {
		if (DataIn_ptr[i] == 0) {
			i++;
			break;
		}
	}
	/* Extract original message */
	if (i != DataInSize)
		memcpy(DataOut_ptr, DataIn_ptr + i, DataInSize - i);
	*DataOutSize_ptr = DataInSize - i;

	return CE2_OK;
} /* End of LLF_RSA_PKCS1_V15_Decode */
