I am working on an Encryption/Decryption program for class and have run into a problem. I seem to have gotten the encryption correct, but I am unable to decrypt what was encrypted in order to get an output equal to what originally went in.

Here is the code I have so far:

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
	char userInput[24], inputFileName[51], encryptionFileName[51], outputFileName[51], encChar, decChar;
	int weightedSum = 0, modSum = 0, currentPos, intValue, fileValue, encVal, endEnc, decVal, endDec;
	fstream inputFile;
	fstream encryptionFile;
	fstream outputFile;

	cout << "Input string: ";
	cin >> userInput;

	//**********Create Encrypt/Decrypt Value*************//

	for(int i = 0; i <= 23; i++)
	{
		intValue = int(userInput[i]) - int('0');
		
		currentPos = 1 + i;
		weightedSum += intValue * currentPos;
	}

	modSum = weightedSum % 7043;

	cout << "modSum: " << modSum;

	//***********Encryption Starts Here*************//

	cout << "Enter the name of the input file: ";
	cin >> inputFileName;

	inputFile.open(inputFileName, ios::in);

	if(!inputFile)
	{
		cout << "\n\n\nThe file titled \"" << inputFileName << "\" cannot be opened or does not exist." << endl;
		cout << "\n\nPress any key to exit . . .";
		_getch();
		return 1;
	}

	cout << "Enter the name of an encryption file: ";
	cin >> encryptionFileName;

	encryptionFile.open(encryptionFileName, ios::out);	

	while(inputFile.get(encChar))
	{
		encVal = int(encChar) - int('0');
		endEnc = encVal + modSum;
		encryptionFile << endEnc;
	}

	inputFile.close();
	encryptionFile.close();

	//********DECRYPTION STARTS HERE**********//

	cout << "Name of output file: ";
	cin >> outputFileName;

	outputFile.open(outputFileName, ios::out);
	encryptionFile.open(encryptionFileName, ios::in);

	while(encryptionFile.get(decChar))
	{
		decVal = decChar - modSum;
		endDec = int(endDec) + int('0');
		outputFile <<  endDec;
	}

	encryptionFile.close();
	outputFile.close();
}

Here is the assignment that I was given:

Simple encryption and decryption of a text file. Allow the user to input any string of up to 23 characters of digits or upper or lower case letters. Calculate the weighted sum of input using the ascii values of the input character. Take the weighted sum and mod by 7043 to get your encryption/decryption value. Ask for the names of an input and encryption file. Both will be plain text, input must exist, encryption can be created if necessary. Read each character of the input file, take the ascii value of the input add the encryption encryption/decryption value and write that character into the output file. The final output file will be nothing but a string of numbers. Close the files. Ask for the name of an output file, reopen the encryption file and create the output file. Read in the encryption file, decrypt the code and write the result back into the output file. Close both files. Reopen the input file and the output file. Compare the files character by character to confirm the code works.

Sorry for the long post. I am completely open to any advice and/or criticism. Right now I am just needing a little advice as to what I am doing wrong with the decryption part, and if you see something that I could improve upon I am open to that also, as I know this code is not perfect or clean. Thank you so much for your time and help.

Recommended Answers

All 14 Replies

You'll want to take a look at your encrypted file. Seems to me it will end up being a long line of digits with no spaces, tabs, commas, etc. dividing them:

345423562352345423512341234234534253455432454325

or whatever, representing a bunch of integers. Here's the problem. When you open the file again to read in a bunch of integers, how do you know when one integer stops and the next one starts? And if you're WRITING integers to the file to encrypt, why are you not READING integers when you decrypt. I would imagine you want to read in exactly what you wrote out, then do whatever conversions you need to do.

Thirdly, this code seems pointless. You calculate a value for decVal, but never use it.

while(encryptionFile.get(decChar))
	{
		decVal = decChar - modSum;
		endDec = int(endDec) + int('0');
		outputFile <<  endDec;
	}

You'll want to take a look at your encrypted file. Seems to me it will end up being a long line of digits with no spaces, tabs, commas, etc. dividing them:

345423562352345423512341234234534253455432454325

or whatever, representing a bunch of integers. Here's the problem. When you open the file again to read in a bunch of integers, how do you know when one integer stops and the next one starts? And if you're WRITING integers to the file to encrypt, why are you not READING integers when you decrypt. I would imagine you want to read in exactly what you wrote out, then do whatever conversions you need to do.

Thirdly, this code seems pointless. You calculate a value for decVal, but never use it.

