C++ Caesar Cipher

profileARapSal
ceasercipherbym.docx

/*===============================================================================================================

Program Overview: This program is designed to take an input file, translate it to an appropriate Ceaser cipher

and then to take metrics on the resulting application of data that is input from the tranlation output file.

Set theoretic estimations for sets are then applied to the information that results and predictions of the

correct shift are then made as each set of rule based sets is specified and applied to the problem.

Variables:

Functions Called: createinput(ifile, ofile)

createciphter(key, ifile, ofile)

Command Line Variables: -k int Sets the key offset

-off int Sets the offset in the file

-l int Sets the length of the file to process

-m float Sets the value of the metric error

-i string Sets the input file path, file name without extender - assumed to be .txt

-o string Sets the output file path, no file name - just path

-stop char Sets the stop criterion: l for length, m for metric error

===============================================================================================================*/

/*===============================================================================================================

Assumptions about the Ceaser Cipher:

1. The corpus is in English only

2. The input contains only alphabetic charaters - there are no spaces

===============================================================================================================*/

// Start with the inclusion of libraries

#include <iostream> //The library of io functions

#include <fstream> //The library of external stream functions

#include <cstdlib> //The library for external errors

#include <string> //The library for string functions

#include <cmath> //The library of C math functions

#include <iomanip> //Allows setting widths, etc. for I/O

#include <stdlib.h>

#include <stdio.h>

using namespace std;

// Define all of the prototypes for functions used in the program

// Counts the number of unique letters seen

int countunique(int *array, int size);

// Creates the input file and formats it for use by the cipher section.

void createinput(string ifile, string ofile);

// Creates the encoded input file

void createcipher(int key, string ifile, string ofile);

// Finds and counts the number of digrams

int digram(int *pointer, string ifile);

// Counts the letter frequency in the encoded input file

int lettercount(int*, string ifile, string ofile);

// Finds the highest count in the singlton (or any other) array

int singleton(int*, int size);

// Trims an input file to the right size starting at an offset

void trimfile(string ifile, string ofile, int offset, int size);

// Begin the main function for testing

int main(int argc, char* argv[])

{

int count=0;

int second=0;

int singlefreq[26];

int *single=singlefreq;

int delta;

int loop; //The loop counter for arguments

int final=0;

int totalcnt;

int key = -1; //Sets the key value

int len = 0; //The length to investigate for testing

int off; //Holds the offset into the file

double m; //Holds the metric error value

double mi = 26; //Figures m_i

char loopletter;

float percent;

float temp; //A temporary variable

string ifile1="";

string ofile1="";

string deflt = "c:\\dissertation\\ShiftandSubcipherC++files\\clean.txt";

string ifile2="";

string ofile2=""; //Holds selected file path names

string cmdarg; //Holds the command line argument

string stop="l"; //Gives the stop condition, assumes l

string reportfile = "c:\\dissertation\\test\\report.txt";

ofstream outs; //Declare an output stream for reporting

int digramc[676]; //Set up the digram array

int *two = digramc; //Point to the digram array

int dicount=0; //Holds the count of the number of digrams

int total=0; //Counts the total number of letters seen for analysis

for(loop=1;loop<argc;loop++) //Decide if we have arguments or must use defaults

{

if(!argv[1])

{

// cout << "No argument found.\n";

ifile1 = deflt;

}

else

{

cmdarg = argv[loop];

if(cmdarg=="-k")

{

loop++;

key = atoi(argv[loop]);

// cout << "key = " << key << endl;

}

if(cmdarg=="-l")

{

loop++;

len = atoi(argv[loop]);

// cout << "Run for " << len << " characters.\n";

}

if(cmdarg=="-m")

{

loop++;

m = atof(argv[loop]);

// cout << "Run until an error less than or equal to " << m << "\n";

}

if(cmdarg=="-off")

{

loop++;

off = atoi(argv[loop]);

// cout << "Start the analysis " << off << " characters into the file.\n";

}

if(cmdarg=="-stop")

{

loop++;

stop = argv[loop];

// cout << "Stop for " << stop << "\n";

}

if(cmdarg=="-i")

{

loop++;

ifile2 = argv[loop];

// cout << "Using input file " << ifile2 << "\n";

}

if(cmdarg=="-o")

{

loop++;

ofile2 = argv[loop];

// cout << "Using output file " << ofile2 << endl;

}

}

}

for(count=0;count<26;count++) //Initialize the frequency arrays to no count

{

singlefreq[count] = 0;

}

for(count=0;count<676;count++) //Initialize the digram array to no count

{

digramc[count] = 0;

}

createinput(ifile2, ofile2);

createcipher(key, ofile2, ofile2);

// cout << ofile2 << endl;

outs.open(reportfile.c_str(),ios::app); // Open the output stream as a binary input stream

if(outs.fail()) // If the input stream cannot open, report it then close the program

{

cerr << "\n\n ERROR - Cannot open " << reportfile << " for reading.\n";

// return EXIT_FAILURE; //failure return

}

else {

// std::cout << "\nOpened the file " << reportfile << ".\n";

}

// cout << "While " << mi << ">" << m << endl;

while(mi > m)

{

trimfile(ofile2,ofile2,off,len);

totalcnt = lettercount(single, ofile2, ofile2);

// cout << "Total count = " << totalcnt << "\n\n";

for(count=0;count<26;count++)

{

loopletter = 97 + count;

if(totalcnt==0) //Used the first time through the loop when totalcnt = 0

{

totalcnt++;

}

percent = (singlefreq[count]*100/totalcnt);

// cout << "For the letter " << loopletter << ", the count = " << setw(10) << setfill('-') << singlefreq[count]

// << " " << setw(4) << percent << "%" << endl;

total = total + singlefreq[count];

}

// cout << "Total number of letters analyzed " << setw(10) << setfill('-') << total << endl;

total = 0;

delta = singleton(single, 26);

final = delta;

delta = delta + 97;

// cout << endl << endl << "The letter E is most likely offset to " << char(delta) << endl;

if(final < 5)

{

final = final + 22;

}

else{

final = final - 4;

}

// cout << "This corresponds to a shift of " << final << "\n\n\n";

temp = float(countunique(single,26));

if(temp == 0) //Eliminates errors first time through the loop

{

temp = temp + 1;

}

mi = float(abs(final - key))/temp;

// cout << "mi = " << mi << " and m = " << m << endl;

// cout << "Testing for " << len << " letter(s). \n\n\n";

// outs << ifile2 << "," << off << "," << key << "," <<final << "," << len << "," << mi << "," << m << endl;

len++;

}

// cout << "Out of the loop\n\n";

// dicount=digram(two, ofile2);

outs << ifile2 << "," << key << "," << final << "," << len << "," << off << "," << m << endl;

outs.close();

return 0;

}

