CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 3 of 3
  1. #1
    Join Date
    Dec 2013
    Posts
    75

    Refactoring this Enigma cipher program

    Hi fellow programmers!

    I was looking through a few old programs I wrote, and I came across this Enigma cipher simulator. I was wondering if you could help me refactor the algorithm, as it doesn't seem to be the most efficient method.

    Thanks for all the help!

    Lexi
    Attached Files Attached Files

  2. #2
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,824

    Re: Refactoring this Enigma cipher program

    Try this. I've basically kept your algorithm but tidyied it up a bit. It will now deal with non-uppercase and digits in the text. Lowercase are converted to uppercase and other chars are kept the same in the output. I've separated out the various encoding strings (Alphabet, Reflector, Plugboard) so that it is now easier to change them if required as they are not now buried in a class.

    Code:
    #include <iostream>
    #include <string>
    #include <cctype>
    using namespace std;
    
    class Rotor
    {
    public:
    	Rotor(char pos = 0);
    
    	void SetRotorPosition(int NewPos);
    	void AdvanceRotor(int Steps);
    	void ReverseRotor(int Steps);
    	int GetSteps() const;
    	char GetCurrentCharacter()const;
    	char GetCharacterIndex(int Index)const;
    	char GetCharacterInverse(int i) const;
    
    private:
    	int CurPos;
    	int steps;
    };
    
    class Enigma
    {
    public:
    	Enigma(char r1, char r2, char r3, char r4, char r5) {
    		R[0] = r1;
    		R[1] = r2;
    		R[2] = r3;
    		R[3] = r4;
    		R[4] = r5;
    	}
    
    	~Enigma(){}
    
    	string Encrypt(const string& cleartext);
    
    	static int CharacterMap(char the_char);
    
    	static const char *Alphabet;
    	static const char *Reflector;
    	static const char *Plugboard;
    	static const int no_chars;
    
    private:
    	char plugboard(char Char);
    	Rotor R[5];
    };
    
    
    Rotor::Rotor(char pos) : CurPos(0), steps(0) 
    {
    	SetRotorPosition(Enigma::CharacterMap(pos));
    }
    
    int Rotor::GetSteps() const
    {
    	return steps;
    }
    
    void Rotor::ReverseRotor(int Steps)
    {
    	AdvanceRotor(-Steps);
    }
    
    char Rotor::GetCurrentCharacter() const
    {
    	return Enigma::Alphabet[CurPos];
    }
    
    char Rotor::GetCharacterIndex(int Index) const
    {
    	return Enigma::Alphabet[(CurPos + Index) % Enigma::no_chars];
    }
    
    char Rotor::GetCharacterInverse(int i) const
    {
    	return (i >= CurPos) ? Enigma::Alphabet[i - CurPos] : Enigma::Alphabet[Enigma::no_chars + i - CurPos];
    }
    
    void Rotor::SetRotorPosition(int NewPos)
    {
    	while (NewPos < 0)
    		NewPos += Enigma::no_chars;
    
    	CurPos = NewPos % Enigma::no_chars;
    	steps = 0;
    }
    
    void Rotor::AdvanceRotor(int Steps)
    {
    	CurPos += Steps;
    	while (CurPos < 0)
    		CurPos += Enigma::no_chars;
    
    	CurPos %= Enigma::no_chars;
    	steps += Steps % Enigma::no_chars;
    }
    
    //Returns index into Alphabet of the_char
    int Enigma::CharacterMap(char the_char)
    {
    char *p = strchr(Alphabet, the_char);
    
    	return p ? (int)(p - Alphabet) : no_chars;
    }
    
    //Returns corresponding char from plugboard for Char
    char Enigma::plugboard(char Char)
    {
    	if (isalpha(Char))
    		return (Plugboard[toupper(Char) - 'A']);
    
    	if (isdigit(Char))
    		return (Plugboard[Char - '0' + 26]);
    
    	//Return bad char
    	return ' ';
    }
    
    //Encrypt string
    string Enigma::Encrypt(const string& cleartext)
    {
    string ciphertext;
    
    	ciphertext.resize(cleartext.size());
    
    	for (size_t i = 0; i < cleartext.length(); i++) {
    		 int vali = CharacterMap(plugboard(cleartext[i]));
    		 char valc;
    
    		if (vali < no_chars) {
    			for (int r = 0; r <= 4; r++) {
    				valc = R[r].GetCharacterIndex(vali);
    				vali = CharacterMap(valc);
    			}
    
    			valc = Reflector[vali];
    			vali = CharacterMap(valc);
    
    			for (int r = 4; r >= 0; r--) {
    				valc = R[r].GetCharacterInverse(vali);
    				vali = CharacterMap(valc);
    			}
    
    			ciphertext[i] = plugboard(valc);
    
    			for (int r = 0; r <= 4; r++) {
    				R[r].AdvanceRotor(1);
    				if ((R[r].GetSteps() % no_chars) != 0)
    					break;
    			}
    
    		} else {
    			//cout << "bad val: " << vali << endl;
    			ciphertext[i] = cleartext[i];
    		}
    	}
    
    	return ciphertext;
    }
    
    const char* Enigma::Alphabet =  "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    const char* Enigma::Reflector = "COAYIWV7E3809TBUZ26NPGF4DQL5RJX1SHKM";
    const char *Enigma::Plugboard = "0QWEDTYUIOPSNMJKBZLFHXCVGRA987654321";
    const int Enigma::no_chars = (int)strlen(Enigma::Alphabet);
    
    int main()
    {
    char opt;
    
    	do {
    		char R1, R2, R3, R4, R5;
    		string ciphertext;
    
    		cout << "Enter the 5 rotor settings: ";
    		cin >> R1 >> R2 >> R3 >> R4 >> R5;
    
    		Enigma encryptor(R1, R2, R3, R4, R5);
    
    		cin.ignore(100, '\n');
    		cout << "Enter text: ";
    		getline(cin, ciphertext);
    		cout << "Ciphertext: " << encryptor.Encrypt(ciphertext) << endl;
    
    		do {
    			cout << "[A]gain or [Q]uit: ";
    			cin >> opt;
    			if ((opt = (char)toupper(opt)) != 'Q' && opt != 'A')
    				cout << "Invalid option\n";
    
    		} while (opt != 'A' && opt != 'Q');
    	} while (opt == 'A');
    
    	return 0;
    }
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  3. #3
    Join Date
    Dec 2013
    Posts
    75

    Re: Refactoring this Enigma cipher program

    Thanks for the help!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured