1 
2 static char rcsid[] = "@(#)$Id: encode.c,v 1.3 1996/03/14 17:28:00 wfp5p Exp $";
3 
4 /*******************************************************************************
5  *  The Elm Mail System  -  $Revision: 1.3 $   $State: Exp $
6  *
7  *                      Copyright (c) 1988-1995 USENET Community Trust
8  *			Copyright (c) 1986,1987 Dave Taylor
9  *******************************************************************************
10  * Bug reports, patches, comments, suggestions should be sent to:
11  *
12  *      Bill Pemberton, Elm Coordinator
13  *      flash@virginia.edu
14  *
15  *******************************************************************************
16  * $Log: encode.c,v $
17  * Revision 1.3  1996/03/14  17:28:00  wfp5p
18  * Alpha 9
19  *
20  * Revision 1.2  1995/09/29  17:42:06  wfp5p
21  * Alpha 8 (Chip's big changes)
22  *
23  * Revision 1.1.1.1  1995/04/19  20:38:35  wfp5p
24  * Initial import of elm 2.4 PL0 as base for elm 2.5.
25  *
26  ******************************************************************************/
27 
28 /** This is a heavily mangled version of the 'cypher' program written by
29     person or persons unknown.
30 
31 **/
32 
33 #include "elm_defs.h"
34 #include "elm_globals.h"
35 #include "s_elm.h"
36 
37 #define RTRSZ	94
38 #define RN	4
39 #define RMASK	0x7fff	/* use only 15 bits */
40 
41 /*
42  *  NOTICE: Some systems take a char as a signed value,
43  *	    a byte wide int. For encryption to work you
44  *	    absolutely need an unsigned char !!
45  *	    According to K&R2 and ANSI it is always
46  *	    permissible to specify unsigned with char.
47  *	    (ukkonen@csc.fi)
48  */
49 
50 static unsigned char	r[RTRSZ][RN];	/* rotors */
51 static unsigned char	ir[RTRSZ][RN];	/* inverse rotors */
52 static unsigned char	h[RTRSZ];		/* half rotor */
53 static unsigned char	s[RTRSZ];		/* shuffle vector */
54 static int		p[RN];		/* rotor indices */
55 
56 static unsigned char the_key[SLEN];	/* unencrypted key */
57 static unsigned char *encrypted_key;	/* encrypted key   */
58 
59 static char *decrypt_prompt = NULL;
60 static char *first_enc_prompt = NULL;
61 static char *second_enc_prompt = NULL;
62 #define PROMPT_LINE		LINES-1
63 
get_encode_key(send)64 get_encode_key(send)
65 int send;
66 {
67 	/** this routine prompts for and returns an encode/decode
68 	    key for use in the rest of the program. **/
69 
70 	char buffer[2][NLEN];
71 
72 	if (decrypt_prompt == NULL) {
73 		decrypt_prompt = catgets(elm_msg_cat, ElmSet, ElmDecryptPrompt,
74 			"Enter decryption key: ");
75 		first_enc_prompt = catgets(elm_msg_cat, ElmSet, ElmFirstEncryptPrompt,
76 			"Enter encryption key: ");
77 		second_enc_prompt = catgets(elm_msg_cat, ElmSet, ElmSecondEncryptPrompt,
78 			"Please enter it again: ");
79 	}
80 
81 	while (1) {
82 	  PutLine0(PROMPT_LINE, 0, (send ? first_enc_prompt : decrypt_prompt));
83 	  (void) enter_string(buffer[0], NLEN, -1, -1, ESTR_PASSWORD);
84 	  if (send) {
85 	    PutLine0(PROMPT_LINE, 0, second_enc_prompt);
86 	    (void) enter_string(buffer[1], NLEN, -1, -1, ESTR_PASSWORD);
87 	    if(strcmp(buffer[0], buffer[1]) != 0) {
88 	      error(catgets(elm_msg_cat, ElmSet, ElmKeysNotSame,
89 		"Your keys were not the same!"));
90 	      if (sleepmsg > 0)
91 		    sleep(sleepmsg);
92 	      clear_error();
93 	      continue;
94 	    }
95 	  }
96 	  break;
97 	}
98         strcpy((char *) the_key, buffer[0]);	/* save unencrypted key */
99 	makekey(buffer[0]);
100 
101 	setup();		/** initialize the rotors etc. **/
102 
103 	ClearLine(PROMPT_LINE);
104 	clear_error();
105 }
106 
recall_encode_key()107 recall_encode_key()
108 {
109 	/** This performs the same action as get_key, but assumes that
110 	    the current value of 'the_key' is acceptable.  This is used
111 	    when a message is encrypted twice... **/
112 
113 	char buffer[SLEN];
114 
115 	strcpy(buffer, (char *) the_key);
116 
117 	makekey( buffer );
118 
119 	setup();
120 }
121 
encode(line)122 encode(line)
123 char *line;
124 {
125 	/** encrypt or decrypt the specified line.  Uses the previously
126 	    entered key... **/
127 
128 	register int i, j, ph = 0;
129 
130 	for (; *line; line++) {
131 	  i = (int) *line;
132 
133 	  if ( (i >= ' ') && (i < '~') ) {
134 	    i -= ' ';
135 
136 	    for ( j = 0; j < RN; j++ )		/* rotor forwards */
137 	      i = r[(i+p[j])%RTRSZ][j];
138 
139 	    i = (((int)h[(i+ph)%RTRSZ])-ph+RTRSZ)%RTRSZ;	/* half rotor */
140 
141 	    for ( j--  ; j >= 0; j-- )		/* rotor backwards */
142 	      i = ((int)ir[i][j]+RTRSZ-p[j])%RTRSZ;
143 
144 	    j = 0;				/* rotate rotors */
145 	    p[0]++;
146 	    while ( p[j] == RTRSZ ) {
147 	      p[j] = 0;
148 	      j++;
149 	      if ( j == RN ) break;
150 	      p[j]++;
151             }
152 
153 	    if ( ++ph == RTRSZ )
154 	      ph = 0;
155 
156 	    i += ' ';
157 	  }
158 
159 	  *line = (char) i;	/* replace with altered one */
160 	}
161 }
162 
163 
makekey(rkey)164 makekey( rkey)
165 char *rkey;
166 {
167 	/** encrypt the key using the system routine 'crypt' **/
168 
169 	static char key[9];
170 	char salt[2];
171 #ifdef CRYPT
172 	char *crypt();
173 #endif /* CRYPT */
174 
175 	strncpy( key, rkey, 8);
176 	key[8] = '\0';
177 	salt[0] = key[0];
178 	salt[1] = key[1];
179 #ifdef CRYPT
180 	encrypted_key = (unsigned char *) crypt( key, salt);
181 #else
182 	encrypted_key = (unsigned char *) key;
183 #endif
184 }
185 
186 /*
187  * shuffle rotors.
188  * shuffle each of the rotors indiscriminately.  shuffle the half-rotor
189  * using a special obvious and not very tricky algorithm which is not as
190  * sophisticated as the one in crypt(1) and Oh God, I'm so depressed.
191  * After all this is done build the inverses of the rotors.
192  */
193 
setup()194 setup()
195 {
196 	register long i, j, k, temp;
197 	long seed;
198 
199 	for ( j = 0; j < RN; j++ ) {
200 		p[j] = 0;
201 		for ( i = 0; i < RTRSZ; i++ )
202 			r[i][j] = i;
203 	}
204 
205 	seed = 123;
206 	for ( i = 0; i < 13; i++)		/* now personalize the seed */
207 	  seed = (seed*encrypted_key[i] + i) & RMASK;
208 
209 	for ( i = 0; i < RTRSZ; i++ )		/* initialize shuffle vector */
210 	  h[i] = s[i] = i;
211 
212 	for ( i = 0; i < RTRSZ; i++) {		/* shuffle the vector */
213 	  seed = (5 * seed + encrypted_key[i%13]) & RMASK;;
214 	  k = ((seed % 65521) & RMASK) % RTRSZ;
215 	  temp = s[k];
216 	  s[k] = s[i];
217 	  s[i] = temp;
218 	}
219 
220 	for ( i = 0; i < RTRSZ; i += 2 ) {	/* scramble the half-rotor */
221 	  temp = h[s[i]];			/* swap rotor elements ONCE */
222 	  h[s[i]] = h[s[i+1]];
223 	  h[s[i+1]] = temp;
224 	}
225 
226 	for ( j = 0; j < RN; j++) {			/* select a rotor */
227 
228 	  for ( i = 0; i < RTRSZ; i++) {		/* shuffle the vector */
229 	    seed = (5 * seed + encrypted_key[i%13]) & RMASK;;
230 	    k = ((seed % 65521) & RMASK) % RTRSZ;
231 	    temp = r[i][j];
232 	    r[i][j] = r[k][j];
233 	    r[k][j] = temp;
234 	  }
235 
236 	  for ( i = 0; i < RTRSZ; i++) 		/* create inverse rotors */
237 	    ir[r[i][j]][j] = i;
238        }
239 }
240