/*=================================================================================================================

Function createinput(ifile, ofile)

Created 9/25/2003

Function Overview: Takes in a text file and reads input data, removing all non-alphabetic characters. Here it

is assumed that the characters in the file are intended for use as the corpus of the cipher translation. All

spaces are removed, and then all instances of upper case letters are translated to lower case in order to make

the data consistant.

Variables used:

ch char Holds the character read in and manipulated for later use

count int Holds the count of the number of words read

table string Holds the value of in input variable for reading a file input

tablein string Holds the value of a string used for a file

outfile Holds the string value of an ouput file

singlefreq Holds the counts of letters in the file to be processed

single Pointer to the singlefreq structure

Functions called: None

===================================================================================================================*/

void createinput(string ifile, string ofile)

{

char ch;

int val = 1;

int count = 0;

// Give the default location of the file containing the data to be read in

string table = "c:\\dissertation\\data.txt"; // Set up a default file for input

string tablein;

string outfile = "c:\\dissertation\\out.txt"; // Set up a default file for output

ifstream ins; // Declare ins an input stream

ofstream outs; // Declare outs and output stream

// cout << "In createinput\n";

if(ifile!="")

{

// cout << "Forming the filename with exenteder\n";

tablein = ifile + ".txt";

// cout << "Creating clean file from " << tablein << endl;

}

else

{

tablein = "i";

}

if(tablein != "i")

{

table = tablein;

}

ins.open(table.c_str(),ios::binary); // Open the input stream as a binary input stream

if(ins.fail()) // If the input stream cannot open, report it then close the program

{

cerr << "\n\n ERROR - Cannot open " << table << " for reading.\n";

// return EXIT_FAILURE; //failure return

}

else {

// std::cout << "\nOpened the file " << table << ".\n";

}

// cout << "Have ofile as " << ofile << endl;

if(ofile!="")

{

outfile = ofile + "\\out.txt";

// cout << "Creating outfile as " << outfile << endl;

}

outs.open(outfile.c_str(),ios::binary); // Open the output stream as a binary input stream

if(outs.fail()) // If the input stream cannot open, report it then close the program

{

cerr << "\n\n ERROR - Cannot open " << outfile << " for reading.\n";

// return EXIT_FAILURE; //failure return

}

else {

// std::cout << "\nOpened the file " << outfile << ".\n";

}

ins >> ch;

// cout << ch; //<< "\n";

while(!ins.eof()){

if(((ch >= 65) && (ch < 91)) || ((ch >= 97) && (ch < 123))) //Check if this is an alpha character

{

if((ch >= 65) && (ch < 91))

{

ch = ch + 32;

}

// std::cout << ch; // << "\n";

outs << ch;

count++;

}

// std::cout << count << "\n";

ins >> ch;

};

// std::cout << "\n\nFinal charater count = " << count <<"\n\n\n";

ins.close(); // Close the input stream

// cout << "\nClosed input file " << table << ".\n";

outs.close(); // Close the output file stream

// cout << "\nClosed output file " << outfile << ".\n\n\n";

}

