ftp.nice.ch/pub/next/unix/mail/elm2.4/elm.2.4pl17.s.tar.gz#/src/encode.c

This is encode.c in view mode; [Download] [Up]

static char rcsid[] = "@(#)$Id: encode.c,v 5.2 1992/12/07 02:34:56 syd Exp $";

/*******************************************************************************
 *  The Elm Mail System  -  $Revision: 5.2 $   $State: Exp $
 *
 *			Copyright (c) 1988-1992 USENET Community Trust
 *			Copyright (c) 1986,1987 Dave Taylor
 *******************************************************************************
 * Bug reports, patches, comments, suggestions should be sent to:
 *
 *	Syd Weinstein, Elm Coordinator
 *	elm@DSI.COM			dsinc!elm
 *
 *******************************************************************************
 * $Log: encode.c,v $
 * Revision 5.2  1992/12/07  02:34:56  syd
 * Traditional C used 'unsigned preserving' rules when an integral data
 * value is widened to integer and ANSI C changed the rules to 'value
 * preserving'. This is one of the few things that the ANSI X3J11 comitte
 * did that might break existing programs.  Casting to (int)
 * From: Bo.Asbjorn.Muldbak <bam@jutland.ColumbiaSC.NCR.COM>
 *
 * Revision 5.1  1992/10/03  22:58:40  syd
 * Initial checkin as of 2.4 Release at PL0
 *
 *
 ******************************************************************************/

/** This is a heavily mangled version of the 'cypher' program written by
    person or persons unknown.  

**/

#include "headers.h"
#include "s_elm.h"

#define RTRSZ	94
#define RN	4
#define RMASK	0x7fff	/* use only 15 bits */

/*
 *  NOTICE: Some systems take a char as a signed value,
 *	    a byte wide int. For encryption to work you
 *	    absolutely need an unsigned char !!
 *	    According to K&R2 and ANSI it is always
 *	    permissible to specify unsigned with char.
 *	    (ukkonen@csc.fi)
 */

static unsigned char	r[RTRSZ][RN];	/* rotors */
static unsigned char	ir[RTRSZ][RN];	/* inverse rotors */
static unsigned char	h[RTRSZ];		/* half rotor */
static unsigned char	s[RTRSZ];		/* shuffle vector */
static int		p[RN];		/* rotor indices */

static unsigned char the_key[SLEN];	/* unencrypted key */
static unsigned char *encrypted_key;	/* encrypted key   */

char *strncpy(), *strcpy();
unsigned long sleep();

static char *decrypt_prompt = NULL;
static char *first_enc_prompt = NULL;
static char *second_enc_prompt = NULL;
#define PROMPT_LINE		LINES-1

getkey(send)
int send;
{
	/** this routine prompts for and returns an encode/decode
	    key for use in the rest of the program. **/

	char buffer[2][NLEN];

	if (decrypt_prompt == NULL) {
		decrypt_prompt = catgets(elm_msg_cat, ElmSet, ElmDecryptPrompt,
			"Enter decryption key: ");
		first_enc_prompt = catgets(elm_msg_cat, ElmSet, ElmFirstEncryptPrompt,
			"Enter encryption key: ");
		second_enc_prompt = catgets(elm_msg_cat, ElmSet, ElmSecondEncryptPrompt,
			"Please enter it again: ");
	}

	while (1) {
	  PutLine0(PROMPT_LINE, 0, (send ? first_enc_prompt : decrypt_prompt));
	  CleartoEOLN();
	  optionally_enter(buffer[0], PROMPT_LINE,
	    strlen(send ? first_enc_prompt : decrypt_prompt), FALSE, TRUE);
	  if (send) {
	    PutLine0(PROMPT_LINE, 0, second_enc_prompt);
	    CleartoEOLN();
	    optionally_enter(buffer[1], PROMPT_LINE, strlen(second_enc_prompt),
	      FALSE, TRUE);
	    if(strcmp(buffer[0], buffer[1]) != 0) {
	      error(catgets(elm_msg_cat, ElmSet, ElmKeysNotSame,
		"Your keys were not the same!"));
	      sleep(1);
	      clear_error();
	      continue;
	    }
	  }
	  break;
	}
        strcpy((char *) the_key, buffer[0]);	/* save unencrypted key */
	makekey(buffer[0]);

	setup();		/** initialize the rotors etc. **/

	ClearLine(PROMPT_LINE);		
	clear_error();
}

