
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#import "FileMD5Hash.h"
#import "FileReader.h"
#import "AESCryptor.h"
#import "KeyDataFileGenerator.h"

#define MOD_KEY 13

#pragma mark -
#pragma mark Constants
//Common message
static NSString *securityToolAutoMessage=@"//************************************************************\n//This file is auto-generated by the SecurityTool v1.0. \n//************************************************************";


//for .h File
static NSString *securityToolMessage1=@"#import <Foundation/Foundation.h>";
static NSString *securityToolMessage2=@"@interface ";
static NSString *securityToolMessage3=@"{\n";
static NSString *securityToolMessage4=@"}\n";
static NSString *securityToolMessage5=@"- (id)getKeyDataForFileAtIndex:(int)fileIndex;";
static NSString *securityToolMessage6=@"- (void)getDataAtIndex:(int)index\n			configData:(int **)configDataPtr\n			 indexData:(int **)indexDataPtr;";

//for .m File
static NSString *securityToolMessage7=@"#import \"";
static NSString *securityToolMessage8=@"@implementation ";
static NSString *securityToolMessage9=@"- (id)getKeyDataForFileAtIndex:(int)fileIndex {\n";
static NSString *securityToolMessage10=@"	NSMutableArray *dataArray=[[NSMutableArray alloc] init];\n";
static NSString *securityToolMessage11=@"	int *configIndex;//=(int *)malloc(sizeof(int));";
static NSString *securityToolMessage12=@"	int *hashIndex;//=(int *)malloc(sizeof(int));";
static NSString *securityToolMessage13=@"	[self getDataAtIndex:fileIndex\n			  configData:&configIndex\n			   indexData:&hashIndex];";
static NSString *securityToolMessage14=@"	for (int i=0; i<48; i++) {";
static NSString *securityToolMessage15=@"		int n=*(configIndex+i);";
static NSString *securityToolMessage16=@"		[dataArray addObject:[NSNumber numberWithInt:n]];";
static NSString *securityToolMessage17=@"	}";
static NSString *securityToolMessage18=@"	for (int i=0; i<48; i++) {";
static NSString *securityToolMessage19=@"		int n=*(hashIndex+i);";
static NSString *securityToolMessage20=@"		[dataArray addObject:[NSNumber numberWithInt:n]];";
static NSString *securityToolMessage21=@"	//free(configIndex);";
static NSString *securityToolMessage22=@"	//free(hashIndex);";
static NSString *securityToolMessage23=@"	return dataArray;";
static NSString *securityToolMessage24=@"- (void)getDataAtIndex:(int)index\n			configData:(int **)configDataPtr\n			 indexData:(int **)indexDataPtr{\n";
static NSString *securityToolMessage25=@"	switch (index) {";
static NSString *securityToolMessage26=@"		case ";
static NSString *securityToolMessage27=@"			*configDataPtr=";
static NSString *securityToolMessage28=@"			*indexDataPtr=";
static NSString *securityToolMessage29=@"			break;";
static NSString *securityToolMessage30=@"		default:";
static NSString *securityToolMessage31=@"@end";

/*
//Actual data locations
static int actualDataSections[49][2]={1,8,9,16,17,25,26,32,33,41,42,47,48,53,54,59,60,65,66,75,76,86,87,99,
									  100,110,111,117,118,126,127,131,132,139,140,148,149,155,156,160,161,169,170,180,181,189,190,200,
									  201,210,211,217,218,225,226,232,233,240,241,250,251,257,258,264,265,273,274,283,284,290,291,300,
									  301,310,311,315,316,327,328,335,336,346,347,357,358,365,366,371,372,379,380,388,389,392,393,399};

//Config data locations
static int configDataSections[49][2]={401,420,421,440,441,460,461,480,481,500,501,520,521,540,541,560,561,580,581,600,601,620,621,640,
									  641,660,661,680,681,700,701,740,741,780,781,820,821,861,863,900,910,940,950,1050,1060,1100,1120,1140,
									  1150,1180,1181,1200,1201,1240,1241,1260,1261,1280,1320,1350,1360,1380,1400,1420,1440,1441,1480,1481,1540,1541,1545,1585,
									  1590,1609,1620,1640,1650,1680,1690,1730,1740,1750,1760,1780,1800,1820,1840,1860,1880,1900,1910,1920,1940,1950,1960,1980};*/
NSString *outputClassName;

#pragma mark -
#pragma mark Function declarations

void createHeaderFile();
void createImplementationFile(const char *indexFilePath,int filesCount);
BOOL createConfigFile(char **binaryFilePath,
					  const char *indexFilePath,
					  const char *configFilePath,
					  const char *hashEncryptionKey,
					  const char *configEncryptionKey,
					  int noOfBinaryFiles);
int generateUniqueRandomNumbersWithinRange(int maxRange,int minRange);
int generateRandomNumbersUptoRange(int maxRange,int minRange);
void autoGenerateKeys(char *keyData);
char* autoGenerateKeysToFile(char *keyData,char *path);
void writeDataToFile(char *dataToWrite,char *path,int sizeOfFile,int dataTypeSize);
void readDataFromFile(char *path,char *outputBuffer,int sizeOfFile);
void printHelp();
int IsPathValid(const char *fname);