/*=================================================================================================================

Function createcipher(int key, string ifile, string ofile)

Created 9/25/2003

Function Overview: Takes a text input file and translates it into a Ceaser Cipher output that is shifted by

modulo 26 of the input value.

Variables used:

ch char Holds the character read in and manipulated for later use

offset int Holds the modulo offset for encoding

val int Used as a flag for a while loop

table string Holds the value of in input variable for reading a file input

tablein string Holds the value of a string used for a file

outfile Holds the string value of an ouput file

Functions called: None

===================================================================================================================*/

void createcipher(int key, string ifile, string ofile)

{

unsigned char ch; //Unsigned because going over 128 in ASCII during a calculation results in a negative number

// and the ASCII number will then appear as negative if the offset added to the letter

// representation is greater than 127 Hex.

int offset;

int val = 0;

// cout << "Read in a key value of: " << key << endl;

// Give the default location of the file containing the data to be read in

string table = "c:\\dissertation\\out.txt"; // Set up a default file for input

string tablein;

string outfile = "c:\\dissertation\\cipher.txt"; // Set up a default file for output

string keys;

ifstream ins; // Declare ins an input stream

ofstream outs; // Declare outs and output stream

// cout << "In createcipher\n";

if(ifile!="")

{

tablein = ifile + "\\out.txt";

}

else

{

tablein = "i";

}

if(tablein != "i")

{

table = tablein;

}

ins.open(table.c_str(),ios::binary); // Open the input stream as a binary input stream

if(ins.fail()) // If the input stream cannot open, report it then close the program

{

cerr << "\n\n ERROR - Cannot open " << table << " for reading.\n";

// return EXIT_FAILURE; //failure return

}

else {

// std::cout << "\nOpened the file " << table << ".\n";

}

if(ofile!="")

{

outfile = ofile + "\\cipher" + ".txt";

}

outs.open(outfile.c_str(),ios::binary); // Open the output stream as a binary input stream

if(outs.fail()) // If the input stream cannot open, report it then close the program

{

cerr << "\n\n ERROR - Cannot open " << outfile << " for reading.\n";

// return EXIT_FAILURE; //failure return

}

else {

// std::cout << "\nOpened the file " << outfile << ".\n";

}

if(key==-1)

{

while(val == 0)

{

cout << "\n\nPlease input the shift for the cipher (from 1 to 25): ";

cin >> offset;

if((offset >= 1) && (offset < 26))

{

cout << "\n\nYou have entered an offset of " << offset << ".\n\n\n";

val = 1;

}

else

{

cout << "You have entered an invalid number, you will be prompted again for the right input value.\n";

}

};

}

else

{

offset = key;

}

ins >> ch;

ch = ch + offset;

// cout << ch; //<< "\n";

while(!ins.eof()){

if(ch > 'z') //Check if this is an alpha character

{

ch = ch - 26;

// cout << ch;

}

// std::cout << ch << " " << int(ch) << " " << offset <<" " << ch+offset <<" ;"; // << "\n";

outs << ch;

ins >> ch;

ch = ch + offset;

};

ins.close(); // Close the input stream

// cout << "\n\nClosed input file " << table << ".\n";

outs.close(); // Close the output file stream

// cout << "\nClosed output file " << outfile << ".\n\n\n";

}

/*=================================================================================================================

Function lettercount(int *pointer)

Created 9/25/2003

Function Overview: Takes an input file and counts all of the letters that are found in the file. This function

assumes that the input file contains ONLY ASCII values for lower case letters. It uses a

pointer that directs the function to the first storage location of an array that will

contain slots for each character in the alphabet. It then reads in each value and increments

the counter for each letter as it recognizes the letter. Note that the offset of the letter

read from 'a' is calculated and used as the array index.

Variables used:

char target Holds the character read in and manipulated for later use

offset int Holds the array offset for incrementing the count in the array

lettercount int Contains the total number of letters in the file

pointer int* Points to the location of the array for letter counts

table string Holds the value of in input variable for reading a file input

tablein string Holds the value of a string used for a file

outfile Holds the string value of an ouput file

Functions called: None

Notes: Lower case letters are found from ASCII 97 ('a') to ASCII 122 ('z')

===================================================================================================================*/

