简体   繁体   中英

c++ caesar cipher decoding trouble

I'm trying to implement a program that reads a text file that has a caesar cipher encryption. My program's purpose is to decode it. With my code it only reads the file and doesnt decode anything. Where am I going wrong? It echoprints the file but it doesnt decode it. I think my logic is flawed at the end of the CaesarCipher function

#include <iostream>         //for standard I/O
#include <fstream>          //necessary for file input
#include <string>           //necessary for fileName input

using namespace std;

void PrintHeading ();           //prototype for printing the initial heading
char PrintMenu ();              //prototype for printing menu and gaining user's choice
void OpenFile (ifstream &);     //prototype for opening file
void CaesarCipher (ifstream &); //prototype for performing a caesar decryption
//void SubCipher (ifstream &);  //prototype for performing a substitution decryption

const int ALPHA_SIZE = 26;
typedef char AlphaArray[ALPHA_SIZE];        //alphabet array with 26 elements
AlphaArray realAlphas;
AlphaArray encryptionArray;
ifstream inFile;



int main()
{
char choice;            //menu choice from user
ifstream inFile;        //opens file
string fileName;        //user inputs name of file
bool condition = true;

PrintHeading();         // prints heading

while(condition)
{
    choice = PrintMenu();       //passes choice to printMenu function
    switch(choice)
    {
        case 'C':                           //choice for caesar substitution
        case 'c': cout << choice << endl;
            OpenFile(inFile);
            CaesarCipher (inFile);
            break;
        case 'S':                           //choice for substitution cipher
        case 's': cout << choice << endl;
            OpenFile(inFile);
            //SubCipher(inFile);
            break;
        case 'Q':                           //choice for quitting the program
        case 'q': condition = false;        //prints closing message when false
            cout << "***********************************************" << endl
                 << "\tThank you for using the DECRYPTER!" << endl
                 << "***********************************************" << endl << endl;
            break;
        default:
            //default statement for incorrect input
            cout << "Not a valid choice. Try again." << endl;
            break;
    }

}

return 0;
}

void PrintHeading ()    //prints heading for decryption program
{
cout << "***********************************************" << endl
     << "\t Welcome to The DECRYPTER!\t\t" << endl
     << endl
     << " You have the option of performing either a" << endl
     << "\t  Caesar decryption or " << endl
     << "\t  a Substitution decryption" << endl
     << endl
     << " You will be asked for a file to be decoded." << endl
     << endl
     << " The DECRYPTER will then echoprint one line " << endl
     << " of your encoded text from your specified file" <<endl
     << " followed by the same text decoded." << endl << endl
     << "***********************************************" << endl
     << endl
     << endl;
}

char PrintMenu ()       //function for displaying menu and gathering user's input
{
char userChoice;    //menu choice from user

//menu for user input
cout << "What would you like to do?" << endl
     << "To decode a text file using the Caesar cipher, press c" << endl
     << "To decode a text file using the substitution cipher, press s" << endl
     << "To quit decoding, press q" << endl
     << "What is your selection ? ";
cin >> userChoice;

while(userChoice != 'C' && userChoice != 'c' && userChoice != 'S' && userChoice != 's' && userChoice != 'Q' && userChoice != 'q')
{
    cout << "Please re-enter a valid menu choice: ";    //prompts user to input choice until it is valid
    cin >> userChoice;
}

return userChoice;              //return user's menu choice
}

