/*
  Copyright (c) 2004,   Beijing Senselock Data Security Centre
  All rights reserved.
  
  File£ºsample_28_hw.c
  
  Briefs£ºThis code will 
    
*/

#include <string.h>
#include "..\..\inc\hardware\ses_v3.h"
#include "..\inc\sample_28.h"

#define _DEBUG

/* global variable defination. */
unsigned char last_ses_error = 0; /* last SES error */
IO_PACKAGE out_pkg;  /* output package */
IO_PACKAGE *output = &out_pkg; 
IO_PACKAGE *input = (IO_PACKAGE *)pbInBuff; /* input package */

/*
	Exit upon an error.
  
	Parameters:
		errcode[in]: error code
		msg[in]: additional error message
		msglen[in]: message length
  
	Return:
		none.

	Remarks:
		none.
*/
void error_exit(unsigned char errcode, unsigned char *msg, int msglen)
{
	output->tag = errcode;
	output->len = 0;
	
	/* for debug purpose only */
#ifdef  _DEBUG
	if (msglen != 0 && msg != NULL)
	{
		memcpy(output->buff, msg, msglen);
		output->len = msglen;
	}
#endif

	_set_response(2+output->len, (unsigned char *)output);
	_exit();
}



/* Function to compute the digest */
int hmac_sha(char*    k,     /* secret key */
			  int      lk,    /* length of the key in bytes */
			  char*    d,     /* data */
			  int      ld,    /* length of data in bytes */
			  char*    out,   /* output buffer, at least "t" bytes */
			  int      *t)
{
       HASH_CONTEXT ictx, octx ;
       char    isha[SHA_DIGESTSIZE], osha[SHA_DIGESTSIZE] ;
       char    key[SHA_DIGESTSIZE] ;
       char    buf[SHA_BLOCKSIZE] ;
       int     i ;
	   unsigned char ret = 0;

       if (*t < SHA_DIGESTSIZE)
	   {
	   		error_exit(ERR_INVALID_PARAMETER, NULL, 0);
	   }
	   if (lk > SHA_BLOCKSIZE) {

               HASH_CONTEXT         tctx ;

               ret = _sha1_init(&tctx) ;
			   if (ret == SES_SUCCESS)
			   {
               		ret = _sha1_update(&tctx, k, lk) ;
					if (ret == SES_SUCCESS)
					{
						ret = _sha1_final(&tctx, key) ;
					}
			   }
               if (ret != SES_SUCCESS)
			   {
			   		last_ses_error = ret;
					return ERR_SES;
			   }

               k = key ;
               lk = SHA_DIGESTSIZE ;
       }

       /**** Inner Digest ****/


       /* Pad the key for inner digest */
       for (i = 0 ; i < lk ; ++i) buf[i] = k[i] ^ 0x36 ;
       for (i = lk ; i < SHA_BLOCKSIZE ; ++i) buf[i] = 0x36 ;

		ret = _sha1_init(&ictx) ;
		if (ret == SES_SUCCESS)
		{
			ret = _sha1_update(&ictx, buf, SHA_BLOCKSIZE) ;
			if (ret == SES_SUCCESS)
			{
				ret = _sha1_update(&ictx, d, ld) ;
				if (ret == SES_SUCCESS)
				{
			       ret = _sha1_final(&ictx, isha) ;
				}
			}
		}
        if (ret != SES_SUCCESS)
		{
			last_ses_error = ret;
			return ERR_SES;
		}
      /**** Outter Digest ****/


       /* Pad the key for outter digest */

       for (i = 0 ; i < lk ; ++i) buf[i] = k[i] ^ 0x5C ;
       for (i = lk ; i < SHA_BLOCKSIZE ; ++i) buf[i] = 0x5C ;

       ret = _sha1_init(&octx) ;
		if (ret == SES_SUCCESS)
		{
	        ret = _sha1_update(&octx, buf, SHA_BLOCKSIZE) ;
			if (ret == SES_SUCCESS)
			{
 		        ret = _sha1_update(&octx, isha, SHA_DIGESTSIZE) ;
				if (ret ==SES_SUCCESS)
				{
			       ret = _sha1_final(&octx, osha) ;
				   if (ret == SES_SUCCESS)
				   {
					   ret = _mem_copy(out, osha, SHA_DIGESTSIZE);
				   }
				}
			}
		}
        if (ret != SES_SUCCESS)
		{
			last_ses_error = ret;
			return ERR_SES;
		}

	   *t =  SHA_DIGESTSIZE;
	   return ERR_SUCCESS;
}

void main()
{
	int ret = 0;
	int length = 0;
	unsigned char idata key[25] = {0x01,0x02,0x03,0x04,0x05,\
	          0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,\
			  0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19};
	//unsigned char idata key[4] = "Jefe";
	

	length =  SHA_DIGESTSIZE;
	ret = hmac_sha(key, sizeof(key),input->buff, input->len, output->buff, &length);
	if (ret != ERR_SUCCESS)
	{
		if (ret == ERR_SES)
		{
			error_exit(ret , &last_ses_error, 1);
		}
		else
		{
			error_exit(ret, NULL, 0);
		}
	}

	output->tag = ERR_SUCCESS;
	output->len = (unsigned char)length;
	_set_response(IO_PACKAGE_HEADER_SIZE+output->len, (unsigned char *)output);
	_exit();  
}
