Blitz2D Advanced: Encryption/Decryption
by Krylar

Introduction:

One of the things that many people want to do when creating a game is protect the data files from being hacked. Now I'm not talking about preventing a game from being pirated here...handling that stuff is a bit over my head. I'm talking about stopping the casual user from looking at your map files and seeing what's going to happen next in the game.

There are a number of ways to handle this type of thing. Here are a few:

  • Put all the files into the executable file
  • XOR each value in the data file with a "key" value
  • Converting from one base to another (ie. Decimal to Hexidecimal)
  • Use a static base series of numbers that represent the actual characters/numbers (ie. 2988 = "E", 8476 = "7")
  • Use a random base series of numbers that represent the actual characters/numbers. This will make the values different each time a file is encrypted.
  • Use a "sliding window" on values for each value. (explained later)

In this tutorial I've decided to use a combination of things. I'm going to create a sliding window of random values that are all XOR'd with a key value. If you just said "huh?" then you should already see that these little things are tough to crack. Not impossible by any means tough.

Please understand that this is somewhat difficult to explain and can get kinda sketchy. I'll do my best to be as clear as possible...at the risk of being patronizingly clear...so if you know alot of this stuff already, please don't get too irritated at my overexplaining ;)

Also, please note that I'm going to use the ASCII value table for example purposes. I'm doing this because there is a fixed number of values and I can show the values demonstrationally. But please keep in mind that you don't need to keep your encryptions to a fixed 256 values...you can go pretty much as high as you want.

What does XOR do?

I want to start with XOR because it's really a simple little concept and it's the basis for most simple encryption schemes. In order to do that effecitively, you need to know how AND and OR work. I'm sure a lot of you already know, but for those who don't here ya go:

The AND command compares each bit in a value against each bit in another value. If those bits are equal, AND returns the value (so 1 and 1 would return 1, 0 AND 0 would return 0). If the values are not equal, AND returns 0. Here's an example:


The OR command compares each bit as well, but it see if either of the bits being compared is a 1. If there is a 1, it will return a 1. If there is no 1, it returns 0. Here's an example:


Finally, the XOR command does some interesting stuff. If there is a 1 being compared to a 1, XOR will return 0. If there is a 0 being compared against a 0, again XOR will return 0. Only if there is a 1 being compared against a 0, will XOR return a 1. Here's an example:


The cool thing about XOR is if you XOR the Value 2 against the result, you'll get Value 1 again! Why is this cool? It's cool because this means that if you XOR a value with a "key" (a key is just a number that you use like a password...you've probably heard the term "encryption key") it will create another value. This XOR'd value no longer looks like the recognizable value you had originally, so the "hacker" doesn't know what it represents. And when you want to know what it is, all you have to do is "decrypt" it by XORing it again with the "encryption key".

I know that's a brain filler, so here's an example. The capital letter "A" has an ASCII decimal value of 65. So, if a hacker type wanted to see what character you were using, he'd simply look at that number 65, compare it to the ASCII chart and find it was an "A". Since we don't want the hacker-type to know what that value is, let's pick a key...say 123...and XOR 65 with it. So, 65 XOR 123 = 58. Now 58 in the ASCII chart is a ":". As you can see, the "A" became a ":" because of the XORing. How do we get it back to an "A"? Simple! Just XOR the current value with the key. So, 58 XOR 123 = ??? 65! We got our "A" back!

Here's the binary representation of this 65 XOR 123:


And here we XOR that 58 with 123 and watch what happens:


Why can't the hacker do this? He could, but only if he knows the key value we used. Huh? If the hacker tries a bunch of XOR's with various numbers, he could conceivably stumble upon the key and break the encryption. This is actually not too complicated a task as a program could easily be written to walk from 1 on up and display a line of output. Once the output looks legible, the hacker has the key.

Because of this, there is another little trick to use that makes things a little more complex to hack.

Random Value Replacemnts

When I started thinking about how to encrypt various values I saw the little XOR problem and thought that I should make a table of my own values that represent my standard values and then XOR those. For explaination purposes, I'll continue using the ASCII table values for examples.

So, in the XOR section I used 65 (the letter "A") as the guinea pig value. Now, what I would do is pick a random number that represents 65...so, using the RND# function in BB, I ask for a random number between 1 and n. Let's say that I ask for a random number between 1320 and 21985, and let's say that BB returns 14209 as the number. I will then have an array that holds the number 14209 in position 65. Then when the file is encrypted, it will take every "A" (65), grab the value in the array for position 65 (14209) and XOR that value with a key (let's say 5383). So, what will be written to the encrypted file for the letter "A", will be 14209 XOR 5383, or 8838. So everytime you see 8838 in the encrypted file, you know it's an encrypted "A"!

Here's some pseudocode that initializes the EncryptionData array:


Notice that I do NOT use the XORing here. This is because I want to put this list of random numbers in a file and have no strong correlation between those numbers and the data in the files that are encrypted. This makes it so the hacker has to not only figure out the XOR key, but also what number goes with what.

Also, there is a problem with this. What happens if RND# returns the same number twice? We can't have "A" holding the same value as "E"...if we did the encryption would be all goofed up. So what we do is keep track of the assigned numbers and make sure they're not used twice (you can see more of this in the actual code).

Where is that Array stored though? Well, that's really up to you. You can store it in a group of Data statements at the end of your program. This is probably the safest method to ensure data integrity. Alternately you could store it in a file all by itself or just make it part of each file that you are encrypting. In the demo, I have code that stores in both a stand-alone file and code to store inside the actual data file.

Since the encryption values are stored in external files, how do you load them in? Simple. There is a function called "Encrypt_LoadEncryptionFile(...)" that loads the values for the random value placements.


Okay, so now all we have to do to encrypt a file is to read it in, find the numeric value for each byte read, take the random number assigned from that array location, XOR it with our key and finally write it out to the encrypted file.

So, here's some pseudo that writes out to a file the value of "A" encrypted.


By the way, notice that I'm outputting stuff as integers. This adds a little more protection because the very casual user will see nothing but gobbledeegook when they open the file. It won't stop more advanced users, but it will likely stop the newer hacker types.

And here's some pseudo that decrypts the value read in.


Now this method is likely more than enough to stop a bunch of wouldbe hacker types, but I decided to take this one more step in order to make it even tougher.

Encryption Precision (The Sliding Window)

When thinking about this problem the thought jumped out that it would be cool to have many different random numbers for each value. This way repetition in the encryption would be lessened. For example, English words have more letter E's than any other letter. This being the cases, a lot of hackers look for what is repeated most and determine that code to be an E. From there they jump down to "A", then to "I", etc. and can usually decipher things. It's NOT easy to do this but it *can* be done, and it's much easier to do using another computer program to do it.

So I started thinking that having more than 1 number to represent "E" would be cool. I call this Precision or using the sliding window. The idea is I set my precision to a number, let's say 5, then when the EncryptionData array is built it will grab 5 random numbers for each ASCII value (again, just using ASCII as the example). So, instead of "E" being the random value of, say, 9876. It's now: 9876, 2352, 19809, 4244, or 21229. So, when determining what number to use for "E", the "window" slides amongst those 5 choices...hence "sliding window". Get it? :)

The major drawbacks to this method are speed decreases in encrypting the files (loading too, but not as bad), and the file size increases slightly.

How do we do this? Simply by running a For...Next Loop for each value and randomizing it's precision. Also, make sure that the EncryptionData Array dimensions have been increased accordingly. Reading it in is just the reverse process.

Conclusion

Don't think that the above can't be cracked. Actually, it's not that hard to crack as long as someone knows what your scheme is. Even if they don't have your key...they can figure it out eventually. So you may want to think about how you could add to this scheme or alter it. One way is to move around all of the data in the file to make it a seemingly jumbled mess that only you know how to decipher. Another is to put the EncryptionData array into DATA statements.

The demo file from this is based off the last two newbie articles articles ("Basic Map File Loading" and "Moving Sprites on Tiled Backgrounds") and has updated file loading routines that you may want to use in place of the old ones. I found a couple of goofy things that I had done and fixed them. Also, so you know what to expect...the demo loads in a text file called "test.txt", encrypts it and outputs it as "text.enc". It also loads in the "map.dat" file, encrypts it as "map.enc" and then loads "map.enc", decrypts and displays the map based on it. You'll also see "enckey.dat". It contains the random numbers for the values created during the initialize. This is used during for the text stuff only, the map data encryption encrypts diretly to the file.

By the way, you want to run the "Spritemap.bb" program from BB to see the demo in action. That's also where you'll see the lines for calling the encryption routines.

To get a demo and all the source code: Click Here

Until next time...cya!

-Krylar


For a printable copy of this article, please click HERE.


This site is Copyright© 2000-2004, BlitzCoder. All rights reserved.