Go Back   SL Forums > Resident Forums > Content Creation > Scripting Tips
Welcome, Al Supercharge.
You last visited: Yesterday at 11:53 PM
User CP GUIDELINES - please read before posting New Posts Quick Links Log Out


Reply
Thread Tools Search this Thread Display Modes
Old 05-13-2008, 04:06 AM   #1
Zolen Giano
Registered User

Join Date: Dec 2007
Posts: 40
Post LSL to PHP HTTP Encryption Example

I needed an encryption system to handle in world payments being sent to my webserver.

I needed a system that would also be safe from message spoofing. I needed to make sure that the datastream URL could not be simply copied and resent. It would be bad if someone somehow copied the datastream URL for a payment and resent it over and over again to the server.

This system (when used with a MySQL DB to store the used keys) will ensure no message can be copied and sent twice.

Since I'm no encryption "Expert", I would like some input into this here system I've developed. Simply put the LSL script in an object and it should hook-up with my webserver.

If this script can be validated as being a decent solution, I would also like it to be made available in the script library as it would seem to be safe if the private keys I use are kept private.


Script for in world object
LSL ========================= LSL

// Written by Zolen Giano

//This script demonstrates passing encrypted data to a PHP webserver and back.
//This script encrypts both the data and public key with a random number.
//Then decrypts the returning data with same random number

//private key for encrypting random seed
string encryptionkey = "MyPrivateKey";

//User Variables
integer MainTimer = 30; //does a cycle every 30 seconds
integer SleepTimer = 5; // seconds to pause after a request
string split="|"; //the field delimiter for parsing

//HTTP info - Server and webpage (don't hammer on my server plz)
string baseURL = "http://clubworks.co.cc/testcrypt.php?";
//dont forget the '?' on the end of pagename

// System Variables
integer channel;
string seed;
string secretkey;
integer fails;
integer goods;
string OwnerName;
integer DataCycles;
key httprequest;

default
{
state_entry()
{
channel=(integer)llFrand(100000)-1000000;
OwnerName=llKey2Name(llGetOwner());
llSay(0, "Warming Up...Hello "+OwnerName+". Communicating on channel "+(string)channel+".");
llSetText("Warming up...",<1,0,0>,1);
llSetTimerEvent(5);
}

on_rez(integer param)
{
llResetScript();
}

touch_start(integer total_number)
{
if (llDetectedKey(0)!=llGetOwner())
llWhisper(0,"Sorry, controlled by "+OwnerName+" only.");
else
{
llSetTimerEvent(MainTimer);
llDialog(llDetectedKey(0),"Please Select", ["Stats", "Reset"],channel);
llListen(channel, "", llGetOwner(), "");
}
}

listen(integer thsichannel, string name, key id, string msg)
{
if (msg=="Stats")
{
llOwnerSay("Free Memory: "+(string)llGetFreeMemory()+" Bytes Free.");
llOwnerSay("Data Cycles: "+(string)DataCycles+". 1 cycle every "+(string)MainTimer+" seconds.");
llOwnerSay("Good Requests: "+(string)goods);
llOwnerSay("Fails: "+(string)fails);
}
if (msg=="Reset")
{
llResetScript();
}
}

timer()
{
// set the timer
llSetTimerEvent(MainTimer);

// count cycles for stats
DataCycles++;

//sample data
string data1=(string)llKey2Name(llGetOwner());
string data2=(string)llGetRegionName();
string data3=(string)((integer)llGetRegionFPS());

//built the data string
string datum=data1+split+data2+split+data3;

//make a large random seed
seed=(string)((integer)llFrand(100000000)+10000000 0);

//add the seed number to the beginning of the data string for checking later
datum=(string)seed+split+datum;

//encrypt the data string with the random seed
string secret=llXorBase64StringsCorrect(llStringToBase64( datum),llStringToBase64((string)seed));

//encrypt the random seed with our private encryption key
string secretkey=llXorBase64StringsCorrect(llStringToBase 64((string)seed),llStringToBase64(encryptionkey));

//build our encrypted URL to send
string thisurl="&k="+llEscapeURL((string)secretkey)+"&d="+llEscapeURL(secret);

//Show progress report in yellow hovertext
llSetText("Sending Data:\n"+(string)thisurl,<1,1,0>,1);
llSleep(SleepTimer);

//Send the request to webserver
httprequest = llHTTPRequest(baseURL+thisurl,[HTTP_METHOD,"GET"],"");

}
//Webserver response
http_response(key request_id, integer status, list metadata, string body)
{
if (request_id == httprequest)
{
//Show status in white
llSetText("Server Response:\n\n"+body, <1,1,1>, 1);
llSleep(SleepTimer);

//Parse the webserver response
list parsed = llParseString2List( body, [ split ], [] );

//pick out the returning encrypted seed
string returnseed=llList2String( parsed, 1 );

//decrypt the returning seed with our private encryption key
returnseed=llBase64ToString(llXorBase64Strings(ret urnseed, llStringToBase64(encryptionkey)));

//Check if our returning seed is the same as our original random seed
if ((string)seed==returnseed)
{
// add to statistics
goods++;

//pick out the encrypted message from the web server response.
string returnsecret=llList2String( parsed, 2 );

//decrypt our returning message with our seed
string returnmessage=llBase64ToString(llXorBase64Strings( returnsecret, llStringToBase64(seed)));
//Show decrypted message in green hovertext
llSetText("Decrypted Message:\n"+returnmessage,<0,1,0>,1);
}
else
{
// add to statistics
fails++;

//Show Failed Status in Red
llSetText("Data Request Failed\nWaiting for Next Cycle",<1,0,0>,1);
}

//limit the number of cycles to 10.
//remove this if you want to hammer on the web server forever
if(DataCycles >10) {llOwnerSay("I'm tired. Sleeping...");llSetTimerEvent(0);}

}
}
}
/LSL=================/LSL



