www.pudn.com > twofish-reference-c.zip > TST2FISH.C


/*************************************************************************** 
	TST2FISH.C	-- Test code for Twofish encryption 
 
	Submitters: 
		Bruce Schneier, Counterpane Systems 
		Doug Whiting,	Hi/fn 
		John Kelsey,	Counterpane Systems 
		Chris Hall,		Counterpane Systems 
		David Wagner,	UC Berkeley 
			 
	Code Author:		Doug Whiting,	Hi/fn 
		 
	Version  1.00		April 1998 
		 
	Copyright 1998, Hi/fn and Counterpane Systems.  All rights reserved. 
		 
	Notes: 
		*	Tab size is set to 4 characters in this file 
		*	A random number generator is generated and used here, so that  
			the same results can be generated on different platforms/compilers. 
		*	Command line arguments: 
				-h or ?	==>	give help message 
				-lNN	==> set sanity count test loop count to NN 
				-m		==> do full MCT generation 
				-pPath	==> set file base path 
				-r      ==> set initial random seed based on time 
				-tNN	==> perform timings with iteration count NN 
				-rNN	==> set initial random seed to NN 
				-v		==> read & verify files instead of creating them 
 
***************************************************************************/ 
 
#include	"aes.h" 
#include	 
#include	 
#include	 
#include	 
#include	 
 
extern	CONST char *moduleDescription;	/* which module is running */ 
extern	CONST char *modeString;			/* which key schedule mode */ 
extern	CONST int  debugCompile;		/* is external module compiled with debug? */ 
 
char CompilerName[8]= 
	#if   defined(__BORLANDC__) 
		"BCC"; 
	#elif defined(_MSC_VER) 
		"MSC"; 
	#elif defined(__WATCOMC__) 
		"WAT"; 
	#else 
		"???"; 
	#endif 
 
#if defined(__WATCOMC__) && defined(_M_IX86) && !defined(NO_TIMER) 
    DWORD ReadTimeStampCounter(void); 
	#pragma aux ReadTimeStampCounter = " db 0Fh,031h" value [eax] modify exact [eax edx] // RDTSC opcode 
#endif 
 
 
/* 
+***************************************************************************** 
*			Constants/Macros/Tables 
-****************************************************************************/ 
 
typedef struct 
	{ 
	FILE *f;				/* the file being written/read */ 
	int  I;					/* test number */ 
	int	 keySize;			/* key size in bits */ 
	int	 gotDebugIO;		/* got any debug IO? */ 
	BYTE pt[BLOCK_SIZE/8];	/* plaintext */ 
	BYTE ct[BLOCK_SIZE/8];	/* ciphertext */ 
 
	keyInstance    ki;		/* use ki.keyDwords as key bits */ 
	cipherInstance ci;		/* use ci.iv as iv bits */ 
	} testData; 
 
 
static char hexTab[]	=	"0123456789ABCDEF"; 
char		filePath[80]=	""; 
 
int			useAsm		=	0;	/* use assembly language */ 
int			mctInner	=	MCT_INNER/100; 
int			mctOuter	=	MCT_OUTER/10; 
int			verify		=	0;	/* set to nonzero to read&verify files */ 
int			debug		=	0;	/* debugging mode */ 
int			verbose		=	0;	/* verbose output */ 
int			quietVerify	=	0;	/* quiet during verify */ 
int			timeIterCnt	=	0;	/* how many times to iterate for timing */ 
DWORD		randBits[64]= {1};	/* use Knuth's additive generator */ 
int			randPtr; 
testData *	debugTD		= NULL;	/* for use with debugIO */ 
int			CLKS_BYTE	=	0;	/* use clks/byte? (vs. clks/block) */ 
int			FMT_LOG		=	0;	/* format for log file */ 
int			CLK_MHZ		=	200;/* default clock speed */ 
 
#define		KEY_BITS_0			128			/* first key bit setting to test */ 
#define		STEP_KEY_BITS		((MAX_KEY_BITS-KEY_BITS_0)/2) 
 
static char  hexString[]= 
		"0123456789ABCDEFFEDCBA987654321000112233445566778899AABBCCDDEEFF"; 
 
/* 
+***************************************************************************** 
*			Functions 
-****************************************************************************/ 
DWORD Here(DWORD x) 
	{ 
	unsigned int mask=~0U; 
 
	return (* (((DWORD *)&x)-1)) & mask; 
	} 
extern DWORD TwofishCodeSize(void); 
 
#ifdef USE_ASM 
int cdecl get_cpu_type(void);			/* return CPU type */ 
#endif 
 
/* 
+***************************************************************************** 
* 
* Function Name:	Rand 
* 
* Function:			Generate random number 
* 
* Arguments:		None. 
* 
* Return:			New random number. 
* 
* Notes:			Uses Knuth's additive generator, other magic 
* 
-****************************************************************************/ 
DWORD Rand(void) 
	{ 
	if (randPtr >= 57) 
		randPtr = 0;			/* handle the ptr wrap */ 
 
	randBits[randPtr] += randBits[(randPtr < 7) ? randPtr-7+57 : randPtr-7]; 
 
	randBits[62]+= randBits[61]; 
	randBits[63] = ROL(randBits[63],9) + 0x6F4ED7D0;	/* very long period! */ 
	 
	return (randBits[randPtr++] ^ randBits[63]) + randBits[62]; 
	} 
 
 
