Game Development Community

dev|Pro Game Development Curriculum

Adding Simple AES Encryption for Data files (Updated 1/16)

by Kevin Mitchell · 01/09/2013 (9:38 pm) · 25 comments

This shows you how to implement a simple object that uses, Rijndael's AES encryption. I know that AES is used somewhere in the engine already but for those that just wants a clean simple API here is one.

Click Here

Instructions

1.Extract to Engine/Source/rpg_engine/
Quote:
Note you can put it any where but I'm following my path structure.

2. Open the engine code and add a filter folder "rpg_engine"
3. Open the engine code and add a filter folder inside of "rpg_engine" called "AES"
4. Click add add Existing Files.
5. Add the Rijndael.cpp,Rijndael.h,SimpleAES.cc, and SimpleAES.h.
6. Compile
7. Add the following test to your code.

function testAES(){
  new SimpleAES(StringCrypt){
  };


   echo(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
   echo(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
   echo(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
   echo(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
   echo(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
   %readFile = new FileObject();
   %path="toEncrypt.txt";
   if(%readFile.openForRead(%path)){
      while(!%readFile.isEOF()){  
         %source=%readFile.readLine();
         echo("1: "@%source);
         %cryptString=StringCrypt.cryptLine(%source);
         //echo("2: "@%cryptString);
         %results=StringCrypt.decryptLine(%cryptString);
         //echo("3: "@%results);
         if(!(%source $= %results)){
            %readFile.close();
            %readFile.delete();
            echo("ERRROR ENCRYPTING: "@%source);
            return;
         }
      }
      %readFile.close();
      %readFile.delete();
   }else{
      %readFile.delete();
      echo("FILE COULD NOT BE OPENED");
   }
   
   %testChars="! Q A Z W S X # E D C $ R F V % T G B ^ Y H N & U J M * I K < > ( O L > ) P : ? _ { + } | 1 q a z 2 w s x 3 e d c 4 r f v 5 t g b 6 y h n 7 u j m 8 i k , 9 o l . 0 p ; / - [ ' = ] ` ~"; 
   %randomChar=getWord(%testChars,getRandom(0,getWordCount(%testChars)));
   while(strlen(%randomChar)<(512)){  
      %source=%randomChar=%randomChar@getWord(%testChars,getRandom(0,getWordCount(%testChars)));
      //echo("1: "@%source);
      %cryptString=StringCrypt.cryptLine(%source);
      //echo("2: "@%cryptString);
      %results=StringCrypt.decryptLine(%cryptString);
      //echo("3: "@%results);
      if(!(%source $= %results)){
         echo("ERRROR ENCRYPTING: "@%source);
         return;
      }
   }
   
  EncryptFile("toEncrypt.txt","toEncrypt.txt.bin");
  DeCryptFile("toEncrypt.txt.bin","NewtoEncrypt.txt");
  echo(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
  echo(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
  echo(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
  echo(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
  echo(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
}


function createAES(){
   if(isObject(StringCrypt))StringCrypt.delete();
   new SimpleAES(StringCrypt){
   };
}

function encrypt(%source){
  %cryptString=StringCrypt.cryptLine(%source);
  return %cryptString;
}

function decrypt(%source){
  %cryptString=StringCrypt.decryptLine(%source);
  return %cryptString;
}


function EncryptFile(%path,%savePath){
  //Might want to change the name of the CryptObject in your release
  if(isObject(StringCrypt))StringCrypt.delete();
  new SimpleAES(StringCrypt){
  };

   %readFile = new FileObject();
   %writeFile = new FileObject();
   
   if(%readFile.openForRead(%path)){
      if(%writeFile.openForWrite(%savePath)){
         while(!%readFile.isEOF()){  
            %source=%readFile.readLine();
            %cryptString=StringCrypt.cryptLine(%source);
            %results=StringCrypt.decryptLine(%cryptString);
            if(!(%source $= %results)){
               echo("ERRROR ENCRYPTING: "@%source);
               %writeFile.close();
               %writeFile.delete();
               %readFile.close();
               %readFile.delete();
               return false;
            }else{
               %writeFile.writeLine(%cryptString);
            }
         }
         %writeFile.close();
         %writeFile.delete();
         %readFile.close();
         %readFile.delete();      
      }else{
         %writeFile.close();
         echo("FILE COULD NOT BE CREATED");
         return false;
      }
   }else{
      %readFile.delete();
      echo("FILE COULD NOT BE OPENED");
      return false;
   }
   return true;
}

//Might not want to include this in the release code
function DeCryptFile(%path,%savePath){
  if(isObject(StringCrypt))StringCrypt.delete();
  new SimpleAES(StringCrypt){
  };

   %readFile = new FileObject();
   %writeFile = new FileObject();
   
   if(%readFile.openForRead(%path)){
      if(%writeFile.openForWrite(%savePath)){
         while(!%readFile.isEOF()){  
            %source=%readFile.readLine();
            %results=StringCrypt.decryptLine(%source);
            %writeFile.writeLine(%results);
         }
         %writeFile.close();
         %writeFile.delete();
         %readFile.close();
         %readFile.delete();      
      }else{
         %writeFile.close();
         echo("FILE COULD NOT BE CREATED");
         return false;
      }
   }else{
      %readFile.delete();
      echo("FILE COULD NOT BE OPENED");
      return false;
   }
   return true;
}
//Uncomment to do test encryption
//testAES();


Notes: You might want to make your own random key. To do this open SimpleAES.cc.

Change the Key[].

Note that the key is currently the highest key avaliable whish is 32 bytes aka 256 bit encryption.
Make sure you change the key to exactly 32 characters.

If you change the key to something lower make sure its 16, 24 and 32 only. And if you change it lower change the #define CRYPTSIZE too.

#define CRYPTSIZE 32
char Key[]=&amp;quot;1qaz2wsx3edc4rfv5tgb6yhn7ujm8ik9&amp;quot;;


You can now save data to a file in an encrypted state and not just have raw text in a text file.

When loading the line from file make sure you decrypt it before using the data.

Happy Coding.


Edited 1/16/2013:

Added the base64 encoding for pure string return. Before I was sending just the encrypted data that is just a binary array and can have null byte causing issues with the return string. Now the encrypted data is using the Base64 code to give an encoded string.


PS: Richard Marrevee thank you for your assistance with the data file.
Page «Previous 1 2
#1
01/10/2013 (1:27 am)
This is very nice and I am going to use it right now. Thanks
#2
01/10/2013 (4:19 am)
This is exactly what I will need soon. I have a system now using text files for character and NPC inventory, dialog etc just to get the basics down. Thank you for sharing this with everyone.
#3
01/10/2013 (7:45 am)
@Kevin:

I get some strange results when encrypting text. When encrypting you get a message stating the size of the encrypted string. With a Cryptsize of 32 you should expect a stringsize of 32, but I get values from 0 to 32 on the same original. When the encrypted string isn't the size of the Cryptsize it won't decrypt. Do you have any idea what is happening?

Thanks
#4
01/10/2013 (7:47 am)
Nice resource,

I have a AES file encryption setup using the Crypto++ library. I use this to secure all of my save data as well. It's quite useful.
#5
01/10/2013 (9:51 am)
When crypting the text I keep the text as 32 sized blocks with padding. This way the decrypted block can keep even blocks of 32.

Can you send me your demo text?
#6
01/10/2013 (12:36 pm)
What is the reason for encrypting saved data files?

If I want to cheat in a game I use Cheat Engine. This program attaches to a live program and adjusts values you select. These values will happily be saved into the save data file.
#7
01/10/2013 (7:39 pm)
@Frank: One must be cautious to not trip off countermeasures that detect invalid encrypted fields and then tell the engine to report the user's info to my email address.

That's how I deal with memory editor cheaters anyways... It's quite simple to protect against Cheat Engine, but I think securing data with encryption keeps problems from surfacing. It can be a little tricky to implement, but once its in place, you'll be thankful it's there.
#8
01/11/2013 (5:03 am)
I only use cheat engine for single player games. Most multiplayer games have server authority and very few things that can be modified to advantage anyway. With those games the save files would be on a server anyway. So I don't really see the benefit to encrypting them locally. Once I beat a game I like to see what else I can do with the game.

Also, if you are sending emails to yourself that could be considered harvesting personal information. Make sure you notify your users you are doing that. There may be laws for that sort of thing. PII is becoming a hot issue. I know since the email scandal that came out recently congress is going to be paying attention to email and privacy.

I guess it goes to two schools of thought:
1. Control everything and keep the game from being modded. Probably really only makes sense for multiplayer.
2. Be lax about it and actually provide editors. The way Bethesda does the Elder Scrolls series.

I guess I am seeing the bark, the branches, the leaves, the roots, but I don't understand that I am looking at a tree. ie, am I missing something?

I don't know that I would want to spend my time policing cheaters.
#9
01/11/2013 (7:42 am)
Well, it's like you just said. It's only for the purpose of multiplayer where data storage and information that is used by leaderboards becomes of more interest. Single Player stuff, I honestly don't care if you cheat on it, it has no effect on other players so I'm generally perfectly fine with that, only when it starts to affect the gameplay and experience of others does it become a problem.

Look at games like CoD and their issues with the past few titles. Any person with half a brain can get past their source code and do some... interesting things (just youtube MW2 Mods on Xbox).

As for the emails, I make it clear in my user agreement that if they cheat in multiplayer the development team will be notified by means of emails. Most of my projects are secure enough that I don't need to worry about things like that though.

I don't intend on releasing Mod tools for games with internal rank and progression systems but things like the a map editor are most definitely supported. I definitely agree with your notion there.

But we have seriously taken this way off topic, lol.
#10
01/11/2013 (10:00 am)
Ahh, okay, I see. You have some specific needs for client held data that you need unaltered.

It is a little bit off topic, but I think other people might have the same questions I have. So this may help.
#11
01/14/2013 (12:56 am)
@Kevin:

Quote:
When crypting the text I keep the text as 32 sized blocks with padding. This way the decrypted block can keep even blocks of 32.

Can you send me your demo text?

Thanks Kevin, padding did the trick.
#12
01/14/2013 (4:12 am)
You should not have to pad it bucause I am via engine code can you let me know what text failed? I'm doing more testing on my end and its not failing with my data if there is a fault I'd like to fix it.
#13
01/16/2013 (2:28 am)
@Kevin:

Just send you an e-mail with a file that was giving me problems. Hope it will help you testing.

#14
01/16/2013 (5:49 pm)
The issue is that the encryption returned can have nulls as part of hte encryption. And sending the results back as a string will not work this way. I'm going to use a different method to trans-code it into string.
#15
01/21/2013 (10:23 am)
I am curious to see what you come up with. Thanks Kevin.
#16
01/21/2013 (1:06 pm)
I already fixed it. Redownload the link
#17
01/22/2013 (1:10 am)
Thanks Kevin, works great.
#18
01/29/2013 (5:31 am)
thanks a lot~~
#19
01/30/2013 (7:48 pm)
Kevin, try encrypting a ZIP file with this method, I want to see if zips in general are just impossible to encrypt or if I royally screwed something up in my code using crypto++.
#20
01/31/2013 (4:07 am)
You have to make sure you have everything setup to pass back pure binary data. The methods that I have currently use string data only. So I can use the StringTable object to send the data back to the script. But for a zip file There are more likely null data bytes that if not parsed fully it will corrupt the data.

I'll add some new methods this weekend to support binary encryption I'll let you know how it goes.

My memory sucks so I might need you to remind me :).
Page «Previous 1 2