# How can I protect my save data from casual hacking?

What options are there for saving game data in a secure manner? I'm interested in solutions specifically tailored for C++.

I'm looking for something that is fast and easy to use. I'm only concerned about storing simple information such as

• Which levels are and are not unlocked

• The user's score for each level

I'm curious again to know what's out there to use, any good libraries to use that give me nice, secure game data files that the average player can't mess with.

I just found this here which looks very nice, but it would be great to get some opinions on potential other libraries/options out there.

• Why do you require the security? If a player wants to cheat to unlock a level by editing the save because they got stuck why not just let them do it?
Feb 3 '12 at 1:18
• well, the game will hopefully go up on IndieCity.com, they have there own achievement system to use. I want to base only a few achievements off defeating certain levels containing bosses. To have the player able to cheat his way to unlocking these achievements isn't allowed. Its against the "CAP" rules as they are called. So i need to have some form of security measure in place, nothing fancy but just to stop the the casual player from altering data Feb 3 '12 at 1:28
• It might be worth telling IndieCity.com that there are limits to that requirement, as it's impossible for you to secure a save game unless the save game stays on your own server. Feb 7 '12 at 20:34

first lets say since you have a very simple save file, you can use text file.

one of the simplest ideas is to use a string key to lock/unlock data:

void encrypt(string& data,string key)
{
for(unsigned i=0;i<data.size();i++)
data[i] += key[i%key.size()];
}

void decrypt(string& data,string key)
{
for(unsigned i=0;i<data.size();i++)
data[i] -= key[i%key.size()];
}


but after a little google search I've found these links, which might be useful:

## Edit:

Based on signed char being "Undefined behavior" as @v.oddou mentioned, I guess using XOR or casting to unsigned char will result in safer/more-cross-platform code. something like this:

void encrypt(string& data,string key)
{
for(unsigned i=0;i<data.size();i++)
data[i] ^= key[i%key.size()];
}

void decrypt(string& data,string key)
{
for(unsigned i=0;i<data.size();i++)
data[i] ^= key[i%key.size()];
}

• this seems like a nice little method :), just enough for my purposes. Im curious to ask a further question here, in terms of a "key", what is an acceptable key? Can i pass in anything i.e a long string? Feb 3 '12 at 1:59
• And you know, i think im just going to go with this, it's exactly what i wanted. Simple and easy to use, and nothing too fancy :). Feb 3 '12 at 2:12
• @Danran yeah every thing is acceptable for the key, it can be a one char string which will result in something like Caesar cipher or any other phrase with any other length you like. you can also use some other algorithm to scramble data positions, eg. swap values in even and odd positions. Feb 3 '12 at 9:45
• It dons't really matter, either you use xor, or increment/decrements, data recovers. note that if incrementing generaees overflow, later decreament will also generate underflow. Feb 3 '12 at 15:22
• This answer is weak. There are two kinds of security for a savegame. Secrecy, storing data the player must not now. Integrity, the data cannot be tempered. A hash based message authentication code is sufficient when secrecy is not required. Still having XML/JSON makes development and testing easier than just encrypting it. Dec 2 '14 at 8:22

Nothing can be considered secure client side; anyone who tells you it is, is lying.

You can use any encryption and scramble method you want, but since the client must be also able to decode it, and the user has access to the client itself, if he is resourceful enough he'll have access to the decryption key / algorithm.

You can only add layers of annoyances to someone willing to crack it, but given enough time it will be cracked, and you can't do anything about that.

• While what you're saying is true, I think the author is aware that a determined hacker could probably still get at it, since he explicitly asked for a way to prevent "casual hacking". :-\ Feb 3 '12 at 19:27
• Exactly, well aware that a hacker if that determined could easily access my game data. I just didn't want the average/casual user to be able just to simple open up the files and start editing them. Feb 4 '12 at 1:54
• @Danran: fine, I don't like that very much but I guess it makes sense in some contexts. I'm not deleting the answer because I think it is important to point this out to people reading this.
– o0'.
Feb 4 '12 at 13:04
• Also, if it's deemed worth hacking someone will likely make it so that hacking it is possible by the casual user. There are entire forums dedicated to just that. Feb 7 '12 at 19:17
• @Noctrine : an active reaction can help in this case. keep aware of the community around your game, when some crack tool is out in the open, change the encryption technique and release a patch. this patch can be made mandatory if the game has an online component. of course no player (and certainly not me) likes to be forced to update stuff at all in the first place, nor do I like to need to be connected. (EA evil, simcity boo...) Aug 7 '15 at 7:37

You can definitely leave your save file unencrypted but add a checksum that is calculated through all the values that you want to "guard".

The cracker would therefore be able to re-produce the hashing (which you off course will use with proper salt) and therefor will have a happy time trying to re-produce.

This would still not be %100 secure but, probably the best time effective solution.

This provided some simple XOR encryption:

#include <iostream>

using namespace std;

string encryptDecrypt(string toEncrypt) {
char key[3] = {'K', 'C', 'Q'}; //Any chars will work
string output = toEncrypt;

for (int i = 0; i < toEncrypt.size(); i++)
output[i] = toEncrypt[i] ^ key[i % (sizeof(key) / sizeof(char))];

return output;
}


And how to use it:

int main(int argc, const char * argv[])
{
string encrypted = encryptDecrypt("kylewbanks.com");
cout << "Encrypted:" << encrypted << "\n";

string decrypted = encryptDecrypt(encrypted);
cout << "Decrypted:" << decrypted << "\n";

return 0;
}


The output of this code is this:

Encrypted: :=.43*-:8m2\$.
Decrypted:kylewbanks.com