#pragma mark -
#pragma mark Main 
int main (int argc, const char * argv[]) {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

	char /*taskTypeData[16],*/noOfFiles[16];
	char indexfile_FilePath[5000],*temp;
	char binary_FilePath[5000],config_FilePath[5000];
	char hashFileEncryptionKey[33],configFileEncryptionKey[33];
	char hashFileEncryptionKeyPath[5000],configFileEncryptionKeyPath[5000];
	int /*taskType,*/totalNumberOfFiles,count;
	char **binary_FilePaths;

	NSString *homeDirectory=NSHomeDirectory();
	NSString *securityToolFolder=[homeDirectory stringByAppendingPathComponent:@"SecurityTool"];

	//createImplementationFile([securityToolFolder UTF8String], 3);

	[[NSFileManager defaultManager] createDirectoryAtPath:securityToolFolder withIntermediateDirectories:YES attributes:nil error:nil];

	NSString *hashFileEnckeyPath=[securityToolFolder stringByAppendingPathComponent:@"hashKey.txt"];
	NSString *confFileEnckeyPath=[securityToolFolder stringByAppendingPathComponent:@"configKey.txt"];
	NSString *configFilePath=[securityToolFolder stringByAppendingPathComponent:@"config.dat"];
	NSString *indexFilePath=[securityToolFolder stringByAppendingPathComponent:@"index.dat"];

	hashFileEncryptionKey[32]='\0';
	configFileEncryptionKey[32]='\0';

	if(argc<2){
		printHelp();
        char binaryChecksum[33];        
        NSString *resPath = [[NSBundle mainBundle] resourcePath];
        NSString *fn = [NSString stringWithFormat:@"%@/%@", resPath, @"SecurityTool"];
        CrackPreventFileMD5HashCreateWithPath((CFStringRef)fn, FileHashDefaultChunkSizeForReadingData,binaryChecksum);
//        NSLog(@"%@",[NSString stringWithCString:binaryChecksum encoding:NSUTF8StringEncoding]);
//        FileMD5HashCreateWithPath((CFStringRef)fn, FileHashDefaultChunkSizeForReadingData,binaryChecksum);
        NSLog(@"Test checksum:%@",[NSString stringWithCString:binaryChecksum encoding:NSUTF8StringEncoding]);        
		return 0;
	}
	else if(argc>2){
		if(strncmp("-I", argv[1], 2)==0){
			printf("\nCreating the index file..\n");
			strcpy(noOfFiles, argv[2]);
			sscanf(noOfFiles,"%d",&totalNumberOfFiles);
			printf("\nTotal Number of files %d\n",totalNumberOfFiles);
			
			if(totalNumberOfFiles<=0 || totalNumberOfFiles==0){
				printHelp();
				return 0;
			}
			
			[indexFilePath getCString:indexfile_FilePath 
							maxLength:5000 
							 encoding:NSUTF8StringEncoding];
			
			//Creating the header file
			createHeaderFile();
			//Creating the implementation file
			createImplementationFile(indexfile_FilePath,totalNumberOfFiles);
			
			[hashFileEnckeyPath getCString:hashFileEncryptionKeyPath 
								 maxLength:5000 
								  encoding:NSUTF8StringEncoding];
			
			[confFileEnckeyPath getCString:configFileEncryptionKeyPath 
								 maxLength:5000 
								  encoding:NSUTF8StringEncoding];
			
			//Generating the keys for binary file encryption
			char* hashKey = autoGenerateKeysToFile(hashFileEncryptionKey, hashFileEncryptionKeyPath);
            [KeyDataFileGenerator genFileWithString32:[NSString stringWithCString:hashKey encoding:NSUTF8StringEncoding] suffix:@"hash" modKey:MOD_KEY];
			//Generating the keys for config file encryption
			char* confKey = autoGenerateKeysToFile(configFileEncryptionKey, configFileEncryptionKeyPath);
            [KeyDataFileGenerator genFileWithString32:[NSString stringWithCString:confKey encoding:NSUTF8StringEncoding] suffix:@"conf" modKey:MOD_KEY];
			
			printf("\n****************************************\n");
			printf("Created files saved in home directory!!!\n");
			printf("****************************************\n");
		}
		else if(strncmp("-C", argv[1], 2)==0){
			
			printf("Creating the configuration file..\n");
			strcpy(noOfFiles, argv[2]);
			sscanf(noOfFiles,"%d",&totalNumberOfFiles);
			printf("Total Number of files %d\n",totalNumberOfFiles);
			
			if(totalNumberOfFiles<=0){
			
				printf("No of files count is zero!!\n");
				return 0;
			}
			
		
			binary_FilePaths = malloc(sizeof(char *) * 10);
			
			for(count = 0; count < totalNumberOfFiles; count ++) {
				
				binary_FilePaths[count] = malloc(sizeof(int) * 5000);
				
			}
			
			count = 0;
			
			for (int i=3; i<argc; i++) {
				
				if(IsPathValid(argv[i])==0){
					
					printf("Invalid path found, please retry..\n");
					return 0;
				}

				
				strcpy(binary_FilePath, argv[i]);
				if((temp = strchr(binary_FilePath, '\n')) != NULL)
					*temp = '\0';
				
				
				strcpy(binary_FilePaths[count],binary_FilePath);
				temp=nil;
				
				count++;
			}
			
			if(count==0 || count !=totalNumberOfFiles){
				
				printf("No of file paths entered are less than the no of files specified!!\n");
				return 0;
			}
            printf("binary_FilePath: %s",binary_FilePath);
			[hashFileEnckeyPath getCString:hashFileEncryptionKeyPath 
								 maxLength:5000 
								  encoding:NSUTF8StringEncoding];

			[confFileEnckeyPath getCString:configFileEncryptionKeyPath 
								 maxLength:5000 
								  encoding:NSUTF8StringEncoding];

			[indexFilePath getCString:indexfile_FilePath 
							maxLength:5000 
							 encoding:NSUTF8StringEncoding];

			[configFilePath getCString:config_FilePath 
							 maxLength:5000 
							  encoding:NSUTF8StringEncoding];
			
			readDataFromFile(hashFileEncryptionKeyPath, hashFileEncryptionKey, 33);
			readDataFromFile(configFileEncryptionKeyPath, configFileEncryptionKey, 33);
			
			hashFileEncryptionKey[32]='\0';
			configFileEncryptionKey[32]='\0';
			
			createConfigFile(binary_FilePaths, indexfile_FilePath,config_FilePath,hashFileEncryptionKey,configFileEncryptionKey,totalNumberOfFiles);
			
			
		}
		else {
			
			printHelp();
			return 0;
		}

	}
	else {
		
		printHelp();
		return 0;
	}
    [pool drain];
    return 0;
}

