Encryption Program Issue

I am having issues with a while loop in an encryption program. When I try to execute this piece of 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
char ch = '\0';	   // individual character in text stream
char transCh = ' ';  // transformed version of 'ch'

// get characters from input file...
inFile.get (ch);

// set decryption key...
Key = setKey (codeKey);

while (!inFile.fail ())
{
	if (ch != ' ')
	{
		// translate them back...
		transCh = translate (ch);
	
		// and put them in output file
		outFile.put (transCh);
		inFile.get (ch);
	}
	else
	{
		continue;
	}
}

it just keeps going like this: I hit enter and it just keeps going.

Encrypt or decrypt? (E/D) Anything else to exit. 
: d
Enter the name of the text file to be decrypted. 
: out.txt
Enter the name of the text file to receive the decrypted text. 
: dec.txt
Enter the decryption key. 
: b





So, I figure the issue is in the while loop, I debugged it and it looks like it is somehow re-initializing "ch" to a ' ' (space).

(lldb) print ch
(char) $1 = '3'
(lldb) c
Process 2357 resuming
Process 2357 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 3.1 4.1
    frame #0: 0x0000000100001526 flex-encrypt`Encryption::decrypt(this=0x00007ffeefbff158, codeKey='b') at flex-encrypt.cc:119
   116 		// set encryption key...
   117 		Key = setKey (codeKey);
   118 		
