| 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 |