get_key_no_prompt()
{
	/** This performs the same action as get_key, but assumes that
	    the current value of 'the_key' is acceptable.  This is used
	    when a message is encrypted twice... **/

	char buffer[SLEN];

	strcpy(buffer, (char *) the_key);

	makekey( buffer );

	setup();
}

encode(line)
char *line;
{
	/** encrypt or decrypt the specified line.  Uses the previously
	    entered key... **/

	register int i, j, ph = 0;

	for (; *line; line++) {
	  i = (int) *line;

	  if ( (i >= ' ') && (i < '~') ) {
	    i -= ' ';

	    for ( j = 0; j < RN; j++ )		/* rotor forwards */
	      i = r[(i+p[j])%RTRSZ][j];

	    i = (((int)h[(i+ph)%RTRSZ])-ph+RTRSZ)%RTRSZ;	/* half rotor */

	    for ( j--  ; j >= 0; j-- )		/* rotor backwards */
	      i = ((int)ir[i][j]+RTRSZ-p[j])%RTRSZ;

	    j = 0;				/* rotate rotors */
	    p[0]++;
	    while ( p[j] == RTRSZ ) {
	      p[j] = 0;
	      j++;
	      if ( j == RN ) break;
	      p[j]++;
            }
  
	    if ( ++ph == RTRSZ )
	      ph = 0;

	    i += ' ';
	  }
	  
	  *line = (char) i;	/* replace with altered one */
	}
}


makekey( rkey)
char *rkey;
{
	/** encrypt the key using the system routine 'crypt' **/

	static char key[9];
	char salt[2];
	unsigned char *crypt();

	strncpy( key, rkey, 8);
	key[8] = '\0';
	salt[0] = key[0];
	salt[1] = key[1];
#ifdef CRYPT
	encrypted_key = crypt( key, salt);
#else
	encrypted_key = (unsigned char *) key;
#endif
}

/*
 * shuffle rotors.
 * shuffle each of the rotors indiscriminately.  shuffle the half-rotor
 * using a special obvious and not very tricky algorithm which is not as
 * sophisticated as the one in crypt(1) and Oh God, I'm so depressed.
 * After all this is done build the inverses of the rotors.
 */

setup()
{
	register long i, j, k, temp;
	long seed;

	for ( j = 0; j < RN; j++ ) {
		p[j] = 0;
		for ( i = 0; i < RTRSZ; i++ )
			r[i][j] = i;
	}

	seed = 123;
	for ( i = 0; i < 13; i++)		/* now personalize the seed */
	  seed = (seed*encrypted_key[i] + i) & RMASK;

	for ( i = 0; i < RTRSZ; i++ )		/* initialize shuffle vector */
	  h[i] = s[i] = i;

	for ( i = 0; i < RTRSZ; i++) {		/* shuffle the vector */
	  seed = (5 * seed + encrypted_key[i%13]) & RMASK;;
	  k = ((seed % 65521) & RMASK) % RTRSZ;
	  temp = s[k];
	  s[k] = s[i];
	  s[i] = temp;
	}

	for ( i = 0; i < RTRSZ; i += 2 ) {	/* scramble the half-rotor */
	  temp = h[s[i]];			/* swap rotor elements ONCE */
	  h[s[i]] = h[s[i+1]];
	  h[s[i+1]] = temp;
	}

	for ( j = 0; j < RN; j++) {			/* select a rotor */

	  for ( i = 0; i < RTRSZ; i++) {		/* shuffle the vector */
	    seed = (5 * seed + encrypted_key[i%13]) & RMASK;;
	    k = ((seed % 65521) & RMASK) % RTRSZ;
	    temp = r[i][j];
	    r[i][j] = r[k][j];
	    r[k][j] = temp;
	  }

	  for ( i = 0; i < RTRSZ; i++) 		/* create inverse rotors */
	    ir[r[i][j]][j] = i;
       }
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.