Net Mail Encryption - cypher.c
utzoo!hcr!tracy
utzoo!hcr!tracy
Thu Jan 13 14:34:44 AEST 1983
/*
* cypher - encrypt messages
*
* cypher implements a four rotor enigma machine with 94 element rotors.
* It is intended to be used to encrypt network mail so that it will not
* be routinely decrypted.
*
* Disclaimer:
*
* No warranty of any kind is made concerning any use of this program.
* The author assumes no responsibility for it's use or for any problems
* arising from it's use by any recipient.
*
* Use:
*
* cypher [-re[k key]] [file] . . .
* rcypher . . .
*
* Description:
*
* Copy standard input to standard output, performing an encryption
* similar to crypt(1) with the following differences:
*
* - only printing character including space and excluding
* newline
* and tilde are encrypted (into the same set).
* - maximun of 512 byte lines (including \n) are allowed
* - if cypher produces a line beginning "From " while encrypting
* it will prepend a tilde to the line.
* - there are four full rotors and one half rotor.
* - encryption occurs only on text on lines between (and not
* including) lines beginning "[cypher]" and "[clear]".
*
* If a filename is given, reads from the file instead of stdin.
*
* Options:
*
* -r causes cypher to accept a list of files and replace them
* with their encrypted form. Any number of filenames may be
* used with this option.
*
* -e start processing the file in encryption mode.
*
* -k key specify a key (otherwise you are asked for it)
*/
#include <stdio.h>
#define RS 94
#define RN 4
#define TEMPLATE "#TC.XXXXXX"
#define RMASK 0x7fff /* use only 15 bits */
#define LINESIZE 512
#define START "[cypher]"
#define STOP "[clear]"
char r[RS][RN]; /* rotors */
char ir[RS][RN]; /* inverse rotors */
char h[RS]; /* half rotor */
char s[RS]; /* shuffle vector */
int p[RN]; /* rotor indices */
char tempfile[512];
int cypher, gotkey, gotfile, replacefile;
char *lock;
main( argc, argv)
char **argv;
{
char *argp;
char *mktemp(), *lastname(), *strcpy();
int i;
if ( *lastname( argv[0]) == 'r' )
replacefile = 1;
for ( i = 1; i < argc; i++ ) {
argp = argv[i];
if ( *argp == '-' ) {
argp++;
for ( ; *argp != '\0'; argp++ ) {
switch ( *argp ) {
case 'e':
cypher = 1;
break;
case 'r':
replacefile = 1;
break;
case 'k':
if ( ++i < argc ) {
gotkey = 1;
argp = argv[i];
makekey( argp);
while ( *argp ) {
*argp = '\0';
argp++;
}
argp--;
}
else
yell( -1, "Need a key following -k\n");
break;
default:
yell( -1, "Bad flag: -%c\n", *argp);
break;
}
}
}
else {
/* argument is a file. process it */
if ( NULL == freopen( argp, "r", stdin) ) {
yell( -1, "Cannot open %s\n", argp);
}
else {
if ( gotfile && !replacefile )
yell( 4, "Only one file allowed\n");
if ( replacefile ) {
strcpy( tempfile, argp);
strcpy( lastname( tempfile), mktemp( TEMPLATE));
if ( NULL == freopen( tempfile, "w", stdout) )
yell( 4, "Cannot open a tempfile!\n");
}
passfile();
if ( replacefile ) {
if ( unlink( argp) == -1 )
yell( 8, "Strange unlink botch\n");
if ( link( tempfile, argp) == -1 )
yell( 8, "Can't link tempfile: %s\n", tempfile);
if ( unlink( tempfile) == -1 )
yell( -1, "I didn't unlink the temp file\n");
}
}
gotfile = 1;
}
}
if ( !gotfile ) {
if ( replacefile )
yell( 4, "need filenames with -r flag\n");
passfile();
}
exit ( 0 );
}
passfile()
{
register int i;
register j, ph = 0;
char *getpass(), sgetchar(), sputchar();
static char keybuffer[9];
while ( !gotkey ) {
strcpy( keybuffer, getpass( "Enter key: "));
if ( strcmp( keybuffer, getpass( "Once more: "))) {
yell( -1, "Your keys were not the same\n");
continue;
}
makekey( keybuffer);
gotkey = 1;
}
setup();
while( ( i = sgetchar()) != EOF ) {
if ( cypher ) {
if ( (i >= ' ') && (i < '~') ) {
i -= ' ';
for ( j = 0; j < RN; j++ ) /* rotor forwards */
i = r[(i+p[j])%RS][j];
i = ((h[(i+ph)%RS])-ph+RS)%RS; /* half rotor */
for ( j-- ; j >= 0; j-- ) /* rotor backwards */
i = (ir[i][j]+RS-p[j])%RS;
j = 0; /* rotate rotors */
p[0]++;
while ( p[j] == RS ) {
p[j] = 0;
j++;
if ( j == RN )
break;
p[j]++;
}
if ( ++ph == RS )
ph = 0;
i += ' ';
}
}
sputchar(i);
}
}
char
sgetchar()
{
static char buffer[LINESIZE], *bP;
char nextchar;
while ( bP == (char *) 0 ) {
if ( NULL == fgets( buffer, LINESIZE, stdin))
return ( EOF );
if ( *buffer == '[' ) {
if ( !strncmp( buffer, START, strlen( START))) {
fputs( buffer, stdout);
cypher = 1;
continue;
}
if ( !strncmp( buffer, STOP, strlen( STOP))) {
fputs( buffer, stdout);
cypher = 0;
continue;
}
}
bP = buffer;
}
nextchar = *bP;
if ( *(++bP) == '\0' ) {
if ( *(bP - 1) != '\n' ) {
yell( 1, "line in text is too long\n");
}
bP = (char *) 0;
}
return ( nextchar );
}
char
sputchar( out)
char out;
{
static char obuffer[LINESIZE], *obP = obuffer;
*(obP++) = out;
if ( out == '\n' ) {
if ( cypher && !strncmp( obuffer, "From ", 5)) {
if ( obP - obuffer < LINESIZE )
putc( '~', stdout); /* prepend a wiggle */
else
yell( 1, "line with \"From \" is too long\n");
}
*(obP++) = '\0';
fputs( obuffer, stdout);
obP = obuffer;
}
}
makekey( rkey)
char *rkey;
{
char key[8], salt[2], *crypt();
strncpy( key, rkey, 8);
salt[0] = key[0];
salt[1] = key[1];
lock = crypt( key, salt);
}
/*
* 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 < RS; i++ )
r[i][j] = i;
}
seed = 123;
for ( i = 0; i < 13; i++) /* now personalize the seed */
seed = (seed*lock[i] + i) & RMASK;
for ( i = 0; i < RS; i++ ) /* initialize shuffle vector */
h[i] = s[i] = i;
for ( i = 0; i < RS; i++) { /* shuffle the vector */
seed = (5 * seed + lock[i%13]) & RMASK;;
k = ((seed % 65521) & RMASK) % RS;
temp = s[k];
s[k] = s[i];
s[i] = temp;
}
for ( i = 0; i < RS; 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 < RS; i++) { /* shuffle the vector */
seed = (5 * seed + lock[i%13]) & RMASK;;
k = ((seed % 65521) & RMASK) % RS;
temp = r[i][j];
r[i][j] = r[k][j];
r[k][j] = temp;
}
for ( i = 0; i < RS; i++) { /* create inverse rotors */
ir[r[i][j]][j] = i;
}
}
}
char *
lastname( name)
char *name;
{
char *where, *rindex();
where = rindex( name, '/');
return ( where ? (where + 1) : name );
}
/*VARARGS2*/
yell( code, fmt, args)
char *fmt;
int code;
{
fprintf( stderr, "cypher: ");
_doprnt( fmt, &args, stderr);
if ( code != -1 )
exit ( code );
}
More information about the Comp.sources.unix
mailing list