/****************************************************************************/
/*	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.																	*/
/****************************************************************************/

#include <crypto/hash.h>
#include "crypto.h"

/****************************************************************************/
/*						User API											*/
/****************************************************************************/

/** @addtogroup hash */
/** @{ */

/**
*	Initialise a HMAC calculation.
*
*	This function prepares for a HMAC operation. It can use MD5 or SHA-1
*	as its hash function. This call prepares the BC_HMAC structure passed
*	as the first argumanet. The hash funtion that will be used is determined
*	by the second argument, which should be one of BC_HASH_MD5, BC_HASH_SHA1,
*	BC_HASH_MD5_FAST or BC_HASH_SHA1_FAST. The third argument is apointer to
*	the key and the fourth is the length of the key, in bytes.
*
*	@param	hmac	Pointer to the HMAC state structure
*	@param	func	The hash function to use, the same as the parameter for
*					the BC_HashInit() function.
*	@param	kptr	Pointer to the HMAC key
*	@param	klen	The length of the key (in bytes).
*/

void	BC_HmacInit( BC_HMAC *hmac, const struct bc_hfun_s *func,
					 const void *kptr, unsigned int klen )
{
unsigned char	temp[ BC_HASH_MAX * sizeof( int ) ];
unsigned char	*keyp;
unsigned char	data;
unsigned int	cntr;

	keyp = (unsigned char *) kptr;

	if ( klen > 64 ) {

		// The key is longer than 64 bytes, we have to transform the
		// key to a shorter form by calculating its hash value.

		BC_HashInit( &hmac->hash, func );
		BC_HashData( &hmac->hash, kptr, klen );
		BC_HashDone( &hmac->hash, temp );
		keyp = temp;
		klen = hmac->hash.f->length;
	}

	// Prepare the output pad.

	BC_HashInit( &hmac->hash, func );

	for ( cntr = 0 ; cntr < klen ; cntr++ ) {

		data = keyp[ cntr ] ^ 0x5c;
		BC_HashData( &hmac->hash, &data, 1 );
	}

	for ( data = 0x5c ; cntr < 64 ; cntr++ )

		BC_HashData( &hmac->hash, &data, 1 );

	// At this point the hash function calculated a full hash, that is,
	// it updated its state. Now we save the state in the HMAC struct.

	for ( cntr = 0 ; cntr < BC_HASH_MAX ; cntr++ )

		hmac->opad[ cntr ] = hmac->hash.s[ cntr ];

	// Now we calculate the hash for the input pad

	BC_HashInit( &hmac->hash, func );

	for ( cntr = 0 ; cntr < klen ; cntr++ ) {

		data = keyp[ cntr ] ^ 0x36;
		BC_HashData( &hmac->hash, &data, 1 );
	}

	for ( data = 0x36 ; cntr < 64 ; cntr++ )

		BC_HashData( &hmac->hash, &data, 1 );
}

/**
*	Process the next data block in a HMAC calculations.
*
*	@param	hmac	Pointer to the HMAC state
*	@param	data	Pointer to data
*	@param	dlen	The length of the data, in bytes.
*/

void	BC_HmacData( BC_HMAC *hmac, const void *data, unsigned dlen )
{
	BC_HashData( &hmac->hash, data, dlen );
}

/**
*	Finalises a HMAC calculation.
*
*	The function modifies neither the HMAC state nor the data, therefore it
*	can be used to calculate the partial HMAC value at any given point of a
*	bytestream.
*
*	@param	hmac	Pointer to the HMAC state
*	@param	data	Pointer to the result buffer (16 or 20 bytes,
*					for MD5 and SHA1 respectively).
*/

void	BC_HmacDone( const BC_HMAC *hmac, void *data )
{
BC_HASH	htmp;
int		cntr;

	// Finalise the first hash

	BC_HashDone( &hmac->hash, data );

	// Start a new hash and preload the output pad value into it

	for ( cntr = 0 ; cntr < BC_HASH_MAX ; cntr++ )

		htmp.s[ cntr ] = hmac->opad[ cntr ];

	htmp.f = hmac->hash.f;
	htmp.n = 64 * 8;

	// Finalise the hash with the result of the previous hash

	BC_HashData( &htmp, data, htmp.f->length );
	BC_HashDone( &htmp, data );
}

/** @} */

