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