void OpenFile (ifstream & infile)
{
string fileName;                //file input from user
cout << endl;
cout << "Please enter the file name to decode -> " << endl;      //asks for file name from user
cin >> fileName;                                                 //user file name
inFile.clear();
inFile.open(fileName.c_str());


while (!inFile)     //loop for if file doesnt exist
{
    cout << "File doesn't exist. Try again: " << endl;
    cin >> fileName;
 
void CaesarCipher (ifstream & infile)
{
char ch, temp;
for (int i = 0; i < 26; i++)
{
    realAlphas[i] = 65 + i;
}

int caesarConstant = 4;
for (int i = 0; i < 26; i++)
{
    encryptionArray[i] = realAlphas[(i + caesarConstant) % ALPHA_SIZE];
}

cout << "Original alphabet: " << realAlphas << endl;
cout << "Encrypted alphabet: " << encryptionArray << endl;
cout << endl;


int i;
while (inFile)
{
    if (!inFile.eof())
    {
        ch = inFile.get();
        cout << ch;
        for (i = 0; i < 26; i++)
        {
            encryptionArray[i] = realAlphas[i];
        }
        if (islower(encryptionArray[i]))
        {
            encryptionArray[i] = (encryptionArray[i] - 'a' + caesarConstant) % 26 + 'a';
        } else if (isupper(encryptionArray[i])) {
            encryptionArray[i] = (encryptionArray[i] - 'A' + caesarConstant) % 26 + 'A';
        }

    }
}


}

For a Caesar Cipher decoding, you'll need to subtract to produce the original character.

char decrypt(char c)
{
    static const std::string lower_case_alphabet = "abcdefghijklmnopqrstuvwxyz";
    static const std::string upper_case_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    std::string::size_type position = lower_case_alphabet.find(c);
    if (position == std::string::npos)
    {
       // character is not lower case.
       position = upper_case_alphabet.find(c);
       if (position == std::string::npos)
       {
          return c;
       }
       else
       {
           static const unsigned int alphabet_size = upper_case_alphabet.size();
           char decrypted = ((c + alphabet_size) - ENCRYPTION_KEY) % alphabet_size;
           decrypted = upper_case_alphabet[decrypted];
           return decrypted;
       }
   }
   static const unsigned int alphabet_size = lower_case_alphabet.size();
   char decrypted = ((c + alphabet_size) - ENCRYPTION_KEY) % alphabet_size;
   decrypted = lower_case_alphabet[decrypted];
   return decrypted;
}

In the above code, I add the alphabet size, before subtraction. The modulo operation behaves like a circle and angles.

Note:

  1. The alphabets are declared as static const because there is only one instance ( static ) and they are read-only ( const ). This helps the compiler optimize the code and storage.

  2. I believe using alphabets are more portable than assuming ASCII encoding (eg 65). You can easily change the alphabet without changing the code and function works the same.

Here's a complete program that does both the encryption and decryption in order to verify that after encrypting and then decrypting it back, we get the same file back.

#include <fstream>
#include <iostream>
#include <string>

int main(int, char*[])
{
    //Create a dummy file to test the algo
    std::ofstream test("test.txt");
    if(!test.is_open()) {
        std::cout<<"failed to open test.txt";
    }
    test<<"  THis Is A tEst fILez\n";
    test.close();

    //Now open the file for operation
    std::fstream file("test.txt");
    if(!file.is_open()) {
        std::cout<<"Error\n";
        return -1;
    }
    std::string line;

    //Verify Contents
    // std::cout<<"Initial contents of the file\n";
    file.clear();
    file.seekg(0);
    while(std::getline(file>>std::ws, line)) {
        std::cout<<line<<'\n';
    }

    const int CAESAR_CONSTANT = 2;
    char readChar;

    //Encryption
    file.clear();
    file.seekg(0);
    while(file>>std::ws>>readChar) {
        if(std::isalpha(readChar)) {
            char baseChar = std::islower(readChar) ? 'a' : 'A';
            file.unget();
            file<<(char((readChar - baseChar + CAESAR_CONSTANT) % 26 + baseChar));
        }
    }

    //Verify Contents of encrypted file
    // std::cout<<"\n\nEncrypted contents of the file\n";
    file.clear();
    file.seekg(0);
    while(std::getline(file>>std::ws, line)) {
        std::cout<<line<<'\n';
    }

    //Decryption
    file.clear();
    file.seekg(0);
    while(file>>std::ws>>readChar) {
        if(std::isalpha(readChar)) {
            char baseChar = std::islower(readChar) ? 'a' : 'A';
            file.unget();
            char offset = readChar - baseChar - CAESAR_CONSTANT;
            if(offset < 0) {
                offset += 26;
            }
            file<<(char(offset + baseChar));
        }
    }

    //Verify Contents of decrypted file
    // std::cout<<"\n\nDecrypted contents of the file\n";
    file.clear();
    file.seekg(0);
    while(std::getline(file>>std::ws, line)) {
        std::cout<<line<<'\n';
    }
}

Output:

THis Is A tEst fILez

VJku Ku C vGuv hKNgb

THis Is A tEst fILez

A lot of complex code for an easy task. . .

The job must be solved first on a piece of paper. Then the formula can be derived easily.

The below code will encrypt or decrypt a message. It handles upper and lower case ASCII characters and converts all alpha characters.

It can shift to left and right. To switch between encyption and decryption, just the sign of the key has to be inverted. You can call "key" also "offset" of "cipher".

The rest is simple, basically handling positive or negative overflows.

std::string caesar(const std::string& in, int key) {
    std::string res(in.size(),' ');
    std::transform(in.begin(),in.end(),res.begin(),[&](char c){return std::isalpha(c)?(char)((((c&31)-1+((26+(key%26))%26))%26+65)|c&32):c;});
    return res;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM