static char rcsid[] = "@(#)$Id: encode.c,v 1.2 2006/05/30 16:33:21 hurtta Exp $"; /***************************************************************************** * The Elm (ME+) Mail System - $Revision: 1.2 $ $State: Exp $ * * Modified by: Kari Hurtta * (was hurtta+elm@ozone.FMI.FI) ***************************************************************************** * Moved from src/encode.c. That code was following copyright: * * The Elm Mail System * * Copyright (c) 1988-1992 USENET Community Trust * Copyright (c) 1986,1987 Dave Taylor *****************************************************************************/ /** This is a heavily mangled version of the 'cypher' program written by person or persons unknown. **/ #include "def_melib.h" #include "s_elm.h" static void setup P_((void)); #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 */ static char *decrypt_prompt = NULL; static char *first_enc_prompt = NULL; static char *second_enc_prompt = NULL; /* For some ANSI C compilers 'char *' and 'unsigned char *' are incompatible * types -- we don't use casting macro here because it disables type checking * altogether: */ static char * sig_str P_((unsigned char * str)); static char * sig_str(str) unsigned char * str; { return (char *)str; } /* 0 == failure 1 == OK -1 == Ctrl-C */ int 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]; int try = 0; buffer[0] = NULL; buffer[1] = NULL; repeat: if (send) buffer[0] = lib_prompt(1,CATGETS(elm_msg_cat, ElmSet, ElmFirstEncryptPrompt, "Enter encryption key: ")); else buffer[0] = lib_prompt(1,CATGETS(elm_msg_cat, ElmSet, ElmDecryptPrompt, "Enter decryption key: ")); if (! buffer[0]) return 0; if (send) { buffer[1] = lib_prompt(1,CATGETS(elm_msg_cat, ElmSet, ElmSecondEncryptPrompt, "Please enter it again: ")); if (! buffer[1]) { free(buffer[0]); return 0; } if(strcmp(buffer[0], buffer[1]) != 0) { lib_error(CATGETS(elm_msg_cat, ElmSet, ElmKeysNotSame, "Your keys were not the same!")); if (sleepmsg > 0) sleep(sleepmsg); if (try++ < 5) goto repeat; if (buffer[0]) free(buffer[0]); if (buffer[1]) free(buffer[1]); return 0; } } strfcpy(sig_str(the_key), buffer[0], sizeof the_key); /* save unencrypted key */ makekey(buffer[0]); setup(); /** initialize the rotors etc. **/ if (buffer[0]) free(buffer[0]); if (buffer[1]) free(buffer[1]); return 1; } void 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]; strfcpy(buffer, sig_str(the_key), sizeof buffer); makekey( buffer ); setup(); } void encode(line) char *line; { /** encrypt or decrypt the specified line. Uses the previously entered key... **/ 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 */ } } void makekey( rkey) char *rkey; { /** encrypt the key using the system routine 'crypt' **/ static char key[9]; char salt[2]; #ifdef CRYPT char *crypt(); #endif /* CRYPT */ strncpy( key, rkey, 8); key[8] = '\0'; salt[0] = key[0]; salt[1] = key[1]; #ifdef CRYPT encrypted_key = (unsigned char *) 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. */ static void 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; } } /* * Local Variables: * mode:c * c-basic-offset:4 * buffer-file-coding-system: iso-8859-1 * End: */