Substitution Cipher, Strings and Functions

closed account (iy5G1hU5)
A
Last edited on
The compiler's telling what's wrong.

You have two loop types that are wrong and, a type mismatch and it's telling you the types 'const char* to char*'

I've made the corrections for you and but the corrections in bold, hopefully they'll show up in the browser.

And for the help, you get to hear about one of my pet hates. Don't call open/close on streams. Think stream, don't think file. And think object, don't think procedures.

So code that looks like:
1
2
3
4
5
6
7
	ifstream infile;
	ofstream outfile;
	infile.open(filename_from.c_str());
	outfile.open(filename_to.c_str());
	// use streams
	infile.close();
	outfile.close();

Should look like:
1
2
3
	ifstream(filename);
	ofstream(filename);
	// use streams 

Isn't it better when you let the constructor and destructor do their jobs?

Now, back to your code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>

using namespace std;

char substitution_cipher(string cipher_key, char char_to_encrypt);
char reverse_substitution_cipher(string cipher_key, char char_to_encrypt);

string EncryptString(string &cipher_key, string string_to_be_encrypted);
string DecryptString(string &cipher_key, string string_to_be_decrypted);

void RotateCipherKey(string &cipher_key);
void DisplayFile(string filename);


void EncryptFile(string cipher_key, string filename_from, string filename_to);
void DecryptFile(string cipher_key, string filename_from, string filename_to);

int main()
{
	string cipher_key = "qwertyuiopasdfghjklzxcvbnm";

	EncryptFile(cipher_key, "test.txt", "test-encrypted.txt");
	DecryptFile(cipher_key, "test-encrypted.txt", "test-ed.txt");

	DisplayFile("test.txt");
	DisplayFile("test-encrypted.txt");
	DisplayFile("test-ed.txt");

	system("PAUSE");
	return 0;
}


//  Rotate the cipher key. Example: abcdef becames bcdefa

void RotateCipherKey(string &cipher_key)
{
	rotate(cipher_key.begin(), cipher_key.begin() + 1, cipher_key.end());
}

// Perform a substitution cipher on a single character 
// using the specified cipher key
char SubstitutionCipher(string cipher_key, char char_to_encrypt)
{
	for (size_t iii = 0; iii < cipher_key.length(); iii++)
	{
		RotateCipherKey(cipher_key);
		char_to_encrypt = cipher_key[iii];
	}
	return char_to_encrypt;
}

// Perform a "reverse" substitution cipher on a single character 
// using the specified cipher key
char ReverseSubstitutionCipher(string cipher_key, char char_to_decrypt)
{
	for (size_t iii = 0; iii < cipher_key.length(); iii++)
	{
		RotateCipherKey(cipher_key);
		char_to_decrypt = cipher_key[iii];
	}
	return char_to_decrypt;
}

// Encrypt String and return it 
// You will use the SubstitutionCipher() function to encrypt the
// individual characters
// 
// Note: We will call RotateCipherKey() after each time we encrypt 
// a character.
string EncryptString(string &cipher_key, string string_to_be_encrypted)
{
	const char *y = string_to_be_encrypted.c_str();
	{
		//SubstitutionCipher(cipher_key, string_to_be_encrypted);
	}
	cout << " " << string_to_be_encrypted;
	string encrypted_string = string_to_be_encrypted;
	return encrypted_string;
}

// Decrypt String and return it 
// You will use the ReverseSubstitutionCipher() function to decrypt the
// individual characters
//
// Note: We will call RotateCipherKey() after each time we encrypt 
// a character.
string DecryptString(string &cipher_key, string string_to_be_decrypted)
{
	string decrypted_string = string_to_be_decrypted;

	return decrypted_string;
}

// Display file specified by the filname parameter
void DisplayFile(string filename)
{
	string str;
	ifstream infile;
	infile.open(filename);
	infile >> str;
	while (infile)
	{
		cout << " " << str;
		infile >> str;
	}
	cout << endl;
}


// Encrypt the specified file using the specified cipher key and 
// write the output to a different file
// This function is complete
void EncryptFile(string cipher_key, string filename_from, string filename_to)
{
	string input;
	ifstream infile;
	ofstream outfile;

	infile.open(filename_from.c_str());
	outfile.open(filename_to.c_str());

	if (!infile)
	{
		cout << "Can not open input file " + filename_from << endl;
		exit(0);
	}

	if (!outfile)
	{
		cout << "Can not open Output file " + filename_to << endl;
		exit(0);
	}


	while (getline(infile, input))
	{
		outfile << EncryptString(cipher_key, input) << endl;
	}
	infile.close();
	outfile.close();
}

// Decrypt the specified file using the specified cipher key and 
// write the output to a different file
// This function is complete
void DecryptFile(string cipher_key, string filename_from, string filename_to)
{
	string input;
	ifstream infile;
	ofstream outfile;

	infile.open(filename_from.c_str());
	outfile.open(filename_to.c_str());

	if (!infile)
	{
		cout << "Can not open input file " + filename_from << endl;
		exit(0);
	}

	if (!outfile)
	{
		cout << "Can not open Output file " + filename_to << endl;
		exit(0);
	}


	while (getline(infile, input))
	{
		outfile << DecryptString(cipher_key, input) << endl;
	}
	infile.close();
	outfile.close();
}
Ok, I've taken another look at this and have a better understanding of what you were given and what you need to do. I have a working example here, but I don't want to just post you the code.

Have you got any further with your code or are you completely stuck?
closed account (iy5G1hU5)
a
Last edited on
Your problems start which trying to do the serial encryption in the wrong function.

I've left out the file stuff for now. Please note that I've fixed the Display function. I've also added loads of const that your professor might not likem so remove them if you need to.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>

using namespace std;


char substitution_cipher(const string& cipher_key, char char_to_encrypt);
char reverse_substitution_cipher(const string& cipher_key, char char_to_encrypt);

string EncryptString(const string &cipher_key, const string& string_to_be_encrypted);
string DecryptString(const string &cipher_key, const string& string_to_be_decrypted);

void RotateCipherKey(string &cipher_key);
void DisplayFile(const string& filename);

void EncryptFile(const string& cipher_key, const string& filename_from, const string& filename_to);
void DecryptFile(const string& cipher_key, const string& filename_from, const string& filename_to);


int main()
{
	string cipher_key = "qwertyuiopasdfghjklzxcvbnm";

	EncryptFile(cipher_key, "test.txt", "test-encrypted.txt");
	DecryptFile(cipher_key, "test-encrypted.txt", "test-ed.txt");

	DisplayFile("test.txt");
	DisplayFile("test-encrypted.txt");
	DisplayFile("test-ed.txt");

	system("PAUSE");
	return 0;
}


//  Rotate the cipher key. Example: abcdef becames bcdefa
void RotateCipherKey(string &cipher_key)
{
	rotate(cipher_key.begin(), cipher_key.begin() + 1, cipher_key.end());
}

// Perform a substitution cipher on a single character 
// using the specified cipher key
char SubstitutionCipher(const string& cipher_key, char char_to_encrypt)
{
	return char_to_encrypt;
}

// Perform a "reverse" substitution cipher on a single character 
// using the specified cipher key
char ReverseSubstitutionCipher(const string& cipher_key, char char_to_decrypt)
{
	return char_to_decrypt;
}

// Encrypt String and return it 
// You will use the SubstitutionCipher() function to encrypt the
// individual characters
// 
// Note: We will call RotateCipherKey() after each time we encrypt 
// a character.
string EncryptString(const string &cipher_key, const string& string_to_be_encrypted)
{
	std::string key = cipher_key; // we'll modify this copy

	string encrypted_string;
	for (size_t iii = 0; iii < string_to_be_encrypted.length(); iii++)
	{
		encrypted_string.append(1, SubstitutionCipher(key, string_to_be_encrypted[iii]));

		RotateCipherKey(key);
	}

	return encrypted_string;
}

// Decrypt String and return it 
// You will use the ReverseSubstitutionCipher() function to decrypt the
// individual characters
//
// Note: We will call RotateCipherKey() after each time we encrypt 
// a character.
string DecryptString(const string &cipher_key, const string& string_to_be_decrypted)
{
	std::string key = cipher_key; // we'll modify this copy

	string decrypted_string;
	for (size_t iii = 0; iii < string_to_be_decrypted.length(); iii++)
	{
		decrypted_string.append(1, SubstitutionCipher(key, string_to_be_decrypted[iii]));

		RotateCipherKey(key);
	}

	return decrypted_string;
}

// Display file specified by the filname parameter
void DisplayFile(const string& filename)
{
	ifstream infile(filename);

	string input;
	while (getline(infile, input))
	{
		cout << " " << input;
	}
	cout << endl;
}


So now, all you have to do is implement SubstitutionCipher() and ReverseSubstitutionCipher(). The thing to watch out for is that the cipher text generated may not be a printable character, it may be any character including character 0. That isn't a problem for a std::string, but it must be a concern whenever calling .c_str(), you must also pass the length as the buffer length .size() or .length().

If your cipher is printable, then you can access the file as a text file, but if it's not, you have to treat it as a binary file.

Got it?
Last edited on
Is the example output the actual output from your current program, or the output you want to get?

Also, two things about the code shown so far:

1. SubstitutionCipher() and ReverseSubstitutionCipher() have the same code. Is ReverseSubstitutionCipher() supposed to be used for decryption? If so, are you going to write a ReverseRotateCipherKey() function?

2. I think you need to rewrite SubstitutionCipher(). Look at the loop:

1
2
3
4
5
	for (size_t iii = 0; iii < cipher_key.length(); iii++)
	{
		RotateCipherKey(cipher_key);
		char_to_encrypt = cipher_key[iii];
	}

Suppose that cipher_key == "A". Obviously the length is 1 and so you rotate it once and get "A". The function returns the last letter of the string, which is 'A'.

Now suppose cipher_key == "AB". The length is 2 so you will need to rotate it twice. Rotate it once to get cipher_key == "BA". Rotate it again to get cipher_key == "AB". The function returns the last letter of the string, which is 'B'.

Suppose cipher_key == "ABC". The length is 3 so you will need to rotate it 3 times. Rotate it once to get cipher_key == "BCA". Rotate it again to get cipher_key == "CAB". Rotate it a third time to get cipher_key == "ABC". The function returns the last letter of the string, which is 'C'.

etc.

So in other words, no matter what you do, you're encrypting using only the last letter of your original cipher_key.
closed account (iy5G1hU5)
a
Last edited on
closed account (iy5G1hU5)
@kbw
Yes, do see. Will begin to implement the functions. Thanks for your code, hopefully I can get this working. Its just the reverse process now I need to work on.
Looking at the example output, I guess your program is supposed to implement the Vigenere cipher.

http://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher

It also looks like you're supposed to only encrypt letters (and numbers?) while leaving everything else as is.

If that's so, then you should modify kbw's code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
string EncryptString(const string &cipher_key, const string& string_to_be_encrypted)
{
	//not sure you actually want to use a copy
	//don't you want to modify the actual key?
	std::string key = cipher_key; // we'll modify this copy

	string encrypted_string;
	for (size_t iii = 0; iii < string_to_be_encrypted.length(); iii++)
	{
		if (!isalpha(string_to_be_encrypted[iii]))
			continue; //skip encrypting anything that's not a letter
		else
			string_to_be_encrypted[iii] = tolower(string_to_be_encrypted[iii]); //make everything lowercase
		encrypted_string.append(1, SubstitutionCipher(key, string_to_be_encrypted[iii]));

		RotateCipherKey(key);
	}

	return encrypted_string;
}


In SubsitutionCipher(), you really only need the first letter of the key, since RotateCipherKey() is done in EncryptString(). So what you need to do in SubsitutionCipher() is to find the difference (the amount of letters) between key[0] and 'a'.

Then you rotate the alphabet (a string in your function such as string alphabet = "abcdefghijklmnopqrstuvwxyz"; by the difference in order to implement a Caesar shift. You would return the first letter of the rotated alphabet.
Last edited on
closed account (iy5G1hU5)
@fg109
I am only encrypting letters, yes. And since I am going off the given output, the decrypted example is all lowercase. So, the function:
1
2
3
4
5
6
7
8
9
10
11
12
13
char SubstitutionCipher(string cipher_key, char char_to_encrypt)
{
	for (int iii = 0; iii < 1; iii++)
	{
		if (char_to_encrypt == ' ')
			char_to_encrypt = ' ';
		else if (char_to_encrypt == '.')
			char_to_encrypt = '.';
		else
			char_to_encrypt = cipher_key[iii];
	}
	return char_to_encrypt;
}

is taking care of that for me. The char is being passed into the function, from
EncryptString and is returning a lowercase letter. It will also check to see if the char passed is equal to a space or a period. So my sample output is:
This is some Random gibberish. Please check all lines for proper encrypt and d
ecrypt. Hopefully, you got this working.
qwer yu opas fghjkl xcvbnmqwe. qwerty iopas fgh klzxc bnm wertyu opasdfg jkl x
cvbnmq. qwertyuiop sdf hjk zxcv nmqwert.
wert ui pasd ghjklz cvbnmqwer. wertyu opasd ghj lzxcv nmq ertyui pasdfgh klz c
vbnmqw. wertyuiopa dfg jkl xcvb mqwerty.
Press any key to continue . . .


The proper idea is that
T -> q -> t
h -> w -> h
i -> e -> i
s -> r - > s
while qwer gets rotated each time a letter is subbed. Not sure at this point, losing my mind over a simple HW.
Last edited on
I wrote the code for this and confirmed that it works. If you're really stumped, you can take a look at it.

http://pastebin.com/LCPNPKZh

A lot of things are different from your code though. Basically, I took a look at your code, and rewrote it from scratch from my understanding of the problem (use Vigenere cipher while keeping spaces and punctuation).

Oops, looks like I forgot to close the files at the end of the encrypt and decrypt functions... Oh well.
Last edited on
closed account (iy5G1hU5)
a
Last edited on
closed account (iy5G1hU5)
Mods delete unsolved
What you have done is extremely rude and selfish. By blanking your posts, nobody else with the same problem can find this thread. Please restore your posts.
Topic archived. No new replies allowed.