/*
*  Object %name    : %
*  State           :  %state%
*  Creation date   :  Mar 29 2007
*  Last modified   :  %modify_time%
*/
/** @file
*  \brief A brief description of this module
*
*  \version CE2_TST_C2.h#1:incl:1
*  \author Yermalayeu Ihar
*  \remarks Copyright (C) 2007 by Discretix Technologies Ltd.
*           All Rights reserved
*/

/************* Include Files ****************/

#include <memory.h>
#include "CryptoEngine2.h"
#include "CE2_TST_Common.h"
#include "CE2_TST_C2.h"

/************************ Defines *******************************/
/************************ Enums *********************************/
/************************ Typedefs ******************************/
/************************ Global Data ***************************/

/*  ECB test data */
DxUint8_t CE2_TST_C2_ECB_Key[] = {
  0x5e, 0x91, 0x6a, 0xef, 0x34, 0x1f, 0xa3
};

DxUint8_t CE2_TST_C2_ECB_PlanData[] = {
  0x2b, 0x7f, 0x06, 0x89, 0x6f, 0x0d, 0xa6, 0xe2
};

DxUint8_t CE2_TST_C2_ECB_CryptData[] = {
  0xe4, 0x5f, 0xe6, 0x8f, 0x05, 0x80, 0xba, 0xf7
};

DxUint8_t CE2_TST_C2_OneWayFuncOut[] = {
  0xcf, 0x20, 0xe0, 0x06, 0x6a, 0x8d, 0x1c, 0x15
};

/*  C-CBC test data */
DxUint8_t CE2_TST_C2_C_CBC_Key[] = {
  0x7c, 0xb3, 0xc4, 0xdb, 0x09, 0x47, 0x13
};

DxUint8_t CE2_TST_C2_C_CBC_PlanData[] = {
  0xd8, 0x32, 0x46, 0xa2, 0x44, 0x08, 0x32, 0x24,
  0xdf, 0x11, 0x81, 0x7d, 0x72, 0x41, 0xe2, 0x8c,
  0xd7, 0x42, 0xbe, 0x76, 0x18, 0x44, 0xb1, 0x0d
};

DxUint8_t CE2_TST_C2_C_CBC_CryptData[] = {
  0xd1, 0x09, 0xfc, 0x50, 0x02, 0x51, 0x1c, 0x69,
  0x2f, 0x32, 0x1d, 0x54, 0x79, 0xfd, 0xe7, 0x68,
  0x3d, 0x0c, 0xa8, 0x91, 0x0d, 0x31, 0x9f, 0x9d
};

//Hash test 1:
//a24632d8 24320844 7d8111df 8ce24172 76be42d7 0db14418
DxUint8_t CE2_TST_C2_HashInput1[] = {
	0xd8, 0x32, 0x46, 0xa2, 0x44, 0x08, 0x32, 0x24, 
	0xdf, 0x11, 0x81, 0x7d, 0x72, 0x41, 0xe2, 0x8c,
	0xd7, 0x42, 0xbe, 0x76, 0x18, 0x44, 0xb1, 0x0d
};
//299eb6db eee75099
DxUint8_t CE2_TST_C2_HashOutput1[] = {
	0xdb, 0xb6, 0x9e, 0x29, 0x99, 0x50, 0xe7, 0xee
};

//Hash test 2:
DxUint8_t CE2_TST_C2_HashInput2[] = {0xFF};
//30A0E072 FC18F1D5
DxUint8_t CE2_TST_C2_HashOutput2[] = {
	0x72, 0xe0, 0xa0, 0x30, 0xd5, 0xf1, 0x18, 0xfc
};

//OneWayFunc test:
DxUint8_t CE2_TST_C2_OneWayFuncD1[] = {
	0xc6, 0x1f, 0x84, 0x36, 0xcc, 0x3c, 0xe5
};
DxUint8_t CE2_TST_C2_OneWayFuncD2[] = {
	0xc4, 0xb4, 0xe0, 0x16, 0xe7, 0xea, 0xfe, 0x5d
};
DxUint8_t CE2_TST_C2_OneWayFuncG[] = {
	0x65, 0x84, 0xa4, 0x33, 0x56, 0x82, 0xdd, 0xba
};

#define CE2_TST_C2_ECB_DATA_SIZE sizeof(CE2_TST_C2_ECB_PlanData) 
#define CE2_TST_C2_C_CBC_DATA_SIZE sizeof(CE2_TST_C2_C_CBC_PlanData) 

/*********************** Private Function ***********************/
/************************ Public Functions **********************/

/*****************************************************************************
* Function Name:                                                           
* 	CE2_TST_C2_ECB 		
* 
* Inputs:
*  @param[in/out] out - output stream for logs;
*
* Outputs:
*  @return - On success returns CE2_TST_VALID; else returns CE2_TST_FAILED.
*
* Description:																	
* 	Verify functionality of CE2_C2() function in ECB mode;
*
* Algorithm:		
*  -#  											
*
******************************************************************************/	
DxStatus CE2_TST_C2_ECB(FILE *out)
{
  DxStatus result = CE2_OK, error;
  DxUint8_t OutData[CE2_TST_C2_ECB_DATA_SIZE];
  int cmp, i;

  PrintTestBeginMsg(out, __FUNCTION__);

  /* Encryption test */
  error = CE2_C2(CE2_TST_C2_ECB_Key, CE2_C2Cipher_Encrypt_mode, 
    CE2_C2Cipher_ECB_mode, CE2_TST_C2_ECB_PlanData, CE2_TST_C2_ECB_DATA_SIZE, OutData);
  if (error != CE2_OK) {
    fprintf(out, "Can't make CE2_C2 encryption  in EBC mode.\n");
    result |= CE2_TST_FAILED;
  }

  cmp = memcmp(OutData, CE2_TST_C2_ECB_CryptData, CE2_TST_C2_ECB_DATA_SIZE);
  if (cmp != 0) {
    fprintf(out, "Wrong CE2_C2 encrypted data in EBC mode.\n");
    for (i = 0; i < CE2_TST_C2_ECB_DATA_SIZE; i++) {
      fprintf(out, "%X", (OutData[i]&0xf0)/0x10);
      fprintf(out, "%X ", OutData[i]&0x0f);
    }
    fprintf(out, " \n");
    for (i = 0; i < CE2_TST_C2_ECB_DATA_SIZE; i++) {
      fprintf(out, "%X", (CE2_TST_C2_ECB_CryptData[i]&0xf0)/0x10);
      fprintf(out, "%X ", CE2_TST_C2_ECB_CryptData[i]&0x0f);
    }
    fprintf(out, " \n");
    result |= CE2_TST_FAILED;
  }

  /* Decryption test */
  error = CE2_C2(CE2_TST_C2_ECB_Key, CE2_C2Cipher_Decrypt_mode, 
    CE2_C2Cipher_ECB_mode, CE2_TST_C2_ECB_CryptData, CE2_TST_C2_ECB_DATA_SIZE, 
    OutData);
  if (error != CE2_OK) {
    fprintf(out, "Can't make CE2_C2 decryption  in EBC mode.\n");
    result |= CE2_TST_FAILED;
  }

  cmp = memcmp(OutData, CE2_TST_C2_ECB_PlanData, CE2_TST_C2_ECB_DATA_SIZE);
  if (cmp != 0) {
    fprintf(out, "Wrong CE2_C2 decrypted data in EBC mode.\n");
    for (i = 0; i < CE2_TST_C2_ECB_DATA_SIZE; i++) {
      fprintf(out, "%X", (OutData[i]&0xf0)/0x10);
      fprintf(out, "%X ", OutData[i]&0x0f);
    }
    fprintf(out, " \n");
    for (i = 0; i < CE2_TST_C2_ECB_DATA_SIZE; i++) {
      fprintf(out, "%X", (CE2_TST_C2_ECB_PlanData[i]&0xf0)/0x10);
      fprintf(out, "%X ", CE2_TST_C2_ECB_PlanData[i]&0x0f);
    }
    fprintf(out, " \n");
    result |= CE2_TST_FAILED;
  }

  PrintTestEndMsg(out, __FUNCTION__, result);

  return result;
}

/*****************************************************************************
* Function Name:                                                           
* 	CE2_TST_C2_C_CBC 		
* 
* Inputs:
*  @param[in/out] out - output stream for logs;
*
* Outputs:
*  @return - On success returns CE2_TST_VALID; else returns CE2_TST_FAILED.
*
* Description:																	
* 	Verify functionality of CE2_C2() function in C-CBC mode;
*
* Algorithm:		
*  -#  											
*
******************************************************************************/	
DxStatus CE2_TST_C2_C_CBC(FILE *out)
{
  DxStatus result = CE2_OK, error;
  DxUint8_t OutData[CE2_TST_C2_C_CBC_DATA_SIZE];
  int cmp, i;

  PrintTestBeginMsg(out, __FUNCTION__);

  /* Encryption test */
  error = CE2_C2(CE2_TST_C2_C_CBC_Key, CE2_C2Cipher_Encrypt_mode, 
    CE2_C2Cipher_C_CBC_mode, CE2_TST_C2_C_CBC_PlanData, CE2_TST_C2_C_CBC_DATA_SIZE, 
    OutData);
  if (error != CE2_OK) {
    fprintf(out, "Can't make CE2_C2 encryption  in C-CBC mode.\n");
    result |= CE2_TST_FAILED;
  }

  cmp = memcmp(OutData, CE2_TST_C2_C_CBC_CryptData, CE2_TST_C2_C_CBC_DATA_SIZE);
  if (cmp != 0) {
    fprintf(out, "Wrong CE2_C2 encrypted data in C-CBC mode.\n");
    for (i = 0; i < CE2_TST_C2_C_CBC_DATA_SIZE; i++) {
      fprintf(out, "%X", (OutData[i]&0xf0)/0x10);
      fprintf(out, "%X ", OutData[i]&0x0f);
    }
    fprintf(out, " \n");
    for (i = 0; i < CE2_TST_C2_C_CBC_DATA_SIZE; i++) {
      fprintf(out, "%X", (CE2_TST_C2_C_CBC_CryptData[i]&0xf0)/0x10);
      fprintf(out, "%X ", CE2_TST_C2_C_CBC_CryptData[i]&0x0f);
    }
    fprintf(out, " \n");
    result |= CE2_TST_FAILED;
  }

  /* Decryption test */
  error = CE2_C2(CE2_TST_C2_C_CBC_Key, CE2_C2Cipher_Decrypt_mode, 
    CE2_C2Cipher_C_CBC_mode, CE2_TST_C2_C_CBC_CryptData, CE2_TST_C2_C_CBC_DATA_SIZE, 
    OutData);
  if (error != CE2_OK) {
    fprintf(out, "Can't make CE2_C2 decryption  in C-CBC mode.\n");
    result |= CE2_TST_FAILED;
  }

  cmp = memcmp(OutData, CE2_TST_C2_C_CBC_PlanData, CE2_TST_C2_C_CBC_DATA_SIZE);
  if (cmp != 0) {
    fprintf(out, "Wrong CE2_C2 decrypted data in C-CBC mode.\n");
    for (i = 0; i < CE2_TST_C2_C_CBC_DATA_SIZE; i++) {
      fprintf(out, "%X", (OutData[i]&0xf0)/0x10);
      fprintf(out, "%X ", OutData[i]&0x0f);
    }
    fprintf(out, " \n");
    for (i = 0; i < CE2_TST_C2_C_CBC_DATA_SIZE; i++) {
      fprintf(out, "%X", (CE2_TST_C2_C_CBC_PlanData[i]&0xf0)/0x10);
      fprintf(out, "%X ", CE2_TST_C2_C_CBC_PlanData[i]&0x0f);
    }
    fprintf(out, " \n");
    result |= CE2_TST_FAILED;
  }

  PrintTestEndMsg(out, __FUNCTION__, result);

  return result;
}

/*****************************************************************************
* Function Name:                                                           
* 	CE2_TST_C2_HASH 		
* 
* Inputs:
*  @param[in/out] out - output stream for logs;
*
* Outputs:
*  @return - On success returns CE2_TST_VALID; else returns CE2_TST_FAILED.
*
* Description:																	
* 	Verify functionality of CE2_C2_HASH() function;
*
* Algorithm:		
*  -#  											
*
******************************************************************************/	
DxStatus CE2_TST_C2_HASH(FILE *out)
{
  DxStatus result = CE2_OK, error;
  DxUint8_t TestMessage1[] = "TestMessage1";
  DxUint8_t TestMessage2[] = "TestMessage2";
  CE2_C2HASH_Result_t hash1, hash2;
  int cmp;

  PrintTestBeginMsg(out, __FUNCTION__);

 
  /* Simple hash test */
  error = CE2_C2_HASH(TestMessage1, sizeof(TestMessage1)/sizeof(DxUint8_t), hash1);
  if (error != CE2_OK) {
    fprintf(out, "Can't make hash for message 1.\n");
    result |= CE2_TST_FAILED;
  }
  
  error = CE2_C2_HASH(TestMessage2, sizeof(TestMessage2)/sizeof(DxUint8_t), hash2);
  if (error != CE2_OK) {
    fprintf(out, "Can't make hash for message 2.\n");
    result |= CE2_TST_FAILED;
  }

  cmp = memcmp(hash1, hash2, sizeof(CE2_C2HASH_Result_t));
  if (cmp == 0) {
    fprintf(out, "There are equal hashes with different messages!\n");
    result |= CE2_TST_FAILED;
  }

	/* Hash test with test vector (test 1) */
	error = CE2_C2_HASH(CE2_TST_C2_HashInput1, sizeof(CE2_TST_C2_HashInput1)/sizeof(DxUint8_t), hash1);
	if (error != CE2_OK) {
		fprintf(out, "Can't make hash (test 1)!.\n");
		result |= CE2_TST_FAILED;
	}
	cmp = memcmp(hash1, CE2_TST_C2_HashOutput1, sizeof(CE2_C2HASH_Result_t));
	if (cmp != 0) {
		fprintf(out, "Wrong output from CE2_C2_HASH (test 1)!\n");
		PrintBuffer(out, (DxUint8_t*)hash1, sizeof(hash1), "Hash1");
		PrintBuffer(out, CE2_TST_C2_HashOutput1, sizeof(CE2_TST_C2_HashOutput1), "Test Hash1");
		result |= CE2_TST_FAILED;
	}
	/* Hash test with test vector (test 2) */
	error = CE2_C2_HASH(CE2_TST_C2_HashInput2, sizeof(CE2_TST_C2_HashInput2)/sizeof(DxUint8_t), hash2);
	if (error != CE2_OK) {
		fprintf(out, "Can't make hash  (test 2)!.\n");
		result |= CE2_TST_FAILED;
	}
	cmp = memcmp(hash2, CE2_TST_C2_HashOutput2, sizeof(CE2_C2HASH_Result_t));
	if (cmp != 0) {
		fprintf(out, "Wrong output from CE2_C2_HASH (test 2)!\n");
		PrintBuffer(out, (DxUint8_t*)hash2, sizeof(hash2), "Hash2");
		PrintBuffer(out, CE2_TST_C2_HashOutput2, sizeof(CE2_TST_C2_HashOutput2), "Test Hash2");
		result |= CE2_TST_FAILED;
	}

	
	PrintTestEndMsg(out, __FUNCTION__, result);

  return result;
}