Webserver script - testcrypt.php
PHP=======================PHP
<?
//Round trip SL to PHP encryption example written by Zolen Giano

//this PHP script decrypts and processes a message sent from SL,
//and returns an encrypted response.

//This system uses random public keys which are decrypted by the
//internal private key to produce a unique data stream every time.


// your private key
$encryptionkey="MyPrivateKey";

//field seperator for parsing
$split="|";


//Simple XOR encryption function
function simplexor($s1, $s2)
{
$s1 = base64_decode($s1);
$s2 = base64_decode($s2);

while(strlen($s2) < strlen($s1))
$s2 .= $s2;

return base64_encode($s1 ^ $s2);
}



//grabs the incomming variables
$thiskey=$_GET['k'];
$secret=$_GET['d'];

//Here is a good spot to do your DB query for duplicate keys.
//store the incomming thiskeys in your DB
//If thiskey already exists in the DB means this is a spoofed or repeated message.

//decrypt the public key using our private key to get the original random seed.
$seed=base64_decode(simplexor($thiskey,base64_enco de($encryptionkey)));

//decrypt the data using the random seed
$datum=base64_decode(simplexor($secret,base64_enco de($seed)));

//parse the data into an array
$parsed = explode ($split,$datum);

//Security check to make sure the outer seed exists and equals the inner seed
if ($seed!="" and ((string)((integer)$seed)==$parsed[0]))
{

//do our processing...
//this is where you can insert your parsed bits to your database

//Send some unencrypted data back to SL for fun
echo "Server Clubworks.co.cc Online\n".$split;

//build a data string we want to encrypt.
$datum = "\nWelcome ".$parsed[1]." from ".$parsed[2].".\n\n Your region FPS is ".$parsed[3];

//encrypt the seed and send it back to SL for checking
echo (simplexor(base64_encode((string)$seed),base64_enc ode($encryptionkey)).$split);

//encrypt our data stream and send it
echo (simplexor(base64_encode($datum),base64_encode($se ed)));

}
else
{
//failed security test
echo "Unauthorized Access";
die();
}

?>


/PHP================/PHP


Cheers!

- zg

Last edited by Zolen Giano : 05-13-2008 at 08:57 AM. Reason: Slight update to the PHP part
Zolen Giano is offline Report Bad Post   Reply With Quote
Old 05-13-2008, 08:57 AM   #2
Strife Onizuka
Moonchild

Join Date: Mar 2004
Location: !quit !quit !quit !quit
Posts: 5,572
I'm not an expert in all types of encryption but I do know quite a bit about using XOR. Your data is not secure. There are some serious problems with this. First of all, I know the xor is 9 characters and because of the XOR the key is effectively also 9 characters, because of how you generate the random number I can also determine the first character of key and every 9th character starting at the first character of the message. If your key contains a number in any of it's 9 positions, given enough captures (about 10) I can determine without a doubt that it is a number. Because I know the seed is all digits I know the top four bits of every byte.

If you just look at the probabilities, the number of bits leaked by your alg are: 47.25 of the 72 bits. Which means that before doing any actual work, I know I only need to try about 28,212,474 seed combinations.

Worst of all, if I manage to decrypt ONE MESSAGE, I can decrypt ALL MESSAGES. It only requires me to guess one seed value for me to know the key. An XOR relates it's inputs, so once we figure out one input we can determine via the relations all the other values.

To some things up:
*Your seed generator does a crappy job of generating random data, the way you are using it, it reveals too much information to the user and it will expose weak spots in the key. Because it's first character is always "1" we know the first character of your key.
*You aren't protecting your secret with a seeded trapdoor function. Since the key is used directly, one cracked message means the key has been compromised.

Last edited by Strife Onizuka : 05-13-2008 at 09:01 AM.
Strife Onizuka is offline Report Bad Post   Reply With Quote
Old 05-13-2008, 10:26 AM   #3
Zolen Giano
Registered User

Join Date: Dec 2007
Posts: 40
I kinda figured using all numbers for a key wasn't good. I did that for simplicity. For my production script I was actually planning on using string of random letters instead of random numbers.

I was also thinking of simply MD5 the random number to make a random string.

I imagine that would help?
Zolen Giano is offline Report Bad Post   Reply With Quote
Old 05-14-2008, 12:25 PM   #4
Strife Onizuka
Moonchild

Join Date: Mar 2004
Location: !quit !quit !quit !quit
Posts: 5,572
MD5 is a fine trapdoor function just be sure that the inputs aren't easily guessed. If you use llMD5String, and the input string is known but not the seed, the attacker can brute force the seed in less then 24 hours.

Lets say we do something like AB = XOR(A, B) and AC = XOR(A,C) and then ABAC = XOR(AB, AC). ABAC will have a pattern where it repeats ever Smallest Common Multiple of B and C. The number of uniquely linked fields is equal to the Largest Common Factor of B and C.

I forgot to mention that the XOR doesn't hide the letter occurrence probabilities. Certain letters are used more then other letters in English, given a long enough message those probabilities hold out strong enough that guess about message values can be made.

You can't quickly encrypt messages in LSL with any assurance they can't be decrypted but you can sign them quickly and if you were not worry about it being broken.

If you ever write an alg that you would like reviewed, I do run a small service where I review encryption algs and provide feedback & suggestions for improvements. All informations and communications about such projects are kept in the strictest of secrecy.
Strife Onizuka is offline Report Bad Post   Reply With Quote
Old 05-14-2008, 04:28 PM   #5
Hewee Zetkin
Registered User

Join Date: Jul 2006
Posts: 1,330
I suspect that if you implement your own pseudo-random number generator and simply encrypt a seed (so long as you think of how to use a decently long seed--perhaps breaking it up to produce multiple pseudo-random number sequences), you might be able to generate a mask without serious performance problems that will be quite a lot better than a simple repeated number or string.
Hewee Zetkin is online now Report Bad Post   Reply With Quote
Old 05-14-2008, 04:59 PM   #6
Kidd Krasner
Registered User

Join Date: Jan 2007
Posts: 968
Quote:
Originally Posted by Strife Onizuka
You can't quickly encrypt messages in LSL with any assurance they can't be decrypted but you can sign them quickly and if you were not worry about it being broken.

This point is worth extra attention. Many people ask for encryption when what they really need is authentication.
Kidd Krasner is offline Report Bad Post   Reply With Quote
Old 05-15-2008, 05:46 AM   #7
Zolen Giano
Registered User

Join Date: Dec 2007
Posts: 40
Thank you very much to the folks that responded.

I've been reading up on a lot of this. Unfortunatly, I might as well be reading a passage of Lorum Ipsum for all the sense most of it makes.

I was hoping to produce something open that peope can use...but it seems best practice here would be to keep your algos private since no matter what you do there is no strong encryption technique.

Seems that obfuscation and confusion would be just as valid as anything else currently available.

- zg
Zolen Giano is offline Report Bad Post   Reply With Quote
Old 05-15-2008, 04:46 PM   #8
Kidd Krasner
Registered User

Join Date: Jan 2007
Posts: 968
Quote:
Originally Posted by Zolen Giano
Thank you very much to the folks that responded.

I've been reading up on a lot of this. Unfortunatly, I might as well be reading a passage of Lorum Ipsum for all the sense most of it makes.

I was hoping to produce something open that peope can use...but it seems best practice here would be to keep your algos private since no matter what you do there is no strong encryption technique.

Seems that obfuscation and confusion would be just as valid as anything else currently available.

There's been a fair bit written about encryption in the forum. You should read [url]http://forums.secondlife.com/showthread.php?t=171296[/url] if you haven't already. I haven't been following the discussions closely, but I think you may find an acceptable system based on XTEA.

How much is at risk? If it's possible for someone to steal a significant amount of money, or violate important privacy, then obfuscation isn't enough. What's the worst that could happen if someone cracked one of your messages? All of them?
Kidd Krasner is offline Report Bad Post   Reply With Quote
Old 05-15-2008, 09:10 PM   #9
Strife Onizuka
Moonchild

Join Date: Mar 2004
Location: !quit !quit !quit !quit
Posts: 5,572
Continue what I was saying before (Sorry for being tired then and not making much sense).

Fast and secure encryption in LSL can't happen. LSL is too slow. If your application needs strong encryption, should you really be running it on a machine you don't own and can't control? If your app needs strong encryption you are putting a lot of faith in LL and it's product. Your connection to the sim isn't encrypted, anyone could intercept the asset uploads meaning when you write the script the text could stolen. Most applications don't actually need encryption, they just need to ensure nobody is spoofing the sender and that the message is hard to read.
Strife Onizuka is offline Report Bad Post   Reply With Quote
Reply



Posting Rules
You may post new threads
You may post replies
You may post attachments
You may edit your posts

vB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Forum Jump



All times are GMT. The time now is 02:35 AM.


Powered by: vBulletin Version 3.0.5
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright 2002-2007 Linden Lab