Jump to content


Photo

String Encryption/Obscurer


  • Please log in to reply
7 replies to this topic

#1 zbox

zbox

    GMC Member

  • GMC Member
  • 2618 posts
  • Version:Unknown

Posted 15 April 2014 - 07:52 PM

This script takes a user-inputted string and a passphrase, combines the two, and spits out an entirely different string that can later (maybe on a online server, maybe when loading from an INI file) be decoded and used again. Please note this only works for ASCII characters, so as long as you are not using anything completely whacky (see ASCII in gm manual for available characters) this wont mess up.

 

GML version:

Well lets get this one over with. There are a few different functions you'll need:

///shift(direction,originalstring,keystring)
//returns buffer
var phraseArray = stringToBuffer(argument1);
var keyArray = stringToBuffer(argument2);
buffer_seek(phraseArray,buffer_seek_start,0);buffer_seek(keyArray,buffer_seek_start,0);
var returnArray = buffer_create(string_length(argument1),buffer_fixed,1);
for (var i=0; i<buffer_get_size(phraseArray); ++i){
    var a = buffer_read(phraseArray,buffer_u8);
    a = modulus(a+(argument0*buffer_peek(keyArray,(i mod (string_length(argument2)-1)), buffer_u8)),256);
    buffer_write(returnArray, buffer_u8, a);
}
buffer_delete(keyArray);
buffer_delete(phraseArray);
return returnArray;
///shift_buffer(direction,originalbuffer,key)
//returns buffer
var phraseArray = argument1;
var keyArray = stringToBuffer(argument2);
buffer_seek(phraseArray,buffer_seek_start,0);buffer_seek(keyArray,buffer_seek_start,0);
var returnArray = buffer_create(buffer_get_size(argument1),buffer_fixed,1);
for (var i=0; i<buffer_get_size(phraseArray); ++i){
    var a = buffer_read(phraseArray,buffer_u8);
    a = modulus(a+(argument0*buffer_peek(keyArray,(i mod (string_length(argument2)-1)), buffer_u8)),256);
    buffer_write(returnArray, buffer_u8, a);
}
buffer_delete(keyArray);
buffer_delete(phraseArray);
return returnArray; 
///stringToBuffer(string)
//returns a buffer
var t = buffer_create(string_length(argument0),buffer_fixed,1);
for (var i=1;i<=string_length(argument0);++i){
    buffer_write(t,buffer_u8,ord(string_char_at(argument0,i)));
}
return t; 
///bufferToString(buffer)
var t = "";
buffer_seek(argument0,buffer_seek_start,0);
for (var i=0;i<buffer_get_size(argument0);++i){
    t+=chr(buffer_read(argument0,buffer_u8));
}
return t; 

Right, now that yuck part is out the way here is how to use it:

enc = shift(1,"Hello","key");
sendString = buffer_base64_encode(enc, 0, buffer_get_size(enc)));
dec = shift_buffer(-1,enc,"key");
show_message(bufferToString(dec)); //show the player the decoded string (in this case "Hello")
buffer_delete(dec); //Prevent memory leaks. The "enc" buffer was deleted at the end of the last shift_buffer function.

Sorry about all the scripts, making double sure that Gamemaker doesn't try to change any of the values. I included a shift_buffer function, because once you have encrypted a string, it is stored in buffer form, and obviously you need a way to decrypt it. The variable on the second line, sendString, is to demonstrate the value you would send to a server or save to a file. To load the encrypted string back into memory to decrypt, the buffer_base64_decode function looks pretty good to me!

 

PHP Version: (for servers etc) 

class shiftEncrypt{
	private $phrase;
	private $key;
	function __construct($phrase,$key){
		$this->phrase = $phrase;
		$this->key = $key;
	}
	public function shift($dir){ 
		$phraseArray = str_split($this->phrase,1);
		$keyArray = str_split($this->key,1);
		$str = "";
		foreach ($phraseArray as $pos=>$letter){
			$phraseArray[$pos] = ord($phraseArray[$pos]);
			$phraseArray[$pos] += $dir*ord($keyArray[$pos % (strlen($this->key)-1)]);
			$phraseArray[$pos] = modulus($phraseArray[$pos],256);
			$str.=chr($phraseArray[$pos]);
		}
		return $str;
	}
} 

I've used an object-orientated setup here (I'm learning OOPHP, this was a good way to practice), so to use it your code would look somewhat like this:

$ins = new shiftEncrypt("hello","key"); //When you are using data from gamemaker it will be in base64. Just replace "hello" with base64_decode(GMDATA)
$enc = $ins->shift(1); //Encrypt the "hello" string
$ins = new shiftEncrypt($enc,"key"); //Create a new shift class instance to decrypt $enc.
$unenc = $ins->shift(-1); //UnEncrypt
echo "Encrypted: ".$enc."<br />Unencrypted: ".$unenc;

Usage:

Using the script is fairly simple, to encrypt you simply call shift(dir,str,key), and when you want to decrypt it, you reverse the direction (either -1 or 1... although now I think about it you could use any value you want really), provide the encrypted string as the "string" argument, and the key as per normal. The Key parameter can be any ASCII string, keep in mind that if the String is shorter than the key, only the first corresponding characters in the key will be used (i.e. if string = "hi" and key = "apple" only the "ap" out of "apple" will be used). If the key is shorter than the string, there is no problem, and the key is just repeated over. I've found this site here is great for generating nice random keys http://passwordsgenerator.net/ .

 

