/*	Konton2.c	*/
/*	Copyright (C) 2002, 2003, 2004 by J. David Sexton. All rights reserved.	*/

#include "Konton2.h"

/*
	KONROL32 rotates theNum, a 32-bit integer, theRot bits to the left.
	Note that theNum and theRot are declared as register variables.
	KONROL32 doesn't return a value; it alters the variable theNum.
	Note, also, that the #ifndef directive allows KONROL32 to be a
	predefined macro.
*/

#ifndef KONROL32

#if defined (THINK_C) || defined (MPW_C)	/*	68K Macintosh compliers	*/

#define KONROL32(theNum,theRot) \
		asm	{ROL.L	theRot, theNum}

#else

/*
	If a definition like the one above cannot be devised, the following
	definition will do the job. The GNU C compiler, version 3.2, compiling
	for an Intel 80386, is actually clever enough to optimize the following
	definition into a single "roll" instruction.
*/

#define KONROL32(theNum,theRot) \
		theNum = ((theNum) << (theRot)) | ((theNum) >> (32 - (theRot)));

#endif

#endif

#ifdef KON4BYTEINT_MORE_THAN_4BYTES

#define KONMOD4G(theNum) \
		theNum &= 0xFFFFFFFF;

#else

#define KONMOD4G(theNum)

#endif

#define KON_STEP_A(theAdder,theState,statePtr) \
		theState = *statePtr + theAdder;

#define KON_STEP_B(theAdder,prevState,theState,statePtr) \
		KON_STEP_A (theAdder, theState, statePtr) \
		if (!prevState) \
			theState += theAdder;

#define KON_STEP_C(theRot,thePRndNum,theState) \
		theRot = (theRot + theState) & 0x1F; \
		KONROL32 (thePRndNum, theRot) \
		theRot = (theRot + thePRndNum) & 0x1F; \
		KONROL32 (theState, theRot) \
		thePRndNum += theState; \
		KONMOD4G (thePRndNum)

#define KON_STEP_D(theRot,thePRndNum,prevState,theState) \
		KONMOD4G (theState) \
		*(statePtr++) = theState; \
		prevState = theState; \
		KON_STEP_C (theRot, thePRndNum, theState)

#define KON_FSTEP(theAdder,theRot,thePRndNum,prevState,theState,statePtr) \
		KON_STEP_A (theAdder, theState, statePtr) \
		KON_STEP_D (theRot, thePRndNum, prevState, theState)

#define KON_MSTEP(theAdder,theRot,thePRndNum,prevState,theState,statePtr) \
		KON_STEP_B (theAdder, prevState, theState, statePtr) \
		KON_STEP_D (theRot, thePRndNum, prevState, theState)

#define KON_LSTEP(theAdder,theRot,thePRndNum,prevState,theState,statePtr) \
		KON_STEP_B (theAdder, prevState, theState, statePtr) \
		KONMOD4G (theState) \
		*statePtr = theState; \
		KON_STEP_C (theRot, thePRndNum, theState) \
		if (!thePRndNum && !theRot) \
			theRot = 1;

/*
	If the processor's instruction cache is small, the
	small-cache version of KonNextPRndNum may be faster.
	Processors with small caches are generally older models.
	Newer processors, like the i686 have large instruction
	caches. On processors with large instruction caches, the
	small-cache version of KonNextPRndNum may be MUCH SLOWER.
	Unless you are compiling for a Motorola MC68000, MC68010,
	MC68020, or MC68030, you should probably NOT use the small
	cache version of KonNextPRndNum.
	To use the small-cache version of KonNextPRndNum,
	define KON_SMALL_CACHE as 1; else define it as 0.
	Note that the #ifndef directive allows KON_SMALL_CACHE to
	be a predefined macro.
*/

#ifndef KON_SMALL_CACHE
#define KON_SMALL_CACHE 0
#endif
#if (KON_SMALL_CACHE != 0 && KON_SMALL_CACHE != 1)
#error "KON_SMALL_CACHE must equal 0 or 1."
#endif