/* 
+***************************************************************************** 
* 
* Function Name:	SetRand 
* 
* Function:			Initialize random number seed 
* 
* Arguments:		seed	=	new seed value 
* 
* Return:			None. 
* 
* Notes:			 
* 
-****************************************************************************/ 
void SetRand(DWORD seed) 
	{ 
	int i; 
	DWORD x; 
 
	randPtr=0; 
	for (i=x=0;i<64;i++) 
		{ 
		randBits[i]=seed; 
		x |= seed;		/* keep track of lsb of all entries */ 
		seed = ROL(seed,11) + 0x12345678; 
		} 
 
	if ((x & 1) == 0)	/* insure maximal period by having at least one odd value */ 
		randBits[0]++; 
 
	for (i=0;i<1000;i++) 
		Rand();			/* run it for a while */ 
 
	randBits[63] = Rand(); 
	randBits[62] = Rand(); 
	randBits[61] = Rand() | 1;	/* make it odd */ 
	} 
 
 
/* 
+***************************************************************************** 
* 
* Function Name:	ClearTestData 
* 
* Function:			Initialize test data to all zeroes 
* 
* Arguments:		t		=	pointer to testData structure 
* 
* Return:			None. 
* 
* Notes:			 
* 
-****************************************************************************/ 
void ClearTestData(testData *t) 
	{ 
	t->gotDebugIO=0; 
	memset(t->pt,0,BLOCK_SIZE/8); 
	memset(t->ct,0,BLOCK_SIZE/8); 
	memset(t->ci.iv32,0,BLOCK_SIZE/8); 
	memset(t->ki.key32,0,MAX_KEY_BITS/8); 
	memset(t->ki.keyMaterial,'0',sizeof(t->ki.keyMaterial)); 
#if defined(COMPILE_KEY) && defined(USE_ASM) 
	t->ki.cSig1=t->ki.cSig2=0; 
#endif 
	} 
 
/* 
+***************************************************************************** 
* 
* Function Name:	FatalError 
* 
* Function:			Output a fatal error message and exit 
* 
* Arguments:		msg		=	fatal error description (printf string) 
*					msg2	=	2nd parameter to printf msg 
* 
* Return:			None. 
* 
* Notes: 
* 
-****************************************************************************/ 
void FatalError(CONST char *msg,CONST char *msg2) 
	{ 
	printf("\nFATAL ERROR: "); 
	printf(msg,msg2); 
	exit(2); 
	} 
 
 
/* 
+***************************************************************************** 
* 
* Function Name:	GetTimer 
* 
* Function:			Return a hi-frequency timer value 
* 
* Arguments:		None 
* 
* Return:			None. 
* 
* Notes: 
* 
-****************************************************************************/ 
DWORD GetTimer(void) 
	{ 
	DWORD x; 
 
#if defined(__BORLANDC__) && defined(__WIN32__) && !defined(NO_TIMER) 
#define	HI_RES_CLK	1 
	x=0; 
#pragma option -Od					/* disable optimizations (it's a REAL hack!) */ 
	__emit__(0x0F);	__emit__(0x31);	/* RDTSC opcode */ 
#pragma option -O.					/* restore optimization setting */ 
#elif defined(_MSC_VER) && defined(_M_IX86) && !defined(NO_TIMER) 
#define	HI_RES_CLK	1 
	_asm 
		{ 
		_emit 0x0F 
		_emit 0x31 
		mov	x,eax 
		}; 
#elif defined(__WATCOMC__) && defined(_M_IX86) && !defined(NO_TIMER) 
	#define	HI_RES_CLK	1 
	x = ReadTimeStampCounter(); 
#elif defined(CLOCKS_PER_SEC) 
	x=clock(); 
#else 
#define CLOCKS_PER_SEC	1			/* very low resolution timer */ 
	x=time(NULL); 
#endif 
 
	return x; 
	} 
 
 
/* 
+***************************************************************************** 
* 
* Function Name:	TimeOps 
* 
* Function:			Time encryption/decryption and print results 
* 
* Arguments:		iterCnt	= how many calls to make 
* 
* Return:			None. 
* 
* Notes:			None. 
* 
-****************************************************************************/ 
void TimeOps(int iterCnt) 
	{ 
	enum { TEST_CNT	= 3, BLOCK_CNT=64 }; 
	int   i,j,k,n,q; 
	DWORD t0,t1,dt[8],minT; 
	DWORD testTime[3][TEST_CNT]; 
	testData t; 
	BYTE text[BLOCK_CNT*(BLOCK_SIZE/8)]; 
	static char *testName[TEST_CNT]={"BlockEncrypt:","BlockDecrypt:","reKeyEncrypt:"}; 
	static char *atomName[TEST_CNT]={"block","block","call "}; 
	static char *format  [TEST_CNT]={"%10.1f/%s ","%10.1f/%s ","%10.1f/%s "}; 
	static int	 denom   [TEST_CNT]={BLOCK_CNT,BLOCK_CNT,1}; 
	static int	 needSet [TEST_CNT]={1,1,0}; 
 
	ClearTestData(&t); 
	for (i=0;i t1-t0) 
					minT = t1-t0; 
				} 
			testTime[q][n]=minT; 
			} 
		} 
	/* now print all the results */ 
