|
/* * engima simulation * * author: Henry Tieman * * references: * "How Polish Mathematicians Deciphered the Enigma", Marian Rejewski, * Annals of the History of Computing, Vol 3, no 3, July 1981, Pg 213 ff * appendix by C. A. Devours. * * "Machine Cryptography and Modern Cryptanalysis", C.A. Deavours and L. * Kurth, Artech House, Dedham, Mass 1985. */ #include <stdio.h> #include <ctype.h> #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif #define LINE_LEN 80 /* * rotor data * reference "Machine Cryptography and Modern Cryptanalysis" pg. 100 * * note: rotor stepping is associated with each @PROGCODE = rotor instead * of position or being constant. */ #define NUM_ROTORS 5 char ref_rotor[27] = "YRUHQSLDPXNGOKMIEBFZCWVJAT"; char rotor[NUM_ROTORS][27] = { /* pre defined rotors */ "EKMFLGDQVZNTOWYHXUSPAIBRCJ", "AJDKSIRUXBLHWTMCQGZNPYFVOE", "BDFHJLCPRTXVZNYEIWGAKMUSQO", "ESOVPZJAYQUIRHXLNFTGKDCMWB", "VZBRGITYUPSDNHLXAWMJQOFECK", }; int step_data[NUM_ROTORS] = { 16, 4, 21, 9, 25 /* steps at: q, e, v, j, z */ }; /* * engima key default settings */ int order[3] = { 0, 1, 2}; /* rotor order, user input is +1 */ char ring[8] = { /* ring settings */ '\0', 'A', 'A', 'A', /* default: AAA */ '\0', '\0', '\0', '\0' }; int n_plugs = 0; /* number of plugs */ char plugs[80] = ""; /* plug string */ int pos[3] = { 0, 0, 0 }; /* rotor positions */ /* * simulation data and machine state data */ int data[8][26]; /* working array for machine */ int step[3]; /* steps corresponding to rotors */ int double_step; /* rotor 2 step twice */ /* * encipher - C implementation of the engima cipher function */ int encipher(int c) { int j; /* index for counting */ int idx; /* rotor index */ if (isalpha(c)) { pos[0] = (pos[0] + 1) % 26; /* first, advances the rotors */ if (pos[0] == step[0]) pos[1] = (pos[1] + 1) % 26; if (double_step) { pos[1] = (pos[1] + 1) % 26; pos[2] = (pos[2] + 1) % 26; double_step = FALSE; } if (pos[1] == step[1]) double_step = TRUE; c -= 'A'; /* start to encipher */ if (n_plugs != 0) c = data[0][c]; for (j=0;j<3;j++) /* do rotors forward */ { idx = (c + pos[j]) % 26; c = (c + data[j+1][idx]) % 26; } c = (data[4][c]) % 26; /* reflecting rotor */ for (j=0;j<3;j++) /* do rotors reverse */ { idx = (c + pos[2-j]) % 26; c = (c + data[j+5][idx]) % 26; } if (n_plugs != 0) c = data[0][c]; c += 'A'; } return(c); } /* * encipher_file - open and encipher a file */ void encipher_file(char *file_name) { FILE *fp; /* plaintext/ciphertext FILE pointer */ char line[LINE_LEN + 1]; /* input data line, inc. '\n' */ char *ret_val; /* value from fgets(), used for EOF check */ char c; /* character from data line */ int len; /* length of data line */ int idx; /* index/counter */ fp = fopen(file_name, "r"); ret_val = fgets(line, LINE_LEN, fp); while(ret_val != NULL) { len = strlen(line); for (idx=0;idx<len;idx++) { c = line[idx]; if (isalpha(c)) { c = encipher((int)(toupper(c))); line[idx] = c; } } printf("%s", line); ret_val = fgets(line, LINE_LEN, fp); } fclose(fp); } /* * init_mach - set up data according to the input data */ void init_mach( void ) { int i, j; /* indexes */ int ds; /* used during ring settings */ int u, v; /* temps for plugboard input */ /* setup rotor data */ for (j=0;j<26;j++) data[4][j] = ((int)ref_rotor[j]-'A'+26)%26; for (i=1;i<4;i++) { step[i-1] = step_data[order[i-1]]; for (j=0;j<26;j++) { data[i][j] = ((int)(rotor[order[i-1]][j])-'A' + 26) % 26; data[8-i][data[i][j]] = j; } } /* setup ring settings */ ring[7] = ring[1]; ring[6] = ring[2]; ring[5] = ring[3]; for (i=1;i<8;i++) if (i != 4) { ds = (int)(ring[i]) - 'A'; if (ds != 0) { for (j=0;j<26;j++) data[0][j] = data[i][j]; for (j=0;j<26;j++) data[i][j] = data[0][(26-ds+j)%26]; } } /* setup plug data */ if (n_plugs != 0) { j = 0; for (i=0;i<26;i++) data[0][i] = i; for (i=0;i<n_plugs;i++) { while (!isalpha(plugs[j])) { j++; if (plugs[j] == '\0') break; } u = toupper(plugs[j++]) - 'A'; v = toupper(plugs[j++]) - 'A'; data[0][u] = v; data[0][u] = u; } } /* convert all moving rotor data to displacements */ for (i=1;i<8;i++) { if (i!=4) for (j=0;j<26;j++) data[i][j] = (data[i][j] - j + 26) % 26; } /* setup rotor starting positions */ double_step = FALSE; /* no previous rotor position */ /* input function has already done the rotor positions */ } /* * read_keyfile - a simple function to read in the key file */ void read_keyfile( char *str ) { FILE *kf; /* input key FILE pointer */ int num; /* dummy returned from fscanf() */ int idx; /* index/counter */ char a[3]; /* dummy for input */ kf = fopen(str, "r"); num = fscanf(kf, "%d %d %d\n", &order[0], &order[1], &order[2]); num = fscanf(kf, "%c %c %c\n", &ring[1], &ring[2], &ring[3]); num = fscanf(kf, "%d\n", &n_plugs); if (n_plugs != 0) num = fscanf(kf, "%[^\n]\n", plugs); num = fscanf(kf, "%c %c %c\n", &a[0], &a[1], &a[2]); for (idx = 0; idx < 3; idx++) { (order[idx])--; ring[idx+1] = toupper(ring[idx+1]); pos[idx] = toupper(a[idx]) - 'A'; } fclose(kf); } /* * usage - function to print out the correct usage of the program */ void usage( char *str ) { fprintf(stderr, "usage: %s [<keyfile>] <infile>\n\n", str); fprintf(stderr, "\tkeyfile has the form:\n"); fprintf(stderr, "\t\tn n n\t\t- for rotor order, 1 <= n <= 5\n"); fprintf(stderr, "\t\tx x x\t\t- for ring settings, x alpha\n"); fprintf(stderr, "\t\tn\t\t- number of plugs, 0 <= n <= 13\n"); fprintf(stderr, "\t\txx xx xx ...\t- plug letter pairs, one pair" " for each n\n"); fprintf(stderr, "\t\tx x x\t\t- initial rotor position, x alpha\n\n"); fprintf(stderr, "\toutput is stdout\n"); exit(0); } /* * main - the main function, nothing special here */ void main( int argc, char ** argv ) { char *infile; /* plaintext/ciphertext file name ptr */ if ((argc < 2) || (argc > 3)) usage(argv[0]); if (argc == 2) { infile = argv[1]; } else { infile = argv[2]; read_keyfile(argv[1]); } init_mach(); encipher_file(infile); } /* * end of engima simulation */