int lettercount(int *pointer, string ifile, string ofile)

{

int lettercount=0;

int offset;

char target;

// Give the default location of the file containing the data to be read in

string table = "c:\\dissertation\\cipher.txt"; // Set up a default file for input

string tablein;

// string outfile = "c:\\dissertation\\cipher.txt"; // Set up a default file for output

ifstream ins; // Declare ins an input stream

// ofstream outs; // Declare outs and output stream

// cout << "In lettercount\n";

if(ifile!="")

{

tablein = ifile + "\\newcipher.txt";

}

else

{

tablein = "i";

}

if(tablein != "i")

{

table = tablein;

}

// cout << "Counting from the file " << table << endl;

ins.open(table.c_str(),ios::binary); // Open the input stream as a binary input stream

if(ins.fail()) // If the input stream cannot open, report it then close the program

{

cerr << "\n\n ERROR - Cannot open " << table << " for reading.\n";

// return EXIT_FAILURE; //failure return

}

else {

// std::cout << "\n\nOpened the file " << table << ".\n";

}

ins>>target;

while(!ins.eof())

{

// cout << target << "\n";

lettercount = lettercount + 1;

offset = target - 97;

// cout << offset << endl;

pointer[offset]++;

// cout << pointer[offset] << endl;

ins>>target;

};

// cout << "Total " << setw(7) << setfill('-') << lettercount << endl;

ins.close();

// cout << lettercount << endl;

return lettercount;

}

/*=================================================================================================================

Function singleton(int *pointer, int size)

Created 9/25/2003

Function Overview: Takes an input array and finds the greatest count from among the input values. This function

will input an arbitrary sized array and goes from the first location, pointed to by the pointer

and successively checks each value. It runs in order n time.

Variables used:

loop int Holds the loop count

highest int Holds the highest count found in the array

tempcnt int Contains the number read by the count going through the array at that time

pointer int* Points to the location of the array for counts

offset int Holds the value of the letter what was found to have the highest count.

Functions called: None

Notes: Lower case letters are found from ASCII 97 ('a') to ASCII 122 ('z')

===================================================================================================================*/

int singleton(int *letter, int size)

{

int loop = 0;

int highest = 0; //Holds the highest letter count to date in the loop

int tempval = 0; //Holds the present value for the letter count

int offset = 0; //Holds the letter offset for the highest value

/* Loop from the first spot in the array to the final spot, as given by size,

and check the value of the letter frequency for that particular encoded letter.

If the value is the highest yet seen, then record that value and the offset.

*/

for(loop=0;loop<size;loop++)

{

tempval = letter[loop];

if(tempval > highest)

{

highest = tempval;

offset = loop;

}

}

return offset;

}

/*=================================================================================================================

Function digram(pointer, ifile)

Created 9/25/2003

Function Overview:

Variables used:

ch char Holds the character read in and manipulated for later use

Functions called: None

===================================================================================================================*/

int digram(int *pointer, string ifile)

{

int lettercount=0;

int offset1, offset2;

int index;

int let1offset,let2offset;

char target;

char target2;

// Give the default location of the file containing the data to be read in

string table = "c:\\dissertation\\cipher.txt"; // Set up a default file for input

string tablein;

// string outfile = "c:\\dissertation\\cipher.txt"; // Set up a default file for output

ifstream ins; // Declare ins an input stream

// ofstream outs; // Declare outs and output stream

// cout << "In digram\n";

if(ifile!="")

{

tablein = ifile + "\\cipher.txt";

}

else

{

tablein = "i";

}

if(tablein != "i")

{

table = tablein;

}

ins.open(table.c_str(),ios::binary); // Open the input stream as a binary input stream

if(ins.fail()) // If the input stream cannot open, report it then close the program

{

cerr << "\n\n ERROR - Cannot open " << table << " for reading.\n";

// return EXIT_FAILURE; //failure return

}

else {

// std::cout << "\n\nOpened the file " << table << ".\n";

}

ins>>target;

ins>>target2;

// cout << target << target2;

while(!ins.eof())

{

// cout << target << "\n";

lettercount = lettercount + 1;

// offset = target - 97;

// cout << offset << endl;

// pointer[offset]++;

// cout << pointer[offset] << endl;

target = target2;

ins>>target2;

offset1 = target - 97;

offset2 = target2 - 97;

index = (offset1*26) + offset2;

// cout << target << target2 << endl;

// cout << offset1 << " " << offset2 << " " << index << endl;

pointer[index]++;

};

ins.close();

// cout << lettercount << endl;

/* for(offset1=0;offset1<677;offset1++)

{

target2 = (offset1 % 26) + 97;

target = ((offset1 - target2 - 97)/26) + 97;

cout << "Number of " << target << target2 << " = " << pointer[offset1] << endl;

}

*/

cout << "\n\n";

offset2 = singleton(pointer,676);

// cout << offset2 << endl << endl;

let2offset = (offset2 % 26);

let1offset = ((offset2 - let2offset))/26;

if(let1offset < 19)

{

let1offset = let1offset + 7;

}

else

{

let1offset = let1offset - 19;

}

if(let2offset < 8)

{

let2offset = let2offset + 19;

}

else

{

let2offset = let2offset - 7;

}

// cout << "Calculated the first digram letter offset to be " << let1offset << endl;

// cout << "Calculated the second digram letter offset to be " << let2offset << endl << endl;

return lettercount;

}

