/*****************************************************************************************
*  Copyright (c) 2004, Beijing Senselock Data Security Centre
*  All rights reserved.
*
*  Filename£ºsample_26_win32.c
*          
*  Briefs£º  The purpose of this snippet is to demonstrate how to use SenseLock EL to do   
*            DES/TDES en/decryption.
*            
*  History:        
*  --------------------------------------------------------        
*            10/28/2004 v1.0.0.0 Lihua created
*            
*            
*******************************************************************************************/

#include <stdio.h>
#include <conio.h>
#include <assert.h>

#include "..\..\inc\win32\sense4.h"
#include "..\..\inc\win32\crypt2.h"
#include "..\..\inc\win32\ses_err_msg.h"/* for debug purpose only */
#include "..\..\common\common.h"

#include "..\inc\sample_26.h"


/* global variables definition */
SENSE4_CONTEXT stS4Ctx = {0};
unsigned long dwResult = 0;
unsigned long dwBytesReturned = 0;

IO_PACKAGE stDataPkgIn = {0};
IO_PACKAGE stDataPkgOut = {0};

#define S4_EXE_FILE_ID "ef26"

/* for debug purpose only : handle results returned by stDataPkgOut.tag */
#ifdef _DEBUG
void HandleError(unsigned char bErrCode, unsigned char *pbErrInfo)
{
	switch(bErrCode)
	{
	case ERR_SUCCESS:
		printf("Success!\n");
		break;
	case ERR_SES:
		printf("Error during SES Execution :\n%s\n", SesErrMsgs[*pbErrInfo]);
		break;
	case ERR_INVALID_PARAMETER:
		printf("Invalid input,pls check your input data\n");
		break;
	default:
		printf("Undefined error code!\n");
		break;
	}
	return;
}
#else
void HandleError(unsigned char bErrCode, unsigned char *pbErrInfo)
{
	return;
}	
#endif

/* check result for S4Execute(...) */
unsigned long CheckS4ExecutionResult(unsigned long dwResult,unsigned long dwBytesReturned,unsigned char tag)
{
	
	if (dwResult != S4_SUCCESS) 
	{
		printf("S4 Execution failed! <error code: 0x%08x>\n", dwResult);
		return 0;
	}
	
	if (dwBytesReturned < 2)
	{
		printf("Invalid data package returned!\n");
		return 0;
	}
	
	if (tag != ERR_SUCCESS)
	{
		HandleError(stDataPkgOut.tag, stDataPkgOut.buff);
		return 0;
	}
	return 1;
}
int enc_dec_ecb(unsigned char cmd, unsigned char *in,  unsigned char inlen, 
				unsigned char *out, unsigned char *outlen)
{
	assert(NULL != out && NULL != outlen && NULL != in);
	assert(cmd == DES_ENC_ECB || cmd == DES_DEC_ECB || cmd == TDES_ENC_ECB || cmd == TDES_DEC_ECB);

	stDataPkgIn.tag = cmd;
	stDataPkgIn.len = inlen;
	memcpy(stDataPkgIn.buff, in, inlen);
	
	dwResult = S4Execute(&stS4Ctx, S4_EXE_FILE_ID, &stDataPkgIn, 
		IO_PACKAGE_HEADER_SIZE+stDataPkgIn.len,
		&stDataPkgOut, sizeof(IO_PACKAGE), &dwBytesReturned);
	if (!CheckS4ExecutionResult(dwResult, dwBytesReturned, stDataPkgOut.tag))
	{
		return 0;
	}
	if (*outlen < stDataPkgOut.len)
	{
		printf("insufficient out-buffer !\n");
		return 0; 		
	}
	*outlen = stDataPkgOut.len;
	memcpy(out,stDataPkgOut.buff,stDataPkgOut.len);	

	return 1;
}	
int enc_dec_cbc(unsigned char cmd, unsigned char *iv, unsigned char *in,  unsigned char inlen, 
				unsigned char *out, unsigned char *outlen)

{

	DATA_BLOCK stDataBlk = {0};

	assert(NULL != out && NULL != outlen && NULL != in && iv != NULL);
	assert(cmd == DES_ENC_CBC || cmd == DES_DEC_CBC || cmd == TDES_ENC_CBC || cmd == TDES_DEC_CBC);
	
	if (inlen > MAX_DATA_BLOCK_LEN)
	{
		printf("input data length must be less than %d", MAX_DATA_BLOCK_LEN);
		return 0;
	}
	memcpy(stDataBlk.iv, iv, sizeof(stDataBlk.iv));
	stDataBlk.len = inlen;
	memcpy(stDataBlk.buff, in, inlen);
	stDataPkgIn.tag = cmd;
	stDataPkgIn.len = sizeof(stDataBlk) - sizeof(stDataBlk.buff) + stDataBlk.len;
	memcpy(stDataPkgIn.buff, &stDataBlk, stDataPkgIn.len);

	dwResult = S4Execute(&stS4Ctx, S4_EXE_FILE_ID, &stDataPkgIn, 
		IO_PACKAGE_HEADER_SIZE+stDataPkgIn.len,
		&stDataPkgOut, sizeof(IO_PACKAGE), &dwBytesReturned);
	if (!CheckS4ExecutionResult(dwResult, dwBytesReturned, stDataPkgOut.tag))
	{
		return 0;
	}
	if (*outlen < stDataPkgOut.len)
	{
		printf("insufficient out-buffer size!\n");
		return 0; 		
	}
	*outlen = stDataPkgOut.len;
	memcpy(out,stDataPkgOut.buff,stDataPkgOut.len);	
	
	return 1;
}			
int main(int argc, char* argv[])
{

	unsigned char lpUserPin[8] = "12345678";
	unsigned char plainText[248];
	unsigned char cipher[248];
	unsigned char plainTextLen = sizeof(plainText);
	unsigned char cipherLen = sizeof(cipher);

	unsigned char iv[8] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07};
	
	if (!(dwResult = OpenS4ByIndex(FIRST_S4_INDEX,&stS4Ctx)))
	{
		return 1;
	}   
	
	dwResult = S4ChangeDir(&stS4Ctx, "\\");
	if (dwResult != S4_SUCCESS) 
	{
		printf("Change directory failed! <error code: 0x%08x>\n",dwResult);
		S4Close(&stS4Ctx);
		return dwResult;
	}
	
	// Call S4VerifyPin(...) to verify User PIN so as to get the privilege to execute the program in SenseLock EL.
	dwResult = S4VerifyPin(&stS4Ctx, lpUserPin, sizeof(lpUserPin), S4_USER_PIN);
	if (dwResult != S4_SUCCESS) 
	{
		printf("Verify Pin failed! <error code: 0x%08x>\n",dwResult);
		S4Close(&stS4Ctx);
		return dwResult;
	}	
	
	memcpy(plainText, "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff", plainTextLen);
	printf("Begin encrypt in DES_ECB mode...\n");
	plainTextLen = 16;
	if (!(dwResult = enc_dec_ecb(DES_ENC_ECB, plainText, plainTextLen, cipher, &cipherLen)))
	{
		ResetAndCloseS4(&stS4Ctx);
		return dwResult;
	}
	printf("Success!\nThe cipher:");	
	hexprint(stdout, cipher, cipherLen);

	printf("Begin decrypt in DES_ECB mode...\n");
	plainTextLen = sizeof(plainText); 
	if (!(dwResult = enc_dec_ecb(DES_DEC_ECB, cipher, cipherLen, plainText, &plainTextLen)))
	{
		ResetAndCloseS4(&stS4Ctx);
		return dwResult;
	}
	printf("Success!\nThe plainText:");	
	hexprint(stdout, plainText, plainTextLen);
    

	printf("Begin encrypt in TDES_ECB mode...\n");
	if (!(dwResult = enc_dec_ecb(TDES_ENC_ECB, plainText, plainTextLen, cipher, &cipherLen)))
	{
		ResetAndCloseS4(&stS4Ctx);
		return dwResult;
	}
	printf("Success!\nThe cipher:");	
	hexprint(stdout, cipher, cipherLen);
	
	printf("Begin decrypt in TDES_ECB mode...\n");
	plainTextLen = sizeof(plainText); 
	if (!(dwResult = enc_dec_ecb(TDES_DEC_ECB, cipher, cipherLen, plainText, &plainTextLen)))
	{
		ResetAndCloseS4(&stS4Ctx);
		return dwResult;
	}
	printf("Success!\nThe plainText:");	
	hexprint(stdout, plainText, plainTextLen);

	printf("Begin encrypt in DES_CBC mode...\n");

    printf("Initial Vector set to be:");
	hexprint(stdout, iv, sizeof(iv));
	if (!(dwResult = enc_dec_cbc(DES_ENC_CBC, iv, plainText, plainTextLen, cipher, &cipherLen)))
	{
		ResetAndCloseS4(&stS4Ctx);
		return dwResult;		
	}
	printf("Success!\nThe cipher:");	
	hexprint(stdout, cipher, cipherLen);
	
	printf("Begin decrypt in DES_CBC mode...\n");
	plainTextLen = cipherLen;
	if (!(dwResult = enc_dec_cbc(DES_DEC_CBC, iv, cipher, cipherLen, plainText, &plainTextLen)))
	{
		ResetAndCloseS4(&stS4Ctx);
		return dwResult;		
	}
	printf("Success!\nThe plainText:");	
	hexprint(stdout, plainText, plainTextLen);
	
	printf("Begin encrypt in TDES_CBC mode...\n");
    printf("Initial Vector set to be:");
	hexprint(stdout, iv, sizeof(iv));
	if (!(dwResult = enc_dec_cbc(TDES_ENC_CBC, iv, plainText, plainTextLen, cipher, &cipherLen)))
	{
		ResetAndCloseS4(&stS4Ctx);
		return dwResult;		
	}
	printf("Success!\nThe cipher:");	
	hexprint(stdout, cipher, cipherLen);
	
	printf("Begin decrypt in TDES_CBC mode...\n");
	plainTextLen = cipherLen;
	if (!(dwResult = enc_dec_cbc(TDES_DEC_CBC, iv, cipher, cipherLen, plainText, &plainTextLen)))
	{
		ResetAndCloseS4(&stS4Ctx);
		return dwResult;		
	}
	printf("Success!\nThe plainText:");	
	hexprint(stdout, plainText, plainTextLen);
	
	/* for better security,use the following instead of using S4close() directly */
	ResetAndCloseS4(&stS4Ctx);
	getch();

	return dwResult;
}