#ifdef HI_RES_CLK 
	if (!FMT_LOG) 
		{ 
		printf("\nCalibrate GetTimer(): ",t1-t0); 
		for (i=0;i> (8*(q&3)));	/* auto-Bswap! */ 
					for (j=0;j= debug) 
						exit(1); 
					printf(";-------------------------------------------------\n"); 
					} 
				} 
			} 
		} 
	debug=saveDebug; 
	if (!quietVerify) printf("  OK\n"); 
	} 
 
 
/* 
+***************************************************************************** 
* 
* Function Name:	AES_FileIO 
* 
* Function:			Output to file or verify file contents vs. string 
* 
* Arguments:		f		=	opened file 
*					s		=	string to output/compare (NULL-->reset, return) 
*					errOK	=	do not fatalError on miscompare 
* 
* Return:			Zero --> compare ok 
* 
* Notes:			On miscompare, FatalError (unless errOK) 
* 
-****************************************************************************/ 
int AES_FileIO(FILE *f,CONST char *s,int errOK) 
	{ 
	int  i; 
	static int  lineNum=0; 
	static int  j=0; 
	static char line[516]=""; 
 
	if (s == NULL)	/* starting new file */ 
		{ 
		line[0]=j=lineNum=0; 
		return 0; 
		} 
 
	if (!verify) 
		{ 
		fprintf(f,s); 
		return 0; 
		} 
				 
	/* here to verify the file against the string */ 
	for (i=0;s[i];i++) 
		{ 
		while (line[j] == 0) 
			{ 
			lineNum++; 
			if (fgets(line,sizeof(line)-4,f) == NULL) 
				{ 
				if ((s[i]=='\n') && (s[i+1]==0)) 
					{ 
					line[0]=j=0;	/* missing final eol is ok */ 
					return 0; 
					} 
				FatalError("Unexpected EOF looking for %s",s); 
				} 
			if (verbose) printf(line); 
			j=0; 
			} 
		if (s[i] != line[j]) 
			{ 
			if ((s[i] == '\n') && ((i==0) || (s[i-1] == '\n'))) continue; /* blank line skip */ 
			if (line[j] == '\n') {j++; continue; } 
			if (!errOK) 
				{ 
				char tmp[1024]; 
				sprintf(tmp,"Miscompare at line #%d:\n%s\nlooking for\n\n%%s",lineNum,line); 
				FatalError(tmp,s); 
				} 
			line[0]=j=0;	/* let caller re-synch if desired */ 
			return 1;		/* return error flag */ 
			} 
		j++; 
		} 
 
	return 0; 
	} 
 
 
 
/* 
+***************************************************************************** 
* 
* Function Name:	AES_PutFileHeader 
* 
* Function:			Output a text header for AES test file 
* 
* Arguments:		fileName	=	name of file to create 
*					testName	=	name of the specific test 
* 
* Return:			Open FILE pointer 
* 
* Notes:			If unable to create, gives FatalError 
* 
-****************************************************************************/ 
FILE *AES_PutFileHeader(CONST char *fileName,CONST char *testName) 
	{ 
	char s[512]; 
	FILE *f; 
 
	sprintf(s,"%s%s",filePath,fileName); 
	if (verify) 
		{ 
		if (!quietVerify) printf("Verifying file %s",s); 
		f=fopen(s,"rt"); 
		AES_FileIO(NULL,NULL,0);		/* reset file read state */ 
		} 
	else 
		{ 
		printf("Creating file %s.\n",s); 
		f=fopen(s,"wt"); 
		} 
	if (f == NULL) FatalError("Unable to open file '%s'",s); 
 
	sprintf(s, 
			"\n=========================\n" 
			"\n" 
			"FILENAME:  \"%s\"\n" 
			"\n" 
			"%s\n" 
			"\n" 
			"Algorithm Name:       TWOFISH\n" 
			"Principal Submitter:  Bruce Schneier, Counterpane Systems\n" 
			"\n" 
			"==========\n" 
			"\n", 
			fileName,testName); 
 
	if (AES_FileIO(f,s,1))		 
		{						/* header mismatch */ 
		if (!verify) 
			FatalError("Miscompare while not verifying??",""); 
		printf("  \tWARNING:  header mismatch!"); 
		fgets(s,sizeof(s)-4,f); 
		do	{					/* skip rest of "bad" header */ 
			if (fgets(s,sizeof(s)-4,f) == NULL) 
				break;			/* end of file? */ 
			} 
		while ((s[0] != '=') || (s[1] != '=')); 
		fgets(s,sizeof(s)-4,f);	/* skip trailing blank line */ 
		} 
 
	if (verify) 
		if (!quietVerify) printf("\n"); 
 
	return f; 
	} 
 