/*=================================================================================================================

Function countunique(*array, size)

Created 8/4/05

Function Overview: Counts the number of unique elements stored in an array of size 'size' located at 'array'.

Each non zero count indicates that an element exists.

Variables used:

Name Type Use

------ ---- ------------------------------------------------------------------------------------------------

*array int Points to the location of the array in memory

size int The size of the array for counting

cnt int The number of non zero array locations (and hence the number of unique elements seen)

loop int An internal loop counter

Functions called: None

===================================================================================================================*/

int countunique(int *array, int size)

{

int cnt=0; //Number of unique letters seen

int loop; //Loop counter

for(loop=0;loop<size;loop++)

{

if(array[loop]>0)

{

cnt++;

}

}

return cnt;

}

/*=================================================================================================================

Function trimfile(ifile, ofile, offset, size)

Created 8/4/05

Function Overview: Reads in a file, then trims the file starting at the 'offset' for 'size' characters and puts

the result in ofile.

Variables used:

Name Type Use

------ ---- ------------------------------------------------------------------------------------------------

cnt int A loop counter

ifile string Holds the input file path

letter char Holds the letter read from the input file

loop int A loop counter

offset int Holds the offset for the first letter of the resulting file

ofile string Holds the output file path

size int Holds the size of the final file, in symbols

Functions called: None

===================================================================================================================*/

void trimfile(string ifile, string ofile, int offset, int size)

{

int loop, cnt; //Loop counters

char letter; //Holds the letter from the input file

string cutfile; //The file to cut

string finalfile; //The final cut from the file

ifstream ins; //Declare the input stream

ofstream outs; //Declare an output stream

// cout << "In trimfile\n";

cutfile = ifile + "\\cipher.txt";

finalfile = ofile + "\\newcipher.txt";

// cout << ifile << " " << ofile << endl << endl;

// cout << cutfile << " " << finalfile << endl;

ins.open(cutfile.c_str(),ios::binary); // Open the input stream as a binary input stream

if(ins.fail()) // If the input stream cannot open, report it then close the program

{

cerr << "\n\n ERROR - Cannot open " << cutfile << " for reading.\n";

// return EXIT_FAILURE; //failure return

}

else {

// std::cout << "\n\nOpened the file " << cutfile << ".\n";

}

outs.open(finalfile.c_str(),ios::binary); // Open the output stream as a binary input stream

if(outs.fail()) // If the input stream cannot open, report it then close the program

{

cerr << "\n\n ERROR - Cannot open " << finalfile << " for reading.\n";

// return EXIT_FAILURE; //failure return

}

else {

// std::cout << "\nOpened the file " << finalfile << ".\n";

}

for(cnt=0;cnt<offset;cnt++)

{

// cout << cnt << endl;

ins >> letter;

// outs<< letter;

}

if(size!=-1)

{

for(loop=0;loop<size;loop++)

{

ins >> letter;

outs << letter;

// cout << cnt << " " << loop << " " << letter << endl;

}

}

else

{

while(!ins.eof())

{

ins >> letter;

outs << letter;

}

}

ins.close();

outs.close();

}

/*=================================================================================================================

Function name(i/o list)

Created date

Function Overview: Takes in a text file and reads input data, removing all non-alphabetic characters. Here it

is assumed that the characters in the file are intended for use as the corpus of the cipher translation. All

spaces are removed, and then all instances of upper case letters are translated to lower case in order to make

the data consistant.

Variables used:

Name Type Use

------ ---- ------------------------------------------------------------------------------------------------

Functions called: None

===================================================================================================================*/