Jump to content

Coding A Vigenere Encypher/Decypher program.

Hi! So I have an assignment in programming where I must encode and decode text via the vinegere method. There are formulas for each all over the web, but I am using ASCII for mine and it just isn't working. It could be because of shoddy code or because of something wrong with my formulas, but all I did was try to implement the normal formulas and add 65(to be ASCII compatible, all caps encoding and decoding.) PLEASE HELP. This program is written for argv[0] as this program name (which is always a given), argv[1] is a flag, choose between -e to encode and -d to decode, argv[2] as the key, argv[3] as the input file name, and argv[4] as the output file name. Here is my code:

 

// Wayne Geissinger, MP4, Encoder/Decoder, 12/5/16

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


using namespace std;

char encipher(char key, char plain);
char decipher(char key, char cipher);

int main(int argc, char *argv[])
{
	char *keyWord = argv[2];
	char plainChar;
	char cipherChar;
	string inputFileName = argv[3];
	string outputFileName = argv[4];

	ifstream inStream;
	inStream.open(inputFileName);
	ofstream outStream;
	outStream.open(outputFileName);


	if (argv[1][0] == '-' && argv[1][1] == 'e')
	{
		for (int i = 0; i < sizeof(plainChar); i++)
		{
			inStream.get(plainChar);
			//testing ASCII codes to make sure only capital letters get through to encoder
			if (plainChar > 97 && plainChar < 122) 
				plainChar -= 76;
			if (!(plainChar >= 65 && plainChar <= 90))
				continue;
			outStream << encipher(keyWord[i], plainChar);
		}

	}
	else if (argv[0][0] == '-' && argv[0][1] == 'd')
	{
		for (int i = 0; i < sizeof(cipherChar); i++)
		{
			inStream.get(cipherChar);
			//testing ASCII codes to make sure only capital letters get through to decoder
			if (cipherChar > 97 && cipherChar < 122)
				cipherChar -= 76;
			if (!(cipherChar >= 65 && cipherChar <= 90))
				continue;
			outStream << decipher(keyWord[i], cipherChar);
		}
	}
	else cout << "incorrect input. " << endl;
}

char encipher(char key, char plain)
{
	char cipher;
	cipher = (((plain + key) % 26) + 65);
	return cipher;
}

char decipher(char key, char cipher)
{
	char plain;
	plain = (((cipher - key) % 26) + 65);
	return plain;
}

 

*_*_*_*_*_*_*Personal Rig*_*_*_*_*_*_*

CPU: Core i7 7700k @ 5.1 GHz

GPU: EVGA GTX 1070 SSC ACX 3.0

MOBO: ASROCK Z270 Killer SLI/AC

RAM: 16 GB HyperX Fury

COOLER: NZXT Kraken X52

CASE: NZXT S340 Elite

STORAGE:  500GB NVME Samsung 960 Pro

500GB Samsung 860 EVO

4TB Seagate Barracuda (7200 RPM)

OS: Windows 10 Pro

 

Link to comment
Share on other sites

Link to post
Share on other sites

UPDATE: New code, same rules as before, I just realized that I can't test the size of a file by the character I just pulled from it. My filesize was always being tested as zero.

 

// Wayne Geissinger, MP4, Encoder/Decoder, 12/5/16

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


using namespace std;

char encipher(char key, char plain);
char decipher(char key, char cipher);
int sizeOfInput(string inputFileName);

int main(int argc, char *argv[])
{
	//declarations
	char *keyWord = argv[2];
	char plainChar;
	char cipherChar;
	string inputFileName = argv[3];
	string outputFileName = argv[4];

	//opening input and output streams for files
	ifstream inStream;
	inStream.open(inputFileName);
	ofstream outStream;
	outStream.open(outputFileName);

	//declaring filesize for reference later
	int filesize = sizeOfInput(inputFileName);

	//checks if the "encode" flag (-e) is used
	if (argv[1][0] == '-' && argv[1][1] == 'e')
	{
		for (int i = 0; i < filesize; i++)
		{
			inStream.get(plainChar);
			//testing ASCII codes to make sure only capital letters get through to encoder
			if (plainChar > 97 && plainChar < 122) 
				plainChar -= 76;
			if (!(plainChar >= 65 && plainChar <= 90))
				continue;
			outStream << encipher(keyWord[i], plainChar);
		}

	}

	//checks if the "decode" flag (-d) is used
	else if (argv[0][0] == '-' && argv[0][1] == 'd')
	{
		for (int i = 0; i < filesize; i++)
		{
			inStream.get(cipherChar);
			//testing ASCII codes to make sure only capital letters get through to decoder
			if (cipherChar > 97 && cipherChar < 122)
				cipherChar -= 76;
			if (!(cipherChar >= 65 && cipherChar <= 90))
				continue;
			outStream << decipher(keyWord[i], cipherChar);
		}
	}

	//if neither flag is used, throws incorrect input.
	else cout << "incorrect flag input. " << endl;
}

//Encipheres a character with a key and plain text.
//preconditions: char key, char plain
//postconditions: cipher
char encipher(char key, char plain)
{
	char cipher;
	cipher = (((plain + key) % 26) + 65);
	return cipher;
}

//Deciphers an enciphered character with a key and enciphered text.
//preconditions: char key, char cipher (enciphered text)
//postconditions: char plain (deciphered text)
char decipher(char key, char cipher)
{
	char plain;
	plain = (((cipher - key) % 26) + 65);
	return plain;
}

//Checks size of phrase in input file
//preconditions: string inputFileName
//postconditions: int size
int sizeOfInput(string inputFileName)
{
	char ch;
	int size = 0;
	ifstream inStream;
	inStream.open(inputFileName);
	while (true)
	{
		inStream.get(ch);
		if (inStream.eof()) break;
		//ASCII value checks
		if ((ch >= 65 && ch <= 90) || (ch >= 97 && ch <= 122))
		{
			size++;
		}
		else continue;
	}
	return size;
}

 

*_*_*_*_*_*_*Personal Rig*_*_*_*_*_*_*

CPU: Core i7 7700k @ 5.1 GHz

GPU: EVGA GTX 1070 SSC ACX 3.0

MOBO: ASROCK Z270 Killer SLI/AC

RAM: 16 GB HyperX Fury

COOLER: NZXT Kraken X52

CASE: NZXT S340 Elite

STORAGE:  500GB NVME Samsung 960 Pro

500GB Samsung 860 EVO

4TB Seagate Barracuda (7200 RPM)

OS: Windows 10 Pro

 

Link to comment
Share on other sites

Link to post
Share on other sites

17 minutes ago, Wayne Geissinger said:

Hi! So I have an assignment in programming where I must encode and decode text via the vinegere method. There are formulas for each all over the web, but I am using ASCII for mine and it just isn't working. It could be because of shoddy code or because of something wrong with my formulas, but all I did was try to implement the normal formulas and add 65(to be ASCII compatible, all caps encoding and decoding.) PLEASE HELP. This program is written for argv[0] as this program name (which is always a given), argv[1] is a flag, choose between -e to encode and -d to decode, argv[2] as the key, argv[3] as the input file name, and argv[4] as the output file name. Here is my code:

 


// Wayne Geissinger, MP4, Encoder/Decoder, 12/5/16

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


using namespace std;

char encipher(char key, char plain);
char decipher(char key, char cipher);

int main(int argc, char *argv[])
{
	char *keyWord = argv[2];
	char plainChar;
	char cipherChar;
	string inputFileName = argv[3];
	string outputFileName = argv[4];

	ifstream inStream;
	inStream.open(inputFileName);
	ofstream outStream;
	outStream.open(outputFileName);


	if (argv[1][0] == '-' && argv[1][1] == 'e')
	{
		for (int i = 0; i < sizeof(plainChar); i++)
		{
			inStream.get(plainChar);
			//testing ASCII codes to make sure only capital letters get through to encoder
			if (plainChar > 97 && plainChar < 122) 
				plainChar -= 76;
			if (!(plainChar >= 65 && plainChar <= 90))
				continue;
			outStream << encipher(keyWord[i], plainChar);
		}

	}
	else if (argv[0][0] == '-' && argv[0][1] == 'd')
	{
		for (int i = 0; i < sizeof(cipherChar); i++)
		{
			inStream.get(cipherChar);
			//testing ASCII codes to make sure only capital letters get through to decoder
			if (cipherChar > 97 && cipherChar < 122)
				cipherChar -= 76;
			if (!(cipherChar >= 65 && cipherChar <= 90))
				continue;
			outStream << decipher(keyWord[i], cipherChar);
		}
	}
	else cout << "incorrect input. " << endl;
}

char encipher(char key, char plain)
{
	char cipher;
	cipher = (((plain + key) % 26) + 65);
	return cipher;
}

char decipher(char key, char cipher)
{
	char plain;
	plain = (((cipher - key) % 26) + 65);
	return plain;
}

 

What is it about it that doesn't work?

Link to comment
Share on other sites

Link to post
Share on other sites

Just now, Glenwing said:

What is it about it that doesn't work?

My output file comes out empty.

 

*_*_*_*_*_*_*Personal Rig*_*_*_*_*_*_*

CPU: Core i7 7700k @ 5.1 GHz

GPU: EVGA GTX 1070 SSC ACX 3.0

MOBO: ASROCK Z270 Killer SLI/AC

RAM: 16 GB HyperX Fury

COOLER: NZXT Kraken X52

CASE: NZXT S340 Elite

STORAGE:  500GB NVME Samsung 960 Pro