/* 
+***************************************************************************** 
* 
* Function Name:	AES_PutTestResult 
* 
* Function:			Output a test result 
* 
* Arguments:		f		=	output file 
*					name	=	name of field 
*					p		=	pointer to bytes/dwords 
*					cnt		=	# bytes to output 
*					fmt32	=	nonzero --> p points to dwords, else bytes 
* Return:			None. 
* 
* Notes: 
* 
-****************************************************************************/ 
void AES_PutBytes(FILE *f,CONST char *name,CONST void *p,int cnt,int fmt32) 
	{ 
	char s[128]; 
	int i,j,a; 
	if (p == NULL) return; 
 
	a = (fmt32) ? ADDR_XOR : 0;	/* handle big/little endian on dword i/o */ 
 
	sprintf(s,"%s=",name); 
	for (j=0;s[j];j++) ; 
	for (i=0;i> 4 ]; 
		s[j++]=hexTab[((BYTE *)p)[i ^ a] & 0xF]; 
		} 
	s[j++]='\n'; 
	s[j  ]=0;	/* terminate the string */ 
 
	AES_FileIO(f,s,0); 
	} 
 
 
/* 
+***************************************************************************** 
* 
* Function Name:	AES_printf 
* 
* Function:			Output a test result 
* 
* Arguments:		t		=	testData (includes output file) 
*					fmt		=	format list (string of chars, see notes) 
* 
* Return:			None. 
* 
* Notes: 
*	The fmt string specifies what is output. The following characters are 
*	treated specially (S,K,P,C,v,V,I).  See the code in the switch statement 
*	to see how they are handled.  All other characters (e.g., '\n') are 
*	simply output to the file. 
* 
-****************************************************************************/ 
void AES_printf(testData *t,CONST char *fmt) 
	{ 
	char s[40]; 
 
	for (s[1]=0;*fmt;fmt++) 
		switch (*fmt) 
			{ 
			case 'I': sprintf(s,"I=%d\n",t->I);				AES_FileIO(t->f,s,0);	break; 
			case 'S': sprintf(s,"KEYSIZE=%d\n",t->keySize); AES_FileIO(t->f,s,0);	break; 
			case 'P': AES_PutBytes(t->f,"PT" ,t->pt		 ,BLOCK_SIZE/8,0);	break; 
			case 'C': AES_PutBytes(t->f,"CT" ,t->ct	     ,BLOCK_SIZE/8,0);	break; 
			case 'v': AES_PutBytes(t->f,"IV" ,t->ci.IV   ,BLOCK_SIZE/8,0);	break; 
			case 'V': AES_PutBytes(t->f,"IV" ,t->ci.iv32 ,BLOCK_SIZE/8,1);	break; 
			case 'K': AES_PutBytes(t->f,"KEY",t->ki.key32,t->keySize/8,1);	break; 
			default:  s[0]=*fmt; s[1]=0; AES_FileIO(t->f,s,0);				break; 
			} 
	} 
 
/* 
+***************************************************************************** 
* 
* Function Name:	AES_EndSection 
* 
* Function:			Insert a separator between sections 
* 
* Arguments:		t		=	ptr to testData, contains file 
* 
* Return:			None. 
* 
* Notes: 
* 
-****************************************************************************/ 
void AES_EndSection(testData *t) 
	{ 
	AES_FileIO(t->f,"==========\n\n",0); 
	} 
 
/* 
+***************************************************************************** 
* 
* Function Name:	AES_Close 
* 
* Function:			Close an AES text file 
* 
* Arguments:		t	=	testData ptr (contains f) 
* 
* Return:			None. 
* 
* Notes: 
* 
-****************************************************************************/ 
void AES_Close(testData *t) 
	{ 
	fclose(t->f); 
	} 
 
/* 
+***************************************************************************** 
* 
* Function Name:	DebugIO 
* 
* Function:			Output debug string 
* 
* Arguments:		s	=	string to output 
* 
* Return:			None. 
* 
* Notes:			 
* 
-****************************************************************************/ 
void DebugIO(CONST char *s) 
	{ 
	if (debugTD) 
		{ 
		AES_FileIO(debugTD->f,s,0); 
		debugTD->gotDebugIO=1; 
		} 
	else 
		printf(s); 
	} 
 
