[C++] Xor encryption

Started by
13 comments, last by kake_fisk 13 years, 11 months ago
I'm going to xor encrypt some files for my C++ game. Right now, I want to read some text from a file, encrypt it and then save the encrypted information to the same file. And when I run the program again, it should decrypt the file and give the original content of the file.
string crypt(string input, char key)
{
    string ret;
    std::size_t size = input.size();
    for(int i=0;i<size;i++)
    {
        ret += input ^ key+i;
    }
    return ret;
}

int main()
{
    ifstream ifile;
    ofstream ofile;
    string content = "";
    string filename = "fox.txt";
    ifile.open(filename.c_str());
    if (ifile.is_open())
    {
        while (!ifile.eof())
        {
            getline (ifile,content);
        }
        ifile.close();
        ifile.clear();
    }
    cout << "content: " << content << endl;
    cout << "content size: " << content.size() << endl;
    content = crypt(content,1);
    cout << "crypt: " << content << endl;
    cout << "crypt size: " << content.size() << endl;
    ofile.open(filename.c_str());
    if (ofile.is_open())
    {
        ofile << content;
        ofile.close();
    }
    return 0;
}
The problem is that, when I encrypt a simple sentence everything goes alright. But when I try to encrypt the file which I am using in my game, it plays a lot of beep sounds and the total amount of characters in the file are decreased. I think the beep sound might come from the bell character, but I'm not sure. When I encrypt "The quick brown fox jumps over the lazy dog.", I get "Ujf$tsnkb*i~bya0w}k4czhj:tjxl?TIGHD\^MEL" and vice versa. But when I encrypt:
Quote:02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 02 00 00 00 02 02 00 00 00 00 00 00 00 00 02 02 00 00 00 02 02 00 00 00 02 03 00 00 00 00 00 00 00 00 04 02 00 00 00 02 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 02 00 00 00 02 01 00 00 00 00 00 00 00 00 03 02 00 00 00 02 02 00 00 00 02 02 00 00 00 00 00 00 00 00 02 02 00 00 00 02 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
It gives:
Quote:10#47&7:):9,=</ #2#&5&%8)(;,/>/? pqbstevwhyzk|}n`qbctefwhizkl}no@QRCTUFWXIZ[L]^O@ARCDUFEXIH[LM^O°¡²³¤µ¶§¸¹ª»¼­¾¿°¡¢³¤¥¶§¨¹ª«¼­®¿‘‚“”…–—ˆ™š‹œŽŸ€‘‚”…„—ˆ‰š‹ŒŽàñðãô÷æ÷øéúûìýþïàáòãäõæçøéêûìíþïÒÁÒÑÄÕÖÇØÙÊÛÜÍÞÝÐÁÀÓÄÅÖÇÈÙÊËÜÍÌß02"34%67(9:+<=.? 1"#4%&7():+(=.- ? parsduvgxyj{|m~pabsdevghyjk|mnPQBSTEVUHYXK\]N_@QBCTEFWHIZKL]NO ±²£´µ¦·¸©º»¬½¾¯ ¡²£¤µ¦§¸©ª»¬­¾¯’‘„•”‡˜™Š›œžŸ‚“„…–‡ˆ™Š‹œŽŸðñâóôåö÷èùúëüýîÿàñâãôåæ÷èéúëìýîíÀÑÐÃÔÕÆ×ØÉÚÛÌÝÞÏÀÁÒÃÄÕÆÇØÉÊÛÌÍÞÏ0!23$56'89*;<->?0!"3$%6'(9*)<-,?? ? `qrctufwxiz{l}~o`arcdufexih{lm~oPARSDUTGXXJ[\M^_PABSDEVGHYJK\MN_°±¢³·¥¶µ¨¹º«¼½®¿ ±¢¡´¥¤·¨©º«¬½®¯€‘ƒ”—†—˜‰š›Œž€’ƒ„•†‡˜‰Š›ŒžòáòñäõöçøùêûüíþýðáàóäåöçèùêëüíîÿÐÑÂÓÔÅÖ×ÈÙÚËÜÝÎßÀÑÂÃÔÅÆ×ÈÉÚËÌÝÎÏ 12#45&78):9,=</ !2#$5&'8)*;,->/ pqbstevuhyxk|nbqbatedwhkzkn}nm@QPCTWFWZIZYL]\O@CRCFUFEXIH[LO^O²¡²±¤
And when I try to decrypt it again, it gives:
Quote:vvjz~nzzfvjznnzjvfzzn~zjvvZJN^JJfvzj~~jzvfjj~njzvvjz~nzxfv öæúúîþúêööúêîþêêæöúêþþêúöæÊÊÞÎÊÚööêúþîúúæöêúîîúêöæúøîþøêöö fvxj~|jzvfjj~njzvvjz~nzzfvJZNNZJtfzxn~zjvvzjn~jhfvxj~~jzvf öõêúþîúúæöêúîîúêöæúúîþúêööÚÊÊÞÊÈæöúêþþêúöæ
Which certainly isn't the same as it started with. I think the problem has something to do with the saving, loading or maybe the encoding as the first sentence works. Sorry for the long post, but I felt all this information was necessary. Thanks for helping.