#pragma mark -
#pragma mark Create header file  
void createHeaderFile() {
	
	NSString *homeDir=NSHomeDirectory();
	
	NSString *securityToolFolder=[homeDir stringByAppendingPathComponent:@"SecurityTool"];
	
	outputClassName=@"KeyDataManager";
	
	NSString *filePath=[securityToolFolder stringByAppendingPathComponent:@"KeyDataManager.h"];

	//Creating the header class file text
	NSString *indexFileData_h=[[NSArray arrayWithObjects:securityToolAutoMessage,@"\n",
								securityToolMessage1,[securityToolMessage2 stringByAppendingFormat:@" %@ : NSObject",outputClassName],
								securityToolMessage3,securityToolMessage4,
								securityToolMessage5,securityToolMessage6,
								securityToolMessage31,nil] componentsJoinedByString:@"\n"];
	
	//Writing file
	if(![indexFileData_h writeToFile:filePath
					  atomically:YES 
						encoding:NSUTF8StringEncoding 
							  error:nil]){
		printf("\n An error has occured while writing the implementation class file!!!\n");
		return;
	}
}

#pragma mark -
#pragma mark Create implementation file
void createImplementationFile(const char *indexFilePath,int filesCount){
	
	FILE *indexFileHandle;

	int indexMax;
	int indexMin;
	int indexLength;
	
	indexMax=512;
	indexMin=0;
	indexLength=512;
	
	int *arrayOfIndexes;
	int indexSize=filesCount*96*sizeof(int);
	arrayOfIndexes=(int *) malloc(indexSize);
	int jcount=0,jmax=96;
	
	for (int i=0; i<filesCount; i++) {
		
		int currentMin;
		int currentMax;
		
		currentMin=indexMin+1;
		currentMax=indexMin+10;
		int indexFileForActulaData[96];

		//generate index for config data
		for(int i=0;i<48;i++){
			
			int n=generateUniqueRandomNumbersWithinRange(currentMax,currentMin);
#ifdef __DEBUG__MODE
//			printf("MAX=%d MIN=%d\n",currentMax,currentMin);
//			printf("AUTOGEN =%d\n",n);
#endif
			indexFileForActulaData[i]=n;
			currentMin=currentMax+1;
			currentMax+=10;
			
		}
		
		indexMin=indexMax;
		indexMax=indexMax+indexLength;
		currentMin=indexMin;
		currentMax=indexMin+10;
		
		//generate index for hash data
		for(int i=0;i<48;i++){
			
			int n=generateUniqueRandomNumbersWithinRange(currentMax,currentMin);
#ifdef __DEBUG__MODE
//			printf("AUTOGEN =%d\n",n);
//			printf("MAX=%d MIN=%d\n",currentMax,currentMin);
#endif
			indexFileForActulaData[i+48]=n;
			currentMin=currentMax+1;
			currentMax+=10;
		}
		
		indexMin=indexMax+1;
		indexMax=indexMax+indexLength;
#ifdef __DEBUG__MODE
		printf("Index for file = %d\n",filesCount);
		printf("*****************************************\n");
#endif
		for(int i=jcount,j=0;i<jmax&&j<96;i++,j++){
		
			arrayOfIndexes[i]=indexFileForActulaData[j];
#ifdef __DEBUG__MODE
//			printf("Actual Index = %d\n",indexFileForActulaData[j]);
#endif

		}
#ifdef __DEBUG__MODE		
		printf("*****************************************\n");
#endif
		jcount=jmax;
		jmax+=96;
	}
	
#ifdef __DEBUG__MODE
	int finalOutputArraySize=filesCount*96;
	for(int i=0;i<finalOutputArraySize;i++){
		
//		printf("Final Index Output= %d\n",arrayOfIndexes[i]);
	}
#endif
    
	[KeyDataFileGenerator genindexFile:arrayOfIndexes modKey:MOD_KEY];
	indexFileHandle = fopen (indexFilePath , "wb" );
	fwrite (arrayOfIndexes , 1 , indexSize , indexFileHandle );
	fclose (indexFileHandle);
			
	NSString *IndexArrayText;
	NSString *getArrayMethodText;	
	
	jcount=0;
	jmax=48;
	
	NSMutableArray *componentsOfIndex;
	NSMutableArray *componentsOfgetArrayMethodText;
	
	componentsOfIndex=[[NSMutableArray alloc] init];
	componentsOfgetArrayMethodText=[[NSMutableArray alloc] init];
	
	for (int i=0; i<filesCount; i++) {
	
		NSString *dataText1=@"static int configIndexData";
		dataText1=[dataText1 stringByAppendingFormat:@"_%d[]={",i+1];
	
		for (int i=jcount; i<jmax; i++) {
		
			int n=arrayOfIndexes[i];
			NSString *value=[NSString stringWithFormat:@"%d",n];
			dataText1=[dataText1 stringByAppendingString:value];
		
			if(i!=(jmax-1))
				dataText1=[dataText1 stringByAppendingString:@","];
		
		}
		dataText1=[dataText1 stringByAppendingFormat:@"};"];
		[componentsOfIndex addObject:dataText1];
		
		NSString *dataText2=@"static int fileIndexData";
		dataText2=[dataText2 stringByAppendingFormat:@"_%d[]={",i+1];
		
		jcount=jmax;
		jmax+=48;
		
		for (int i=jcount; i<jmax; i++) {
		
			int n=arrayOfIndexes[i];
			NSString *value=[NSString stringWithFormat:@"%d",n];
			dataText2=[dataText2 stringByAppendingString:value];
		
			if(i!=(jmax-1))
				dataText2=[dataText2 stringByAppendingString:@","];
		
		}
		dataText2=[dataText2 stringByAppendingFormat:@"};"];
		[componentsOfIndex addObject:dataText2];
		
		jcount=jmax;
		jmax+=48;
		
		NSString *dataText3=[securityToolMessage26 stringByAppendingFormat:@"%d:\n",i+1];
		dataText3=[dataText3 stringByAppendingFormat:@"%@configIndexData_%d;\n",securityToolMessage27,i+1];
		dataText3=[dataText3 stringByAppendingFormat:@"%@fileIndexData_%d;\n",securityToolMessage28,i+1];
		dataText3=[dataText3 stringByAppendingFormat:@"%@\n",securityToolMessage29];
		
		[componentsOfgetArrayMethodText addObject:dataText3];
	}
	
	
	IndexArrayText=[componentsOfIndex componentsJoinedByString:@"\n"];
	getArrayMethodText=[componentsOfgetArrayMethodText componentsJoinedByString:@"\n"];
	getArrayMethodText=[getArrayMethodText stringByAppendingFormat:@"%@\n%@\n",securityToolMessage30,securityToolMessage29];
	
	outputClassName=@"KeyDataManager";
	
	//Creating the implementation class file text
	NSString *indexFileData_m=[[NSArray arrayWithObjects:securityToolAutoMessage,@"\n",
								[securityToolMessage7 stringByAppendingFormat:@"%@.h\"",outputClassName],IndexArrayText,@"\n",[securityToolMessage8 stringByAppendingFormat:@"%@",outputClassName],
								securityToolMessage9,securityToolMessage10,
								securityToolMessage11,securityToolMessage12,
								securityToolMessage13,securityToolMessage14,
								securityToolMessage15,securityToolMessage16,
								securityToolMessage17,securityToolMessage18,
								securityToolMessage19,securityToolMessage20,
								securityToolMessage17,securityToolMessage21,
								securityToolMessage22,securityToolMessage23,
								securityToolMessage4,securityToolMessage24,
								securityToolMessage25,getArrayMethodText,
								securityToolMessage17,securityToolMessage4,
								securityToolMessage31,nil] componentsJoinedByString:@"\n"];
	
	NSString *homeDir=NSHomeDirectory();
	
	NSString *securityToolFolder=[homeDir stringByAppendingPathComponent:@"SecurityTool"];
		
	NSString *filePath=[securityToolFolder  stringByAppendingPathComponent:@"KeyDataManager.m"];
		
	//Writing the file
	if(![indexFileData_m writeToFile:filePath 
					  atomically:YES 
						encoding:NSUTF8StringEncoding 
						   error:nil]){
	
		printf("\n An error has occured while writing the header class file!!!\n");
		[componentsOfgetArrayMethodText release];
		[componentsOfIndex release];
		return;
	}
	
	[componentsOfgetArrayMethodText release];
	[componentsOfIndex release];
}