/* 
+***************************************************************************** 
* 
* Function Name:	AES_Test_VK 
* 
* Function:			Run variable key test 
* 
* Arguments:		fname	=	file name to produce 
* 
* Return:			None. 
* 
* Notes: 
* 
-****************************************************************************/ 
void AES_Test_VK(CONST char *fname) 
	{ 
	testData t; 
 
	memset(t.ki.keyMaterial,'0',MAX_KEY_SIZE); 
 
	t.f=AES_PutFileHeader(fname, 
			  "Electronic Codebook (ECB) Mode\nVariable Key Known Answer Tests"); 
 
	if (cipherInit(&t.ci,MODE_ECB,NULL) != TRUE) 
		FatalError("cipherInit error during %s test",fname); 
 
	for (t.keySize=KEY_BITS_0;t.keySize<=MAX_KEY_BITS;t.keySize+=STEP_KEY_BITS) 
		{ 
		ClearTestData(&t); 
		AES_printf(&t,"S\nP\n");	/* output key size, plaintext */ 
		for (t.I=1;t.I<=t.keySize;t.I++) 
			{ 
			t.ki.keyMaterial[(t.I-1)/4]='0' + (8 >> ((t.I-1) & 3)); 
			if (makeKey(&t.ki,DIR_ENCRYPT,t.keySize,t.ki.keyMaterial) != TRUE) 
				FatalError("Error parsing key during %s test",fname); 
			if (blockEncrypt(&t.ci,&t.ki,t.pt,BLOCK_SIZE,t.ct) != BLOCK_SIZE) 
				FatalError("blockEncrypt return during %s test",fname); 
			AES_printf(&t,"IKC\n");	/* output I, KEY, CT, newline */ 
 
			t.ki.keyMaterial[(t.I-1)/4]='0';	/* rezero the key bit */ 
			} 
		AES_EndSection(&t); 
		} 
 
	AES_Close(&t); 
	} 
 
/* 
+***************************************************************************** 
* 
* Function Name:	AES_Test_Intermediate 
* 
* Function:			Run intermediate value test 
* 
* Arguments:		fname	=	file name to produce 
* 
* Return:			None. 
* 
* Notes: 
* 
-****************************************************************************/ 
void AES_Test_Intermediate(CONST char *fname) 
	{ 
	testData t; 
 
	if ((useAsm) || (!debugCompile)) 
		{ 
		if (!quietVerify) printf("WARNING: Skipping %s test\n",fname); 
		return; 
		} 
 
	memset(t.ki.keyMaterial,'0',MAX_KEY_SIZE); 
 
	t.f=AES_PutFileHeader(fname, 
			  "Electronic Codebook (ECB) Mode\nIntermediate Value Tests"); 
 
	if (cipherInit(&t.ci,MODE_ECB,NULL) != TRUE) 
		FatalError("cipherInit error during %s test",fname); 
 
	for (t.keySize=KEY_BITS_0;t.keySize<=MAX_KEY_BITS;t.keySize+=STEP_KEY_BITS) 
		{ 
		ClearTestData(&t); 
		debugTD=&t; 
		debug=1; 
 
		if (t.keySize > KEY_BITS_0) 
			memcpy(t.ki.keyMaterial,hexString,sizeof(t.ki.keyMaterial)); 
		debug=0; 
		if (makeKey(&t.ki,DIR_ENCRYPT,t.keySize,t.ki.keyMaterial) != TRUE) 
			FatalError("Error parsing key during %s test",fname); 
		debug=1; 
		AES_printf(&t,"S\nK\n");	/* output key size, key */ 
		if (makeKey(&t.ki,DIR_ENCRYPT,t.keySize,t.ki.keyMaterial) != TRUE) 
			FatalError("Error parsing key during %s test",fname); 
 
		AES_printf(&t,"P\n");		/* output plaintext */ 
		AES_FileIO(t.f,"Encrypt()\n",0); 
 
		if (blockEncrypt(&t.ci,&t.ki,t.pt,BLOCK_SIZE,t.ct) != BLOCK_SIZE) 
			FatalError("blockEncrypt return during %s test",fname); 
		AES_printf(&t,"\nC\n");	/* output CT, newline */ 
 
		AES_FileIO(t.f,"Decrypt()\n",0); 
		AES_printf(&t,"\nC\n");	/* output CT, newline */ 
		if (blockDecrypt(&t.ci,&t.ki,t.ct,BLOCK_SIZE,t.pt) != BLOCK_SIZE) 
			FatalError("blockDecrypt return during %s test",fname); 
		AES_printf(&t,"\nP\n");	/* output PT, newline */ 
 
		AES_EndSection(&t); 
		if (!t.gotDebugIO) 
			FatalError("Need to run DEBUG version to test %s",fname); 
		debug=0; 
		debugTD=NULL; 
		} 
 
	AES_Close(&t); 
	} 
 
 
/* 
+***************************************************************************** 
* 
* Function Name:	AES_Test_VT 
* 
* Function:			Run variable text test 
* 
* Arguments:		fname	=	file name to produce 
* 
* Return:			None. 
* 
* Notes: 
* 
-****************************************************************************/ 
void AES_Test_VT(CONST char *fname) 
	{ 
	testData t; 
 
	memset(	t.ki.keyMaterial,'0',MAX_KEY_SIZE); 
 
	t.f=AES_PutFileHeader(fname, 
			  "Electronic Codebook (ECB) Mode\nVariable Text Known Answer Tests"); 
 
	if (cipherInit(&t.ci,MODE_ECB,NULL) != TRUE) 
		FatalError("cipherInit error during %s test",fname); 
 
	for (t.keySize=KEY_BITS_0;t.keySize<=MAX_KEY_BITS;t.keySize+=STEP_KEY_BITS) 
		{ 
		ClearTestData(&t); 
		if (makeKey(&t.ki,DIR_ENCRYPT,t.keySize,t.ki.keyMaterial) != TRUE) 
			FatalError("Error parsing key during %s test",fname); 
 
		AES_printf(&t,"S\nK\n");	/* output key size, key */ 
		for (t.I=1;t.I<=BLOCK_SIZE;t.I++) 
			{ 
			t.pt[(t.I-1)/8] = 0x80 >> ((t.I-1) & 7); 
			if (blockEncrypt(&t.ci,&t.ki,t.pt,BLOCK_SIZE,t.ct) != BLOCK_SIZE) 
				FatalError("blockEncrypt return during %s test",fname); 
			AES_printf(&t,"IPC\n");	/* output I, PT, CT, newline */ 
			t.pt[(t.I-1)/8] = 0; 
			} 
		AES_EndSection(&t); 
		} 
	AES_Close(&t); 
	} 
 
