MODULE: EncryptedFile v0.9b

Started by HeirOfNorton, Mon 17/10/2005 05:28:56

Previous topic - Next topic

monkey0506

I've opted to write my own module because it's easier to debug my own code than someone else's. One of the problems that I encountered was that when using the Append mode, HoN decided that the offset in the encryption key would be the same as the length of the file when read in one char at a time. In my tests, this isn't the case however.

Another problem would be with trying to decrypt a single char from an encrypted file. If the char wasn't written in as a char (i.e., if you wrote in an int) then the decryption would fail. Essentially this means that if you tried to do a step-by-step decryption one char at a time, it wouldn't work unless it had been written in using the same method.

To fix this problem, I'm converting all data to chars first, and then writing out the files one char at a time. This means that you can successfully decrypt the file one char at a time, no matter what was written into it. This method will also keep the index in the encryption key updated properly so that I can use my custom functions to get the proper offset when appending to a file.

This won't really solve any speed issues, in fact, it may be a bit slower (since I have to convert a 4 byte int into 4 one byte chars), but it may provide a more stable means for data encryption. Of course the credit goes to HoN for the original idea...but maybe HoN knew what he was doing when he labeled this as version 0.9. ;)

Monsieur OUXX

Quote from: monkey_05_06 on Tue 17/07/2007 21:24:45
I have to convert a 4 byte int into 4 one byte chars

I'm interested in the code you're using. I've written a little routine, but i get bugs with the heavier-weight char (byte), so my function bugs when converting an int   >256^3   or   <0 (the sign is stored in the last byte).

 

monkey0506

#22
I've written a custom class (though I wasn't sure what to name it, and I'm not excited about what I chose):

Code: ags
struct SplitInt {
  writeprotected char Bytes[4]; // store the "split" data
  import void Split(int i); // split I into 4 bytes; use this to set the Bytes property
  import int Merge(); // merge Bytes back into a single int and return it
  import static int MergeBytes(char left, char midleft, char midright, char right); // statically merges 4 bytes and returns the integer value
  };

void SplitInt::Split(int i) {
  int j = 0;
  while (j < 4) {
    this.Bytes[j] = (i >> (8 * j)) & 255; // shift relevant data for byte J into the right-most byte, then use &255 to grab only the right-most byte
    j++;
    }
  }

int SplitInt::Merge() {
  int i = 0;
  int j = 3;
  while (j >= 0) {
    i += (this.Bytes[j] << (8 * j));
    j--;
    }
  return i;
  }

static int SplitInt::MergeBytes(char left, char midleft, char midright, char right) {
  int i = (left << 24);
  i += (midleft << 16);
  i += (midright << 8);
  i += right;
  return i;
  }


It took me a bit of trial-and-error since this is technically the first time I've ever really used the bitwise operators, but it appears to be fully functional, even with numbers >256^3 and <0. ;)

Quote from: Monsieur OUXX on Tue 24/07/2007 16:24:02(the sign is stored in the last byte).

I assume you mean bit not byte...and by "last" I hope you mean left-most, because that is where the sign bit is stored at is the left-most bit, not the right-most.

Also I'd be interested in seeing what you were using just to see what your take on it was.

Monsieur OUXX

Quote from: monkey_05_06 on Tue 24/07/2007 17:06:18
Quote from: Monsieur OUXX on Tue 24/07/2007 16:24:02(the sign is stored in the last byte).
I assume you mean bit not byte...and by "last" I hope you mean left-most

Yes, i mean "left-most". I wrote "byte" because my error comes from the left-most byte, which actually contains the left-most bit.

Quote from: monkey_05_06 on Tue 24/07/2007 17:06:18
Also I'd be interested in seeing what you were using just to see what your take on it was.

I'm doing the same thing as you, but at "merge-time" i'm OR-ing* the four ints (the ones that get created by shifting chars) instead of ADDing them. I can't visualize why it causes an error, but since it works with an addition, it's a happy end.

*i mean the bitwise OR (|), not the boolean one (||)
 

monkey0506

#24
I'd forgotten that I had verified HoN's module to be malfunctioning when encrypting/decrypting videos (here). He did a good job with his module, it established the base for the one that I've written, there were simply some misconceptions that lead to invalid output corrupting the data. The module I've written clears up some of these and I've verified it to work successfully with video files.

I've also included functions for encrypting/decrypting files in the background. I did a background encryption/decryption operation of a sample video (~2322 KB) successfully at a rate of 1 KB per game loop in 4644 loops (2322 KB * 2-way operation) with no impact to speed. My tests show that attempting to decrypt more than this in a single game loop would result in a dramatic drop in game speed.

So Dualnames, as long as you can be absolutely sure that there will be one game loop run for every KB of data in your video, it may be possible to use encrypted videos in-game! The following example uses the module I've written, which I'll upload just the module for now, and try to work up some documentation over the next few days.

Code: ags
// encrypt operation -- do this prior to distribution
// game_start
EncryptedFile.Encrypt("shoryuken.wmv", "deadaswell", "shoryuken.scbr");

// repeatedly_execute_always
if (EncryptedFile.IsEncryptionComplete("shoryuken.wmv")) {
  File* video = File.Open("shoryuken.wmv", eFileWrite);
  if (video != null) video.Close();
  }


Code: ags
// decrypt operation -- do this in-game
bool VideoReadyForPlayback = false;

// game_start
EncryptFile.Decrypt("shoryuken.scbr", "deadaswell", "shoryuken.wmv");

// repeatedly_execute_always
if (EncryptedFile.IsDecryptionComplete("shoryuken.scbr")) VideoReadyForPlayback = true;

// time to play the video
if (VideoReadyForPlayback) {
  PlayVideo("shoryuken.wmv", 0, 0);
  File* video = File.Open("shoryuken.wmv", eFileWrite);
  if (video != null) video.Close();
  }


I've just reread your message about your personal results with a 45 KB file. Using this method that would translate to 45 game loops, taking barely over a second to decrypt! A 1 MB file would take 1024 game loops, or approximately 26 seconds.

Note that my module requires AGS 2.8 Beta 5. This is because I've been developing with it, and I internally use a dynamic array.

You can download my test game here (right-click, save as RAR archive).

You can download the module (no documentation) here (right-click, save as SCM).

Hope you'll find this useful. I've got to go to work for now. Maybe I'll get some documentation up soon...


SMF spam blocked by CleanTalk