#pragma mark -
#pragma mark Create config file 
BOOL createConfigFile(char **binaryFilePath,
					  const char *indexFilePath,
					  const char *configFilePath,
					  const char *hashEncryptionKey,
					  const char *configEncryptionKey,
					  int noOfBinaryFiles) {
	
	char outputFile[512];
	char *finalOutputFile;
	int *indexFiles;
	int tempIndexFile[96];
	int indexFileCounter,indexFileMaxCount;
	int finalOutputFileCounter,finalOutputFileMaxCount;
	char binaryChecksum[33];
	char encryptedbinaryChecksum[49];
	char configChecksum[33];
	char encryptedconfigChecksum[49];
	
	FILE *indexFileHandle;
	FILE *configFileHandle;
	
	int indexFileSize=noOfBinaryFiles*96*sizeof(int);
	indexFiles=(int *) malloc(indexFileSize);
	
	int finalOutputFileSize=noOfBinaryFiles*1024*sizeof(char);
	finalOutputFile=(char *)malloc(finalOutputFileSize+1);
	finalOutputFile[finalOutputFileSize]='\0';
	
    printf("\nindexFilePath: %s",indexFilePath);
	//Reading the index file
	if((indexFileHandle = fopen (indexFilePath , "rb" ))) {
		
		indexFileHandle = fopen (indexFilePath , "rb" );
		fread (indexFiles , 1 ,indexFileSize, indexFileHandle );
		fclose (indexFileHandle);
	}
	else {
		printf("\n Unable to read the index file\n");
		free(finalOutputFile);
		free(indexFiles);
		return FALSE;
	}
	
	indexFileMaxCount=96;
	indexFileCounter=0;
	
	finalOutputFileMaxCount=512;
	finalOutputFileCounter=0;
	
	AESCryptor *cryptor=[[AESCryptor alloc] init];
	//Initializing the binary checksum array
	for(int i=0;i<finalOutputFileSize;i++)
		finalOutputFile[i]=arc4random()%99;

	for (int count=0; count<noOfBinaryFiles; count++) {
		
		//Read the first index data
		for (int i=indexFileCounter,j=0; i<indexFileMaxCount; i++,j++) {
#ifdef __DEBUG__MODE
//			printf("INDEX = %d\n",*(indexFiles+i));
#endif
			tempIndexFile[j]=*(indexFiles+i);
		}
		
		//Initializing the binary checksum array
		for(int i=0;i<32;i++)
			binaryChecksum[i]=0;
		binaryChecksum[32]='\0';
		
		//Putting random data in outputfile for binary hash data
		for(int i=0;i<512;i++)
			outputFile[i]=0;
		
		//Creating the hash for binary data
		NSString *binaryFilePathText=[NSString stringWithCString:(*(binaryFilePath+count)) encoding:NSUTF8StringEncoding]; //Ae mod add encode
        
//		FileMD5HashCreateWithPath((CFStringRef)binaryFilePathText, FileHashDefaultChunkSizeForReadingData,binaryChecksum);
		CrackPreventFileMD5HashCreateWithPath((CFStringRef)binaryFilePathText, FileHashDefaultChunkSizeForReadingData,binaryChecksum);
		binaryChecksum[32]='\0';
		//Hashed data for the binary
		NSData *hashedData=[NSData dataWithBytes:binaryChecksum 
										  length:33];
		//Checking whether hashed data is NULL
		if(hashedData==nil){
			
			printf("\n Unable to create the hash for the binary at index = %d!!!",count);
			free(finalOutputFile);
			free(indexFiles);
			[cryptor release];
			return FALSE;
		}
		
#ifdef __DEBUG__MODE
		//Hashed data
		printf("\n Hash data for binary at index = %d\n",count);
		for(int i=0;i<33;i++) {
//			printf("%d \t",binaryChecksum[i]);
        }
#endif
		//Encrypting the binary data
		NSData *encrypted=[cryptor encrypt:hashedData 
								   withKey:[NSString stringWithCString:hashEncryptionKey encoding:NSUTF8StringEncoding]];
		//Is encrypted successfully
		if(encrypted==nil){
			
			printf("\n Unable to encrypt the hash for the binary at index = %d!!!",count);
			free(finalOutputFile);
			free(indexFiles);
			[cryptor release];
			
			return FALSE;
		}
		//Getting encrypted bytes from encyptred binary check sum data
		[encrypted getBytes:encryptedbinaryChecksum 
					 length:48];
#ifdef __DEBUG__MODE
		//Encrypted data
		printf("\n Encrypted data for the binary at index =%d\n",count);
		for(int i=0;i<48;i++) {
//			printf("%d \t",encryptedbinaryChecksum[i]);
        }
#endif
	
		//Putting the encrypted binary check sum in output file based on index file data
		for (int i=0; i<48; i++) {
			
			int n=tempIndexFile[i];
			finalOutputFile[n]=encryptedbinaryChecksum[i];
#ifdef __DEBUG__MODE
//			int k=finalOutputFile[n];
			printf("\nVALUE AT INDEX %d %d %d   value=%d\t",i,encryptedbinaryChecksum[i],finalOutputFile[n],n);
#endif
		}

#ifdef __DEBUG__MODE
		//Config data for the binary
		printf("\n Config data For binary at index =%d\n",count);
		for(int i=0;i<512;i++) {
//			printf("%d \t",outputFile[i]);
        }

				
		//Copying config data to final output file 
		printf("\n Copying config data to final output file \n"); 
#endif
		for(int i=0,j=finalOutputFileCounter;j<finalOutputFileMaxCount;i++,j++){
			
			outputFile[i]=finalOutputFile[j]; 
#ifdef __DEBUG__MODE
//			printf("%d \t",finalOutputFile[j]);
#endif
		}

		//Creating the hash for config data of the binary
		DataMD5HashCreate(outputFile, FileHashDefaultChunkSizeForReadingData, configChecksum,512 );
		configChecksum[32]='\0';
#ifdef __DEBUG__MODE
		printf("\n Config Check Sum \n");
		for(int i=0;i<32;i++) {
//			printf("%d \t",configChecksum[i]);
        }
#endif
		
		NSData *encryptedconfigChecksumData=[cryptor encrypt:[NSData dataWithBytes:configChecksum length:33]
													 withKey:[NSString stringWithCString:configEncryptionKey encoding:NSUTF8StringEncoding]];
		//Is encrypted check sum NULL
		if(encryptedconfigChecksumData==nil){
			
			printf("\n Unable to encrypt the hash for config data!!!");
			free(finalOutputFile);
			free(indexFiles);
			[cryptor release];
			return FALSE;
		}
		//Getting the bytes from encrypted config checksum
		[encryptedconfigChecksumData getBytes:encryptedconfigChecksum 
									   length:[encryptedconfigChecksumData length]];
#ifdef __DEBUG__MODE
		//Config data for the binary
		printf("\n Config encrypted check sum %d\n",count);
		for(int i=0;i<48;i++)
			printf("%d \t",encryptedconfigChecksum[i]);

		
		// Copying encrypted config checksum to final output file
		printf("\n Copying encrypted config checksum to final output file\n");
#endif
		for(int i=0,j=48;i<48 && j<96;i++,j++){
			
			int n=tempIndexFile[j];
			finalOutputFile[n]=encryptedconfigChecksum[i]; 
#ifdef __DEBUG__MODE
			printf("%d \t",finalOutputFile[n]);
#endif
		}
		
		//Resetiing final output file loop counters
		finalOutputFileCounter=finalOutputFileMaxCount;
		finalOutputFileMaxCount+=512;

#ifdef __DEBUG__MODE
		//Config data for the binary
		printf("\n CONFIG PART =%d\n",count);
		for(int i=finalOutputFileCounter;i<finalOutputFileMaxCount;i++)
			printf("%d \t",finalOutputFile[i]);
#endif
		
		//Resetiing final output file loop counters
		finalOutputFileCounter=finalOutputFileMaxCount;
		finalOutputFileMaxCount+=512;
		
		//Resetiing index file loop counters
		indexFileCounter=indexFileMaxCount;
		indexFileMaxCount+=96;
	}
	
#ifdef __DEBUG__MODE	
	//Config data for the binary
	printf("\n ************** FINAL OUTPUT FILE **************\n");
	for(int i=0;i<finalOutputFileSize;i++)
		printf("%d \t",finalOutputFile[i]);
#endif
	//Is output file NULL
	if(finalOutputFile==nil){
		
		printf("\n Unable to create the configuration file!!!");
		free(finalOutputFile);
		free(indexFiles);
		[cryptor release];
		
		return FALSE;
	}
	
	indexFileCounter=0;
	indexFileMaxCount=48;
	
#ifdef __DEBUG__MODE
	for (int k=0; k<noOfBinaryFiles; k++) {
		
		//Read the first index data
		for (int i=indexFileCounter,j=0; i<indexFileMaxCount; i++,j++) {
			
			printf("INDEX = %d\n",*(indexFiles+i));
			tempIndexFile[j]=*(indexFiles+i);
		}
		
		printf("\n Binary Check Sum\n");
		for (int i=0; i<48; i++) {
			
			int n=tempIndexFile[i];
			printf("%d \t",finalOutputFile[n]);
			encryptedbinaryChecksum[i]=finalOutputFile[n];
		}
		encryptedbinaryChecksum[48]='\0';
						
		indexFileCounter=indexFileMaxCount;
		indexFileMaxCount+=48;
		
		for (int i=indexFileCounter,j=0; i<indexFileMaxCount; i++,j++) {
			
			printf("INDEX = %d\n",*(indexFiles+i));
			tempIndexFile[j]=*(indexFiles+i);
		}
		
		printf("\n Config Check Sum \n");
		for (int i=48; i<96; i++) {
			int n=tempIndexFile[i];
			printf("%d \t",finalOutputFile[n]);
		}
		
		indexFileCounter=indexFileMaxCount;
		indexFileMaxCount+=48;
	}
	printf("\n ********************************************************************************************************* \n");
#endif
	
	//Encrypting the finalouput file
	NSData *encryptedFinalConfigFile=[cryptor encrypt:[NSData dataWithBytes:finalOutputFile length:finalOutputFileSize]
											  withKey:[NSString stringWithCString:configEncryptionKey encoding:NSUTF8StringEncoding]];
	//Is encrypted final config NULL
	if(encryptedFinalConfigFile==nil){
		
		printf("Unable to encrypt file for the final output file");
		free(finalOutputFile);
		free(indexFiles);
		[cryptor release];

		return FALSE;
	}
	
	//Allocating memory for encrypted final config file 
	char *encryptedFinalOutputFile;
	int encryptedFinalOutputFileSize=[encryptedFinalConfigFile length];
	encryptedFinalOutputFile=(char *)malloc(encryptedFinalOutputFileSize);
	
	//getting bytes from encrypted final config file
	[encryptedFinalConfigFile getBytes:encryptedFinalOutputFile 
								length:encryptedFinalOutputFileSize];
	
	//Writing the config file data 
	configFileHandle = fopen ( configFilePath , "wb" );
	fwrite (encryptedFinalOutputFile , 1 , encryptedFinalOutputFileSize , configFileHandle );
	fclose (configFileHandle);
	
	free(encryptedFinalOutputFile);
	
	printf("Config file saved to SecurityTool folder in users home directory\n");
	
	/*for(int i=0;i<512;i++){
		
		int n=arc4random()%99;
		outputFile[i]=n;
	}
	outputFile[512]='\0';
	
	
	for(int i=0;i<1024;i++){
		
		int n=arc4random()%99;
		finalOutputFile[i]=n;
	}
	finalOutputFile[1024]='\0';
	
	binaryFilePathText=[NSString stringWithCString:(*(binaryFilePath+2))];
	
	
	//Hashed data for the binary
	NSData *hashedData=[NSData dataWithBytes:binaryChecksum 
									  length:33];
	
	if(hashedData==nil){
		
		printf("\n Unable to create the hash for the binary!!!");
		return FALSE;
	}
	
	//Encrypting the binary data
	AESCryptor *cryptor=[[AESCryptor alloc] init];
	NSData *encrypted=[cryptor encrypt:hashedData 
							   withKey:[NSString stringWithCString:hashEncryptionKey]];
	
	if(encrypted==nil){
		
		printf("\n Unable to encrypt the hash!!!");
		return FALSE;
	}

	[encrypted getBytes:encryptedbinaryChecksum 
				 length:[encrypted length]];
	
	printf("\n Encrypted data \n");
	for(int i=0;i<48;i++){
		
		printf("%d \t",encryptedbinaryChecksum[i]);
	}
	
	for (int i=0; i<48; i++) {
		
		int n=indexFile[i];
		outputFile[n]=encryptedbinaryChecksum[i];
	}
	
	printf("\n Config data \n");
	for(int i=0;i<400;i++){
		
		printf("%d \t",outputFile[i]);
	}
	
	printf("\n Hash data \n");
	for(int i=0;i<8;i++){
		
		printf("%d \t",binaryChecksum[i]);
	}
	
	printf("\n Copied Original data \n");
	for(int i=0;i<400;i++){
		
		finalOutputFile[i]=outputFile[i]; 
		printf("%d \t",finalOutputFile[i]);
	}
		
	DataMD5HashCreate(outputFile, FileHashDefaultChunkSizeForReadingData, configChecksum,400 );
	
	NSData *encryptedconfigChecksumData=[cryptor encrypt:[NSData dataWithBytes:configChecksum length:32]
												 withKey:[NSString stringWithCString:configEncryptionKey]];
	
	printf("\n binary Key \n");
	for (int i=0; i<32; i++) {
		
		printf("%c \t",hashEncryptionKey[i]);
	}
	
	printf("\n Config Key \n");
	for (int i=0; i<32; i++) {
		
		printf("%c \t",configEncryptionKey[i]);
	}
	
	if(encryptedconfigChecksumData==nil){
		
		printf("\n Unable to encrypt the hash!!!");
		return FALSE;
	}
	
	[encryptedconfigChecksumData getBytes:encryptedconfigChecksum 
								   length:[encryptedconfigChecksumData length]];
	
	printf("\n Copied Original data \n");
	for(int i=400,j=48;i<2024 && j<96;i++,j++){
		
		int n=indexFile[j];
		finalOutputFile[n]=encryptedconfigChecksum[j-48]; 
		printf("%d \t",finalOutputFile[n]);
	}
	finalOutputFile[2024]='\0';
	
	
	NSData *encryptedFinalConfigFile=[cryptor encrypt:[NSData dataWithBytes:finalOutputFile length:2024]
											  withKey:[NSString stringWithCString:configEncryptionKey]];
	char encryptedFinalOutputFile[2032];
	
	[encryptedFinalConfigFile getBytes:encryptedFinalOutputFile 
								length:2032];
	
	if(finalOutputFile==nil){
		
		printf("\n Unable to create the configuration file!!!");
		return FALSE;
	}
	
	printf("\n ********************************************************************************************************* \n");
	
	printf("\n Binary Check Sum\n");
	for (int i=0; i<48; i++) {
		
		int n=indexFile[i];
		printf("%d \t",finalOutputFile[n]);
	}
	
	printf("\n Config Check Sum \n");
	for (int i=48; i<96; i++) {
		
		int n=indexFile[i];
		printf("%d \t",finalOutputFile[n]);
	}
	
	printf("\n ********************************************************************************************************* \n");
	
	configFileHandle = fopen ( configFilePath , "wb" );
	fwrite (encryptedFinalOutputFile , 1 , 2032 , configFileHandle );
	fclose (configFileHandle);*/
	
	
#ifdef __DEBUG__MODE	
	FILE *testHandle;
	char *testBuffer;
	char *testBufferEnc;
	testBufferEnc=(char *)malloc(encryptedFinalOutputFileSize);
	
 	testHandle = fopen (configFilePath , "rb" );
	fread (testBufferEnc , 1 ,encryptedFinalOutputFileSize, testHandle );
	fclose (testHandle);
	
	NSData *decryptedBuffer=[cryptor decrypt:[NSData dataWithBytes:testBufferEnc length:encryptedFinalOutputFileSize] 
									 withKey:[NSString stringWithCString:configEncryptionKey]];
	
	testBuffer=(char *)malloc([decryptedBuffer length]);

	[decryptedBuffer getBytes:testBuffer 
				     length:[decryptedBuffer length]];
	printf("\n ********************************************************************************************************* \n");
	
	printf("\n ********************************************************************************************************* \n");
	
	printf("\n ********************************************************************************************************* \n");
	indexFileCounter=0;
	indexFileMaxCount=48;
	
	char tempData1[49],tempData2[33],tempData3[49],tempData4[33];
	
	for (int k=0; k<noOfBinaryFiles; k++) {

		printf("\nEncrypted Binary Check Sum \n");
		for (int i=indexFileCounter,j=0; i<indexFileMaxCount; i++,j++) {
			
			int n=*(indexFiles+i);
			printf("%d \t",testBuffer[n]);
			tempData1[j]=testBuffer[n];
		}
		//tempData1[22]=128;
		tempData1[48]='\0';
		NSData *decryptedtempData1=[cryptor decrypt:[NSData dataWithBytes:tempData1 length:48]	
											withKey:[NSString stringWithCString:hashEncryptionKey]];
		[decryptedtempData1 getBytes:tempData2 
							  length:33];
		tempData2[32]='\0';
		
		printf("\n Decrypted Binary Check Sum \n");
		for(int i=0;i<32;i++)
			printf("%d \t",tempData2[i]);
		
		
		indexFileCounter=indexFileMaxCount;
		indexFileMaxCount+=48;
		
		printf("\nEncrypted Config Check Sum \n");
		for (int i=indexFileCounter,j=0; i<indexFileMaxCount; i++,j++) {
		
			int n=*(indexFiles+i);
			printf("%d \t",testBuffer[n]);
			tempData3[j]=testBuffer[n];
		}
		tempData3[48]='\0';
		NSData *decryptedtempData2=[cryptor decrypt:[NSData dataWithBytes:tempData3 length:48] 
											withKey:[NSString stringWithCString:configEncryptionKey]];
		[decryptedtempData2 getBytes:tempData4
							  length:33];	
		tempData4[32]='\0';
		
		printf("\n Decrypted Config Check Sum \n");
		for(int i=0;i<32;i++)
			printf("%d \t",tempData4[i]);
		
		indexFileCounter=indexFileMaxCount;
		indexFileMaxCount+=48;
	}
	printf("\n ********************************************************************************************************* \n");
		
	free(testBufferEnc);
	free(testBuffer);
	
#endif

	free(finalOutputFile);
	free(indexFiles);
	[cryptor release];
	
	return TRUE;
}

