[net.sources] Crypt - modified not to use crypt

philip@axis.UUCP (02/21/87)

Since posting the original article, it has become apparent that many
UNIX systems (and DOS) lack the makekey program, and sometimes even
the crypt(3) functions.

This is not actually too important - I only used makekey/crypt because
it was there.

The crypt(3) function is complicated - based upon the DES algorithms.
It is used normally on UNIX to generate the encrypted passwords which
are stored in the password file. Since these are publicly available,
a good encryption routine is needed to stop people deriving the password
from its crypted form. In my crypt program, the result of this routine
is used simply to seed a pseudo-random number generator.

The 'string' used to do this is never stored anywhere outside the program,
thus it is not too important if it is possible to derive the input key
from this initialisation string. What this means is that you can replace
crypt(3) with just about anything. You can even use the password that the user
gives directly, although I would suggest using some method of generating
something a little longer to use as the intialisation string - like
replicating the users key (for example). Doing this should not do too much
damage to the security of the system (but then I am no expert in these
matters ...)

The following is a hacked version of the original, without any calls
to makekey or crypt(3) - it should be suitable for UNIX systems with
no encryption available, and even for DOS - if you can write your
own version of getpass(3). This version simply replicates the input key
until it is 13 characters long, and uses that to seed the random number
generator.

If it is important that data encrypted on one machine should be decryptable
on another, this is probably the version to use, since some vendors seem
to have replaced the DES based crypt(3) with their own version, and thus
systems using that will not be compatible.

Philip

=============================================================================

#include <stdio.h>

#define	ROTORSIZ	256
#define	MASK		0377
#define	EMPTY		07777
#define	X_SIZE		4099

char	*strrchr();

unsigned	r1[ROTORSIZ];
unsigned	r2[ROTORSIZ];
unsigned	r3[ROTORSIZ];

unsigned char	x[X_SIZE];

init(password, decrypt)
char	*password;
int	decrypt;
{
	register int	index;
	register int	i;
	unsigned	random;
	long		seed = 123L;
	char		buf[14];

	strncpy(buf, password, 13);

	while (strlen(buf) < 13) strncat(buf, password, 13 - strlen(buf));

	for (i = 0 ; i < ROTORSIZ; i++) r1[i] = r2[i] = r3[i] = EMPTY;

	for (i = 0; i < 13; i++) seed = seed * buf[i] + i;

	i = 0;
	while (i < ROTORSIZ)
	{
		seed = (long)(5L * seed + (long)i);
		random = (unsigned)(seed % 65521L);
		index = (int)(random & MASK);
		if (r1[index] == EMPTY)
			r1[index] = i++;
		else
			continue;
	}

	i = 0;
	while (i < ROTORSIZ)
	{
		seed = (long)(5L * seed + (long)i);
		random = (unsigned)(seed % 65521L);
		index = (int)(random & MASK);
		if (r2[index] == EMPTY)
			r2[index] = i++;
		else
			continue;
	}

	i = 0;
	while (i < ROTORSIZ)
	{
		seed = (long)(5L * seed + (long)i);
		random = (unsigned)(seed % 65521L);
		index = (int)(random & MASK);
		if (r3[index] == EMPTY)
			r3[index] = i++;
		else
			continue;
	}

	for (i = 0; i < X_SIZE; i++)
	{
		seed = (long)(5L * seed + (long)i);
		random = (unsigned)(seed % 65521L);
		x[i] = random & 03;
	}

	if (decrypt)
	{
		invert(r1);
		invert(r2);
		invert(r3);
	}
}

invert(r)
unsigned r[ROTORSIZ];
{
	unsigned	t[ROTORSIZ];
	register int	i;

	for (i = 0; i < ROTORSIZ; i++) t[i] = r[i];
	for (i = 0; i < ROTORSIZ; i++) r[t[i]] = i;
}

crypt()
{
	register	int		ch;
	register	int		i    = 0;
	register	unsigned	ofs1 = 0;
	register	unsigned	ofs2 = 0;
	register	unsigned	ofs3 = 0;

	while ((ch = getchar()) != EOF)
	{
		putchar(r3[r2[r1[ch+ofs1&MASK]+ofs2&MASK]+ofs3&MASK]);

		switch (x[i]){
		case 00:
				ofs1 = ++ofs1 & MASK;
				break;
		case 01:
				ofs2 = ++ofs2 & MASK;
				break;
		case 02:
				ofs3 = ++ofs3 & MASK;
				break;
		}

		if (ofs1 == 0) ofs2 = ++ofs2 & MASK;
		if (ofs2 == 0) ofs3 = ++ofs3 & MASK;

		if (++i == X_SIZE) i = 0;
	}
}

decrypt()
{
	register	int		ch;
	register	int		i    = 0;
	register	unsigned	ofs1 = 0;
	register	unsigned	ofs2 = 0;
	register	unsigned	ofs3 = 0;

	while ((ch = getchar()) != EOF)
	{
		putchar(r1[r2[r3[ch]-ofs3&MASK]-ofs2&MASK]-ofs1&MASK);

		switch (x[i]){
		case 00:
				ofs1 = ++ofs1 & MASK;
				break;
		case 01:
				ofs2 = ++ofs2 & MASK;
				break;
		case 02:
				ofs3 = ++ofs3 & MASK;
				break;
		}

		if (ofs1 == 0) ofs2 = ++ofs2 & MASK;
		if (ofs2 == 0) ofs3 = ++ofs3 & MASK;

		if (++i == X_SIZE) i = 0;
	}
}

main(argc, argv)
int	argc;
char	*argv[];
{
	int	flag;
	char	*p;

	p = strrchr(argv[0], '/');

	if (p == NULL) p = argv[0];
	else ++p;

	if (strcmp(p, "crypt") == 0) flag = 0;
	else				   flag = 1;

	if (argc != 2)
		init(getpass("Enter key: "), flag);
	else
		init(argv[1], flag);

	if (flag) decrypt();
	else      crypt();
}