diff --git a/Headers/Playfair.hpp b/Headers/Playfair.hpp new file mode 100644 index 0000000..07fc81e --- /dev/null +++ b/Headers/Playfair.hpp @@ -0,0 +1,50 @@ +//Ciphers/Headers/Playfair.hpp +//Matthew Ellison +// Created: 4-25-18 +//Modified: 4-25-18 +//This file contains the declaration of the Playfair class +//It is designed to encrypt and decrypt strings using the Playfair cipher + + +#ifndef PLAYFAIR_HPP +#define PLAYFAIR_HPP + +#include + + +class Playfair{ +private: + static char REPLACED; //The letter that will need to be replaced in the grid and any input string or keyword + static char REPLACER; //The letter that replaced REPLACED in any input string or keyword + static char DOUBLED; //The letter that will be placed between double letters in the input string if necessary or to make the string length even + std::string inputString; + std::string outputString; + std::string keyword; + char grid[5][5]; + void createGrid(); + bool checkGrid(const char letter) const; + void searchGrid(char letter, int& row, int& col); +public: + Playfair(); + ~Playfair(); + void reset(); + std::string encode(); + std::string encode(std::string keyword, std::string input); + std::string decode(); + std::string decode(std::string keyword, std::string input); + void setKeyword(std::string key); + std::string getKeyword() const; + void setInputString(std::string input); + std::string getInputString() const; + std::string getOutputString() const; + std::string getGrid() const; + //Change static variables + static char getReplaced(); + static void setReplaced(const char replaced); + static char getReplacer(); + static void setReplacer(const char replacer); + static char getDoubled(); + static void setDoubled(const char doubled); +}; + +#endif //PLAYFAIR_HPP diff --git a/SourceFiles/Playfair.cpp b/SourceFiles/Playfair.cpp new file mode 100644 index 0000000..a5cfa7a --- /dev/null +++ b/SourceFiles/Playfair.cpp @@ -0,0 +1,394 @@ +//Ciphers/Headers/Playfair.cpp +//Matthew Ellison +// Created: 4-25-18 +//Modified: 4-25-18 +//This file contains the implementation of the Playfair class +//It is designed to encrypt and decrypt strings using the Playfair cipher + + +#include "../Headers/Playfair.hpp" +#include +#include +#include + +char Playfair::REPLACED = 'J'; +char Playfair::REPLACER = 'I'; +char Playfair::DOUBLED = 'X'; + +Playfair::Playfair(){ + reset(); +} + +Playfair::~Playfair(){ +} + +void Playfair::createGrid(){ + unsigned int row, column; + bool found = false; + row = column = 0; + + //Add any new leters from the keyword to the grid + ///If you reach row 5 then the entire grid has been filled + char current; + for(int cnt = 0;(cnt < keyword.size()) && (row < 5);++cnt){ + current = keyword[cnt]; + //If the current letter needs to be replaced, do so + if(current == REPLACED){ + current = REPLACER; + } + + //Search the grid for the current letter + found = checkGrid(current); + + //If the letter is not in the grid add it + if(!found){ + grid[row][column] = keyword[cnt]; + ++column; + //If the column number is too high reset it and advance the row + if(column >= 5){ + column = 0; + ++row; + } + } + } + + //Until you reach the end of the grid you need to start with the first letter and try to add them to the grid + current = 'A'; + while((row < 5) && (current <= 'Z')){ + ////Start here + //Make sure the is not the replaced letter + if(current == REPLACED){ + ++current; + } + + //Check the grid for the current letter + found = checkGrid(current); + + //If the letter was not found in the grid add it to the current location + if(!found){ + grid[row][column] = current; + ++column; + //If you have reached the end of the row move to the beginning of the next one + if(column >= 5){ + column = 0; + ++row; + } + } + ++current; + } + //Put a check here that row == 5. If it doesn't then there is a problem + ///Make this a propper exception throw rather than this + if(row != 5){ + std::cout << "There is a problem with the grid!\n" << getGrid() << std::endl;; + } +} + +bool Playfair::checkGrid(const char letter) const{ + //Step through every element in the grid and check for it + for(int rowCnt = 0;rowCnt < 5;++rowCnt){ + for(int colCnt = 0;colCnt < 5;++colCnt){ + //If you find the letter in the grid return true + if(letter == grid[rowCnt][colCnt]){ + return true; + } + //If you reach a \0 then there are no more symbols past that and no reason to continue checking + else if(grid[rowCnt][colCnt] == '\0'){ + return false; + } + } + } + //If it did not trigger the true, then it must be false + return false; +} + +void Playfair::searchGrid(char letter, int& row, int& col){ + ////Start here + //Check if letter needs to be replaced + if(letter == REPLACED){ + letter = REPLACER; + } + + //Go through every element in the grid until you find the correct letter + for(row = 0;row < 5;++row){ + for(col = 0;col < 5;++col){ + //If it is the correct letter you just need to return (row and col are passed by reference) + if(grid[row][col] == letter){ + return; + } + } + } + + //If letter was not found you need to throw an error + ///Turn this into a propper exception throw rather than this + std::cout << "Error in searchGrid()\nLetter: " << letter << "\n\n" << getGrid() << std::endl; +} + +void Playfair::reset(){ + inputString = outputString = keyword = ""; + //Clear the grid + for(int cnt1 = 0;cnt1 < 5;++cnt1){ + for(int cnt2 = 0;cnt2 < 5;++cnt2){ + grid[cnt1][cnt2] = '\0'; + } + } +} + +std::string Playfair::encode(){ + outputString = ""; + char letter1, letter2; + int row1, col1, row2, col2; + //Step through every element in the input string and encode a pair + for(int cnt = 1;cnt < inputString.size();cnt += 2){ + //Grab two elements from the input string and search the grid for them + letter1 = inputString[cnt - 1]; + letter2 = inputString[cnt]; + + //Get the location in the grid of each letter + searchGrid(letter1, row1, col1); + searchGrid(letter2, row2, col2); + + //If the letters are in the same row, shift the column right by 1 + if(row1 == row2){ + ++col1; + ++col2; + + //Wrap around + if(col1 > 4){ + col1 -= 5; + } + if(col2 > 4){ + col2 -= 5; + } + } + //If the letters are in the same column, shift the row down by 1 + else if(col1 == col2){ + ++row1; + ++row2; + + //Wrap around + if(row1 > 4){ + row1 -= 5; + } + if(row2 > 4){ + row2 -= 4; + } + } + //If neither of the above then treat them like oposite corners in a square and swap their column variables + else{ + std::swap(col1, col2); + } + + //Get the new letters + letter1 = grid[row1][col1]; + letter2 = grid[row2][col2]; + //Add the new strings to the outputString + outputString += letter1; + outputString += letter2; + } + + return outputString; +} + +std::string Playfair::encode(std::string keyword, std::string input){ + setKeyword(keyword); + setInputString(input); + return encode(); +} + +std::string Playfair::decode(){ + outputString = ""; + char letter1, letter2; + int row1, col1, row2, col2; + //Step through every element in the input string and encode a pair + for(int cnt = 1;cnt < inputString.size();cnt += 2){ + //Grab two elements from the input string and search the grid for them + letter1 = inputString[cnt - 1]; + letter2 = inputString[cnt]; + + //Get the location in the grid of each letter + searchGrid(letter1, row1, col1); + searchGrid(letter2, row2, col2); + + //If the letters are in the same row, shift the column left by 1 + if(row1 == row2){ + --col1; + --col2; + + //Wrap around + if(col1 > 4){ + col1 += 5; + } + if(col2 > 4){ + col2 += 5; + } + } + //If the letters are in the same column, shift the row up by 1 + else if(col1 == col2){ + --row1; + --row2; + + //Wrap around + if(row1 > 4){ + row1 += 5; + } + if(row2 > 4){ + row2 += 4; + } + } + //If neither of the above then treat them like oposite corners in a square and swap their column variables + else{ + std::swap(col1, col2); + } + + //Get the new letters + letter1 = grid[row1][col1]; + letter2 = grid[row2][col2]; + //Add the new strings to the outputString + outputString += letter1; + outputString += letter2; + } + + return outputString; +} + +std::string Playfair::decode(std::string keyword, std::string input){ + setKeyword(keyword); + setInputString(input); + return decode(); +} + +void Playfair::setKeyword(std::string key){ + //Make sure the keyword is blank + keyword = ""; + //Remove all punctuation and make everything capital + for(int cnt = 0;cnt < key.size();++cnt){ + //If it is an upper case letter, just add it to the keyword + if(isupper(key[cnt])){ + keyword += key[cnt]; + } + //If it is a lower case letter, make it upper case and add it to the keyword + else if(islower(key[cnt])){ + keyword += toupper(key[cnt]); + } + //If it is not a letter, then just ignore it + } + //Create the grid from the new keyword + createGrid(); +} + +std::string Playfair::getKeyword() const{ + return keyword; +} + +void Playfair::setInputString(std::string input){ + //Make sure inputString is empty + inputString = ""; + //Remove all punctuation and make everything capital + for(int cnt = 0;cnt < input.size();++cnt){ + char temp = input[cnt]; + if(isupper(temp)){ + //If the letter is the character than needs replaced, replace it + if(temp == REPLACED){ + temp = REPLACER; + } + inputString += temp; + } + else if(islower(temp)){ + temp = toupper(temp); + //If the letter is the character than needs replaced, replace it + if(temp == REPLACED){ + temp = REPLACER; + } + inputString += temp; + } + //If it is not a letter do nothing to it + } + + //Check if anything is doubled and needs bumped down by DOUBLED + for(int cnt = 1;cnt < inputString.size();){ + char letter1, letter2; + //Get two adjacent letters and compare them + letter1 = inputString[cnt - 1]; + letter2 = inputString[cnt]; + //If they are the same insert DOUBLED between them + if(letter1 == letter2){ + inputString.insert((inputString.begin() + cnt), DOUBLED); + } + //If they are not the same, do nothing + + //Advance the counter by 2 + cnt += 2; + } + + //Check if the string length is odd and add DOUBLED to the end if it is + if((inputString.size() % 2) == 1){ + inputString += DOUBLED; + } +} + +std::string Playfair::getInputString() const{ + return inputString; +} + +std::string Playfair::getOutputString() const{ + return outputString; +} + +std::string Playfair::getGrid() const{ + std::string temp; + for(int row = 0;row < 5;++row){ + for(int col = 0;col < 5;++col){ + temp += grid[row][col] + " "; + } + temp += '\n'; + } + return temp; +} + +char Playfair::getReplaced(){ + return REPLACED; +} + +void Playfair::setReplaced(const char replaced){ + //Make sure the letter is in the correct range + if(replaced >= 'A' && replaced <= 'Z'){ + //Make sure the letter is not the same as the one that is replacing it + if(replaced != REPLACER){ + REPLACED = replaced; + } + } + else if(replaced >= 'a' && replaced <= 'z'){ + REPLACED = toupper(replaced); + } +} + +char Playfair::getReplacer(){ + return REPLACER; +} + +void Playfair::setReplacer(const char replacer){ + //Make sure the letter is in the correct range + if(replacer >= 'A' && replacer <='Z'){ + //Make sure the letter is not the same as the one that it is replacing + if(replacer != REPLACED){ + REPLACER = replacer; + } + } + else if(replacer >= 'a' && replacer <= 'z'){ + REPLACER = toupper(replacer); + } +} + +char Playfair::getDoubled(){ + return DOUBLED; +} + +void Playfair::setDoubled(const char doubled){ + //Make sure the letter is in the correct range + if(doubled >= 'A' && doubled <= 'Z'){ + DOUBLED = doubled; + } + else if(doubled >= 'a' && doubled <= 'z'){ + DOUBLED = toupper(doubled); + } +} diff --git a/main.cpp b/main.cpp index f7e4300..5b005b3 100644 --- a/main.cpp +++ b/main.cpp @@ -18,7 +18,7 @@ #ifdef TEST_VERSION #define CAESAR_TEST -//#define PLAYFAIR_TEST +#define PLAYFAIR_TEST enum codingState { ENCODE, DECODE }; std::string testingError(codingState type, const std::string& input, const std::string& output, const std::string& cipher); #endif //TEST_VERSION definition @@ -50,6 +50,7 @@ int main(int argc, char** argv){ else{ resultString += "Caesar Cipher error:\n" + errorString; } + std::cout << "Test1: " << resultString << std::endl; //Reset the variables errorString = ""; testResult = false; @@ -173,7 +174,35 @@ bool caesarTest(std::string& errorString){ #ifdef PLAYFAIR_TEST bool playfairTest(std::string& errorString){ + bool passed = true; + std::string keyword, inputString, outputString, cipherString; + Playfair cipher; + //Test from wikipedia + keyword = "Playfair Example"; + inputString = "Hide the gold in the tree stump"; + outputString = "BMODZBXDNABEKUDMUIXMMOUVIF"; + //Setup the cipher + cipherString = cipher.encode(keyword, inputString); + //If the cipher didn't spit out the correct string throw an error + if(cipherString != outputString){ + errorString += testingError(ENCODE, inputString, outputString, cipherString); + passed = false; + } + //This removes the spaces and turns everything capital so the reverse will work correctly + inputString = cipher.getInputString(); + + //Do the same thing in reverse + cipher.reset(); + cipherString = cipher.decode(keyword, outputString); + //If the cipher didn't spit out the correct string throw an error + if(cipherString != inputString){ + errorString += testingError(DECODE, outputString, inputString, cipherString); + passed = false; + } + + //Return if the cipher passed the tests + return passed; } #endif //PLAYFAIR_TEST @@ -185,7 +214,7 @@ enum CipherFlagLocation { CAESAR, PLAYFAIR }; void getFlags(bool flags[]); int main(int argc, char** argv){ - + //Add the ability to input and output files with the appropriate strings } void getFlags(bool flags[]){ diff --git a/makefile b/makefile index fc0adde..17bfb8e 100644 --- a/makefile +++ b/makefile @@ -14,6 +14,7 @@ libPlayfair.a: SourceFiles/Playfair.cpp Ciphers: main.cpp (CXX) -O3 -std=c++11 -o $@ $< -lCaesar -lPlayfair +#Linux libCaesar.lib: SourceFiles/Caesar.cpp g++ -shared -std=c++11 -O3 -fPIC -o $@ $<