/*****************************************************************************
* Function Name:                                                           
* 	CE2_TST_C2_OneWayFunc 		
* 
* Inputs:
*  @param[in/out] out - output stream for logs;
*
* Outputs:
*  @return - On success returns CE2_TST_VALID; else returns CE2_TST_FAILED.
*
* Description:																	
* 	Verify functionality of CE2_C2_OneWayFunc() function;
*
* Algorithm:		
*  -#  											
*
******************************************************************************/	
DxStatus CE2_TST_C2_OneWayFunc(FILE *out)
{
  DxStatus result = CE2_OK, error;
  DxUint8_t OutData[CE2_TST_C2_ECB_DATA_SIZE];
  int cmp, i;

  PrintTestBeginMsg(out, __FUNCTION__);

  /* One way function test */
  error = CE2_C2_OneWayFunc(CE2_TST_C2_ECB_Key, CE2_TST_C2_ECB_PlanData, OutData);
  if (error != CE2_OK) {
    fprintf(out, "Can't make CE2_C2_OneWayFunc.\n");
    result |= CE2_TST_FAILED;
  }

  cmp = memcmp(OutData, CE2_TST_C2_OneWayFuncOut, CE2_TST_C2_ECB_DATA_SIZE);
  if (cmp != 0) {
    fprintf(out, "Wrong CE2_C2_OneWayFunc result.\n");
    for (i = 0; i < CE2_TST_C2_ECB_DATA_SIZE; i++) {
      fprintf(out, "%X", (OutData[i]&0xf0)/0x10);
      fprintf(out, "%X ", OutData[i]&0x0f);
    }
    fprintf(out, " \n");
    for (i = 0; i < CE2_TST_C2_ECB_DATA_SIZE; i++) {
      fprintf(out, "%X", (CE2_TST_C2_C_CBC_PlanData[i]&0xf0)/0x10);
      fprintf(out, "%X ", CE2_TST_C2_C_CBC_PlanData[i]&0x0f);
    }
    fprintf(out, " \n");
    result |= CE2_TST_FAILED;
  }

	/* One way function test with test vector */
	error = CE2_C2_OneWayFunc(CE2_TST_C2_OneWayFuncD1, CE2_TST_C2_OneWayFuncD2, OutData);
	if (error != CE2_OK) {
		fprintf(out, "Can't make CE2_C2_OneWayFunc.\n");
		result |= CE2_TST_FAILED;
	}

	cmp = memcmp(OutData, CE2_TST_C2_OneWayFuncG, sizeof(CE2_C2_BLOCK_BYTES_t));
	if (cmp != 0) {
		fprintf(out, "Wrong output from CE2_C2_HASH!\n");
		PrintBuffer(out, OutData, sizeof(CE2_C2_BLOCK_BYTES_t), "OneWayFunc");
		PrintBuffer(out, CE2_TST_C2_OneWayFuncG, sizeof(CE2_C2_BLOCK_BYTES_t), "Test OneWayFunc");
		result |= CE2_TST_FAILED;
	}

  PrintTestEndMsg(out, __FUNCTION__, result);

  return result;
}