-> 119 		while (!inFile.fail ())
   120 		{
   121 			if (ch != ' ')
   122 			{
Target 0: (flex-encrypt) stopped.
(lldb) print ch
(char) $2 = ' '
(lldb) c
Process 2357 resuming
Process 2357 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 3.1 4.1
    frame #0: 0x0000000100001526 flex-encrypt`Encryption::decrypt(this=0x00007ffeefbff158, codeKey='b') at flex-encrypt.cc:119
   116 		// set encryption key...
   117 		Key = setKey (codeKey);
   118 		
-> 119 		while (!inFile.fail ())
   120 		{
   121 			if (ch != ' ')
   122 			{
Target 0: (flex-encrypt) stopped.
(lldb) print ch
(char) $3 = ' '


Here is the first bit of the text file I am trying to read from.
3 2 75 4 115 4 115 4 104 4 36 4 105 4 122


Any help would be appreciated. If you want to see more of the program, feel free to ask, I didn't want to take up a whole bunch of space if I don't need to. I can't think as it is getting close to dinnertime and I'm getting hungry and a headache, so if it's something really obvious, that's why I didn't see it.
Thanks!
max
Last edited on
If ch ever becomes ' ' within your loop, then your loop essentially becomes:
1
2
3
4
while (!inFile.fail())
{
	continue;
}

(Having a "continue" as the last instruction in a loop also doesn't achieve any difference in behavior, so the else branch in your code doesn't do anything)
Last edited on
Perhaps just:

1
2
3
for (char ch {}; inFile.get(ch); )
	if (ch != ' ')
		outFile.put(translate(ch));

@Ganado,
Oh...I see, you're right. Dang, I didn't notice that. So...how do I take care of it?

@seeplus,
Ok, I'll try it! Thanks!

Edit:
Well, I tried it. No go. Sorry, but it just did the same thing as my while loop did.
Last edited on
3 2 75 4 115 4 115 4 104 4 36 4 105 4 122


Is the contents of the file exactly like this - if you view the file with a text editor then you see 3 2 75 (and not K) ?

If yes, then do you want to treat 75 as one char (K) or two chars - char 7 and char 5? This affects how the fie is read.

If actually as numbers separated by a space (treating 75 as one and not two), then you don't read char by char, you read by int. Something like (not tried):

1
2
for (int i {}; inFile >> i; )
    outFile.put(translate(i));

Agreed, seeplus. agent max, it would help to explain some example inputs/outputs, otherwise we're just guessing what you want to do specifically.
@seeplus,
Dang, that makes sense. I didn't think of reading it as integers! But of course that's got to be it because if it's reading it by characters, it's only reading one at a time! Thanks!!

I'm not sure if I can fit the entire program in here, but I'll try.
Note: I am planning to put the class and implementation in separate files, however I found this is easier for debugging.

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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
#include <iostream>
#include <string>
#include <fstream>
#include <string>
#include <cstdlib>
#include <cassert> // needed to use assert() function

using namespace std;

class Encryption
{
protected:
	ifstream inFile;
	ofstream outFile;
	int Key;
   
public:
	Encryption (const string& inFileName, const string& outFileName);
   
	virtual ~Encryption ();
   
	// Pure virtual functions
	virtual int transform (char ch) const = 0;
	
	virtual char translate (char ch) const = 0;
	
	virtual int setKey (char codeKey) = 0;
	
	// Do the actual work.
	virtual void encrypt (char codeKey) final; // encrypter
	
	virtual void decrypt (char codeKey) final; // decrypter
};

//**************************************************************************
// Constructor opens the input and output file, and checks for errors.	   *
//**************************************************************************
Encryption::Encryption (const string& inFileName, const string& outFileName)
{
	inFile.open (inFileName);
   
	outFile.open (outFileName);
   
    Key = 0; // initialize code key to zero
	
	assert (inFile); // terminates program and outputs error message if infile does not open
	assert (outFile);
}

//**************************************************
//Destructor closes files.						   *
//**************************************************
Encryption::~Encryption ()
{
	inFile.close ();
	outFile.close ();
}

//*****************************************************
//Encrypt function uses the virtual transform		  *
//member function to transform individual characters. *
//***************************************************** 
void Encryption::encrypt (char codeKey)
{
	char ch = ' ';	   // individual character in text stream
	int transCh;  // transformed version of 'ch'
	char f = ' ';
	
	// get characters from input file...
	inFile.get (ch);
	
	// set encryption key...
	Key = setKey (codeKey);
	
	/*
	while (!inFile.fail ())
	{
		// transform them...
		transCh = transform (ch);
		
		// and put them in output file
		outFile << transCh;
		outFile.put (f);
		inFile.get (ch);
	}
	*/
	for (char ch {}; inFile.get(ch); )
	{	
		if (ch != ' ')
		{
			outFile.put (translate(ch));
		}
	}
}

//*****************************************************
//Decrypt function uses the virtual translate		  *
//member function to translate individual characters  *
//back to their original form.						  *
//***************************************************** 
void Encryption::decrypt (char codeKey)
{
	char ch = '\0';	   // individual character in text stream
	char transCh = ' ';  // transformed version of 'ch'

	// get characters from input file...
	inFile.get (ch);

	// set decryption key...
	Key = setKey (codeKey);

	while (!inFile.fail ())
	{
		if (ch != ' ')
		{
			// translate them back...
			transCh = translate (ch);
	
			// and put them in output file
			outFile.put (transCh);
			inFile.get (ch);
		}
		else
		{
			continue;
		}
	}
}

//*******************************************
// The subclass simply overides the virtual *
// transform function						*
//*******************************************
class SimpleEncryption : public Encryption 
{
public:
	// transform member function
	int transform (char ch) const override
	{
		int c = ch;
		return c + Key;
	}
	
	// translate member function
	char translate (char ch) const override
	{
		return ch - Key;
	}
	
	// set code key
	int setKey (char codeKey) override
	{
		{
			switch (codeKey)
			{
				case 'a':
				{
					return 12;
				}
				break;
		
				case 'b':
				{
					return 4;
				}
				break;
				
				case 'c':
				{
					return 1;
				}
				break;
			
				// you can add more code key options here
		
				default:
				{
					exit (0);
				}
			}
		}
	}
	
	SimpleEncryption (const string& inFileName, const string& outFileName) : Encryption (inFileName, outFileName)
	{}
};

int main (int argc, char const* argv[])
{
	string inFileName, outFileName;
	char key, choice;
	
	cout << "Encrypt or decrypt? (E/D) Anything else to exit. \n: ";
	cin >> choice;
	
	switch (choice)
	{
		case 'E': // This uses the fall-through function to accept either capital or lowercase letters
		case 'e':
		{
			cout << "Enter the name of the text file to be encrypted. \n: ";
			cin >> inFileName;
	
			cout << "Enter the name of the text file to receive the encrypted text. \n: ";
			cin >> outFileName;
	
			cout << "Enter the encryption key. \n: ";
			cin >> key;
			
			// initialize an object of the SimpleEncryption class
			SimpleEncryption obfuscate (inFileName, outFileName);
			
			// call to encrypt member function
			obfuscate.encrypt (key);
			
			cout << "File encrypted. \n";
		}
		break;
		
		case 'D':
		case 'd':
		{
			cout << "Enter the name of the text file to be decrypted. \n: ";
			cin >> inFileName;
	
			cout << "Enter the name of the text file to receive the decrypted text. \n: ";
			cin >> outFileName;
	
			cout << "Enter the decryption key. \n: ";
			cin >> key;
			
			SimpleEncryption obfuscate (inFileName, outFileName);
			
			obfuscate.decrypt (key);
			
			cout << "File decrypted. \n";
		}
		break;
		
		default:
		{
			break;
		}
	}
	
	return 0;
}


Wow, it all fits in here. I'll try @seeplus's idea and see if it works.

Thanks!
max

Edit:
Welp, no go for that one either. It did the exact same thing as before. I'll see if I can cook up something that does what you suggested.
Maybe it's my program...?
Last edited on
The less code in your program the fewer opportunities are available to make errors. Don't create nonessential problems just to solve them and make mistakes in the process.

Accomplish this by considering how design decisions affect the quality of your deliverables.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <algorithm>
#include <iostream>
#include <string_view>
#include <iterator>

int main(int argc, char const *argv[])
{
  if (argc == 3)
  {
    int key = (std::hash<std::string_view>{}(argv[2]) % 127) + 1;
    if (argv[1][0] == 'd') key = -key;
  
    std::transform(std::istreambuf_iterator<char>{std::cin},
                   std::istreambuf_iterator<char>{},
                   std::ostreambuf_iterator<char>{std::cout},
                   [key](unsigned char ch) { return static_cast<char>(ch + key); });
  } 
  else std::cerr << "usage: " << argv[0] << " {encrypt|decrypt} password\n";
}


std::hash is used to convert a password string to a number. Our usage assumes some things about the hash algorithm, but any decent one should suffice. The resulting number must be nonzero, or else the encrypted message will be indistinguishable from the original one.

One can't skip spaces without being careful to avoid encrypting non-spaces into spaces.

Further, one needs to make sure that all arithmetic is done modulo 256 so that the encrypted data can be written out completely as an 8-bit character. Modular arithmetic is the correct reason to use unsigned numbers in a C++ program. This explains the careful and deliberate use of unsigned char.

After building, try running the following command at a shell
echo "Hello my name is mbozzi!" | ./a.out encrypt my_password
Follow it up by decrypting the output
echo "Hello my name is mbozzi!" | ./a.out encrypt my_password | ./a.out decrypt my_password
Don't forget about redirection
https://wiki.bash-hackers.org/howto/redirection_tutorial
Last edited on
@mbozzi,
I haven't used shells much...do I need to name the program a specific thing? Or does the shell automatically name it? I'm sorry, I just am not too familiar with shells. Like...once I wrote a simple Makefile (copied from an online tutorial) so I could compile a program, header, and implementation files and that is about it.

max

Also, do I enter the
echo "Hello my name is mbozzi!" | ./a.out encrypt my_password
right into the command line or do I need to write a separate shell script for it?

Edit:
Um, well I tried writing a shell script:
 
echo "Hello my name is mbozzi!" | ./hash-encrypt encrypt my_password

where "hash-encrypt" was the name of the executable, that much I gathered. But I got this when I ran the script???
����ڋ�����Ћ�ދ�����Ԍu
Last edited on
The output of the encryption in mbozzi's example may not necessarily be printable ASCII, so that might explain the question marks or weird symbols you get.
@Ganado,
Oh. That's weird. Can I store it in a binary file, and would I be able to be read it from the binary file?
I haven't used shells much
You were using Bash in a prior thread so I assumed you were more familiar with it. No worries.

Firstly you shouldn't need to write a separate script for each of these commands. Just type them right in. Although again I'm very unfamiliar with Apple stuff so I might be wrong.

Can I store it in a binary file

Sure can! Redirect the program's output (i.e., cout) to any file (output.bin here). This will destroy the file's prior contents, if any exist:
echo "My message" | ./hash-encrypt encrypt my_password >output.bin

Then decrypt output.bin by telling bash to use it as the input to hash-encrypt:
<output.bin ./hash-encrypt decrypt my_password

I may be getting ahead of myself. The command ./hash-encrypt just runs the program named hash-encrypt in the current directory. The dot-slash means "current directory". It doesn't do anything, except print a diagnostic message.

The command ./hash-encrypt decrypt my_password
Gives the words "decrypt" and "my_password" to the program ./hash-encrypt by passing them to its main function through the parameters argv and argc. That's how the program knows what to do. See this tutorial:
https://www.learncpp.com/cpp-tutorial/command-line-arguments/
If you run this command the program will read from std::cin forever or until there is no more input. Type a brief message if you want, then tell the shell there is no more input by pressing Ctrl+D.

This isn't a very easy way to use the program; it will most likely print garbage all over the screen. That's where Bash comes in. The trick is figuring out how to tell Bash what to do.
Last edited on
Oh...well I have some scanty knowledge of Bash but not very much. Just enough to compile/run/debug programs, change directories, do some text editing (with vim).

Wow. Not exactly what I meant but if it works, all good! I meant if there was any way to modify the program so it would just automatically store in a binary file, but this will work fine! Thanks!

max
The program I wrote is an example of a filter, which are fairly common outside of Windows.

For example there's cat and sed and sort and tail which all have a similar interface with the redirection, etc. You'll encounter this again if you keep using Bash for anything.
Last edited on
and for that matter, I have a package called cygwin hacked into my windows cmd (its just win paths to force it to work) that lets me use awk/sed/grep/etc on windows. A lot of these tools are very useful for programmers.
You can also download the GNU utils separately from cygwin, which is what I've done on my laptop.
http://gnuwin32.sourceforge.net/packages.html
That's weird. When I used vim to read the file "output.bin" it just had this in it:
¿ÓÔÞ<8b>ÔÞ<8b>Ì<8b>ßÐÞßu


I guess that's the binary code?

Edit:
But wow, it works! Thanks so much, mbozzi!

max

Edit 2:
I went one step further, and figured out that I can do this, too:
<message.txt ./hash-encrypt encrypt my_password >encoded.bin


And that works too!

Edit 3:
I also realized that I can save the code as anything I want...dat, bin, exe, rtf, etc. I'm wondering though, is this a good idea?
I even tried saving it as something random "encoded.poop" and it still saved it! My computer thinks it's an executable.
Last edited on
I also realized that I can save the code as anything I want...dat, bin, exe, rtf, etc. I'm wondering though, is this a good idea?


Yeah, the file extension is just part of its name -- it doesn't make any difference.

That being said, other programs might assume certain things about files based on their names.

unix assumes nothing; exectuable files' extension is often blank, it uses the attributes one of which is executable.
its not a good idea to make random binary files marked as executable or labeled .exe on win. The os will try to execute the file if someone double clicks or types the name, and it could have random destructive statements. Usually it just fails, but that one in a million time when it runs a bit can be horrible. An intern ran an intel chip program on our irix/sgi machine and wiped the disk :( not exactly the same thing but it for sure executed random statements

use .enc or if trying to disguise what it is, something harmless like .RGB (this is a raw image file, it won't do any harm if something opens it incorrectly) or unused (.zzz, .qqq, stuff like that is not used by anything common. I mean, use common sense... .jpg is common, .doc is common, .html is common, etc. )
Last edited on
@jonnin,
Thanks for the warning! I am careful, because I know what can happen with this kind of stuff if you aren't. e.g. my cousin and I accidentally wiped his mom's computer once with a random Python program he made. Thankfully they were able to restore it, but I've been very careful ever since.

Note: I actually did try saving those commands as shell scripts, and they work! All I have to do is run them!

But thanks guys, @mbozzi, @jonnin, @Ganado, @seeplus!

max
Topic archived. No new replies allowed.