while(encryptionFile.get(decChar))
	{
		decVal = decChar - modSum;
		endDec = int(endDec) + int('0');
		outputFile <<  endDec;
	}

Yes, I noticed the same thing with the encrypt file. That once the encryption is done to the original text file and is being put into the encrypt text file that there is no way to specify which numbers go with which original character. Yet, I also do not know how to do this. The assignment states that the encrypt text file will just be a long string of numbers that represent the characters in the original text input file. If I told it to add a space or something after each time it does a conversion that should solve the separation issue, which should be easy enough to do. But I am not sure what I need to do after that. I have a text file with a bunch of numbers in it and now I have to change it back to letters and output it to a new file so that I can proceed with the step about comparing the final output and the original input. The code that you said was useless was actully typed out wrong, but even after I corrected it on my end, it still does not do what I need it to do. It takes each number in the encrypted file, subtracts the modSum from the conversion process, then I attempt to make it into a character, but instead it just stays a number and outputs that to the file, so I end up with a completely new string of numbers in my final output file. So, the code that you posted above was orignally supposed to be:

while(encryptionFile.get(decChar))
{
	decVal = decChar - modSum;
	endDec = char(decVal);
	outputFile <<  endDec;
}

But as I said it still does not work. Any ideas or examples. I am also not sure exactly what you meant by:

"And if you're WRITING integers to the file to encrypt, why are you not READING integers when you decrypt. I would imagine you want to read in exactly what you wrote out, then do whatever conversions you need to do."

Because I am using the encrypt file to catch what is encrypted from the original input file, which it is being used as output then. Then I close it and re-open it as an input file and read from it, which is where I am stuck with the decryption. I apologize if I am misunderstanding something, which I am sure I am. But this is the first time I have had to do a program like this. Thank you again for your response and any future help you offer.

You may need to go back to your professor for clarification on what's required. First, let's parse this sentence:

The final output file will be nothing but a string of numbers.

I would read it as "no spaces allowed between the numbers", but others may read it differently. If you were ALLOWED to stick spaces in, your problem of where one starts and the other stops is no longer a problem.

But let's assume that I'm reading this correctly and that you are NOT allowed to do that. How then does one distinguish one integer from the next? Perhaps there's a math trick in there (i.e. you are guaranteed that each integer will be a certain number of digits). You could analyze every possible combination and perhaps there may be some conclusion you can draw on the value of modSum as far as number of characters or whatever. I doubt it though, particularly if this isn't a math class. You should assume modSum can be any number from 0t to 7043, so no help there as far as the number of digits.

Your other alternative is to write and read from the file as binary data. Integers will take the same number of bytes each time, so you can delineate them that way. But then you'd have to compare the files using a binary editor like Hex Editor Neo. Doubtful.

How advanced is this class anyway? Is this the kind of stuff your professor throws at you (i.e. you have to find some "gimmick" to get it to work) or is this a flat-out text manipulation exercise?

