#include "unimate.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "./sha1/sha1.h"
#include "./des/des.h"

#define PKI_DDF				0x1F00

#define EVP_MAX_KEY_LENGTH		32
#define EVP_MAX_IV_LENGTH		16
unsigned long EncodeOldPin(unsigned long utHandle,
	const char* szPrintNumber, unsigned long ulPrintNumberLen,
	const char* szOldPin, unsigned long ulOldPinLen,
	char** EncodedOldPin, unsigned long* EncodedOldPinLen,
	char** szEKEY)
{
	char randomNumber[33];
	char PIN_HID[64];
	char HPIN[20];
	char AKEY[EVP_MAX_KEY_LENGTH];
	char* EKEY = (char*)calloc(24, sizeof(char));
	int i;
	char iv[EVP_MAX_IV_LENGTH];
	unsigned char ARC[512+8];
	int outl;
	char* encodedPin;
	unsigned long ret;
	DES_key_schedule ks1,ks2,ks3;
	unsigned char inputBuffer[40];
	int ii;
	//////////////////////////////////////////////////////////////////////////
	SHA1Context sha;
	char tmp;

	memset(randomNumber, 0x00, 33);
	printf("UT_GetRandom() len=%d\n", 16);
	ret = UT_GetRandom(utHandle, (CK_BYTE_PTR)randomNumber, 16);
	printf("returned %04x, randomNumber = %s\n", ret, randomNumber);


	memcpy(PIN_HID, szOldPin, ulOldPinLen);
	memcpy(PIN_HID+ulOldPinLen, szPrintNumber, ulPrintNumberLen);


	SHA1Reset(&sha);
	SHA1Input(&sha,(const unsigned char*)PIN_HID,ulOldPinLen + ulPrintNumberLen);
	SHA1Result(&sha);
	memcpy(HPIN, sha.Message_Digest, 20);
	for (ii = 0; ii < 20; ii+=4) {
		tmp = HPIN[ii];
		HPIN[ii] = HPIN[ii+3];
		HPIN[ii+3] = tmp;

		tmp = HPIN[ii+1];
		HPIN[ii+1] = HPIN[ii+2];
		HPIN[ii+2] = tmp;
	}


	memset(AKEY, 0x00, EVP_MAX_KEY_LENGTH);
	memcpy(AKEY, HPIN, 16);
	memcpy(AKEY+16, HPIN, 8);

	//生成EKEY
	srand((unsigned int)time(NULL));
	for(i = 0; i < 24; i++)
	{
		EKEY[i] = (char)(rand() % 256);
	}

	for(i =0;i<EVP_MAX_IV_LENGTH;i++)
	{
		iv[i]=(char)(EVP_MAX_IV_LENGTH - i);
	}

	memcpy(inputBuffer, randomNumber, 16);
	memcpy(inputBuffer+16, EKEY, 24);

	DES_set_key_unchecked((unsigned char (*)[8])AKEY, &ks1);
	DES_set_key_unchecked((unsigned char (*)[8])(AKEY+8), &ks2);
	DES_set_key_unchecked((unsigned char (*)[8])(AKEY+16), &ks3);

	for (ii = 0; ii < 40; ii+= 8){
		DES_ecb3_encrypt((unsigned char (*)[8])&inputBuffer[ii], (unsigned char (*)[8])&ARC[ii], &ks1, &ks2, &ks3, DES_ENCRYPT);
	}
	outl = 40;

	encodedPin = (char*)calloc(outl, sizeof(char));
	memcpy(encodedPin, ARC, outl);


	*szEKEY = EKEY;
	*EncodedOldPin = encodedPin;
	*EncodedOldPinLen = outl;

	return 0;
}