500GB Samsung 860 EVO

4TB Seagate Barracuda (7200 RPM)

OS: Windows 10 Pro

 

Link to comment
Share on other sites

Link to post
Share on other sites

1 minute ago, Glenwing said:

What is it about it that doesn't work?

If you notice under my sizeOfInput file, I have an opening of the same file but in a different function. I have since added a close stream at the end of the function, is that all legal?

 

*_*_*_*_*_*_*Personal Rig*_*_*_*_*_*_*

CPU: Core i7 7700k @ 5.1 GHz

GPU: EVGA GTX 1070 SSC ACX 3.0

MOBO: ASROCK Z270 Killer SLI/AC

RAM: 16 GB HyperX Fury

COOLER: NZXT Kraken X52

CASE: NZXT S340 Elite

STORAGE:  500GB NVME Samsung 960 Pro

500GB Samsung 860 EVO

4TB Seagate Barracuda (7200 RPM)

OS: Windows 10 Pro

 

Link to comment
Share on other sites

Link to post
Share on other sites

It is probably simpler to read the whole input file into a string, and then go character by character off the string, based on the length of the string. You could write something to get the length of text from the file itself, but it is more complicated.

 

I got your code to output doing what I did above (and replacing all the argv stuff with manual strings for testing), but it doesn't encode correctly. I'm a bit confused on why this bit is -76 instead of -97. That would make 'a' = 21, 'b' = 22, etc. and I'm not clear on how that fits into the cipher.

if (plainChar > 97 && plainChar < 122) 
	plainChar -= 76;

Also I'm not sure whether your keys are being input numerically, or as characters, but if you're using characters then those will need to be offset by 65 (or 97 for lowercase) as well.

 

I think it would probably be easier to write an "alphabet string" and use that to determine the "value" of each character rather then trying to account for ASCII offsets at every turn, where it's easy to miss something. For example:

string Alphabet = "ABCDE";

Alphabet.find('A'); // returns 00
Alphabet.find('B'); // returns 01

// likewise, 

Alphabet[0]; // returns 'A'
Alphabet[1]; // returns 'B'

// Therefore in the vigenere cipher, you just offset the input character's value by the key character's value.
// Or in other words, to get the encoded character's value: E_value = (Alphabet.find(input_char) + Alphabet.find(key_char))
// And then Alphabet[E_value] would give you the character represented by that value, and you would write that to the output.

 

Link to comment
Share on other sites

Link to post
Share on other sites

19 hours ago, Glenwing said:

It is probably simpler to read the whole input file into a string, and then go character by character off the string, based on the length of the string. You could write something to get the length of text from the file itself, but it is more complicated.

 

I got your code to output doing what I did above (and replacing all the argv stuff with manual strings for testing), but it doesn't encode correctly. I'm a bit confused on why this bit is -76 instead of -97. That would make 'a' = 21, 'b' = 22, etc. and I'm not clear on how that fits into the cipher.


if (plainChar > 97 && plainChar < 122) 
	plainChar -= 76;

Also I'm not sure whether your keys are being input numerically, or as characters, but if you're using characters then those will need to be offset by 65 (or 97 for lowercase) as well.

 

I think it would probably be easier to write an "alphabet string" and use that to determine the "value" of each character rather then trying to account for ASCII offsets at every turn, where it's easy to miss something. For example:


string Alphabet = "ABCDE";

Alphabet.find('A'); // returns 00
Alphabet.find('B'); // returns 01

// likewise, 

Alphabet[0]; // returns 'A'
Alphabet[1]; // returns 'B'

// Therefore in the vigenere cipher, you just offset the input character's value by the key character's value.
// Or in other words, to get the encoded character's value: E_value = (Alphabet.find(input_char) + Alphabet.find(key_char))
// And then Alphabet[E_value] would give you the character represented by that value, and you would write that to the output.

 

I do like your ideas quite a bit, but my professor gave us a specific set of parameters to follow today. I did learn a bit, and I now have an almost fully working program. I have to encipher and decipher the Gettysburg Address through my program. Once I encipher it, it spits a bunch of unprintable/unknown characters into whatever output file I choose. Then once I decipher by running the program a second time, it gets to "Four score and seven years ag" and ends there. Here are the parameters you'd need to run the program yourself through CMD. Navigate to the folder through CMD, then type filename (space) -e or -d (-e for encode and -d for decode) (space) keyword (I use lemon) (space) input file name(.txt) (space) output file name(.txt) and press enter. This will pull from whatever input file you have typed and will dump into an output file, and creates one if it is nonexistent. Please let me know if you see a flaw in my code that would inhibit me from doing the full Gettysburg Address. Keep in mind my vigenere cipher is a modified version which covers the 95 printable characters in the ASCII alphabet. Here's my code:

 

// Wayne Geissinger, MP4, Encoder/Decoder, 12/5/16

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

