/***********************************************************************/
/*********************************************************************
* This software is Copyright (C) 1988 by Steven Dorner and the
* University of Illinois Board of Trustees, and by CSNET.  No warranties of
* any kind are expressed or implied.  No support will be provided.
* This software may not be redistributed without prior consent of CSNET.
* You may direct questions to [email protected].
**********************************************************************/

#define ROTORSZ 256
#define MASK 0377

#ifdef VMS
#include <types.h>
#else
#include <sys/types.h>
#include <sys/stat.h>
#endif

#include <signal.h>
#include <stdio.h>
#include <ctype.h>
/*# include <sgtty.h>
#include <strings.h> */

char  t1[ROTORSZ];
char  t2[ROTORSZ];
char  t3[ROTORSZ];

int   Encrypting = 0;
static int ccnt, nchars, n1, n2;
char   *Visible();

crypt_start(pass)
char   *pass;
{

 n1 = 0;
 n2 = 0;
 ccnt = 0;
 nchars = 0;
 Encrypting = 1;
 crypt_init(pass);
}


char   *
decrypt(to, from)
char   *to;
char   *from;
{
 char  scratch[4096];
 char   *sp;
 int   count;

 count = decode((unsigned char *)scratch, (unsigned char *)from);
 for (sp = scratch; count--; sp++)
 {
   *to++ = t2[(t3[(t1[(*sp + n1) & MASK] + n2) & MASK] - n2) & MASK] - n1;

   n1++;
   if (n1 == ROTORSZ)
   {
     n1 = 0;
     n2++;
     if (n2 == ROTORSZ)
       n2 = 0;
   }
 }
 *to = '\0';         /* null-terminate */
 return (0);
}

decrypt_end()
{
 Encrypting = 0;
}

/* single character decode */
#define DEC(c)  (((unsigned char)(c) - '#') & 077)

decode(to, from)
unsigned char *to;
unsigned char *from;
{
 int   n;
 int   chars;

 chars = n = DEC(*from++);

 while (n > 0)
 {
   /*
    * convert groups of 3 bytes (4 Input characters).
    */
   *to++ = DEC(*from) << 2 | DEC(from[1]) >> 4;
   *to++ = DEC(from[1]) << 4 | DEC(from[2]) >> 2;
   *to++ = DEC(from[2]) << 6 | DEC(from[3]);
   from += 4;
   n -= 3;
 }
 return (chars);
}

crypt_init(pw)
char   *pw;
{
 int   ic, i, k, temp;
 unsigned random;
 char  buf[13];
 int  seed;
 char   *crypt();

 /* must reinitialize the arrays */
 for (i = 0; i < ROTORSZ; i++)
   t1[i] = t2[i] = t3[i] = 0;

 strncpy(buf, crypt(pw, pw), 13);

 seed = 123;
 for (i = 0; i < 13; i++)
   seed = seed * buf[i] + i;
 for (i = 0; i < ROTORSZ; i++)
   t1[i] = i;
 for (i = 0; i < ROTORSZ; i++)
 {
   seed = 5 * seed + buf[i % 13];
   random = seed % 65521;
   k = ROTORSZ - 1 - i;
   ic = (random & MASK) % (k + 1);
   random >>= 8;
   temp = t1[k];
   t1[k] = t1[ic];
   t1[ic] = temp;
   if (t3[k] != 0)
     continue;
   ic = (random & MASK) % k;
   while (t3[ic] != 0)
     ic = (ic + 1) % k;
   t3[k] = ic;
   t3[ic] = k;
 }
 for (i = 0; i < ROTORSZ; i++)
   t2[t1[i] & MASK] = i;
}

/***********************************************************************
* encrypts a string
* first byte of string is encoded length of string
* returns length of encoded string
***********************************************************************/
encryptit(to, from)
char   *to;
char   *from;
{
 char  scratch[4096];
 char   *sp;

 sp = scratch;
 for (; *from; from++)
 {
   *sp++ = t2[(t3[(t1[(*from + n1) & MASK] + n2) & MASK] - n2) & MASK] - n1;
   n1++;
   if (n1 == ROTORSZ)
   {
     n1 = 0;
     n2++;
     if (n2 == ROTORSZ)
       n2 = 0;
   }
 }
 return (encode(to, scratch, sp - scratch));
}

/*
* * Basic 1 character encoding function to make a char printing.
*/
#define ENC(c) (((unsigned char)(c) & 077) + '#')

encode(out, buf, n)       /* output a line of binary (up to 45 chars)
                * in */
int   n;            /* a readable format, converting 3 chars to 4  */
char   *buf;
char   *out;
{
 int   i;
 char   *outStart;

 outStart = out;
 *out++ = ENC(n);

 for (i = 0; i < n; buf += 3, i += 3, out += 4)
   threecpy((unsigned char *)out, (unsigned char *)buf);

 /* null terminate */
 *out = '\0';
 return (out - outStart);
}

threecpy(to, from)
unsigned char *to;
unsigned char *from;
{
 int   c1, c2, c3, c4;

 c1 = *from >> 2;
 c2 = (*from << 4) & 060 | (from[1] >> 4) & 017;
 c3 = (from[1] << 2) & 074 | (from[2] >> 6) & 03;
 c4 = from[2] & 077;
 *to++ = ENC(c1);
 *to++ = ENC(c2);
 *to++ = ENC(c3);
 *to = ENC(c4);
}