Added Playfair Cipher

This commit is contained in:
2018-04-28 12:33:27 -04:00
parent 3503a42e77
commit 0b85e0b9f3
4 changed files with 476 additions and 2 deletions

50
Headers/Playfair.hpp Normal file
View File

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

394
SourceFiles/Playfair.cpp Normal file
View File

@@ -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 <string>
#include <cctype>
#include <iostream>
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);
}
}

View File

@@ -18,7 +18,7 @@
#ifdef TEST_VERSION #ifdef TEST_VERSION
#define CAESAR_TEST #define CAESAR_TEST
//#define PLAYFAIR_TEST #define PLAYFAIR_TEST
enum codingState { ENCODE, DECODE }; enum codingState { ENCODE, DECODE };
std::string testingError(codingState type, const std::string& input, const std::string& output, const std::string& cipher); std::string testingError(codingState type, const std::string& input, const std::string& output, const std::string& cipher);
#endif //TEST_VERSION definition #endif //TEST_VERSION definition
@@ -50,6 +50,7 @@ int main(int argc, char** argv){
else{ else{
resultString += "Caesar Cipher error:\n" + errorString; resultString += "Caesar Cipher error:\n" + errorString;
} }
std::cout << "Test1: " << resultString << std::endl;
//Reset the variables //Reset the variables
errorString = ""; errorString = "";
testResult = false; testResult = false;
@@ -173,7 +174,35 @@ bool caesarTest(std::string& errorString){
#ifdef PLAYFAIR_TEST #ifdef PLAYFAIR_TEST
bool playfairTest(std::string& errorString){ 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 #endif //PLAYFAIR_TEST
@@ -185,7 +214,7 @@ enum CipherFlagLocation { CAESAR, PLAYFAIR };
void getFlags(bool flags[]); void getFlags(bool flags[]);
int main(int argc, char** argv){ int main(int argc, char** argv){
//Add the ability to input and output files with the appropriate strings
} }
void getFlags(bool flags[]){ void getFlags(bool flags[]){

View File

@@ -14,6 +14,7 @@ libPlayfair.a: SourceFiles/Playfair.cpp
Ciphers: main.cpp Ciphers: main.cpp
(CXX) -O3 -std=c++11 -o $@ $< -lCaesar -lPlayfair (CXX) -O3 -std=c++11 -o $@ $< -lCaesar -lPlayfair
#Linux
libCaesar.lib: SourceFiles/Caesar.cpp libCaesar.lib: SourceFiles/Caesar.cpp
g++ -shared -std=c++11 -O3 -fPIC -o $@ $< g++ -shared -std=c++11 -O3 -fPIC -o $@ $<