using namespace std;

//function prototypes
char encipher(char key, char plain);
char decipher(char key, char cipher);
void pressEnterToContinue(void);

int main(int argc, char *argv[])
{
	//declarations
	string keyWord = string(argv[2]);
	char plainChar;
	char cipherChar;
	string inputFileName = argv[3];
	string outputFileName = argv[4];

	//opening input and output streams for files
	ifstream inStream;
	inStream.open(inputFileName);
	ofstream outStream;
	outStream.open(outputFileName);

	//checks if the "encode" flag (-e) is used
	if (argv[1][0] == '-' && argv[1][1] == 'e')
	{
		//repeats drawing new character, enciphering it, and dumping to output file.
		int i = 0;
		while(true)
		{
			i++;
			if (i == keyWord.length()) i = 0;
			inStream.get(plainChar);
			if (inStream.eof()) break;
			char ch = encipher(keyWord[i], plainChar);
			outStream << ch;
		}
	}


	//checks if the "decode" flag (-d) is used
	else if (argv[1][0] == '-' && argv[1][1] == 'd')
	{
		//repeats drawing new character, enciphering it, and dumping to output file.
		int i = 0;
		while(true)
		{
			i++;
			if (i == keyWord.length()) i = 0;
			inStream.get(cipherChar);
			if (inStream.eof()) break;
			char ch = decipher(keyWord[i], cipherChar);
			outStream << ch;
		}
	}

	//if neither flag is used, throws incorrect input.
	else cout << "incorrect flag input. " << endl;

	//closing program
	inStream.close();
	outStream.close();
	cout << "Done!" << endl;
	pressEnterToContinue();
}

//Encipheres a character with a key and plain text.
//preconditions: char key, char plain
//postconditions: cipher
char encipher(char key, char plain)
{
	char cipher;
	int offset = ' ';
	int alphabet = 95; // The ASCII printable alphabet is 95 characters.
	cipher = plain + (key - offset);
	if (cipher < 32) cipher += alphabet;
	return cipher;
}

//Deciphers an enciphered character with a key and enciphered text.
//preconditions: char key, char cipher (enciphered text)
//postconditions: char plain (deciphered text)
char decipher(char key, char cipher)
{
	char plain;
	int offset = ' ';
	int alphabet = 95;
	plain = cipher - (key - offset);
	if (plain < 32) plain -= alphabet;
	return plain;
}

//Ends program, no pre/post conditions.
void pressEnterToContinue(void) 
{
	cout << "Press enter to continue... ";
	cin.ignore(1024, '/n');
	cin.clear();
	exit(1);
}

 

*_*_*_*_*_*_*Personal Rig*_*_*_*_*_*_*

CPU: Core i7 7700k @ 5.1 GHz

GPU: EVGA GTX 1070 SSC ACX 3.0

MOBO: ASROCK Z270 Killer SLI/AC

RAM: 16 GB HyperX Fury

COOLER: NZXT Kraken X52

CASE: NZXT S340 Elite

STORAGE:  500GB NVME Samsung 960 Pro

500GB Samsung 860 EVO

4TB Seagate Barracuda (7200 RPM)

OS: Windows 10 Pro

 

Link to comment
Share on other sites

Link to post
Share on other sites

10 hours ago, Wayne Geissinger said:

Once I encipher it, it spits a bunch of unprintable/unknown characters into whatever output file I choose. Then once I decipher by running the program a second time, it gets to "Four score and seven years ag" and ends there.

 

 

If the enciphered file contains unprintable/special characters as you say, then you will need to open it in binary mode in order to read bytes correctly as you expect:

inStream.open(inputFileName, ios::in | ios::binary);

 

Other things that come to mind after a quick glance of your code:

-Check for things such as a failure to open files.

-Const correctness.

-Dont let the "pressEnterToContinue" exit using "exit". Simply have it return normally to main and let the program end normally. Using exit may cause a hard forced exit and prevent proper cleanup and destructors from running.

Link to comment
Share on other sites

Link to post
Share on other sites

Thanks to all who helped. Here is my final solution which works well, I just had to create an exception for the newline character. I excluded the possibility of all characters below 32 (in ASCII) being written, then hard-coded an exception for newline.

http://pastebin.com/uWrQXNL1

*_*_*_*_*_*_*Personal Rig*_*_*_*_*_*_*

CPU: Core i7 7700k @ 5.1 GHz

GPU: EVGA GTX 1070 SSC ACX 3.0

MOBO: ASROCK Z270 Killer SLI/AC

RAM: 16 GB HyperX Fury

COOLER: NZXT Kraken X52

CASE: NZXT S340 Elite

STORAGE:  500GB NVME Samsung 960 Pro

500GB Samsung 860 EVO

4TB Seagate Barracuda (7200 RPM)

OS: Windows 10 Pro

 

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×