/****************************************************************************/
/*	Copyright (c) 2009, Bendor Research Pty. Ltd. All rights reserved.		*/
/*	This software is released under the GNU General Public License, version	*/
/*	3, with the exemptions that 1) the header files installed by this 	 	*/
/*	package can be included in closed-source code and 2) the libraries		*/
/*	built by this package can be statically linked into a closed-source 	*/
/*	binary. See the file LICENSE for the details.							*/
/*	This software is provided "AS IS", without any warranty or guarantee.	*/
/*	By using this software you acknowledge that neither Bendor Research nor	*/
/*	any of its personnel or affiliates can be held liable for any damages,	*/
/*	including, but not limited to, loss of business, loss of money, loss of */
/*	life, loss or reputation, arising out of this software being faulty or	*/
/*	not performing as advertised, even if Bendor Research was aware of such	*/
/*	faults in the software. You use this software at your own risk, any and */
/*	all liabilities that arise out of your using this software are strictly	*/
/*	yours.																	*/
/****************************************************************************/

#define	BLC_STRING_INLINE
#include <string.h>
#include <crypto/rsa.h>

/****************************************************************************/
/*					Local prototypes										*/
/****************************************************************************/

static int	rsa_mlen( BC_NANU nanu, BC_RSA_PUBLIC_KEY *kp );

/****************************************************************************/
/*					Public interface										*/
/****************************************************************************/

/** @addtogroup rsa */
/** @{ */

/**
*	Encrypt a message with the public key.
*
*	The function encrypts a message with the public key using the procedure
*	described in the PKCS#1-1.5 document.
*	<br><br>
*	The function receives a BC_NANU object that must contain an already
*	initialised natual number calculation workspace; see BC_RsaPublicCore()
*	for further details.
*	<br><br>
*	The function also receives a pointer to the public key structure and a
*	pointer to a buffer, at least as long as the modulus, that contains the
*	message (starting at its first byte).  The length of the message, which
*	must be at least 3 bytes shorter than the modulus, is given in the last
*	function argument. Upon return the buffer will contain the encrypted
*	message, which is always exactly as long as the modulus.
*	<br><br>
*	The function returns BC_NANU_NANU in case of success or one of the
*	error codes defined in <tt>nanu.h</tt> or <tt>rsa.h</tt> in case of
*	failure.
*
*	@param	nanu	An already initialised BC_NANU object
*	@param	keys	Pointer to an RSA public key structure
*	@param	data	Pointer to a data buffer that contains the cleartext at
*					entry and will contain the ciphertext at exit
*	@param	dlen	The length of the cleartext, in bytes
*	@param	seed	A number that is not 0, which will be used as a seed
*					for a random number generator. You should generate
*					the seed as random as you can, preferably using some
*					hard to predict hardware value, also possibly the
*					current date and time. Try to avoid using the same
*					seed for consecutive encryptions.
*
*	@retval	BC_NANU_NANU	Success
*	@retval	BC_NANU_SOVR	Natural numbers library stack overflow
*	@retval	BC_NANU_OMEM	Natural numbers library out of memory
*	@retval	BC_NANU_SIZE	Invalid size in one of the key components
*	@retval	BC_NANU_NANN	Invalid value in one of the key components
*	@retval BC_RSA_KEYL		Key length is invalid
*	@retval	BC_RSA_DLEN		Cleartext is too long
*	@retval BC_RSA_SEED		Incorrect seed value (i.e. it was 0)
*/