unsigned long EncodeNewPin(const char* szPrintNumber, unsigned long ulPrintNumberLen,
	const char* szNewPin, unsigned long ulNewPinLen,
	const char* EKEY,
	char** EncodedNewPin, unsigned long* EncodedNewPinLen)
{
	char PIN_HID[64];
	char HPIN[20];
	char CHK[20];
	unsigned char UTC[512+8];
	int outl;
	char* encodedPin;
	SHA1Context sha;
	unsigned char inputBuffer[40];
	DES_key_schedule ks1, ks2, ks3;
	int ii;
	char tmp;

	memcpy(PIN_HID, szNewPin, ulNewPinLen);
	memcpy(PIN_HID+ulNewPinLen, szPrintNumber, ulPrintNumberLen);

	SHA1Reset(&sha);
	SHA1Input(&sha,(const unsigned char*)PIN_HID,ulNewPinLen + ulPrintNumberLen);
	SHA1Result(&sha);
	memcpy(HPIN, sha.Message_Digest, 20);
	for (ii = 0; ii < 20; ii+=4) {
		tmp = HPIN[ii];
		HPIN[ii] = HPIN[ii+3];
		HPIN[ii+3] = tmp;

		tmp = HPIN[ii+1];
		HPIN[ii+1] = HPIN[ii+2];
		HPIN[ii+2] = tmp;
	}

	SHA1Reset(&sha);
	SHA1Input(&sha,(const unsigned char*)HPIN,20);
	SHA1Result(&sha);
	memcpy(CHK, sha.Message_Digest, 20);
	for (ii = 0; ii < 20; ii+=4) {
		tmp = CHK[ii];
		CHK[ii] = CHK[ii+3];
		CHK[ii+3] = tmp;

		tmp = CHK[ii+1];
		CHK[ii+1] = CHK[ii+2];
		CHK[ii+2] = tmp;
	}

	memcpy(inputBuffer, HPIN, 20);
	memcpy(inputBuffer+20, CHK, 20);

	DES_set_key_unchecked((unsigned char (*)[8])EKEY, &ks1);
	DES_set_key_unchecked((unsigned char (*)[8])(EKEY+8), &ks2);
	DES_set_key_unchecked((unsigned char (*)[8])(EKEY+16), &ks3);

	for (ii = 0; ii < 40; ii+= 8){
		DES_ecb3_encrypt((unsigned char (*)[8])&inputBuffer[ii], (unsigned char (*)[8])&UTC[ii], &ks1, &ks2, &ks3, DES_ENCRYPT);
	}
	outl = 40;

	encodedPin = (char*)calloc(outl*2, sizeof(char));
	memset(encodedPin, 0x00, outl*2);
	memcpy(encodedPin, UTC, 40);

	//返回出参
	*EncodedNewPin = encodedPin;
	*EncodedNewPinLen = outl/**2*/;

	return 0;
}


void testLib()
{
	CK_ULONG i;
	DHANDLE handle[MAX_DEVICE_COUNT];
	CK_ULONG count;
	CK_RV ret;
	CK_BYTE UTID[100];
	CK_ULONG UTSN[100];
	CK_BYTE temp1[20], temp2[20];
	char sn[20];

	CK_FID recordFileFid = 0xEF01;

	CK_FID file1Fid = 0x0E00;
	CK_ULONG file1Addr = 0;
	CK_ULONG file1Len = 9*264;
	CK_BYTE file1[9*264+100];


	CK_BYTE hpin[20];
	CK_ULONG hpinLen = 16;
	CK_BYTE defaultPin[] = "00000000";
	CK_ULONG defaultPinLen = 8;
	CK_BYTE newPin[] = "11111111";
	CK_ULONG newPinLen = 8;
	CK_BYTE_PTR encode;
	CK_ULONG encode_len;
	CK_BYTE_PTR ekey;
	CK_BYTE_PTR enNewPin;
	CK_ULONG ennewlen;
	CK_ULONG pinAttemptMax;
	CK_ULONG pinAttemptCount;

	CK_ALG hashid = HASH_MD5;
	CK_BYTE publicText[128] = {0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 
		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 
		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 
		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 
		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 
		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 
		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 
		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 
		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 
		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 
		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 
		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 
		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 
		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 
		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 
		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11};
	CK_ULONG publicTextLen = 128;

	CK_BYTE digistText[128];
	CK_ULONG digistLen = 0;
	CK_BYTE signText[128];
	CK_ULONG signLen = 0;

	CK_FID pubKeyFid = 0x1E31;
	CK_FID priKeyFid = 0x1E51;
	CK_ULONG rsaKeyBit = 1024;
	PUB_KEY pubKey;

	//--------------------------device operation-------------------------//
	printf("\nUT_Initialize()\n");
	ret = UT_Initialize();
	printf("returned %04x\n", ret);

	printf("\nUT_Find()\n");
	ret = UT_Find(handle, &count);
	printf("returned %04x, count = %d\n", ret, count);

	printf("\nUT_GetID()\n");
	memset(UTID, 0X00, 100);
	ret = UT_GetID(handle[0], UTID);
	printf("returned %04x, UT ID = %s\n", ret, UTID);
	
	printf("\nUT_GetCOSVersion()\n");
	ret = UT_GetCOSVersion(handle[0], UTSN);
	printf("returned %04x, UT COSVersion = %d\n", ret, UTSN[0]);
	
	printf("\nUT_GetSpace()\n");
	ret = UT_GetSpace(handle[0], UTSN);
	printf("returned %04x, UT Space = %d\n", ret, UTSN[0]);

	printf("\nUT_GetSN()\n");
	ret = UT_GetSN(handle[0], UTSN);

	sprintf((char*)temp1, "%d", (UTSN[0]*0x100000000+UTSN[1])/100000000);
	sprintf((char*)temp2, "%08d", (UTSN[0]*0x100000000+UTSN[1])%100000000);
	sprintf((char*)sn, "%s%s", temp1, temp2);
	printf("returned %04x, SN = %s\n", ret, sn);
	

	//---------------------------pin operation------------------------//

	//calc HPIN
	CK_BYTE_PTR PIN_HID = NULL;
	CK_RV rv = 0;
	SHA1Context sha;
	int ii;
	char tmp;

	//级联PIN码和印刷编号
	PIN_HID = (CK_BYTE_PTR)calloc(strlen((char*)defaultPin)+strlen((char*)sn), sizeof(CK_BYTE));
	memcpy(PIN_HID, defaultPin, strlen((char*)defaultPin));
	memcpy(PIN_HID+strlen((char*)defaultPin), sn, strlen((char*)sn));
	
	//生成长度的HPIN
	SHA1Reset(&sha);
	SHA1Input(&sha,(const unsigned char*)PIN_HID,strlen((char*)defaultPin) + strlen((char*)sn));
	SHA1Result(&sha);
	memcpy(hpin, sha.Message_Digest, 20);
	for (ii = 0; ii < 20; ii+=4) {
		tmp = hpin[ii];
		hpin[ii] = hpin[ii+3];
		hpin[ii+3] = tmp;
		
		tmp = hpin[ii+1];
		hpin[ii+1] = hpin[ii+2];
		hpin[ii+2] = tmp;
	}

	free(PIN_HID);

	printf("\nUT_OpenFID() (PKI DDF)\n");
	ret = UT_OpenFID(handle[0], PKI_DDF);
	printf("returned %04x\n", ret);

	printf("\nUT_ChangePIN() old pin = %s, new pin = %s\n", defaultPin, newPin);
	EncodeOldPin(handle[0], (char*)sn, strlen((char*)sn), 
		(char*)defaultPin, defaultPinLen, (char **)&encode, &encode_len, (char **)&ekey);
	EncodeNewPin((char*)sn, strlen((char*)sn), 
		(char*)newPin, newPinLen, (char *)ekey, (char **)&enNewPin, &ennewlen);
	ret = UT_ChangePIN(handle[0], encode, encode_len, enNewPin, ennewlen);
	printf("returned %04x\n", ret);

	printf("\nUT_VerifyPIN_ADMIN() pin = %s\n", defaultPin);
	EncodeOldPin(handle[0], (char*)sn, strlen((char*)sn), 
		(char*)defaultPin, defaultPinLen, (char **)&encode, &encode_len, (char **)&ekey);
	ret = UT_VerifyPIN_ADMIN(handle[0], encode, encode_len);
	printf("returned %04x\n", ret);

	printf("\nUT_ReloadPIN() (HPIN)\n");
	ret = UT_ReloadPIN(handle[0], hpin, hpinLen);
	printf("returned %04x\n", ret);
	
	printf("\nUT_VerifyPIN() pin = %s\n", defaultPin);
	EncodeOldPin(handle[0], (char*)sn, strlen((char*)sn), 
		(char*)defaultPin, defaultPinLen, (char **)&encode, &encode_len, (char **)&ekey);
	ret = UT_VerifyPIN(handle[0], encode, encode_len);
	printf("returned %04x\n", ret);

	printf("\nUT_GetAttempt()\n");
	ret = UT_GetAttempt(handle[0], &pinAttemptMax, &pinAttemptCount);
	printf("returned %04x, max count = %d, left count = %d\n", ret, pinAttemptMax, pinAttemptCount);


	//-------------------------file system--------------------------//

	printf("\nUT_OpenFID() (0x%04x)\n", file1Fid);
	ret = UT_OpenFID(handle[0], file1Fid);
	printf("returned %04x\n", ret);

	printf("\nUT_ReadFile() addr=%04x, len=%d\n", file1Addr, file1Len);
	ret = UT_ReadFile(handle[0], file1Addr, file1Len, file1);
	printf("returned %04x\n", ret);
	//for(i=0; i<file1Len; i++)
	//{
	//	printf("%02x ", file1[i]);
	//	if(i%16 == 15)
	//		printf("\n");
	//}
	printf("\n");
	printf("\nUT_WriteFile() addr=%04x, len=%d\n", file1Addr, file1Len);
	ret = UT_WriteFile(handle[0], file1Addr, file1Len, file1);
	printf("returned %04x\n", ret);

	printf("\nUT_OpenFID() (0x%04x)\n", recordFileFid);
	ret = UT_OpenFID(handle[0], recordFileFid);
	printf("returned %04x\n", ret);
	
	printf("\nUT_AppendRecord()\n");
	i=rand()%64;
	sprintf((char*)UTID, "index = %d",i);
	ret = UT_AppendRecord(handle[0], UTID, 0x10);
	printf("returned %04x,write %s\n", ret, UTID);

	printf("\nUT_GetRecord()\n");
	ret = UT_GetRecord(handle[0], 1, UTID, 0x10);
	printf("returned %04x, last record = %s\n", ret, UTID);


	//--------------------------encrypt/decrypt-------------------------//
	
	printf("\nUT_Hash()\nPublicText=\n");
	for (i=0; i<publicTextLen; ++i)
	{
		printf("%02x ", publicText[i]);
		if (i%16==15)
		{
			printf("\n");
		}
	}
	ret = UT_Hash(handle[0], hashid, publicText, publicTextLen);
	printf("returned %04x\n", ret);

	printf("\nUT_HashFinalize()\n");
	ret = UT_HashFinalize(handle[0], digistText, &digistLen);
	printf("returned %04x\n", ret);
	//for (i=0; i<digistLen; ++i)
	//{
	//	printf("%02x ", digistText[i]);
	//	if (i%16==15)
	//	{
	//		printf("\n");
	//	}
	//}
	//printf("\n");


	printf("\nUT_GenRSA()\n");
	ret = UT_GenRSA(handle[0], pubKeyFid, priKeyFid, rsaKeyBit);
	printf("returned %04x\n", ret);

	printf("\nUT_GetRSAPubKey()\n");
	ret = UT_GetRSAPubKey(handle[0], pubKeyFid, &pubKey);
	printf("returned %04x, pubkey.n =\n", ret);
	for (i=0; i<128; ++i)
	{
		printf("%02x ", *((CK_BYTE_PTR)&(pubKey.n)+i));
		if (i%16==15)
		{
			printf("\n");
		}
	} 
	printf("pubkey.e =\n", ret);
	for (i=0; i<5; ++i)
	{
		printf("%02x ", *((CK_BYTE_PTR)&(pubKey.e)+i));
	}
	printf("\n");

	printf("\nUT_SelectRSA()\n");
	ret = UT_SelectRSA(handle[0], pubKeyFid, priKeyFid);
	printf("returned %04x\n", ret);

	printf("\nUT_VerifyPIN() pin = %s\n", defaultPin);
	EncodeOldPin(handle[0], (char*)sn, strlen((char*)sn), 
		(char*)defaultPin, defaultPinLen, (char **)&encode, &encode_len, (char **)&ekey);
	ret = UT_VerifyPIN(handle[0], encode, encode_len);
	printf("returned %04x\n", ret);

	printf("\nUT_RSASign()\n");
	ret = UT_RSASign(handle[0], publicText, publicTextLen, signText, &signLen);
	printf("returned %04x\nsign result = \n", ret);
	for (i=0; i<signLen; ++i)
	{
		printf("%02x ", signText[i]);
		if (i%16==15)
		{
			printf("\n");
		}
	} 

	printf("\nUT_RSAVerify()\n");
	ret = UT_RSAVerify(handle[0], signText, signLen, digistText, &digistLen);
	printf("returned %04x\n", ret);

	if (digistLen != publicTextLen)
	{
		printf("text length error!\n");
	}
	else
	{
		for (i=0; i<digistLen; ++i)
		{
			if (digistText[i] != publicText[i])
			{
				printf("%04d: %d  %d\n", i, publicText[i], digistText[i]);
			}
		}
	}

	printf("\nUT_RSAEncrypt()\n");
	ret = UT_RSAEncrypt(handle[0], publicText, publicTextLen, signText, &signLen);
	printf("returned %04x\n", ret);

	printf("\nUT_RSADecrypt()\n");
	ret = UT_RSADecrypt(handle[0], signText, signLen, digistText, &digistLen);
	printf("returned %04x\n", ret);

	if (digistLen != publicTextLen)
	{
		printf("text length error!\n");
	}
	else
	{
		for (i=0; i<digistLen; ++i)
		{
			if (digistText[i] != publicText[i])
			{
				printf("%04d: %d  %d\n", i, publicText[i], digistText[i]);
			}
		}
	}

	//---------------------------------------------------//

	printf("\nUT_SoftReset()\n");
	ret = UT_SoftReset(handle[0]);
	printf("returned %04x\n", ret);

	printf("\nUT_Finalize()\n");
	ret = UT_Finalize();
	printf("returned %04x\n", ret);
}
int main(int argc, int* argv[])
{
	testLib();
	system("pause");
	return 0;
}

