/*  $Id: cryutils.c,v 1.14 1998/06/12 18:40:59 iarce Exp $
 * Cryptographic Routines 
 *
 * Author: Ariel Futoransky
 */
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include "audit.h"
#include "blf.h"
#include "cryutils.h"
#include "randpool.h"

blf_ctx cryptoc;

unsigned char outbuf[CRYPTBUFSIZE];
unsigned char inbuf[CRYPTBUFSIZE];

unsigned int iv[2], ov[2];
unsigned int opos, ipos;

int
cflushout (fd)
		 int fd;
{
	unsigned int b[2];

	if (opos > 0)
		{
			if (opos < CRYPTBUFSIZE)
				rand_get (outbuf + opos, CRYPTBUFSIZE - opos);
			b[0] = ntohl (iv[0] ^ (*(int *) outbuf));
			b[1] = ntohl (iv[1] ^ (*(int *) (outbuf + 4)));
			Blowfish_encipher (&cryptoc, (u_int32_t *) & b[0], (u_int32_t *) & b[1]);
			b[0] = htonl (b[0]);
			b[1] = htonl (b[1]);
			iv[0] = b[0];
			iv[1] = b[1];
			write (fd, &b, CRYPTBUFSIZE);
			opos = 0;
		}

	return (0);
}

int
cwrite (fd, buf, len)
		 int fd;
		 u_int8_t *buf;
		 int len;
{
	int tot = 0;

	while (len-- > 0)
		{
			outbuf[opos++] = *(buf++);
			tot++;
			if (opos >= CRYPTBUFSIZE)
				cflushout (fd);
		}
	return (tot);
}

int
cflushin (fd)
		 int fd;
{
	ipos = CRYPTBUFSIZE;
	return (0);
}

int
cread (fd, buf, len)
		 int fd;
		 u_int8_t *buf;
		 int len;
{
	unsigned int a[2], b[2];
	char *c;
	int l, tot;
	int t, r;

	tot = 0;
	while (len > 0)
		{
			l = CRYPTBUFSIZE - ipos > len ? len : CRYPTBUFSIZE - ipos;

			if (l > 0)
				{
					if (buf)
						{
							memcpy (buf, inbuf + ipos, l);
							buf += l;
						}
					ipos += l;
					tot += l;
					len -= l;
				}
			if (ipos == CRYPTBUFSIZE && len > 0)
				{
					t = CRYPTBUFSIZE;
					c = (char *) &b;
					while (t > 0)
						{
							r = read (fd, c, t);
							if (r > 0)
								{
									c += r;
									t -= r;
								}
							else
								return (-1);
						}


					a[0] = ntohl (b[0]);
					a[1] = ntohl (b[1]);
					Blowfish_decipher (&cryptoc, (u_int32_t *) & a[0], (u_int32_t *) & a[1]);
					a[0] = htonl (a[0]);
					a[1] = htonl (a[1]);
					*(int *) inbuf = a[0] ^ iv[0];
					*(int *) (inbuf + 4) = a[1] ^ iv[1];
					iv[0] = b[0];
					iv[1] = b[1];
					ipos = 0;
				}

		}
	return (tot);
}

int
cput_int32 (fd, i)
		 int fd;
		 u_int32_t i;
{
	u_int32_t l;

	if (rand_need ())
		rand_add ((char *) &i, sizeof (i));
	l = htonl (i);
	return (cwrite (fd, (char *) &l, sizeof (l)));
}

int
cget_int32 (fd)
		 int fd;
{
	u_int32_t l;

	cread (fd, (char *) &l, sizeof (l));
	if (rand_need ())
		rand_add ((char *) &l, sizeof (l));
	return (ntohl (l));
}

int
cput_str (fd, s)
		 int fd;
		 char *s;
{
	if (!s)
		{
			cput_int32 (fd, 0);
			return (0);
		}
	if (rand_need ())
		rand_add (s, strlen (s));
	cput_int32 (fd, strlen (s));
	return (cwrite (fd, s, strlen (s)));
}

int
cget_str (fd, s, maxlen)
		 int fd;
		 char *s;
		 int maxlen;
{
	int len;

	len = cget_int32 (fd);
	if (len > maxlen)
		{
			cread (fd, s, maxlen);
			cread (fd, (char *) NULL, len - maxlen);
			return (len);
		}

	return (cread (fd, s, len));
}

int
getrandomkey (key, keylen, maxkey)
		 char *key;
		 int *keylen;
		 int maxkey;
{
	rand_get (key, maxkey);
	*keylen = maxkey;
}

int
authpeer (int fd, u_int8_t * key, int keylen, u_int32_t * data)
{
	u_int32_t a[2], b[2];
	blf_ctx state;

	blf_key (&state, key, keylen);

	b[0] = ntohl (data[0]);
	b[1] = ntohl (data[1]);
	Blowfish_encipher (&state, &b[0], &b[1]);
	b[0] = htonl (b[0]);
	b[1] = htonl (b[1]);
	write (fd, &b, sizeof (b));

	read (fd, &b, sizeof (b));
	b[0] = ntohl (b[0]);
	b[1] = ntohl (b[1]);
	Blowfish_decipher (&state, &b[0], &b[1]);
	b[0] = htonl (b[0]);
	b[1] = ntohl (b[1]);
	a[0] = ntohl (~b[0]);
	a[1] = ntohl (~b[1]);
	Blowfish_encipher (&state, &a[0], &a[1]);
	a[0] = htonl (a[0]);
	a[1] = htonl (a[1]);
	write (fd, &a, sizeof (a));

	read (fd, &a, sizeof (a));
	a[0] = ntohl (a[0]);
	a[1] = ntohl (a[1]);
	Blowfish_decipher (&state, &a[0], &a[1]);
	a[0] = htonl (a[0]);
	a[1] = htonl (a[1]);
	if ((~a[0] != data[0]) || (~a[1] != data[1]))
		return -1;

	b[0] = (b[0] ^ data[0]);
	b[1] = (b[1] ^ data[1]);

	blf_key (&cryptoc, (u_int8_t *) & b, sizeof (b));
	iv[0] = 0;
	iv[1] = 0;
	ov[0] = 0;
	ov[1] = 0;
	ipos = CRYPTBUFSIZE;
	opos = 0;

	return (0);
}