I'd ask the professor. You need SOME way of telling subsequent integers apart for this to work. You're either supposed to figure that out, as mentioned, by the number of digits (if that's even possible, as mentioned above), or they need to be delineated by white space or something like that. Regardless, I feel extremely confident that you are supposed to get that data from the file into an integer, not a character, so this isn't going to work.

decVal = decChar - modSum;
endDec = int(endDec) + int('0');

modSum can be up to 7043, decChar is a character, so you're looking at decVal being negative, and I'm not sure what endDec is here. You should be using decVal somewhere and if you're adding a '0' to it, presumably, you want something ending up as a positive number, so -7000 or whatever isn't going to work.

You may need to go back to your professor for clarification on what's required. First, let's parse this sentence:

I would read it as "no spaces allowed between the numbers", but others may read it differently. If you were ALLOWED to stick spaces in, your problem of where one starts and the other stops is no longer a problem.

But let's assume that I'm reading this correctly and that you are NOT allowed to do that. How then does one distinguish one integer from the next? Perhaps there's a math trick in there (i.e. you are guaranteed that each integer will be a certain number of digits). You could analyze every possible combination and perhaps there may be some conclusion you can draw on the value of modSum as far as number of characters or whatever. I doubt it though, particularly if this isn't a math class. You should assume modSum can be any number from 0t to 7043, so no help there as far as the number of digits.

Your other alternative is to write and read from the file as binary data. Integers will take the same number of bytes each time, so you can delineate them that way. But then you'd have to compare the files using a binary editor like Hex Editor Neo. Doubtful.

How advanced is this class anyway? Is this the kind of stuff your professor throws at you (i.e. you have to find some "gimmick" to get it to work) or is this a flat-out text manipulation exercise?

I'd ask the professor. You need SOME way of telling subsequent integers apart for this to work. You're either supposed to figure that out, as mentioned, by the number of digits (if that's even possible, as mentioned above), or they need to be delineated by white space or something like that. Regardless, I feel extremely confident that you are supposed to get that data from the file into an integer, not a character, so this isn't going to work.

decVal = decChar - modSum;
endDec = int(endDec) + int('0');

modSum can be up to 7043, decChar is a character, so you're looking at decVal being negative, and I'm not sure what endDec is here. You should be using decVal somewhere and if you're adding a '0' to it, presumably, you want something ending up as a positive number, so -7000 or whatever isn't going to work.

I understand what you mean, I will send an email to the professor asking him to elaborate on this a little more. The professor has been of no help to us this semester, he listed 15 programs on the website at the beginning of the semester but never actually "taught" us anything, then about 2-3 weeks ago he put up another 10 programs for us to do by the end of the semester and most of them are like this. The assignments that he has posted he has had to re-write 2-3 times each because of errors and him not knowing the correct calculations (perfect example is his idea that an ISBN-13 number was a weighted sum modded by 7, very incorrect). But yes, these are the types of programs we have had to do all semester, where there is a so-called "gimmick" to get it to work. This is an on campus class, yet he has only shown up for about 3-4 classes claiming sickness, etc., so everything is being done through the website with little response from him, he has mentioned several times that this is a self-taught course and that he is there for backup, but if so, then the book he chose is worthless and nothing ever stated the fact that that is what this course is. Either way, this is supposed to be a little above beginner C++ course, the class below this one is doing very beginner stuff and psuedo-code assignments, so I guess intermediate, but it's just called C++ Programming. But once again, I will ask and post back with his response so that I might be able to get on the right track with this program.

Ok, as for the last part of your reply, you stated that decVal would be negative due to decChar being a char value, when I changed decChar from a char to an int value I recieved this error:

error C2664: 'std::basic_istream<_Elem,_Traits> &std::basic_istream<_Elem,_Traits>::get(_Elem &)' : cannot convert parameter 1 from 'int' to 'char &'1>

endDec is just the holder of the final character value and is printed into the final output file, stands for end decryption.

But let me send a mail to my professor and let him clarify this more and I will re-post. Once again, thank you so much for you help.

You're welcome. Definitely ask for clarification. It would be silly to jump through all the hoops and then find out that you were actually allowed to stick a space between integers. Sometimes professors aren't as precise with their language/requirements as they need to be.

Delete lines 69 -74 and rewrite that decryption segment from scratch. Presumably you want to do the exact opposite of what you did to encrypt, so list the steps that you did to encrypt, then do the exact reverse in reverse order to decrypt, so if you WROTE an integer to the file as the LAST step of encryption, you need to READ an integer from a file as the FIRST step in decryption.

You're welcome. Definitely ask for clarification. It would be silly to jump through all the hoops and then find out that you were actually allowed to stick a space between integers. Sometimes professors aren't as precise with their language/requirements as they need to be.

Delete lines 69 -74 and rewrite that decryption segment from scratch. Presumably you want to do the exact opposite of what you did to encrypt, so list the steps that you did to encrypt, then do the exact reverse in reverse order to decrypt, so if you WROTE an integer to the file as the LAST step of encryption, you need to READ an integer from a file as the FIRST step in decryption.

Ok, I got a response stating that I am supposed to "Pad each result with zeros so each will be 4 digits even if the mod resulted in a number less than 4 digits. Then when reading in you can convert those 4 appropriately." Then it goes on to say that the use of spaces, commas, etc. allow hackers to distinguish elements of the code and they would figure it out to easily. Then he says that this would require "multiple different modifiers for the letters in a pattern based on something different than a single prime." He then states that if my code can't easily be converted to allow this then I can go ahead and use spaces and to just let him know which I use. So, I guess I'll just use spaces since I honestly do not understand in any way how to do that with zeros like he stated. So, I'm assuming that in my code I will need to add a space to the end of the encryption code as such:

while(inputFile.get(encChar))
{
	encVal = int(encChar) - int('0');
	endEnc = encVal + modSum;
	encryptionFile << endEnc << " ";
}

If this is the correct way to do that then we're on to the decryption aspect of the program. The way that I had the program setup seemed that I was at least close to doing the decryption process backwards from the encryption process, but if you see something wrong with it then it must still not be right. Also, you said that I needed to read an integer in as the first step of decryption, decChar would be the variable that I am using to read in using the .get functionality there, if I change decChar from char decChar; to int decChar; I get the error that I posted last night a couple of comments up from this one, not sure why. With the extra space after each of the sets of integers in the encryption file, how will I pull them in groups in order to do the correct calculations and turn them back into characters?

If you don't want to tackle the zero padding and just add spaces instead, then yeah, that looks OK for the encryption. As for the decryption, assuming you are adding the spaces, as you need to read in an integer using the >> operator. You read an integer from the encrypted file, not a character, and you use the >> operator. Then you take the integer and subtract what you added before and add what you subtracted before (i.e. modSum and '0'), then you convert it to a character and if you did everything right, it'll be the original character.

Make your life easy and start with a string like "0", "1", "2", "00", then "11", then "01", then "22", then "23", etc. Pick really easy strings to convert so you can check them easily. When those all work, start doing the more complex ones. If you start with "A628TU42", you'll never find your bugs.

I have a feeling your conversion process is what your other thread is about. Take the result of the equation I suggested in this post and combine it with an output manipulator to produce a continuous string of padded "numeric" characters. Then, when reading the file, use a character-based input function to read groups of 4 bytes into a stringstream, then extract from the stringstream to an integer.

If you don't want to tackle the zero padding and just add spaces instead, then yeah, that looks OK for the encryption. As for the decryption, assuming you are adding the spaces, as you need to read in an integer using the >> operator. You read an integer from the encrypted file, not a character, and you use the >> operator. Then you take the integer and subtract what you added before and add what you subtracted before (i.e. modSum and '0'), then you convert it to a character and if you did everything right, it'll be the original character.

Make your life easy and start with a string like "0", "1", "2", "00", then "11", then "01", then "22", then "23", etc. Pick really easy strings to convert so you can check them easily. When those all work, start doing the more complex ones. If you start with "A628TU42", you'll never find your bugs.

Ok, the first thing I wanted to do was just to make sure that I get a letter as output from the decryption, since up till now it has been a bunch of integers that were negative. So I made the following changes to the decryption:

while(encryptionFile)
{
	encryptionFile >> decInt;
	decVal = decInt - modSum;
	endDec = int(decVal) + int('0');
	outputFile <<  char(endDec);
}

Here is exactly what is happening, when I run the program:

The modSum is calculated correctly at 4922 entering an encryption string of zxzxzxzxzxzxzxzxzxzxzxz. This is then correctly added to the ascii value of what I have in the text file. At this time the only thing in the text file is the letter a. So the sum is 4971 now, and this number with a space after is put into the encryption file. Now decryption starts. The decryption code that I put above seems to loop 2 times but i'm not sure why. I put a cout for each variable in it to get what they state at the time they are calculated or executed:

decInt: 4971 //this is the integer coming in from the file
decVal: 49 //subtracted modSum, this is correct
endDec: 97 //adding int('0') to int(decVal), I believe this is correct?

It then repeats these 3 calulations again, same numbers and output. The output file has 2 a's in it in the end. So, I think I am making progress here as I started with 1 a in the input file and ended with 2 a's in the output file. Any idea on as to why it is repeating that decryption 2 times, and once I get that working then I will try two letters and calculating them seperately because of the space there.

I have a feeling your conversion process is what your other thread is about. Take the result of the equation I suggested in this post and combine it conjunction with an output manipulator to produce a continuous string of padded "numeric" characters. Then, when reading the file, use a character-based input function to read groups of 4 bytes into a stringstream, then extract from the stringstream to an integer.

No, actually these are not tied together in any way. They are completely seperate programs. The other thread was just trying to clean up some code on a program that is already finished, this one is completely different. Thanks for your help though.

>> Any idea on as to why it is repeating that decryption 2 times

Most likely the input stream isn't failing when you think it is. The stream reads in the last integer and when it does, it hasn't failed yet. It fails when it attempts to read in a new integer and can't.

In other words it fails on line 3, but you don't check that before proceeding to lines 4 through 6. The check will occur on line 1, but by then you've gone through once too many times.

while(encryptionFile)
{
      encryptionFile >> decInt;
      decVal = decInt - modSum;
      endDec = int(decVal) + int('0');
      outputFile << char(endDec)
}

Try changing it to this and see if it works better(or do it the way you have it above and check the encryptionFile stream AGAIN after line 3 above:

while(encryptionFile >> decInt)
{
      decVal = decInt - modSum;
      endDec = int(decVal) + int('0');
      outputFile << char(endDec)
}

>> Any idea on as to why it is repeating that decryption 2 times

Most likely the input stream isn't failing when you think it is. The stream reads in the last integer and when it does, it hasn't failed yet. It fails when it attempts to read in a new integer and can't.

In other words it fails on line 3, but you don't check that before proceeding to lines 4 through 6. The check will occur on line 1, but by then you've gone through once too many times.

while(encryptionFile)
{
      encryptionFile >> decInt;
      decVal = decInt - modSum;
      endDec = int(decVal) + int('0');
      outputFile << char(endDec)
}

Try changing it to this and see if it works better(or do it the way you have it above and check the encryptionFile stream AGAIN after line 3 above:

while(encryptionFile >> decInt)
{
      decVal = decInt - modSum;
      endDec = int(decVal) + int('0');
      outputFile << char(endDec)
}

Ok, I did what you said and changed the code to:

while(encryptionFile >> decInt)
{
      decVal = decInt - modSum;
      endDec = int(decVal) + int('0');
      outputFile << char(endDec)
}

And it worked great, it only output one a instead of 2 and output is identical to input. I then tried it with 2 letters in the input, ab. This also worked, so did a sentence as well as a paragraph with punctuation included. So, now my question is exactly how does the little amount of changing that we did to the decryption part of this program do this. I am just curious about how it works, how does it know that there are spaces and to skip them, then start a new character afterwards, etc. Other than that, thank you so much for your help, I'll mark this thread solved tomorrow to give you time to get back to me if you want. I'll start a new thread if I run into problems with the comparison of the files at the end of the program, though I hope that I can get that without help. Have a great night, and once again thanks.

You're welcome. I'm not sure about the answer below, but I think it's possibly close enough to justify posting it, so just remember the disclaimer. Don't bank on the explanation being 100% (or even 90%) correct. If you're interested, it might be worth starting another thread. There are definitely people who DO know for sure.

But here goes...

An ifstream returns a null pointer if it's in a state where you can't read from it. There are three bits that can be set: eofbit, failbit, badbit.. When >> tries to read an integer, but can't because there are none left, I think the eofbit and the failbit are set. This in turn causes there to be a null pointer. See this page:

http://www.cplusplus.com/reference/iostream/ios/operator_voidpt/

In particular, see this part of it:

Return Value
null pointer if either failbit or badbit is set.
A non-null pointer otherwise.

So you try to read from the stream here:

while(encryptionFile >> decInt)

and the failbit gets set, so the stream points to null(0), so your while condition fails. The problem you had before was that the stream failed INSIDE of the loop and you were only checking at the TOP of the loop. The stream doesn't fail when you read the LAST integer. It fails AFTER that(when it tries to read an integer and can't).

It's a fairly common mistake. People test the stream with the eof() function at the top of a loop, then read it inside the loop and have the same difficulty. The stream is still considered a valid stream even after the last piece of information is read, so i suggested that you instead try to read from it, THEN check it rather than vice versa.

You're welcome. I'm not sure about the answer below, but I think it's possibly close enough to justify posting it, so just remember the disclaimer. Don't bank on the explanation being 100% (or even 90%) correct. If you're interested, it might be worth starting another thread. There are definitely people who DO know for sure.

But here goes...

An ifstream returns a null pointer if it's in a state where you can't read from it. There are three bits that can be set: eofbit, failbit, badbit.. When >> tries to read an integer, but can't because there are none left, I think the eofbit and the failbit are set. This in turn causes there to be a null pointer. See this page:

http://www.cplusplus.com/reference/iostream/ios/operator_voidpt/

In particular, see this part of it:

So you try to read from the stream here:

while(encryptionFile >> decInt)

and the failbit gets set, so the stream points to null(0), so your while condition fails. The problem you had before was that the stream failed INSIDE of the loop and you were only checking at the TOP of the loop. The stream doesn't fail when you read the LAST integer. It fails AFTER that(when it tries to read an integer and can't).

It's a fairly common mistake. People test the stream with the eof() function at the top of a loop, then read it inside the loop and have the same difficulty. The stream is still considered a valid stream even after the last piece of information is read, so i suggested that you instead try to read from it, THEN check it rather than vice versa.

Surprisingly, I actually somewhat understand what you are talking about here. It's an intersting topic and always good to understand the way this stuff works to be more efficient in its use in the future. I'll read up on that link you posted and may even post to the forums here for more info in the future. Thanks for everything, I'm having a couple problems with the compare part of the program so I'll probably be posting a new thread about it soon. Just glad that I got this part of it working for the moment being. Marking this thread solved. Have a great day.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.