#pragma mark -
#pragma mark Generate random numbers 
int generateUniqueRandomNumbersWithinRange(int maxRange,int minRange)
{
		
	int n=arc4random()%(maxRange-minRange+1) + minRange;
	
	return n;
}

int generateRandomNumbersUptoRange(int maxRange,int minRange)
{

	return 0;
}

#pragma mark -
#pragma mark Priniting the help note
void printHelp() {
	
	printf("\n***********************************Security Tool v1.0*************************************\n");
	printf("* Usage: SecurityTool operation parameters..  Tool                                       *\n");
	printf("*                     -I [No of files] =>> Create index file                             *\n");
	printf("*                     -C [No of files] [file paths] =>> Create config file               *\n");
	printf("******************************************************************************************\n");
}

#pragma mark -
#pragma mark Generate random key string 
void autoGenerateKeys(char *keyData) {
	
	
	time_t currentTime;
	struct tm * timeInfo;
	char tempKeyBytes[32];
	char *tempTimeBytes;
	int lengthOfTime;
	
	time ( &currentTime );
	timeInfo = localtime ( &currentTime );
	
	tempTimeBytes=asctime (timeInfo);
	lengthOfTime=strlen(tempTimeBytes);
	
	for (int i=0; i<lengthOfTime; i++) {
		
		tempKeyBytes[i]=tempTimeBytes[i];
	}
	
	int counter=lengthOfTime-1;
	for (; counter<32; counter++) {
		
		 tempKeyBytes[counter]=arc4random()%256;
	}
	
	DataMD5HashCreate(tempKeyBytes, FileHashDefaultChunkSizeForReadingData, keyData, 32);
		
#ifdef __DEBUG__MODE
	printf ( "Auto generated Key: %s Key Length : %lu\n", keyData,strlen(keyData));
#endif		
	
}

char* autoGenerateKeysToFile(char *keyData,char *path) {
	
	autoGenerateKeys(keyData);
	writeDataToFile(keyData, path, 32, 1);
    return keyData;
}

#pragma mark -
#pragma mark File manipulation functions
void writeDataToFile(char *dataToWrite,char *path,int sizeOfFile,int dataTypeSize) {
	
	FILE *writeFileHandle;
	writeFileHandle = fopen ( path , "wb" );
	fwrite (dataToWrite , dataTypeSize , sizeOfFile , writeFileHandle );
	fclose (writeFileHandle);
}

void readDataFromFile(char *path,char *outputBuffer,int sizeOfFile) {
	
	FILE *readFileHandle;
	readFileHandle = fopen (path , "rb" );
	fread (outputBuffer , 1 ,sizeOfFile, readFileHandle );
	fclose (readFileHandle);
}

int IsPathValid(const char *fname) {
	
	int ok = 0;
	FILE* f;
	
	if (fname && ((f=fopen(fname,"r")) != nil)) {
		fclose(f);
		ok = 1;
	}
	return ok;
	
}

