Sign in to follow this  
Sigiloso

Encryptor Advice Please

Recommended Posts

Hi I am relatively new to Cpp(been working with the language for about a year). I read up on XOR encryption, found it interesting, and decided to write a simple encryption program using the method. My first draft works rather well and runs at a decent speed(IMO). What I am looking for now is some constructive criticism and suggestions for adding features(it is a bit TOO simple). Source Code: Main.cpp:
// our included files
#include <iostream> // for input output operations
#include <fstream> // for file operations
#include <string> // contains the string interface
#include <windows.h> // for timing purposes only

using namespace std; // we use the standard namespace

#define BufferSize 16000000 // Buffer Size set 16mb chage it and recompile if you like :)

char* Buffer = NULL; // this one is important it is our buffer we use it to store temporary data for encryption	

//this function encrypts the data by the XOR method (google it for more info)
void XOR(char* Data,long DataSize)
{
	for(long I = 0; I < DataSize;++I)
	{
		Data[I] = Data[I]^'I';
	}
}
// this is the main BODY of the program (hint... hint...) this function is looped through
// till the user specify's he wants to exit
int Body()
{

	fstream File; // the file interface 
	fstream File2; // a secondary interface 
	string FilePath; // our file path

	long FileSize = 0;long FileStart = 0;long FileEnd = 0; 
	float TimeStart = 0; float TimeEnd = 0; 
	long Location = 0;long temp = 0; // stores our location on the file 
	
	cout<<"Enter File Path:(No Spaces Allowed) \n->";
	cin>>FilePath; 

	File.open(FilePath.c_str(),ios::in|ios::out|ios::binary); 

	//calculate the length of the file
	File.seekg(0,ios::beg); FileStart = File.tellg();
	File.seekg(0,ios::end); FileEnd = File.tellg();
	FileSize = FileEnd - FileStart;
	File.seekg(0,ios::beg);

	if(FileSize < 1) // check to see if the file is acctually open
	{
		cout<<"\nError opening file";
		File.close();
		return 1;
	}

	cout<<"\nOperation Started\n"<<"FileSize: "<<FileSize/1000<<" KB";
	TimeStart = float(GetTickCount()); //start the timer for our operation ;)


	cout<<"\n\nWorking...";

	// if the file is smaller then the buffer size we
	//encrypt the whole thing in one shot

	if(FileSize <= BufferSize) 
	{
		File.seekg(0,ios::beg);
		File.read(Buffer,FileSize);
		XOR(Buffer,FileSize); // function that encrypts the data
		File.seekg(0,ios::beg);
		File.write(Buffer,FileSize);
		File.close();

	}
         /*if the file is bigger then the buffer we encrypt it one piece at a time by filling the buffer encrypting it and flushing it back to the HardDrive*/
	else  
	{
		File2.open(FilePath.c_str(),ios::in|ios::out|ios::binary);
		File.seekg(0,ios::beg);
		File2.seekg(0,ios::beg);
		Location = File.tellg(); // set the current location to the beginning

		while(1<2)//loop through the file until its completely encrypted
		{
			if((FileSize - Location) < BufferSize)//finish and exit
			{
				File.read(Buffer,(FileSize - Location));
				XOR(Buffer,(FileSize - Location));
				File2.write(Buffer,(FileSize - Location));
				File.close();
				File2.close();
				break; // exit the loop now that we are finished
			}
			File.read(Buffer,BufferSize);//read data
			XOR(Buffer,BufferSize); // encrypt data
			File2.write(Buffer,BufferSize);// write encrypted data back
			Location = File.tellg();//update location
		}
				
	}

	TimeEnd = float(GetTickCount()); // done the operation so stop the timer

	// display the time the operation took
	cout<<"\n\nOperation Finnished in: "<<float((TimeEnd - TimeStart) / 1000)<<" Seconds"; 

	return 0;// everything went fine so return 0
}
int main() // our main function(program starts here) 
{
	/*
	this function does nothing more then loop through the 'Body()' function
	and ask the user if he wants to exit after every iteration.
	*/
	bool Exit = false; // a varaible for exiting
	char temp;// for input of y or n at exit screen

	Buffer = new char[BufferSize];// create our buffer
	cout<<"Enigma Encryptor v1.1 \n\n";

	while(Exit == false) // while the user doesn't want out
	{
		Body();// execute the main part of the program

		// ask the user if he wants to exit
		cout<<"\nExit? y/n\n";
		cin>>temp;
		if(temp == 'y'){Exit = true;}
	}

	delete[] Buffer;// delete the buffer do this unless you want on massive memory leak :P
	return 0;// exit with 0
}

