/************************************************************************** Peggy Dagley CMSC 443 Programming assignment #2 (rotor machine) This program is designed to emulate a 2-rotor encryption machine that uses a reflector, so that if an A is encrypted to a W, then a W must also encrypt to an A. I have assigned a 2 dimensional array to hold the rotor alphabets. The user must call the program with a.out followed by an input filename and an output filename. The user will then be prompted to provide a key. This key is two alphabetic uppercase characters separated by a space. This program operates in UPPERCASE only, if a lowercase letter is detected, that letter will be converted to uppercase. **************************************************************************/ #include #include int crypt_key(void); int crypt_file(char *, char *); void set_up_rotors(void); int encrypt (int); void print_welcome(void); static int pos[2]; /* holds the position of the rotors */ static int ltr[2][26]; /* holds the alphabetic letters on the rotors */ main(int argc, char *argv[]) { int error; if(argc != 3) { printf("USAGE: [input file] [output file]\n"); printf("Exiting\n"); exit(0); } else { print_welcome(); error = crypt_key(); /* get key */ if(error == 0) /* if valid key, proceed, else exit */ error = crypt_file(argv[1], argv[2]); /* perform encryption/decryption*/ if(error == 0) printf("The program has successfully completed\n"); else printf("There has been an error, please re-run program\n"); } } /*************************************************************************** Function: print_welcome() This function prints a welcome message that explains the program in broad terms *************************************************************************/ void print_welcome(void) { printf("\n*************************************************************"); printf("\n WELCOME TO PEGGY'S VERSION OF"); printf("\n 2-ROTOR MACHINE"); printf("\n\nThis device prompts the user for a two (2) letter key"); printf("\nThen sets up the rotors accordingly. This device will"); printf("\nperform encryption or decryption because it uses a "); printf("\nreflector. The output text will be printed in the"); printf("\noutput file specified. GOOD LUCK\n"); printf("\n************************************************************\n\n"); } /**************************************************************************** Function: crypt_key This function prompts the user for a 2-character (uppercase) key. Then sets the positions of the rotors according to the key. In the event that two uppercase letters are not entered, an error message is displayed and the program exits. If a valid key is entered, then a 0 is returned signifying success. 1 signifies failure. ***********************************************************************/ int crypt_key () { int i = 0; /* number of chars in key*/ int idx; /* index/counter */ char a[2]; /* temporarily hold input*/ char ch; /* holds key character */ fflush(stdout); fflush(stdin); printf ("Initial rotor position (2 letters separated by spaces): "); while((ch = getchar()) != '\n') { if(isalpha(ch)) { ch = (toupper(ch)); a[i] = ch; i++; } } if(i > 2) /* Too many letters entered for key */ { printf("You must enter 2 letters separated by spaces for the key\n"); printf("This program is exiting.\n"); return 1; } else /*good key - proceed*/ { for (idx = 0; idx < 2; idx++) /*setting positions chars*/ pos[idx] = (a[idx]) - 'A'; /* according to key*/ return 0; } } /************************************************************************* Function: crypt_file This function takes in the input filename and output filenames as args. It sets up the rotors by calling the set_up_rotors function and then attempts to open both input and output files for reading and writing respectively. If success function continues, otherwise the function returns a 1, specifying failure and exits program. Once the files are successfully opened, the input file is read character-by-character and the function encrypt is called to encrypt/decrypt each character. Upon completion of encrypting/decrypting a character, that character is written to the output file. When the entire input file is processed, the files are closed and the program exits. *************************************************************************/ int crypt_file (char *source, char *dest) { int c; /*input char changed to int*/ FILE *ifp; /* input filename */ FILE *ofp; /* output filename */ set_up_rotors(); /*function call to set up machine*/ if ((ifp = fopen (source, "rb")) == NULL) { fprintf (stderr, "Can not open %s for reading.\n", source); return 1; } if ((ofp = fopen (dest, "wb")) == NULL) { fprintf (stderr, "Can not open %s for writing.\n", dest); fclose (ifp); return 1; } pos[0] = 0; /* ensuring positions of rotors are set to 0 */ pos[1] = 0; /* before starting encrypt/decrypt phase*/ while((c = fgetc (ifp)) != EOF) { if (isalpha (c)) { c = encrypt ((int) (toupper(c)));/* function call to encrypt/decrypt */ } if (fputc (c, ofp) == EOF) /* unable to write to output file*/ { fprintf (stderr, "Could not write to output file %s\n", dest); fclose (ifp); fclose (ofp); return 1; } } fclose (ifp); fclose (ofp); return 0; } /************************************************************************* Function: set_up_rotors This function sets up the rotors so that the starting positions of the rotors correspond to the desired key and then assigns the remaining positions accordingly. **************************************************************************/ void set_up_rotors (void) { int i, j; for (j = 0; j < 26; j++) /* setting up first rotor to correspond to key */ { ltr[0][j] = pos[0] % 26; pos[0]++; } for (j = 0; j < 26; j++) /* setting up second rotor to correspond to key */ { ltr[1][j] = pos[1] % 26; pos[1]++; } } /************************************************************************ Function: encrypt This function actually performs the encryption/decryption of each character in the input file. It uses the Affine Cipher algorithm ax+b mod 26. The character from the input file is multiplied by a constant number (which must have an inverse in mod 26) then added to the present positions corresponding character. This output of the first rotor is then mutliplied by the inverse of the first rotors' constant number, then its added to the present positions corresponding character in the second rotor and this result is the ciphertext/plaintext character. This character is then returned for writing to the output file. ***************************************************************************/ int encrypt (int c) { static int i, j; /* counters */ int f; /* holds result of output of first rotor */ int k; /* holds result of output of second rotor */ if (isalpha (c)) { i = pos[1]; /* start to encipher */ j = pos[0]; c = c - 'A'; /* put char in mod 26 format */ f = ((c*1) + ltr[0][j]) % 26; k = ((f*25) + ltr[1][i]) % 26; k += 'A'; /* put char back into ASCII equivalent */ } pos[0] = (pos[0]+1) %26; /* increment first rotor forward once */ j = (j+1) %26; if(pos[0] == 0) /* if first rotor has completed a complete */ { /* cycle, increment second rotor once */ pos[1] = (pos[1] + 1) % 26;; i++; } return (k); /* return ciphertext/plaintext */ }