/* 
+***************************************************************************** 
* 
* Function Name:	AES_Test_TBL 
* 
* Function:			Run tabl test 
* 
* Arguments:		fname	=	file name to produce 
* 
* Return:			None. 
* 
* Notes: 
* 
-****************************************************************************/ 
void AES_Test_TBL(CONST char *fname) 
	{ 
	int i; 
	testData t; 
 
	t.f=AES_PutFileHeader(fname, 
			"Electronic Codebook (ECB) Mode\nTables Known Answer Test\n" 
			"Tests permutation tables and MDS matrix multiply tables."); 
 
	for (t.keySize=KEY_BITS_0;t.keySize <= MAX_KEY_BITS;t.keySize+=STEP_KEY_BITS) 
		{ 
		AES_printf(&t,"S\n");	/* output key size */ 
		TableOp(TAB_ENABLE); 
		TableOp(TAB_RESET); 
 
		ClearTestData(&t); 
		if (cipherInit(&t.ci,MODE_ECB,NULL) != TRUE) 
			FatalError("Error cipherInit() during %s test",fname); 
 
		for (t.I=1;TableOp(TAB_QUERY) == FALSE;t.I++) 
			{ 
			if (makeKey(&t.ki,DIR_ENCRYPT,t.keySize,t.ki.keyMaterial) != TRUE) 
				FatalError("Error parsing key during %s test",fname); 
			if (blockEncrypt(&t.ci,&t.ki,t.pt,BLOCK_SIZE,t.ct) != BLOCK_SIZE) 
				FatalError("blockEncrypt during %s test",fname); 
			AES_printf(&t,"IKPC\n");		/* show the 'vector' */ 
			memcpy(t.ki.keyMaterial+MAX_KEY_SIZE/2,t.ki.keyMaterial,MAX_KEY_SIZE/2); 
			for (i=0;i> 4]; 
				t.ki.keyMaterial[i+1]=hexTab[t.pt[i/2] &0xF]; 
				} 
			memcpy(t.pt,t.ct,BLOCK_SIZE/8);	/* use ciphertext as new plaintext */ 
			} 
		TableOp(TAB_DISABLE); 
		AES_EndSection(&t);		/* output separator */ 
		if (!quietVerify) printf("  [%d,%3d]",t.keySize,t.I); 
		} 
	if (!quietVerify) printf("\n"); 
	AES_Close(&t); 
	} 
 
/* 
+***************************************************************************** 
* 
* Function Name:	AES_Test_ECB_E_MCT 
* 
* Function:			Run ECB Monte Carlo test for ECB encryption 
* 
* Arguments:		fname	=	file name to produce 
* 
* Return:			None. 
* 
* Notes: 
* 
-****************************************************************************/ 
void AES_Test_ECB_E_MCT(CONST char *fname) 
	{ 
	int i,j,q; 
	testData t; 
 
	t.f=AES_PutFileHeader(fname, 
				"Electronic Codebook (ECB) Mode - ENCRYPTION\nMonte Carlo Test"); 
 
	if (cipherInit(&t.ci,MODE_ECB,NULL) != TRUE) 
		FatalError("cipherInit error during %s test",fname); 
 
	for (t.keySize=KEY_BITS_0,q=0;t.keySize<=MAX_KEY_BITS;t.keySize+=STEP_KEY_BITS,q+=2) 
		{ 
		AES_printf(&t,"S\n");			/* output key size */ 
		if (!quietVerify) printf("  keyLen = %3d. ",t.keySize); 
 
		ClearTestData(&t);				/* start with all zeroes */ 
		if (makeKey(&t.ki,DIR_ENCRYPT,t.keySize,t.ki.keyMaterial) != TRUE) 
			FatalError("Error parsing key during %s test",fname); 
 
		for (t.I=0;t.I=q) ? ((DWORD *)t.ct)[i-q] : 
										   ((DWORD *)t.pt)[BLOCK_SIZE/32-q+i]); 
				BlockCopy(t.pt,t.ct); 
				} 
			AES_printf(&t,"C\n"); 
			if (reKey(&t.ki) != TRUE) 
				FatalError("reKey return during %s test",fname); 
			} 
		AES_EndSection(&t); 
		} 
	if (!quietVerify) printf("   \n"); 
	AES_Close(&t); 
	} 
 