#if KON_SMALL_CACHE

Kon4ByteInt	KonNextPRndNum (register KonEnvStruct *theEnv)

		{register	Kon1ByteInt	theRot;
		register	Kon4ByteInt	thePRndNum, prevState, theState, *statePtr;
		register	Kon4ByteInt	theAdder;

		statePtr = theEnv->stateData;
		thePRndNum = theEnv->lastPRN;
		theRot = theEnv->lastRot;
		theAdder = 0xEDCBA987;
		KON_FSTEP (theAdder, theRot, thePRndNum, prevState, theState, statePtr)
		theAdder += theAdder + theAdder;
		KONMOD4G (theAdder)
		do
			{KON_MSTEP (theAdder, theRot, thePRndNum, prevState, theState, statePtr)
			theAdder += theAdder + theAdder;
			KONMOD4G (theAdder)}
#if (KONCRYPTSTRENGTH == 1)
		while (theAdder != 0x7AE1444D);
#elif (KONCRYPTSTRENGTH == 2)
		while (theAdder != 0x4757796D);
#elif (KONCRYPTSTRENGTH == 3)
		while (theAdder != 0x68DF028D);
#elif (KONCRYPTSTRENGTH == 4)
		while (theAdder != 0xBB805FAD);
#elif (KONCRYPTSTRENGTH == 5)
		while (theAdder != 0x751410CD);
#elif (KONCRYPTSTRENGTH == 6)
		while (theAdder != 0x974295ED);
#elif (KONCRYPTSTRENGTH == 7)
		while (theAdder != 0xA1846F0D);
#else
		while (theAdder != 0x83221C2D);
#endif
		KON_LSTEP (theAdder, theRot, thePRndNum, prevState, theState, statePtr)
		theEnv->lastPRN = thePRndNum;
		theEnv->lastRot = theRot;
		return (thePRndNum);}

#else

Kon4ByteInt	KonNextPRndNum (register KonEnvStruct *theEnv)

		{register	Kon1ByteInt	theRot;
		register	Kon4ByteInt	thePRndNum, prevState, theState, *statePtr;

		statePtr = theEnv->stateData;
		thePRndNum = theEnv->lastPRN;
		theRot = theEnv->lastRot;
		KON_FSTEP (0xEDCBA987, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0xC962FC95, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x5C28F5BF, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x147AE13D, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x3D70A3B7, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0xB851EB25, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x28F5C16F, theRot, thePRndNum, prevState, theState, statePtr)
#if (KONCRYPTSTRENGTH == 1)
		KON_LSTEP (0x7AE1444D, theRot, thePRndNum, prevState, theState, statePtr)
#else
		KON_MSTEP (0x7AE1444D, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x70A3CCE7, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x51EB66B5, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0xF5C2341F, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0xE1469C5D, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0xA3D3D517, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0xEB7B7F45, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0xC2727DCF, theRot, thePRndNum, prevState, theState, statePtr)
#if (KONCRYPTSTRENGTH == 2)
		KON_LSTEP (0x4757796D, theRot, thePRndNum, prevState, theState, statePtr)
#else
		KON_MSTEP (0x4757796D, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0xD6066C47, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x821344D5, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x8639CE7F, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x92AD6B7D, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0xB8084277, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x2818C765, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x784A562F, theRot, thePRndNum, prevState, theState, statePtr)
#if (KONCRYPTSTRENGTH == 3)
		KON_LSTEP (0x68DF028D, theRot, thePRndNum, prevState, theState, statePtr)
#else
		KON_MSTEP (0x68DF028D, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x3A9D07A7, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0xAFD716F5, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x0F8544DF, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x2E8FCE9D, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x8BAF6BD7, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0xA30E4385, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0xE92ACA8F, theRot, thePRndNum, prevState, theState, statePtr)
#if (KONCRYPTSTRENGTH == 4)
		KON_LSTEP (0xBB805FAD, theRot, thePRndNum, prevState, theState, statePtr)
#else
		KON_MSTEP (0xBB805FAD, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x32811F07, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x97835D15, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0xC68A173F, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x539E45BD, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0xFADAD137, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0xF09073A5, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0xD1B15AEF, theRot, thePRndNum, prevState, theState, statePtr)
#if (KONCRYPTSTRENGTH == 5)
		KON_LSTEP (0x751410CD, theRot, thePRndNum, prevState, theState, statePtr)
#else
		KON_MSTEP (0x751410CD, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x5F3C3267, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x1DB49735, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x591DC59F, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x0B5950DD, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x220BF297, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x6623D7C5, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x326B874F, theRot, thePRndNum, prevState, theState, statePtr)
#if (KONCRYPTSTRENGTH == 6)
		KON_LSTEP (0x974295ED, theRot, thePRndNum, prevState, theState, statePtr)
#else
		KON_MSTEP (0x974295ED, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0xC5C7C1C7, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x51574555, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0xF405CFFF, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0xDC116FFD, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x94344FF7, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0xBC9CEFE5, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x35D6CFAF, theRot, thePRndNum, prevState, theState, statePtr)
#if (KONCRYPTSTRENGTH == 7)
		KON_LSTEP (0xA1846F0D, theRot, thePRndNum, prevState, theState, statePtr)
#else
		KON_MSTEP (0xA1846F0D, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0xE48D4D27, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0xADA7E775, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x08F7B65F, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x1AE7231D, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0x50B56957, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0xF2203C05, theRot, thePRndNum, prevState, theState, statePtr)
		KON_MSTEP (0xD660B40F, theRot, thePRndNum, prevState, theState, statePtr)
		KON_LSTEP (0x83221C2D, theRot, thePRndNum, prevState, theState, statePtr)
#endif
#endif
#endif
#endif
#endif
#endif
#endif
		theEnv->lastPRN = thePRndNum;
		theEnv->lastRot = theRot;
		return (thePRndNum);}