I did my best to document the code as much as possible. This is the only source file for the program. Visual Cpp 2008 Express Edition was used to compile it. On my system(p4 3.0ghz., 512mb ram, win XP sp2) it can encrypt a 700mb file in ~30 seconds when compiled in release mode(all compiler optimizations turned on and debugging symbols stripped). Note: To decrypt a file, run it through the program again.

Share this post


Link to post
Share on other sites
I'm sure you know this, but just in case, XOR encryption is dangerously easy to crack.

You could do the following things:

1. Allow specifying the filename on the command line, instead of asking it like that. In fact, your program looks more like a command line tool anyway, so don't make it interactive. You can add some command line option handling.

2. Allow the use of other keys than 'I' and maybe longer keys, so that the characters in the key are applied successively to the characters in the input.

3. Use std::vector<char> or std::string instead of char array.

4. Write your file input routines so that you don't need to know the file size. This allows you to read from sources that don't allow seeking to the end.

Share this post


Link to post
Share on other sites
Writing crypto algorithms is fun, tempting, and fascinating to play with, but please be aware that it's nothing but that. If you have anything to hide, please do yourself a favour and use a proven, established algorithm (AES, Twofish, Blowfish, XXTEA, anything...). Otherwise, you will suffer great pain.
Designing your own crypto algorithm is something only a handful of people on this planet are successful with.

Xor encryption is generally not considered a "serious" encryption at all, because it is very easy (trivial) to break. Never use Xor for something that shouldn't be read by anyone.

The only ways in which Xor encryption can be used are one time pad encryption (perfect security, but impractical, because your key must be as long as the message) or by combining it with a secure random number generator, or a block cipher in OFB mode, or something similar.

If you like playing with cryptography, read up on "Feistel network". It's the base of many/most modern ciphers. Coding a Feistel cipher is quite easy too, and a lot of fun to play with :)

Share this post


Link to post
Share on other sites
What if you compress it first and then XOR it with a 256 character long key? Would that have atleast some security?

I mainly try to keep ppl away that have no knowledge and just try to get the files. That is basically 99% of the ppl that look for your files. For that other 1%, or even less you'd use/buy a better encryption.

If they want, they can crack it. Simple as that. But what you should be aiming for, is making it as hard as possible.

Share this post


Link to post
Share on other sites
xor encryption is horrendously easy to break. for one, you can break it a piece at a time, because if your program trying to break it is doing statistical tests it might find a pattern its looking for and just not change that part of the key, and narrow down the size of the search even further.

i broke one as part of a projecteuler.net problem.

Share this post


Link to post
Share on other sites
Quote:
Original post by ibebrett
xor encryption is horrendously easy to break.


Bad XOR encryption is. If you can guarantee that your key is used once and only once, is completely random, is at least the same length as the plaintext, and (more importantly) is completely secure then it's basically unbreakable (you have a one time pad; of course, as soon as you start reusing the key, it's trivially broken – the Soviets fell down here, AFAIK).

But for more practical purposes, you are better off using something else.

Share this post


Link to post
Share on other sites
Quote:
Original post by Decrius
What if you compress it first and then XOR it with a 256 character long key? Would that have atleast some security?

Why not just use some better encryption algorithm? If you compress it with some well-known compression scheme, you'll only make it easier to crack, since it becomes easy to guess what the first bytes should be, giving away parts of the key.