Visit my website ?


Sacred Water

Advertisement
For starters, you should probably be handling files in binary mode, instead of in text mode. You should also work one byte at a time, instead of one line at a time:

#include <iostream>#include <fstream>#include <string>using namespace std;int main() {	ifstream in( "fox.txt", ios::binary );	ofstream out( "fox.dat", ios::binary );	char key = 1;		if ( in.is_open() && out.is_open() ) {		for ( int count = 0; !in.eof(); ++count ) {			char ch;			if ( in.get( ch ) ) {				ch = (ch ^ key) + count;				// When reversing, you need to: 				// ch = (ch - count) ^ key				out.put( ch );			}			}	}}


Quote:
it plays a lot of beep sounds and the total amount of characters in the file are decreased. I think the beep sound might come from the bell character, but I'm not sure.


Yes, those beeps are from the bell character. Also note that any character below 32 are considered ASCII control characters.
I tried to open the file in binary mode, but it didn't make much change. And I do work with one byte at a time, I just read the whole file first. The crypt function takes one character at a time and crypts it. And to be honest, I doubt I have to subtract the character by anything when I decrypt as the first sentence was decrypted as it should have. But regarding the control characters, I found some backspace characters and some other characters I don't even know what means. Can this be what causes the file's character decrease?

Visit my website ?


Sacred Water

Your working with strings while really it should be done with byte arrays. Binary mode will make a big difference as it won't fix up new lines.
Quote:Original post by kake_fisk
I tried to open the file in binary mode, but it didn't make much change.
Which file? The input file or the output file?

Quote:
And I do work with one byte at a time, I just read the whole file first.
while (!ifile.eof()) {	getline (ifile,content);}
getline replaces content. So this bit o' code will only store the last line of ifile into content. See Reading a whole file into a string, with ifstream.

Quote:And to be honest, I doubt I have to subtract the character by anything when I decrypt as the first sentence was decrypted as it should have.

You have to reverse the mathematical operations you perform on a character in order to expect it to work correctly. See sample code.

Quote:But regarding the control characters, I found some backspace characters and some other characters I don't even know what means. Can this be what causes the file's character decrease?
Try writing the string directly:
outfile.write( str.c_str(), str.len() );
You don't need to build up a transformed string at all.

Spoilers! Either ignore or study in detail as you prefer ;)

#include <iostream>#include <fstream>#include <iterator>#include <algorithm>// A functor for applying the encryption, which remembers the xor 'key' state.struct encrpytor {	char key;	char operator()(char input) {		return input ^ key++;	}} e = { 1 };int main() {	// This won't work if you are trying to write to the same file you read from,	// of course; but you really should make a new file for the output anyway,	// and then use that to replace the original file once you know everything	// went right. That way, you don't lose or corrupt your input file if there's	// a problem. Figuring out how to get the file names is left up to you.	std::ifstream input("in.txt", std::ios::binary);	std::ofstream output("out.txt", std::ios::binary);	std::transform(std::istreambuf_iterator<char>(input), std::istreambuf_iterator<char>(), std::ostreambuf_iterator<char>(output), e);}
Quote:Original post by Zahlman
This won't work if you are trying to write to the same file you read from,
of course; but you really should make a new file for the output anyway,
and then use that to replace the original file once you know everything
went right. That way, you don't lose or corrupt your input file if there's
a problem.

Ah, reminds me of good old copy-and-swap :)
Okay, I tried to follow some of the advice posted. But I still haven't manage to solve the problem. Here's the current code:

string encrypt(string input, char key){    string ret;    std::size_t size = input.size();    for(int i=0;i<size;i++)    {        ret += input ^ key+i;    }    return ret;}string decrypt(string input, char key){    string ret;    std::size_t size = input.size();    for(int i=0;i<size;i++)    {        ret += input ^ key-i;    }    return ret;}int main(){    ifstream ifile;    ofstream ofile;    string filename = "numbers.txt";    string content = "";    int answer = 0;    cout << "Press 1 for encrypting or 2 for decrypting." << endl;    cin >> answer;    ifile.open(filename.c_str(), ios::binary);    content.append((istreambuf_iterator<char>(ifile)), istreambuf_iterator<char>());    cout << "content: " << content << endl;    cout << "content size: " << content.size() << endl;    if (answer == 1)    {        content = encrypt(content,1);    }    else if (answer == 2)    {        content = decrypt(content,1);    }    cout << "crypt: " << content << endl;    cout << "crypt size: " << content.size() << endl;    ofile.open(filename.c_str());    if (ofile.is_open(), ios::binary)    {        ofile << content;        ofile.close();    }    return 0;}


But by making both a encrypt and decrypt function, even the fox sentence fails.

PS: It might sound like I'm using hexadecimal values, but it isn't. :)

Visit my website ?


Sacred Water

Quote:
ret += input ^ key+i;
(char)+(int) is handled as int-addition, not char-addition. The integer-ness propagates to the XOR.
Quote:
ret += input ^ key-i;
That's not the opposite operation.
Quote:getline
getline is for textual data, which your encoded file most certainly is not.
Also, moved to For Beginners.

This topic is closed to new replies.

Advertisement