int	BC_RsaPublicEncrypt( BC_NANU nanu, BC_RSA_PUBLIC_KEY *keys,
						 void *data, unsigned dlen, unsigned seed )
{
char	*b;
int		l, i;

	if ( ! seed ) return( BC_RSA_SEED );

	if ( ( l = rsa_mlen( nanu, keys ) ) < 0 ) {

		// Invalid length for modulus

		return( l );
	}

	if ( dlen > (unsigned) l - 3 ) {

		// The cleartext is too long

		return( BC_RSA_DLEN );
	}

	// Move the message to the end of the buffer

	memrcpy( (char *) data + l - dlen, data, dlen );

	// Messages encrypted by the private key have the following format:
	// 0x00 0x02 0x?? 0x?? ... 0x?? 0x00 <user data> (as per PKCS#1) where
	// 0x?? is a random byte other than 0. We generate our own random bytes
	// using a cryptographically unsafe generator. Although PKCS#1 suggests
	// the use of a safe RNG, it is not mandatory because a weak RNG doesn't
	// actually compromise the RSA algorithm. SO we opt for the fast and
	// simple solution here.

	b = data;
	*b++ = 0;
	*b++ = 2;

	for ( i = 2 ; i < l - (int) dlen - 1 ; i++ ) {

		do {

			seed = 1103515245 * seed + 12345;

		} while ( ! ( ( seed >> 12 ) & 255 ) );

		*b++ = seed >> 12;
	}

	*b++ = 0;

	// Now we can do the actual calculation

	l = BC_RsaPublicCore( nanu, keys, data );
	return( l < 0 ? l : BC_NANU_NANU );
}

/**
*	Decrypt a message with the public key.
*
*	The function decrypts a message with the public key using the procedure
*	described in the PKCS#1-1.5 document.
*	<br><br>
*	The function receives a BC_NANU object that must contain an already
*	initialised natual number calculation workspace; see BC_RsaPublicCore()
*	for further details.
*	<br><br>
*	The function also receives a pointer to the public key structure and a
*	pointer to a buffer containing the ciphertext. The ciphertext is exactly
*	as long as the modulus. Upon return the buffer will contain the decrypted
*	message, which is at least 3 bytes shorter than the modulus.
*	<br><br>
*	The function returns the length of the decrypted message in case of
*	success or one of the error codes defined in <tt>nanu.h</tt> or
*	<tt>rsa.h</tt> in case of failure.
*
*	@param	nanu	An already initialised BC_NANU object
*	@param	keys	Pointer to an RSA private key structure
*	@param	data	Pointer to a data buffer that contains the ciphertext at
*					entry and will contain the cleartext at exit
*
*	@retval >=0				Success, the returned value is the length of
*							the decrypted cleartext.
*	@retval	BC_NANU_SOVR	Natural numbers library stack overflow
*	@retval	BC_NANU_OMEM	Natural numbers library out of memory
*	@retval	BC_NANU_SIZE	Invalid size in one of the key components
*	@retval	BC_NANU_NANN	Invalid value in one of the key components
*	@retval BC_RSA_KEYL		Key length is invalid
*	@retval	BC_RSA_DLEN		Cleartext is too long
*/

int	BC_RsaPublicDecrypt( BC_NANU nanu, BC_RSA_PUBLIC_KEY *keys, void *data )
{
char	*b;
int		l, i;

	if ( ( l = BC_RsaPublicCore( nanu, keys, data ) ) < 0 ) {

		// Calculation error

		return( l );
	}

	// Check if the message matches. It must have been encrypted with
	// the private key, so it should start with 0x00 0x01, followed by
	// zero or more 0xff filler bytes, a 0x00 byte and the cleartext.

	b = data;

	if ( *b++ != 0x00 || *b++ != 0x01 ) {

		// Format error

		return( BC_RSA_FMAT );
	}

	for ( i = l - 2 ; i && *b == 0xff ; b++, i-- );

	if ( ! i || *b ) {

		// The separator 0x00 between the fillers and the cleartext
		// can not be found, this is not a valid message

		return( BC_RSA_FMAT );
	}

	// The message is valid and i is its actual length + 1, b points to
	// the 0x00 byte

	memcpy( data, ++b, --i );
	return( i );
}

/**
*	Core public key RSA operation.
*
*	Calculates <tt>C = M<sup>e</sup> <i>mod</i> n</tt>
*	where M is the message to be encrypted with the public key or the
*	ciphertext encrypted with the private key, C is the encrypted ciphertext
*	the decrypted message, respectively; e is the public exponent and n is
*	the modulus.<br>
*	C and M must have the same length as n.
*	<br><br>
*	This function is the core used in the RSA public key functions and it can
*	be used to implement the 2.1 version RSA scheme. The core operation is the
*	same, but the way the user message is turned into M is different for the
*	version 1.5 and version 2.x RSA standards.
*	<br><br>
*	The first parameter is a natural number workspace object that has to
*	have been obtained by a call to BC_NanuInit(). The memory needed for
*	the calculations is 3 times the size of the modulus plus the administrative
*	area and the stack depth must be at least 4. That, is, if you have a key
*	with a modulus length of N (in bits), you need:
*	@code
*	//
*	//	The length of the modulus in words
*	//
*	#define	RSA_MOD_LEN		(N/32)
*	//
*	//	Minimum stack size required by the public RSA functions
*	//
*	#define RSA_STACK		4
*	//
*	// 	The size of the workspace
*	//
*	#define	RSA_WORKSPACE	( BC_NANU_POOL( RSA_STACK ) + 3 * RSA_MOD_LEN )
*	//
*	//	Define the workspace
*	//
*	static int workspace[ RSA_WORSPACE ];
*	//
*	//	Prepare the workspace before passing it to the RSA routine
*	//
*	nanu = BC_NanuInit( workspace, RSA_WORKSPACE, RSA_STACK );
*	@endcode
*	The function returns the length of the modulus (in bytes) in case of
*	success or one of the (negative) error codes defined in <tt>nanu.h</tt>
*	or <tt>rsa.h</tt> in case of failure.
*
*	@param	nanu	An already initialised BC_NANU object
*	@param	keys	Pointer to an RSA public key structure
*	@param	data	Pointer to a data buffer that contains M at
*					entry and will contain C at exit.
*
*	@retval >0				Success, the returned value is the length of
*							the key (in bytes).
*	@retval	BC_NANU_SOVR	Natural numbers library stack overflow
*	@retval	BC_NANU_OMEM	Natural numbers library out of memory
*	@retval	BC_NANU_SIZE	Invalid size in one of the key components
*	@retval	BC_NANU_NANN	Invalid value in one of the key components
*	@retval BC_RSA_KEYL		Key length is invalid. The routine accepts
*							keys with length of whole multiplies of 256,
*							up to 8192. Other keylengths result in this error.
*/

int	BC_RsaPublicCore( BC_NANU nanu, BC_RSA_PUBLIC_KEY *keys, void *data )
{
int		e, l;

	l = rsa_mlen( nanu, keys );
	e = l;

	// For the public key operation we do a modular exponentiation
	// as described in the theory, that is, c = m^e mod n.
	// We have no other info but the exponent and the modulus, so
	// we can't do any shortcuts. Fortunately, the public exponent is
	// really small, so we will need to do only a few modular
	// multiplications.

	if ( e >= 0 ) e = BC_NanuPush( nanu, data, l );		// x
	if ( e >= 0 ) e = BC_NanuCons( nanu, keys->e );		// e x
	if ( e >= 0 ) e = BC_NanuCons( nanu, keys->n );		// n e x
	if ( e >= 0 ) e = BC_NanuMexp( nanu );				// x^e%m, the result
	if ( e >= 0 ) e = BC_NanuPull( nanu, data, l );		// result stored

	return( e >= 0 ? l : e );
}

/** @} */

/****************************************************************************/
/*					Local functions											*/
/****************************************************************************/

/*
*	Calculates the length of the modulus
*	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/

static int	rsa_mlen( BC_NANU nanu, BC_RSA_PUBLIC_KEY *kp )
{
int		l, e;

	// Work out the length of the modulus
	// It is the sum of the lengths of the two primes

	if ( ( e = BC_NanuCons( nanu, kp->n ) ) < 0 ) {

		// Report the error returned by the natural number library

		return( e );
	}

	// These functions will never fail

	l = BC_NanuSize( nanu );
	BC_NanuDrop( nanu );

	// As per the standard, the length of the modulus must be one of
	// 768, 1024 or 2048 bits. We are more tolerant and accept any
	// keylength that is at least 512, at most 8192 and is a whole
	// multiple of 256 bits.

	if ( l < 512 || l > 8192 || ( l & 255 ) )

		return( BC_RSA_KEYL );
	else
		return( l >> 3 );
}