Share this post


Link to post
Share on other sites
assumming that your data your encrypting is pretty random, then yes it is practically unbreakable,

but if your data is easy to spot, you can break the key a piece at a time

Share this post


Link to post
Share on other sites
Quote:
Original post by Decrius
What if you compress it first and then XOR it with a 256 character long key? Would that have atleast some security?
Compressing data before encrypting is a well-known method to increase the strength of the encryption (since there's less entropy) - regardless of the encryption algorithm.
However, for Xor encryption it means that you need 1-2 minutes instead of 10 seconds to crack it.

As always the question is "what do you want?". If keeping your 9 year old sister (or your mother) from reading your love letters is your goal, then Xor will work just fine. If preventing a noob user from reading your level files is your goal, it'll probably still work. But for everything else, it will fail, and you'll not only have the damages, but people will probably laugh at you, too.
Imagine it turns out that you used Xor encryption (or something similarly cheap) for the communication between your game clients and the server, and someone eavesdropped 5000 passwords over night only because you didn't use a proper algorithm. That would be so embarrassing, and it would be on every blog worldwide, for sure.

A "good" encryption doesn't perform much slower than a bad one (for example, AES runs at 85 MB/s on my system), but is a lot harder (near impossible for most people) to crack.

It is still hard enough to create something secure when using a good crypto algorithm, and still easy enough to create something entirely unsafe even then (unwillingly).

Share this post


Link to post
Share on other sites
Quote:
Original post by Decrius
What if you compress it first and then XOR it with a 256 character long key? Would that have atleast some security?


It's still symetric encryption.

In geneeral, such assumptions lead to some dangerous mistakes. For example, wouldn't it be much safer, if you encrypt it twice with XOR?

Share this post


Link to post
Share on other sites

SnotBob said:
Quote:

I'm sure you know this, but just in case, XOR encryption is dangerously easy to crack.


Yes, I read that you should not use it for serious encryption purposes.(I could be wrong)

SnotBob also said:
Quote:

You could do the following things:

1. Allow specifying the filename on the command line, instead of asking it like that. In fact, your program looks more like a command line tool anyway, so don't make it interactive. You can add some command line option handling.

2. Allow the use of other keys than 'I' and maybe longer keys, so that the characters in the key are applied successively to the characters in the input.

3. Use std::vector<char> or std::string instead of char array.

4. Write your file input routines so that you don't need to know the file size. This allows you to read from sources that don't allow seeking to the end.


All good idea's I will consider working on all of them actually. (BTW I thought my program looked more like an overrated script :P)

samoth said:
Quote:

Writing crypto algorithms is fun, tempting, and fascinating to play with, but please be aware that it's nothing but that. If you have anything to hide, please do yourself a favour and use a proven, established algorithm (AES, Twofish, Blowfish, XXTEA, anything...). Otherwise, you will suffer great pain.
Designing your own crypto algorithm is something only a handful of people on this planet are successful with.


and:
Quote:

As always the question is "what do you want?". If keeping your 9 year old sister (or your mother) from reading your love letters is your goal, then Xor will work just fine. If preventing a noob user from reading your level files is your goal, it'll probably still work. But for everything else, it will fail, and you'll not only have the damages, but people will probably laugh at you, too.
Imagine it turns out that you used Xor encryption (or something similarly cheap) for the communication between your game clients and the server, and someone eavesdropped 5000 passwords over night only because you didn't use a proper algorithm. That would be so embarrassing, and it would be on every blog worldwide, for sure.


I agree that it is loads of fun that is EXACTLY why I decided to give it a shot I am a rookie programmer(a newbie if you will) and I am still learning so why not keep my interest and spirits high with something moderately entertaining(I like game programming to :))? It really helps when facing a language as daunting as Cpp (a year and I still haven't got all the concepts down). Ironically your granny/love letter scenario is not to far of. You see, I am a high school student learning to program on the side with a few good friends we are the only technically competent people within a few hundred miles so yes even "horrendously easy to break" encryption will suffice. I Never actually used it on any serious files though I am scared their will be a memory violation or error and my program will crash leaving the file corrupted or something. Memory leaks haunt me in my Cpp studies. My first language was VB6 in which you don't have to manage memory (as you all probably know) and this for me is a huge responsibility. Though I have to admit their are some pretty insane stuff you can pull of with pointers(the void one's tend to blow up in my face though XD)

I wonder though, just out of curiosity if you used several dozen layers of XOR, all with different key's and each of which rearranged pieces of the file (swapping them around like Lego bricks) would that qualify as "Secure"?

Share this post


Link to post
Share on other sites
Quote:
Original post by Sigiloso
I wonder though, just out of curiosity if you used several dozen layers of XOR, all with different key's and each of which rearranged pieces of the file (swapping them around like Lego bricks) would that qualify as "Secure"?

No.

Share this post


Link to post
Share on other sites
The whole idea of XOR encryption is that there's NO record ANYWHERE of the key, except the owner's brain.

XORing with 'I' 0x49 is in no-way at all secure, especially since the character 'I' is in your code.

A (xor) encryption program should have no idea what the key is itself.

I suggest 'password' xoring it. Ask for an encryption password (long and random) and then ask for the same password when decrypting it. This can be broken by a brute force attack to de-xor it. The longer you make your password the more secure it is since brute-force means up to length^range attempts are needed.

A 32 character (alpha-numeric) key allows 63,340,286,662,973,277,706,162,286,946,812,000,000,000,000,000,000 (63.34 trillion trillion trillion trillion) combinations :D Whereas your 'I' has only one possible combination - 'I'

If a XOR attempt took maybe 1ms (random guess), then it would take a VERRRRRRRYY LONGGGGGG TIMMMME (millions of years...) to brute force crack it.

Brute force is a last resort tho.

Share this post


Link to post
Share on other sites
heres the thing with xor encryption.

say your pretty sure that ur love letter contains the word 'hello.' now we search the thing on a 5 character based key to get hello. the problem is that 5 character key we know is part of the big key. xor keys can be built like this.

Share this post


Link to post
Share on other sites
Quote:

I'm sure you know this, but just in case, XOR encryption is dangerously easy to
3. Use std::vector<char> or std::string instead of char array.

I think I should clarify this a bit. It's ok to use local array variables, like you could use

char Buffer[BufferSize];

defined in your Body() function.
But you should use a vector instead of an array, if you need to dynamically allocate space. That way you don't need to remember to delete. And you can often use std::string for storing sequences of characters instead of an array or vector.

Share this post


Link to post
Share on other sites
Quote:
I wonder though, just out of curiosity if you used several dozen layers of XOR, all with different key's and each of which rearranged pieces of the file (swapping them around like Lego bricks) would that qualify as "Secure"?
Funnily, most good algorithms are based on Xor encryption nevertheless, and many (for example, all Feistel ciphers) do something very similar to what you describe. However, they all do it a bit different, and this difference is the important thing.

Feistel ciphers will break a message into blocks which consist of two halves (usually two computer words, but it could be anything). Some kind of "function" is calculated from one block, and the other block is Xored with the result. Then the blocks are swapped, and the procedure is repeated (usually 8 or 16 times). So, if you want to see it that way, a Feistel cipher is "just" n-way xor.
The important difference lies in the round function, which takes some input (usually half of the block) and combines it with the key in some manner that is not reversible (or at least, very very hard). It is up to you what exactly you do.
Often, there will for example be substitution tables which map a larger alphabet onto a smaller one. Obviously this loses some information, but that doesn't matter, since we're not really interested in the information, we only need "some function" of it.
For example, imagine you make a table (on a piece of paper) with a field for every letter in the alphabet and roll dice to write a number between 1 and 6 into each field. If A, C, J and Q all have the number 4, it is not possible to tell what letter it was originally, if you're given "4".
But then it is impossible to decrypt your message, isn't it? It certainly is possible, and the ingenious thing about it is that it's very easy too. As long as your round function produces the same output for the same input, the magic of Xor will restore the original (but, since the function depends on the key, you must know the key!). You don't need to worry whether it's hard to reverse the function, because you never do it.
Another nice property of Feistel ciphers is that even a relatively weak round function can be used, if just throw in a few more rounds. TEA is an example of that. While TEA initially did have some issues with weak keys (those have been fixed), it is ridiculously easy to implement, has a very small code size, doesn't have to do any complicated setup, and needs no lookup tables or anything (and it's a billion times better than Xor encryption).

Another way to do "xor encryption" is to use a cryptographically secure random number generator, or a hash function, or a block cipher in OFB mode to generate a pseudorandom stream which is then simply xored with the message. To restore the message, the same procedure is repeated.

When I was in school in the late 70s/early 80s, everyone who could afford a computer was playing with ROT13 and its derivatives, which is not so much different from Xor encryption, in principle (addition and modulo, but still... similarly easy).
I had never heard of encryption before at that time, but when a friend proudly showed me his masterpiece, it immediately struck me that you could almost see the original text with the naked eye, even without trying. So I modified the algorithm to simply add 1 to the rotation for every character encoded. The next day in school, everyone was impressed because my encoded messages looked like random garbage with no visible patterns, and no one could decode it to something readable, no matter what number they tried.
Obviously, the security of that algorithm depends on keeping it secret. Once you know that you only have to add 1 for every character, it's useless.

That is one of the main points in which good algorithms differ from bad ones. If you don't have the key, it doesn't matter what else you know. It is even assumed that you know the algorithm and know approximately what the message must look like. However, if you don't have the key, you'll not be able to figure it out anyway.

Share this post


Link to post
Share on other sites
Isn't "XOR encryption" basically an oxymoron?

Here's some constructive criticism for you:
If you can crack a file encrypted with your own algorithm when you don't know the key, then it's technically useless. In encryption you have to assume that the cracker knows every bit as much as you do, short of the actual key used.
Asymetric encryption takes that a step furthur. Even knowing the algorithm used AND the public key used to encrypt the data, you still can't decrypt it without knowing the private key.

Seriously XOR encryption is worse than leaving your key under the doormat. It's like leaving the key in the lock! Just because you can't simply turn the handle and enter, doesn't mean it's going to stop anyone at all, or even slow them down a noticeable amount.


Now about your code... Don't cast the result of GetTickCount to a float! You actually lose some of the resolution doing that. GetTickCount has a low enough resolution as it is. If your computer has been running for a reasonable length of time (such as 1 week) then the timing could easily be so inaccurate as to measure in chunks of 5 seconds instead of the usual 60th of a second.
Use the same type as returned to you right up until the time you need to calculate the difference, then and only then after subtracting these values should you convert to float.
The other problem you'd get is that after running your computer for long enough until the value wraps around (which IIRC is somewhere on the order of one month) then the subtraction can give a wrong result if you've stored the data in floats.

Share this post


Link to post
Share on other sites
Quote:

Now about your code... Don't cast the result of GetTickCount to a float! You actually lose some of the resolution doing that. GetTickCount has a low enough resolution as it is. If your computer has been running for a reasonable length of time (such as 1 week) then the timing could easily be so inaccurate as to measure in chunks of 5 seconds instead of the usual 60th of a second.
Use the same type as returned to you right up until the time you need to calculate the difference, then and only then after subtracting these values should you convert to float.
The other problem you'd get is that after running your computer for long enough until the value wraps around (which IIRC is somewhere on the order of one month) then the subtraction can give a wrong result if you've stored the data in floats.


DOH!

Well anyways since I clearly don't know what I am doing(when it comes to encryption not Cpp. I would like to think I am at least somewhat Cpp competent though even that would be a matter of opinion. ) I think I will stick to game programing OpenGL here I come!

Thanks for all of your opinions I value all of them. Also it was was nice meeting all of you. I look forward to discussing many interesting topics with all of you in the near future.

Share this post


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

Sign in to follow this