#endif

	void	KonCryptSynch (register KonEnvStruct *theEnv, void *theData,
						size_t theLength)

		{register	Kon1ByteInt	*theByte;
		register	Kon4ByteInt	thePRndNum;
		register	size_t		theIndex;

		if ((theIndex = theLength))
			{theByte = theData;
			do
				{thePRndNum = KonNextPRndNum (theEnv) >> 16;
				*(theByte++) ^= (Kon1ByteInt) thePRndNum;
				if (!(--theIndex))
					break;
				thePRndNum >>= 8;
				*(theByte++) ^= (Kon1ByteInt) thePRndNum;}
			while (--theIndex);}
		return;}

#ifdef KON4BYTEINT_MORE_THAN_4BYTES

#define KON_FEEDBACK_A(theEnv,theChar) \
		(theEnv)->lastPRN = ((theEnv)->lastPRN + \
			(Kon4ByteInt) (theChar)) & 0xFFFFFFFF;

#define KON_FEEDBACK_B(theEnv,theChar) \
		(theEnv)->lastPRN = ((theEnv)->lastPRN + \
			(((Kon4ByteInt) (theChar)) << 8)) & 0xFFFFFFFF;

#else

#define KON_FEEDBACK_A(theEnv,theChar) \
		(theEnv)->lastPRN += (Kon4ByteInt) (theChar);

#define KON_FEEDBACK_B(theEnv,theChar) \
		(theEnv)->lastPRN += ((Kon4ByteInt) (theChar)) << 8;

