Previous | Table of Contents | Next |
The program POLY2.CPP, which represents the C++ language version of the POLY2.BAS program, was developed as a continuation of our strategy of providing encryption examples in both languages. Listing 5.7 includes the POLY2.CPP program listing. The actual program, as well as the executable version of the program, are located in the C directory on the CD-ROM. Concerning the executable version of the program, its filename follows the naming convention used in this book, resulting in the filename POLY2.EXE. To distinguish the executable versions of the BASIC and C++ programs from one another, it is important to remember that although they have the same filename, they are located in different directories. That is, the file POLY2.EXE located in the directory BASIC represents the executable version of the program POLY2.BAS while the file POLY2.EXE located in the C directory represents the executable version of the program POLY2.CPP.
Listing 5.7 The POLY2.CPP program listing.
/*poly2.cpp C++ code written by Jonathan Held, April 1, 1998, using Microsoft's Visual C++ version 5.0. */ //standard includes #include<iostream.h> #include<assert.h> #include<string.h> #include<ctype.h> #include<fstream.h> //constants we will use const int FIVE = 5, TWENTYFIVE = 25, TWENTYSIX = 26, TWENTYSEVEN = 27, SIXTYFIVE = 65, NINETY = 90, NINETYTWO = 92, SIZE = 256, BIGSIZE = 1000; //function prototypes bool checkInput(char * &); void createStream(char *, char []); void createTable(char [][TWENTYSEVEN], const char [], const char []); void display(char *); void formatData(char []); bool encryptText(char *, char *, const char PTEXT[], const char [][TWENTYSEVEN], char []); char* formCipheredMessage(const char [], const char [] [TWENTYSEVEN], const char[], char []); void getFileNames(char *&, char *&); int getInputType(void); int getKeyword(char *&); bool getMessage(char *, char *, const char [], const char [][TWENTYSEVEN], char []); void groupBUFFER(ofstream, int); void printCipherToFile(ofstream, char[]); bool writeMatrixToFile(const char [], const char [][TWENTYSEVEN]); char BUFFER[BIGSIZE] = {'\0'}; //---------------------------------------------------------------- //Function: main() //Parameters: None //Return Type: int - 0 means program terminated normally //Purpose: Runs the main part of the program. //---------------------------------------------------------------- int main() { char plaintext[TWENTYSEVEN] = {'A','B','C','D','E','F','G','H', 'I','J','K','L','M','N','O','P', 'Q','R','S','T','U','V','W','X', 'Y','Z','\0'}; char *ptext_keyword, *ctext_keyword, *infile, *outfile; //p_stream is used to help form the alphabetic-shifted cipher //alphabets char p_stream[TWENTYSIX] = {'\0'}; //c_stream represented the top row of the polyalphabetic ciphertext //matrix char c_stream[TWENTYSIX] = {'\0'}; //table is the actual polyalphabetic ciphertext matrix char table[TWENTYSIX][TWENTYSEVEN], message_to_cipher[SIZE]; int type_of_input; bool success = false; cout << "Enter plaintext keyword or keyword phrase in UPPERCASE: "; getKeyword(ptext_keyword); cout << "Enter ciphertext keyword or keyword phrase in UPPERCASE: "; getKeyword(ctext_keyword); createStream(ptext_keyword, p_stream); createStream(ctext_keyword, c_stream); createTable(table, plaintext, c_stream); getFileNames(infile, outfile); type_of_input = getInputType(); //handle file input if (type_of_input){ success = encryptText(infile, outfile, p_stream, table, message_to_cipher); } //keyboard input else { success = getMessage(infile, outfile, p_stream, table, message_to_cipher); } //report success of operation if (!success){ cerr << "Error: Invalid filename specified. Goodbye." << endl; } else { cout << "Press return to display resulting enciphered message." << endl; //get the newlines off the current input stream cin.get(); if (type_of_input){ cin.get(); } display(outfile); } writeMatrixToFile(p_stream, table); delete [] ptext_keyword; delete [] ctext_keyword; return (0); }//end main() //---------------------------------------------------------------- //Function: checkInput() //Parameters: input - the keyword the user entered //Return Type: bool - true if the input string contains an error, // false otherwise //Purpose: Checks the user's keyword for invalid characters. //---------------------------------------------------------------- bool checkInput(char * &input) { bool error = false; int count = strlen(input); for (int ix=0; ix<count; ix++){ int char_value = static_cast<int>(*(input+ix)); //determine if the user did not enter an uppercase character if ((char_value < SIXTYFIVE) || (char_value > NINETY)){ error = true; cerr << "\aYou entered an invalid keyword!" << endl << endl << "Re-enter keyword: "; break; } } //check for just the newline and no other characters entered if (count == 0){ cerr << "\aYou entered an invalid keyword!" << endl << endl << "Re-enter keyword: "; error = true; } return error; }//end checkInput() //---------------------------------------------------------------- //Function: createStream() //Parameters: input - the keyword the user entered // stream - streams used in the polyalphabetic cipher // matrix. //Return Type: None //Purpose: Creates a preliminary stream that will be used in //conjunction with the polyalphabetic cipher matrix. //---------------------------------------------------------------- void createStream(char *input, char stream[]) { bool used[TWENTYSIX]; int index = 0, count = strlen(input); //no characters are initially used for (int ix=0; ix<TWENTYSIX; ix++){ used[ix] = false; } //keep track of each character used, start forming the keyword //alphabet for (int jx=0; jx<count; jx++){ //get each character of the input string (integer value) int char_value = static_cast<int>(*(input+jx)); if (used[char_value-SIXTYFIVE]){ //do nothing - the character was already used } else { //mark as used and add to the keyword alphabet used[char_value-SIXTYFIVE] = true; *(stream+index++) = static_cast<char>(char_value); } } //go through the list of characters used - those which weren't //used should be added to the keyword alphabet for (int kx=0; kx<TWENTYSIX; kx++){ if (!(used[kx])){ *(stream+index++) = static_cast<char>(SIXTYFIVE+kx); } } stream[TWENTYSIX] = '\0'; return; }//end createStream() //---------------------------------------------------------------- //Function: createTable() //Parameters: tbl - the polyalphabetic ciphertext matrix we are // creating // PTEXT - the plaintext alphabet we use to form // shifted keyword alphabets; starting position // within the plaintext alphabet is determined by // the cipher stream // CSTREAM - the cipher stream that represents the top // row of the polyalphabetic ciphertext matrix //Return Type: None //Purpose: Creates a polyalphabetic ciphertext matrix. Each character //in the cipherstream represents a row in the polyalphabetic ciphertext //matrix; this row is a shifted alphabet that starts at the character //subsequent to the cstream character. //---------------------------------------------------------------- void createTable(char tbl[][TWENTYSEVEN], const char PTEXT[], const char CSTREAM[]) { for (int ix=0; ix<TWENTYSIX; ix++){ int start_pos = (static_cast<int>(CSTREAM[ix]) - SIXTYFIVE + 1) % TWENTYSIX; for (int jx=0; jx<TWENTYSIX; jx++){ tbl[ix][jx] = PTEXT[(start_pos + jx) % TWENTYSIX]; } tbl[ix][TWENTYSIX] = '\0'; } return; }//end createTable() //---------------------------------------------------------------- //Function: display() //Parameters: name - the name of the file the user wants displayed //Return Type: None //Purpose: Echoes the resulting output file to the screen. //---------------------------------------------------------------- void display(char *name) { ifstream infile(name, ios::in); char input[SIZE]; if (!(infile)){ cerr << "Unable to open input file for display." << endl; } else { while (infile.getline(input, SIZE, '\n')){ cout << input << endl; } } cout << endl; return; }//end display() //---------------------------------------------------------------- //Function: encryptText() //Parameters: inp_file - the name of the input plaintext file / outp_file - the name of the output file to save the / encrypted text / PSTREAM[] - the top row of the polyalphabetic ciphertext / matrix / TBL[][] - the polyalphabetic ciphertext matrix / encoded_msg[] - the message to be encoded //Return Type: bool, indicating success of operation //Purpose: Used to encrypt file input. Takes each line of the input //file, encrypts it, and saves the result to the specified output //file. //---------------------------------------------------------------- bool encryptText(char * inp_file, char * outp_file, const char PSTREAM[], const char TBL[][TWENTYSEVEN], char encoded_msg[]) { bool success = false; char ip[SIZE]; //declare file stream objects ifstream input(inp_file, ios::in); ofstream output(outp_file, ios::app); if ((!input) || (!output)){ //do nothing - I/O error; user will be notified upon //procedure's return to main() } else { success = true; while (input.getline(ip, BIGSIZE, '\n')){ //check to see if the user wants the line to appear in plaintext if (ip[0] == '/'){ if (strlen(BUFFER)>0){ //empty whatever is in the buffer groupBUFFER(output, strlen(BUFFER)); //adjust the buffer strcpy(BUFFER, (BUFFER+strlen(BUFFER))); //output plaintext } output << ip << endl; } else { //encipher the line char *msg = formCipheredMessage(PSTREAM, TBL, ip, encoded_msg); //print the cipher in groups of five to the ouput file printCipherToFile(output, msg); } } //empty the rest of the buffer groupBUFFER(output, strlen(BUFFER)); //notify user where plaintext and ciphertext files are cout << "Plaintext file is: " << inp_file << endl; cout << "Encrypted file is: " << outp_file << endl << endl; } //don't forget to close the files input.close(); output.close(); //return success of the operation return success; }//end encryptText() //---------------------------------------------------------------- //Function: formatData() //Parameters: data - the array we want to format //Return Type: None //Purpose: Get rid of all spaces in the array. //---------------------------------------------------------------- void formatData(char data[]) { for (int mx=0, nx=0; (*(data+nx) != '\0'); nx++){ if (*(data+nx) == ' '){ //do nothing - skip over the space in the data } else { *(data+mx++) = *(data+nx); } } //don't forget to add the null terminator *(data+mx) = '\0'; return; }//end formatData() //---------------------------------------------------------------- //Function: formCipheredMessage() //Parameters: PSTREAM - the top row of the polyalphabetic cipher matrix // TBL - the actual polyalphabetic cipher matrix // MESSAGETOCIPHER - the message we want to encipher // enc_message - the enciphered message //Return Type: char* - a pointer to the encoded information. //Purpose: Encipher the user's message. //---------------------------------------------------------------- char* formCipheredMessage(const char PSTREAM[], const char TBL[] [TWENTYSEVEN], const char MESSAGETOCIPHER[], char enc_message[]) { int length = strlen(MESSAGETOCIPHER)+1; //location identifies where in the CSTREAM character the plaintext //character is int location = 0; //use this variable to keep track of which cipher alphabet //we are using - making it a static ensures that its value //is preserved when we make subsequent function calls static int which_cipher_alphabet = 0; for (int ix=0; ix<length; ix++){ //test to see if we have an alphabetic character; if not, //simply copy it to our encrypted message - this preserves //characters such as ', ! etc... if (!isalpha(static_cast<int>(MESSAGETOCIPHER[ix]))){ enc_message[ix] = MESSAGETOCIPHER[ix]; } else { //find the location of the character we want to //encipher in the CSTREAM for (int jx=0; jx<TWENTYSIX; jx++){ if (MESSAGETOCIPHER[ix] == PSTREAM[jx]){ location = jx; break; } } enc_message[ix] = TBL[which_cipher_alphabet%TWENTYSIX][location]; //go to the next cipher alphabet which_cipher_alphabet++; } } //return a reference to the encoded message return enc_message; }//end formCipheredMessage() //---------------------------------------------------------------- //Function: getFileNames() //Parameters: infile_name - the input file outfile_name - the output file we will write the enciphered text to //Return Type: None //Purpose: Get file information from the user. //---------------------------------------------------------------- void getFileNames(char * &infile_name, char * &outfile_name) { char data[SIZE]; cout << "Enter filename to store/retrieve plaintext message: "; cin >> data; infile_name = new char[strlen(data) + 1]; strcpy(infile_name, data); cout << "Enter filename to store enciphered message: "; cin >> data; outfile_name = new char[strlen(data) + 1]; strcpy(outfile_name, data); cout << endl; return; }//end getFileNames() //---------------------------------------------------------------- //Function: getInputType() //Parameters: None //Return Type: int - 0 indicates keyboard input, 1 indicates file // input //Purpose: Determines if the user will be manually entering text to //be enciphered or if the user wants a file to be enciphered. //---------------------------------------------------------------- int getInputType(void) { char type; bool error = false; int value; do { //prompt user for input from file or keyboard cout << "Is file input from keyboard (K, k) or file (F, f): "; cin >> type; //make type an uppercase letter type = static_cast<char>(toupper(static_cast<int>(type))); //check for an invalid character if ((type != 'K') && (type != 'F')){ cerr << "You have entered an invalid character!" << endl << endl; error = true; } else { if (type == 'K') value = 0; //value of 0 represents keyboard input else value = 1; //value of 1 represents file input error = false; } } while (error); cout << endl; return value; }//end getInputType() //---------------------------------------------------------------- //Function: getKeyword() //Parameters: text - the keyword that the user enters //Return Type: int - the length of the keyword //Purpose: Prompts the user for a keyword and continues until //a valid keyword has been entered. Returns the length of the //keyword. //---------------------------------------------------------------- int getKeyword(char * &text) { bool error = false; char buffer[SIZE]; do { cin.getline(buffer, SIZE, '\n'); assert(text = new char[strlen(buffer) + 1]); strcpy(text, buffer); error = checkInput(text); //delete text if there was an error if (error){ delete [] text; } } while (error); cout << endl; return strlen(buffer); }//end getKeyword() //---------------------------------------------------------------- //Function: getMessage() //Parameters: input - the name of the input plaintext file output the name of the output ciphertext file msg_to_cipher - the message to be encoded // PSTREAM - the top row of the polyalphabetic ciphertext // matrix; used to index into the actual table // TBL - the polyalphabetic ciphertext matrix //Return Type: bool, indicating success of operation //Purpose: Allow the user to manually input text from the keyboard. //Save the text in plaintext to the input file; encrypt the text //and save it to the specified output file for later retrieval. //---------------------------------------------------------------- bool getMessage(char* input, char* output, const char PSTREAM[], const char TBL[][TWENTYSEVEN], char msg_to_cipher[]) { bool go_on = true, success = false; ofstream textFile(input, ios::app); ofstream cipherFile(output, ios::app); if ((!textFile) || (!cipherFile)){ //do nothing - error will be noted to user later } else { success = true; //get the newline character off of the input stream cin.get(); cout << "Enter the message in UPPERCASE or lowercase characters. " << endl << "Non-alphabetic characters may be entered but are ignored." << endl << "Use a / at the beginning of each line that should remain" << endl << "in plaintext and a \\ on a separate line to indicate the" << endl << "end of an enciphered message." << endl < <endl; while (go_on) { //get the entire line, up to 256 characters cin.getline(msg_to_cipher, SIZE, '\n'); //case user doesn't want the text to be encrypted if (msg_to_cipher[0] == '/'){ if (strlen(BUFFER)>0){ //empty whatever is in the buffer groupBUFFER(cipherFile, strlen(BUFFER)); //adjust the buffer strcpy(BUFFER, (BUFFER+strlen(BUFFER))); } //output plaintext textFile << msg_to_cipher << endl; cipherFile << msg_to_cipher << endl; } //case user is done entering text else if (static_cast<int>(msg_to_cipher[0]) == NINETYTWO){ go_on = false; } //encrypt the text else { textFile << msg_to_cipher << endl; char enciphered_msg[BIGSIZE]; formCipheredMessage(PSTREAM, TBL, msg_to_cipher,enciphered_msg); printCipherToFile(cipherFile,enciphered_msg); } } //empty the rest of the buffer groupBUFFER(cipherFile, strlen(BUFFER)); } //close the files textFile.close(); cipherFile.close(); //notify user where plaintext and ciphertext files are cout << "\nPlaintext file is: " << input << endl; cout << "Encrypted file is: " << output << endl << endl; return success; }//end getMessage() //---------------------------------------------------------------- //Function: groupBUFFER() //Parameters: out - the output stream we are writing to num - the number of characters we want to output //Return Type: None //Purpose: Output the buffer in groups of five characters at a //time. //---------------------------------------------------------------- void groupBUFFER(ofstream out, int num) { for (int kx=0;kx<num;kx++){ if ((kx!=0) && (kx%TWENTYFIVE==0)){ out << endl; } if ((kx!=0) && (kx%FIVE == 0) && (kx%TWENTYFIVE!=0)){ out << " " << *(BUFFER+kx); } else { out << *(BUFFER+kx); } } out << endl; return; }//end groupBUFFER() //---------------------------------------------------------------- //Function: printCipherToFile() //Parameters: op - the output file we are writing to // msg - the cipher text we are displaying //Return Type: None //Purpose: Group the cipher in 5-block characters in the //specified output file. //---------------------------------------------------------------- void printCipherToFile(ofstream op, char msg[]) { formatData(msg); //check to see if there are more than 25 characters //in the buffer; if so, print out as many groups of //25 as possible if (strlen(BUFFER) >= TWENTYFIVE){ int numchars = (strlen(BUFFER)/TWENTYFIVE)*TWENTYFIVE; //print the contents of the buffer to the output stream groupBUFFER(op, numchars); //shift whatever is left in the buffer strcpy(BUFFER, (BUFFER+numchars)); //append data to the buffer strcat(BUFFER, msg); } //if buffer contents are less than 25, simply append the new //data to the buffer else if ((strlen(BUFFER) >= 0) && (strlen(BUFFER) < TWENTYFIVE)){ strcat(BUFFER, msg); } return; }//end printCipherToFile() //---------------------------------------------------------------- //Function: writeMatrixToFile() //Parameters: CSTREAM - the top row of the polyalphabetic cipher matrix // TBL - the actual matrix //Return Type: bool - indicates success of the operation //Purpose: Prints the matrix to a file "table.dat" for future //reference. //---------------------------------------------------------------- bool writeMatrixToFile(const char PSTREAM[], const char TBL[][TWENTYSEVEN]) { ofstream output("table.dat", ios::out); bool success = false; if (output){ success = true; output << PSTREAM << endl << endl; for (int ix=0; ix<TWENTYSIX; ix++) output << TBL[ix] << endl; } cout << "Polyalphabetic matrix was written to file table.dat" << endl << endl; output.close(); return success; }//end writeMatrixToFile() //end file poly2.cpp
Previous | Table of Contents | Next |