// --------------------------------------------------------------------------
// Citadel: Crypt.CPP
//
// Encryption/decryption stuff.
//
// --------------------------------------------------------------------------
// This module contains code adapted from Borland's C/C++ Run Time Library
// Version 6.0, Copyright (c) 1987, 1993 by Borland International. As Citadel
// may be compiled with different compilers and for different platforms, and
// to have one node be able to decrypt messages encrypted on another node the
// sequence of pseudo- random numbers generated has to be exactly the same,
// Borland's random number routines have been included here, so we are not
// reliant on the run time library. (Since there is, of course, no standard
// sequence to be generated by the random number generator.

#include "ctdl.h"
#pragma hdrstop

// --------------------------------------------------------------------------
// Contents
//
// encrypt()		encrypt text
// decrypt()		decrypt text


// Beginning of Borland-derived code...

#define MULTIPLIER		0x015a4e35L
#define INCREMENT		1
#define RAND_MAX		0x7FFFU

static long Seed = 1;

int CitRand(void)
	{
	Seed = MULTIPLIER * Seed + INCREMENT;
	return ((int) (Seed >> 16) & 0x7fff);
	}

inline int CitRandom(int __num)
	{
	return (int) (((long) CitRand() * __num) / (RAND_MAX + 1));
	}

// ...end of Borland-derived code.

Bool decrypt(char *text, const char *key)
	{
	int xx = 0, i;
	int slt = strlen(text);
	int slk = strlen(key);
	int wowness1 = hash(key);
	uint wowness;
	char *wowit;

	if (!slt)
		{
		return (FALSE);
		}

	wowness = (slk * (uint) wowness1) % slt;

	// first change the values
	Seed = wowness1;

	for (i = 0; i < slt; i++)
		{
		int j;
		char order[8], oldval = text[i], newval = 0;

		for (j = 0; j < key[xx]; j++)
			{
			CitRand();
			}
		xx = (xx + 1) % slk;

		for (j = 0; j < 8; j++)
			{
			order[j] = 0;
			}

		for (j = 1; j < 9; j++)
			{
			int tmp = CitRandom(7);

			while (order[tmp])
				{
				tmp = (tmp + 1) % 8;
				}

			order[tmp] = (char) j;
			}

		for (j = 0; j < 8; j++)
			{
			newval |= (((oldval & (1 << j)) >> j) << (order[j] - 1));
			}

		text[i] = newval;
		}
	text[i] = 0;

	// then unfold it
	wowit = new char[slt + 1];

	if (wowit)
		{
		for (i = 0; i < slt; i++)
			{
			wowit[(i + wowness) % slt] = text[i];
			}
		wowit[i] = 0;

		strcpy(text, wowit);
		delete [] wowit;
		}
	else
		{
		mPrintf(getmsg(188), getmsg(608));
		return (FALSE);
		}

	return (TRUE);
	}

Bool encrypt(char *text, const char *key)
	{
	int xx = 0, i;
	int slt = strlen(text);
	int slk = strlen(key);
	int wowness1 = hash(key);
	uint wowness = (slk * (uint) wowness1) % slt;
	char *wowit;

	if (!slt)
		{
		return (FALSE);
		}

	// first fold it over
	wowit = new char[slt + 1];

	if (wowit)
		{
		for (i = 0; i < slt; i++)
			{
			wowit[i] = text[(i + wowness) % slt];
			}

		strcpy(text, wowit);

		delete [] wowit;

		// then change the values
		Seed = wowness1;

		for (i = 0; i < slt; i++)
			{
			int j;
			char order[8], oldval = text[i], newval = 0;

			for (j = 0; j < key[xx]; j++)
				{
				CitRand();
				}
			xx = (xx + 1) % slk;

			for (j = 0; j < 8; j++)
				{
				order[j] = 0;
				}

			for (j = 1; j < 9; j++)
				{
				int tmp = CitRandom(7);

				while (order[tmp])
					{
					tmp = (tmp + 1) % 8;
					}

				order[tmp] = (char) j;
				}

			for (j = 0; j < 8; j++)
				{
				newval |= (((oldval & (1 << (order[j] - 1))) >> (order[j] - 1)) << j);
				}

			text[i] = newval;
			}
		text[i] = 0;

		return (TRUE);
		}
	else
		{
		mPrintf(getmsg(188), getmsg(609));
		return (FALSE);
		}
	}