#endif

	void	KonEncryptData (register KonEnvStruct *theEnv, void *theData,
						size_t theLength)

		{register	Kon1ByteInt	*theByte;
		register	Kon4ByteInt	thePRndNum;
		register	size_t		theIndex;

		if ((theIndex = theLength))
			{theByte = theData;
			do
				{thePRndNum = KonNextPRndNum (theEnv) >> 16;
				KON_FEEDBACK_A (theEnv, *theByte)
				*(theByte++) ^= (Kon1ByteInt) thePRndNum;
				if (!(--theIndex))
					break;
				thePRndNum >>= 8;
				KON_FEEDBACK_B (theEnv, *theByte)
				*(theByte++) ^= (Kon1ByteInt) thePRndNum;}
			while (--theIndex);}
		return;}

	void	KonDecryptData (register KonEnvStruct *theEnv, void *theData,
						size_t theLength)

		{register	Kon1ByteInt	*theByte;
		register	Kon4ByteInt	thePRndNum;
		register	size_t		theIndex;

		if ((theIndex = theLength))
			{theByte = theData;
			do
				{thePRndNum = KonNextPRndNum (theEnv) >> 16;
				*theByte ^= (Kon1ByteInt) thePRndNum;
				KON_FEEDBACK_A (theEnv, *(theByte++))
				if (!(--theIndex))
					break;
				thePRndNum >>= 8;
				*theByte ^= (Kon1ByteInt) thePRndNum;
				KON_FEEDBACK_B (theEnv, *(theByte++))}
			while (--theIndex);}
		return;}

	void	KonEncryptASCII (register KonEnvStruct *theEnv, void *theData,
						size_t theLength)

		{register	Kon1ByteInt	*theByte, theChar, thePRndNum;
		register	size_t		theIndex;

		if ((theIndex = theLength))
			{theByte = theData;
			do
				{theChar = *theByte;
				if (theChar > 0x1F && theChar < 0x7F)
					{thePRndNum = ((KonNextPRndNum (theEnv) >> 8) * 0x5F) >> 24;
					KON_FEEDBACK_A (theEnv, theChar)
					theChar -= 0x20;
					if (thePRndNum < theChar)
						theChar = 0x5F - (theChar - thePRndNum);
					else
						theChar = thePRndNum - theChar;
					theChar += 0x20;}
				*(theByte++) = theChar;}
			while (--theIndex);}
		return;}

	void	KonDecryptASCII (register KonEnvStruct *theEnv, void *theData,
						size_t theLength)

		{register	Kon1ByteInt	*theByte, theChar, thePRndNum;
		register	size_t		theIndex;

		if ((theIndex = theLength))
			{theByte = theData;
			do
				{theChar = *theByte;
				if (theChar > 0x1F && theChar < 0x7F)
					{thePRndNum = ((KonNextPRndNum (theEnv) >> 8) * 0x5F) >> 24;
					theChar -= 0x20;
					if (thePRndNum < theChar)
						theChar = 0x5F - (theChar - thePRndNum);
					else
						theChar = thePRndNum - theChar;
					theChar += 0x20;
					KON_FEEDBACK_A (theEnv, theChar)}
				*(theByte++) = theChar;}
			while (--theIndex);}
		return;}

	void	KonEncryptText (register KonEnvStruct *theEnv, void *theData,
						size_t theLength)

		{register	Kon1ByteInt	*theByte, theChar, thePRndNum;
		register	size_t		theIndex;

		if ((theIndex = theLength))
			{theByte = theData;
			do
				{theChar = *theByte;
				if (theChar > 0x1F)
					{thePRndNum = ((KonNextPRndNum (theEnv) >> 8) * 0xE0) >> 24;
					KON_FEEDBACK_A (theEnv, theChar)
					theChar -= 0x20;
					if (thePRndNum < theChar)
						theChar = 0xE0 - (theChar - thePRndNum);
					else
						theChar = thePRndNum - theChar;
					theChar += 0x20;}
				*(theByte++) = theChar;}
			while (--theIndex);}
		return;}

	void	KonDecryptText (register KonEnvStruct *theEnv, void *theData,
						size_t theLength)

		{register	Kon1ByteInt	*theByte, theChar, thePRndNum;
		register	size_t		theIndex;

		if ((theIndex = theLength))
			{theByte = theData;
			do
				{theChar = *theByte;
				if (theChar > 0x1F)
					{thePRndNum = ((KonNextPRndNum (theEnv) >> 8) * 0xE0) >> 24;
					theChar -= 0x20;
					if (thePRndNum < theChar)
						theChar = 0xE0 - (theChar - thePRndNum);
					else
						theChar = thePRndNum - theChar;
					theChar += 0x20;
					KON_FEEDBACK_A (theEnv, theChar)}
				*(theByte++) = theChar;}
			while (--theIndex);}
		return;}

	void	KonInitCrypt (register KonEnvStruct *theEnv)

		{register	Kon1ByteInt	theIndex;
const	register	Kon1ByteInt	*keyPtr;
		register	Kon4ByteInt	theState, *statePtr;

		statePtr = theEnv->stateData;
		keyPtr = theEnv->cryptKey;
		theIndex = kKonStateLength;
		do
			{theState = ((Kon4ByteInt) *(keyPtr++));
			theState = (theState << 8) | ((Kon4ByteInt) *(keyPtr++));
			theState = (theState << 8) | ((Kon4ByteInt) *(keyPtr++));
			theState = (theState << 8) | ((Kon4ByteInt) *(keyPtr++));
			*(statePtr++) = theState;}
		while (--theIndex);
		theEnv->lastPRN = 0;
		theEnv->lastRot = 0;
		return;}

	void	KonSetCryptKey (register KonEnvStruct *theEnv, const void *theKey,
						size_t keyLength)

		{register	Kon1ByteInt	*keyArrayPtr;
const	register	Kon1ByteInt	*keyPtr;
		register	size_t		keyArrayIndex, keyIndex;

		keyArrayIndex = kKonCryptKeyLength;
		keyArrayPtr = theEnv->cryptKey;
		do
			*(keyArrayPtr++) = 0;
		while (--keyArrayIndex);
		keyPtr = theKey;
		keyIndex = keyLength;
		while (keyIndex)
			{KonInitCrypt (theEnv);
			keyArrayIndex = kKonCryptKeyLength;
			if (keyArrayIndex > keyIndex)
				keyArrayIndex = keyIndex;
			keyIndex -= keyArrayIndex;
			keyArrayPtr = theEnv->cryptKey;
			do
				*(keyArrayPtr++) ^= *(keyPtr++);
			while (--keyArrayIndex);
			KonEncryptData (theEnv, theEnv->cryptKey,
				kKonCryptKeyLength);
			KonEncryptData (theEnv, theEnv->cryptKey,
				kKonCryptKeyLength);}
		KonInitCrypt (theEnv);
		return;}

	void	KonIndexState (register KonEnvStruct *theEnv,
						register Kon4ByteInt theIndex)

		{register	Kon1ByteInt	stateIndex;
		register	Kon4ByteInt	*statePtr;

		KonInitCrypt (theEnv);
		statePtr = theEnv->stateData;
		stateIndex = kKonStateLength;
		do
			*(statePtr++) += theIndex;
		while (--stateIndex);
		return;}

	void	KonDoubleIndexState (register KonEnvStruct *theEnv,
						register Kon4ByteInt aIndex,
						register Kon4ByteInt bIndex)

		{register	Kon1ByteInt	stateIndex;
		register	Kon4ByteInt	*statePtr;

		KonInitCrypt (theEnv);
		statePtr = theEnv->stateData;
		stateIndex = kKonStateLength / 2;
		do
			{*(statePtr++) += aIndex;
			*(statePtr++) += bIndex;}
		while (--stateIndex);
		return;}

	void	KonQuadrupleIndexState (register KonEnvStruct *theEnv,
						register Kon4ByteInt aIndex,
						register Kon4ByteInt bIndex,
						register Kon4ByteInt cIndex,
						register Kon4ByteInt dIndex)

		{register	Kon1ByteInt	stateIndex;
		register	Kon4ByteInt	*statePtr;

		KonInitCrypt (theEnv);
		statePtr = theEnv->stateData;
		stateIndex = kKonStateLength / 4;
		do
			{*(statePtr++) += aIndex;
			*(statePtr++) += bIndex;
			*(statePtr++) += cIndex;
			*(statePtr++) += dIndex;}
		while (--stateIndex);
		return;}

	void	KonZapCrypt (register KonEnvStruct *theEnv)

		{KonSetCryptKey (theEnv, (void *) 0, 0);
		return;}