/* 
+***************************************************************************** 
* 
* Function Name:	AES_Test_ECB_D_MCT 
* 
* Function:			Run ECB Monte Carlo test for ECB decryption 
* 
* Arguments:		fname	=	file name to produce 
* 
* Return:			None. 
* 
* Notes: 
* 
-****************************************************************************/ 
void AES_Test_ECB_D_MCT(CONST char *fname) 
	{ 
	int i,j,q; 
	testData t; 
 
	t.f=AES_PutFileHeader(fname, 
				"Electronic Codebook (ECB) Mode - DECRYPTION\nMonte Carlo Test"); 
 
	if (cipherInit(&t.ci,MODE_ECB,NULL) != TRUE) 
		FatalError("cipherInit error during %s test",fname); 
 
	for (t.keySize=KEY_BITS_0,q=0;t.keySize <= MAX_KEY_BITS;t.keySize+=STEP_KEY_BITS,q+=2) 
		{ 
		AES_printf(&t,"S\n");			/* output key size */ 
		if (!quietVerify) printf("  keyLen = %3d. ",t.keySize); 
 
		ClearTestData(&t);				/* start with all zeroes */ 
		if (makeKey(&t.ki,DIR_DECRYPT,t.keySize,t.ki.keyMaterial) != TRUE) 
			FatalError("Error parsing key during %s test",fname); 
 
		for (t.I=0;t.I=q) ? ((DWORD *)t.pt)[i-q] : 
									       ((DWORD *)t.ct)[BLOCK_SIZE/32-q+i]); 
				BlockCopy(t.ct,t.pt); 
				} 
			AES_printf(&t,"P\n"); 
			if (reKey(&t.ki) != TRUE) 
				FatalError("reKey return during %s test",fname); 
			} 
		AES_EndSection(&t); 
		} 
	if (!quietVerify) printf("   \n"); 
	AES_Close(&t); 
	} 
 
/* 
+***************************************************************************** 
* 
* Function Name:	AES_Test_CBC_E_MCT 
* 
* Function:			Run ECB Monte Carlo test for CBC encryption 
* 
* Arguments:		fname	=	file name to produce 
* 
* Return:			None. 
* 
* Notes: 
* 
-****************************************************************************/ 
void AES_Test_CBC_E_MCT(CONST char *fname) 
	{ 
	int i,j,q; 
	testData t; 
	BYTE ctPrev[BLOCK_SIZE/8]; 
	BYTE IV[BLOCK_SIZE/8]; 
#define	CV	t.ci.IV						/* use t.ci.IV as CV */ 
 
	t.f=AES_PutFileHeader(fname, 
			"Cipher Block Chaining (CBC) Mode - ENCRYPTION\nMonte Carlo Test"); 
 
	if (cipherInit(&t.ci,MODE_ECB,NULL) != TRUE) 
		FatalError("cipherInit error during %s test",fname); 
 
	for (t.keySize=KEY_BITS_0,q=0;t.keySize<=MAX_KEY_BITS;t.keySize+=STEP_KEY_BITS,q+=2) 
		{ 
		AES_printf(&t,"S\n");			/* output key size */ 
		if (!quietVerify) printf("  keyLen = %3d. ",t.keySize); 
 
		ClearTestData(&t);				/* start with all zeroes */ 
		memset(IV,0,sizeof(IV)); 
		if (makeKey(&t.ki,DIR_ENCRYPT,t.keySize,t.ki.keyMaterial)	 != TRUE) 
			FatalError("Error parsing key during %s test",fname); 
 
		BlockCopy(CV,IV);				 
		for (t.I=0;t.I=q) ? ((DWORD *)t.ct  )[i-q] : 
								   ((DWORD *)ctPrev)[BLOCK_SIZE/32-q+i]); 
			BlockCopy(t.pt,ctPrev); 
			BlockCopy(CV,t.ct); 
 
			if (reKey(&t.ki) != TRUE) 
				FatalError("reKey return during %s test",fname); 
			} 
		AES_EndSection(&t); 
		} 
	if (!quietVerify) printf("   \n"); 
	AES_Close(&t); 
	} 
 
/* 
+***************************************************************************** 
* 
* Function Name:	AES_Test_CBC_D_MCT 
* 
* Function:			Run ECB Monte Carlo test for CBC decryption 
* 
* Arguments:		fname	=	file name to produce 
* 
* Return:			None. 
* 
* Notes: 
* 
-****************************************************************************/ 
void AES_Test_CBC_D_MCT(CONST char *fname) 
	{ 
	int i,j,q; 
	testData t; 
	BYTE ptPrev[BLOCK_SIZE/8]; 
	BYTE IV[BLOCK_SIZE/8]; 
#define	CV	t.ci.IV						/* use t.ci.IV as CV */ 
 
	t.f=AES_PutFileHeader(fname, 
			"Cipher Block Chaining (CBC) Mode - DECRYPTION\nMonte Carlo Test"); 
 
	if (cipherInit(&t.ci,MODE_ECB,NULL) != TRUE) 
		FatalError("cipherInit error during %s test",fname); 
 
	for (t.keySize=KEY_BITS_0,q=0;t.keySize <= MAX_KEY_BITS;t.keySize+=STEP_KEY_BITS,q+=2) 
		{ 
		AES_printf(&t,"S\n");			/* output key size */ 
		if (!quietVerify) printf("  keyLen = %3d. ",t.keySize); 
 
		ClearTestData(&t);				/* start with all zeroes */ 
		memset(IV,0,sizeof(IV)); 
		if (makeKey(&t.ki,DIR_DECRYPT,t.keySize,t.ki.keyMaterial)	 != TRUE) 
			FatalError("Error parsing key during %s test",fname); 
 
		BlockCopy(CV,IV);				 
		for (t.I=0;t.I=q) ? ((DWORD *)t.pt  )[i-q] : 
								   ((DWORD *)ptPrev)[BLOCK_SIZE/32-q+i]); 
			if (reKey(&t.ki) != TRUE) 
				FatalError("reKey return during %s test",fname); 
			} 
		AES_EndSection(&t); 
		} 
	if (!quietVerify) printf("   \n"); 
	AES_Close(&t); 
	} 
 