Please feel free to comment on the level of security this gives the protected string, I'm no expert myself but as far as I can see this significantly increases the difficulty of changing the content - especially combined with a hash. If you had a hash on the end of your string that summarizes its contents, there are 2.135987e+96 possible combinations. On top of this, you also have to figure out what the hash represents in the first place! 

 

A bit of an edit (read this if you want to use the scripts)

The original scripts I provided were not cross compatible, but worked within their own rights. Seeing as that would be only useful on GM's side for saving (quite useful  - but communication to a server is the fun part!), I spent a loooong time rewriting them... and having them still be not cross compatible. Anyway, long story short, GM strings are not binary compatible, and I feel like a douche as I should have known that. Anyway, now I have completed the new scripts, they are entirely compatible with eachother. The php version is my favourite as strings in php are binary friendly and therefore the code is fairly elegant. Gamemaker though, I had to use buffers to store and be able to retrieve information, and a few workaround-y things, because as soon as the encrypted "string" gets stored as a string it is toast. That is why buffers are used (my new favourite feature!), because we can pull them as a base64 string, which will not get molested by GM's prying fingers when we store it.


Edited by zbox, 20 April 2014 - 01:16 PM.

  • 1

#2 Floofpaws

Floofpaws

    Fox

  • GMC Member
  • 2161 posts
  • Version:Unknown

Posted 15 April 2014 - 08:44 PM

Now obsolete, but this shows the vulnerabilities in the above algrithm (at least the old one):

///shift_decrypt(original direction,encrypted string,destination string)
//Assumes you know the original content. This script will spit out the key that was used.
//A good usage of this script is when for example you know your HP value when you save. Then simply decrypt it and get the key. Edit that value and any others encrypted with the same key to your heart's content!
//direction: -1 or 1
//Not a perfect decryption; characters near the beginning or end of the character "spectrum" may be messed up.
//Also, the key will most likely be repeated to the size of the encrypted string.
result = "";
for (i=1; i<=string_length(argument1); i+=1){
strc=string_char_at(argument1,i)
strcasc=ord(strc)
destc=string_char_at(argument2,i)
destcasc=ord(destc)
if argument0=1 diff=strcasc-destcasc
else diff=destcasc-strcasc
    result+=chr(diff);
}
return result;

Edited by darkwalker247, 22 September 2014 - 04:48 PM.

  • 0

#3 zbox

zbox

    GMC Member

  • GMC Member
  • 2618 posts
  • Version:Unknown

Posted 20 April 2014 - 01:15 PM

I'm sorry darkwalker, your's isn't as nice ;P Also suffers that problem I mentioned at the end of my post :( I fixed it though and should be fully functioning now!


  • 0

#4 Floofpaws

Floofpaws

    Fox

  • GMC Member
  • 2161 posts
  • Version:Unknown

Posted 21 April 2014 - 03:31 PM

What I posted was a decryption for your algorithm, to show you the vulnerability in it...
  • 0

#5 zbox

zbox

    GMC Member

  • GMC Member
  • 2618 posts
  • Version:Unknown

Posted 22 April 2014 - 07:07 AM

What I posted was a decryption for your algorithm, to show you the vulnerability in it...

Oh I see! Ok so if it was how I had it before I edited the post, you'd still have to know the entire content encrypted in the first place at least one time? I imagine this could be easily solved by throwing a few random characters in here and there, or even just a hash as I mentioned, 40 gobbeldygook characters would really stuff someone trying to decrypt it up I think :P


  • 0

#6 blackhawkrobbo

blackhawkrobbo

    GMC Member

  • GMC Member
  • 1121 posts
  • Version:GM:Studio

Posted 22 September 2014 - 11:09 AM

I guess an implementation of the Rijndael AES would be great :)

Perhaps a GML variant of a DLL like this: http://gmc.yoyogames...howtopic=245305
  • 1

#7 zbox

zbox

    GMC Member

  • GMC Member
  • 2618 posts
  • Version:Unknown

Posted 22 September 2014 - 11:25 AM

I guess an implementation of the Rijndael AES would be great :)

Perhaps a GML variant of a DLL like this: http://gmc.yoyogames...howtopic=245305

Yeah indeed it would be, I've thought about doing that, though probably would do it in extension form for each platform to get some extra speed - I looked at the AES spec and got a bit scared by the large task that would be writing it from spec :S

 

Now I think about it though probably wouldn't be too bad, since there are heaps of open source implementations of AES in Java/Objective C, could just snag those...

 

For my game ATM though I just used a RC4 cipher that I adapted to work with GM:Studio from gmlscripts.com :P


  • 0

#8 blackhawkrobbo

blackhawkrobbo

    GMC Member

  • GMC Member
  • 1121 posts
  • Version:GM:Studio

Posted 22 September 2014 - 12:32 PM

I guess an implementation of the Rijndael AES would be great :)

Perhaps a GML variant of a DLL like this: http://gmc.yoyogames...howtopic=245305

Yeah indeed it would be, I've thought about doing that, though probably would do it in extension form for each platform to get some extra speed - I looked at the AES spec and got a bit scared by the large task that would be writing it from spec :S
 
Now I think about it though probably wouldn't be too bad, since there are heaps of open source implementations of AES in Java/Objective C, could just snag those...
 
For my game ATM though I just used a RC4 cipher that I adapted to work with GM:Studio from gmlscripts.com :P


True, its not the simplest encryption. But its good tho. Maybe a little extension would be nice indeed :) A fast GML version would be even cooler! Maybe i'll look into it once i have some spare time, heheh
  • 0