/* 
+***************************************************************************** 
* 
* Function Name:	ShowParams 
* 
* Function:			Print out the settings of settable parameters 
* 
* Arguments:		None. 
* 
* Return:			None. 
* 
* Notes: 
* 
-****************************************************************************/ 
void ShowParams(void) 
	{ 
	int saveDebug=debug; 
	testData t; 
 
	debug=0;	/* turn off debug output */ 
	memset(t.ki.keyMaterial,'0',sizeof(t.ki.keyMaterial)); 
 
	printf("(keyLen,numRounds): "); 
	for (t.keySize=KEY_BITS_0;t.keySize<=MAX_KEY_BITS;t.keySize+=STEP_KEY_BITS) 
		{ 
		if (makeKey(&t.ki,DIR_ENCRYPT,t.keySize,t.ki.keyMaterial) != TRUE) 
			FatalError("Error parsing key during ShowParam",""); 
		printf("  (%d,%d)",t.keySize,t.ki.numRounds); 
		} 
	printf("\n"); 
	debug=saveDebug; 
	} 
 
/* 
+***************************************************************************** 
* 
* Function Name:	ParseArgFile 
* 
* Function:			Parse commands from argument file 
* 
* Arguments:		fName		=	name of file to read 
*					argList		=	list of ptrs to fill in 
*					maxArgCnt	=	size of argList 
* 
* Return:			None. 
* 
* Notes:	'/' and ';' are comment to end of line characters in the file 
*			This function is used to allow a "custom" set of switches to 
*			be automatically read from a file at startup. 
* 
-****************************************************************************/ 
int ParseArgFile(CONST char *fName,char *argList[],int maxArgCnt) 
	{ 
	static char buf[1024]; 
	static int  bufCnt=0;		/* current # chars in buf */ 
 
	int i,j,k,argCnt; 
	char line[256]; 
	FILE *f=fopen(fName,"rt"); 
 
	if (f == NULL) return 0; 
	if (debug) printf("Reading args from file %s: ",fName); 
 
	for (argCnt=0;argCnt ' ') break; 
			if (line[j]==0) break; 
			for (k=j;line[k];k++) 
				if (line[k] <= ' ') break; 
			/* now j..k-1 defines a token */ 
			if (k-j+1 > (int)(sizeof(buf) - bufCnt)) 
				FatalError("Arg file too large: %s",line); 
			if (argCnt >= maxArgCnt) 
				break; 
			memcpy(buf+bufCnt,line+j,k-j); 
			buf[bufCnt+k-j]=0;	/* terminate the token */ 
			if (debug) printf(" %s",buf+bufCnt); 
			argList[argCnt++]=buf+bufCnt; 
			bufCnt+=k-j+1; 
			i=k;				/* skip to next token */ 
			} 
		} 
	fclose(f); 
	if (debug) printf("\n"); 
	return argCnt; 
	} 
 
/* 
+***************************************************************************** 
* 
* Function Name:	GiveHelp 
* 
* Function:			Print out list of command line switches 
* 
* Arguments:		None. 
* 
* Return:			None. 
* 
* Notes: 
* 
-****************************************************************************/ 
void GiveHelp(void) 
	{ 
	printf("Syntax:   TST2FISH [options]\n" 
		   "Purpose:  Generate/validate AES Twofish code and files\n" 
		   "Options:  -lNN    ==> set sanity check loop to NN\n" 
		   "          -m      ==> do full MCT generation\n" 
		   "          -pPath  ==> set file path\n" 
		   "          -s      ==> set initial random seed based on time\n" 
		   "          -sNN    ==> set initial random seed to NN\n" 
		   "          -tNN    ==> time performance using NN iterations\n" 
		   "          -v      ==> validate files, don't generate them\n", 
		   MAX_ROUNDS 
		  ); 
	exit(1); 
	} 
 
#ifdef TEST_EXTERN 
void	Test_Extern(void); 
#endif 
 
void ShowHex(FILE *f,CONST void *p,int bCnt,CONST char *name) 
	{ 
	int i; 
 
	fprintf(f,"    ;%s:",name); 
	for (i=0;i