This is an XTEA implementation that has both LSL and PHP scripts to allow strong encryption not only inside LSL but also between LSL and a PHP serverscript.
For those who want to see this in action with your Web server try these. Be sure that if you edit these that Rounds and Key Phrase are the same in both LSL and PHP versions.
LSL - PLACE IN PRIM -- Edit to change URL and tosend text.
CODE
//************************************************//
//* Masa's XTEA encryption/decryption v3 *//
//* Modified by SleightOf Hand for Stability and *//
//* intercommunication with PHP version *//
//************************************************//
// NOTE: This version only encodes 60 bits per 64-bit block!
// This code is public domain.
// Sleight was here 20070522
// masa was here 20070315
// so was strife 20070315
//
// This was Modified by SleightOf Hand to allow
// Strong encryption between LSL and PHP.
//************************************************//
//* XTEA IMPLEMENTATION *//
//************************************************//
integer XTEA_DELTA = 0x9E3779B9; // (sqrt(5) - 1) * 2^31
integer xtea_num_rounds = 6;
list xtea_key = [0, 0, 0, 0];
integer hex2int(string hex) {
if(llGetSubString(hex,0,1) == "0x")
return (integer)hex;
if(llGetSubString(hex,0,0) == "x")
return (integer)("0"+hex);
return(integer)("0x"+hex);
}
// Convers any string to a 32 char MD5 string and then to a list of
// 4 * 32 bit integers = 128 bit Key. MD5 ensures always a specific
// 128 bit key is generated for any string passed.
list xtea_key_from_string( string str )
{
str = llMD5String(str,0); // Use Nonce = 0
return [ hex2int(llGetSubString( str, 0, 7)),
hex2int(llGetSubString( str, 8, 15)),
hex2int(llGetSubString( str, 16, 23)),
hex2int(llGetSubString( str, 24, 31))];
}
// Encipher two integers and return the result as a 12-byte string
// containing two base64-encoded integers.
string xtea_encipher( integer v0, integer v1 )
{
integer num_rounds = xtea_num_rounds;
integer sum = 0;
do {
// LSL does not have unsigned integers, so when shifting right we
// have to mask out sign-extension bits.
v0 += (((v1 << 4) ^ ((v1 >> 5) & 0x07FFFFFF)) + v1) ^ (sum + llList2Integer(xtea_key, sum & 3));
sum += XTEA_DELTA;
v1 += (((v0 << 4) ^ ((v0 >> 5) & 0x07FFFFFF)) + v0) ^ (sum + llList2Integer(xtea_key, (sum >> 11) & 3));
} while( num_rounds = ~-num_rounds );
//return only first 6 chars to remove "=="'s and compact encrypted text.
return llGetSubString(llIntegerToBase64(v0),0,5) +
llGetSubString(llIntegerToBase64(v1),0,5);
}
// Decipher two base64-encoded integers and return the FIRST 30 BITS of
// each as one 10-byte base64-encoded string.
string xtea_decipher( integer v0, integer v1 )
{
integer num_rounds = xtea_num_rounds;
integer sum = XTEA_DELTA*xtea_num_rounds;
do {
// LSL does not have unsigned integers, so when shifting right we
// have to mask out sign-extension bits.
v1 -= (((v0 << 4) ^ ((v0 >> 5) & 0x07FFFFFF)) + v0) ^ (sum + llList2Integer(xtea_key, (sum>>11) & 3));
sum -= XTEA_DELTA;
v0 -= (((v1 << 4) ^ ((v1 >> 5) & 0x07FFFFFF)) + v1) ^ (sum + llList2Integer(xtea_key, sum & 3));
} while ( num_rounds = ~-num_rounds );
return llGetSubString(llIntegerToBase64(v0), 0, 4) +
llGetSubString(llIntegerToBase64(v1), 0, 4);
}
// Encrypt a full string using XTEA.
string xtea_encrypt_string( string str )
{
// encode string
str = llStringToBase64(str);
// remove trailing =s so we can do our own 0 padding
integer i = llSubStringIndex( str, "=" );
if ( i != -1 )
str = llDeleteSubString( str, i, -1 );
// we don't want to process padding, so get length before adding it
integer len = llStringLength(str);
// zero pad
str += "AAAAAAAAAA=";
string result;
i = 0;
do {
// encipher 30 (5*6) bits at a time.
result += xtea_encipher(
llBase64ToInteger(llGetSubString(str, i, i += 4) + "A="),
llBase64ToInteger(llGetSubString(str, ++i, i += 4) + "A=")
);
} while ( ++i < len );
return result;
}
// Decrypt a full string using XTEA
string xtea_decrypt_string( string str ) {
integer len = llStringLength(str);
integer i;
string result;
do {
result += xtea_decipher(
llBase64ToInteger(llGetSubString(str, i, i += 5) + "=="),
llBase64ToInteger(llGetSubString(str, ++i, i += 5) + "==")
);
} while ( ++i < len );
// Replace multiple trailing zeroes with a single one
i = llStringLength(result);
while ( llGetSubString(result, --i, i) == "A" );
result = llGetSubString(result, 0, i);
i = llStringLength(result);
integer mod = i%4; //Depending on encoded length diffrent appends are needed
if(mod == 1) return llBase64ToString(result + "A==");
else if(mod == 2 ){
if((llSubStringIndex(base64,llGetSubString(result, -1,-1))) & 0x0F) return llBase64ToString(result + "A=");
else return llBase64ToString(result + "==");
}
else if(mod == 3){
if((llSubStringIndex(base64,llGetSubString(result, -1,-1))) & 0x03) return llBase64ToString(result + "A");
return llBase64ToString(result + "=");
}
return llBase64ToString( result );
}
key requestid; // just to check if we're getting the result we've asked for; all scripts in the same object get the same replies
string base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx yz0123456789+/";
string url = "http://<enter your URL here>/test-script.php";
default
{
touch_start(integer number)
{
string tosend = "this is a message to send";
llWhisper(0, "Message to Send = " + tosend);
xtea_key = xtea_key_from_string("this is a test key");
string message = xtea_encrypt_string(tosend);
llWhisper(0, "Message to Server = " + message);
requestid = llHTTPRequest(url,
[HTTP_METHOD, "POST",
HTTP_MIMETYPE, "application/x-www-form-urlencoded"],
"parameter1=" + llEscapeURL(message));
}
http_response(key request_id, integer status, list metadata, string body)
{
if (request_id == requestid)
llWhisper(0, "Web server sent: " + body);
integer clean = 0;
string cleanbody = "";
while(~llSubStringIndex(base64,llGetSubString(body ,clean,clean))){
cleanbody += llGetSubString(body,clean,clean++);
}
llWhisper(0, "Cleaned : " + cleanbody);
llWhisper(0, "Web server said: " + xtea_decrypt_string( cleanbody ));
}
}
PHP Code - Place on web server at location that LSL URL will be looking for.
CODE
<?php
//************************************************//
//* Sleight's PHP XTEA encryption/decryption v3 *//
//* Modified by SleightOf Hand for Stability and *//
//* intercommunication between PHP & LSL *//
//************************************************//
// NOTE: This version only encodes 60 bits per 64-bit block!
// This code is public domain.
// Sleight was here 20070522
// masa was here 20070315
// so was strife 20070315
//
// This was converted from the LSL version by
// SleightOf Hand to allow Strong encryption
// between LSL and PHP. If you find this usefull
// any donations apreciated.
//************************************************//
//* XTEA IMPLEMENTATION *//
//************************************************//
$_XTEA_DELTA = 0x9E3779B9; // (sqrt(5) - 1) * 2^31
$_xtea_num_rounds = 6;
$_xtea_key = array(0, 0, 0, 0);
$_base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".
"abcdefghijklmnopqrstuvwxyz".
"0123456789+/";
// Returns Integer based on 8 byte Base64 Code XXXXXX== (llBase64ToInteger)
function base64_integer($str){
global $_base64;
if(strlen($str) != 8) return 0;
return ((strpos($_base64,$str{0}) << 26)|
(strpos($_base64,$str{1}) << 20)|
(strpos($_base64,$str{2}) << 14)|
(strpos($_base64,$str{3}) << 8) |
(strpos($_base64,$str{4}) << 2) |
(strpos($_base64,$str{5}) >> 4));
}
// Returns 8 Byte Base64 code based on 32 bit integer ((llIntegerToBase64)
function integer_base64($int){
global $_base64;
if($int != (integer) $int) return 0;
return $_base64{($int >> 26 & 0x3F)} .
$_base64{($int >> 20 & 0x3F)} .
$_base64{($int >> 14 & 0x3F)} .
$_base64{($int >> 8 & 0x3F)} .
$_base64{($int >> 2 & 0x3F)} .
$_base64{($int << 4 & 0x3F)} . "==";
}
//strict 32 bit addition using logic
function binadd($val1 , $val2){
$ta = $val1 ^ $val2;
while($tc = (($val1 & $val2) << 1) & 0x0FFFFFFFF){
$ta = ($val1 = $tc) ^ ($val2 = $ta);
}
return $ta; // $ta will now be the result so return it
}
// Convers any string to a 32 char MD5 string and then to a list of
// 4 * 32 bit integers = 128 bit Key.
function xtea_key_from_string( $str ) {
global $_xtea_key;
$str = md5($str . ":0"); // Use nonce = 0 in LSL for same output
eval("\$_xtea_key[0] = 0x" . substr($str,0,8) . ";");
eval("\$_xtea_key[1] = 0x" . substr($str,8,8) . ";");
eval("\$_xtea_key[2] = 0x" . substr($str,16,8) . ";");
eval("\$_xtea_key[3] = 0x" . substr($str,24,8) . ";");
}
// Encipher two integers and return the result as a 12-byte string
// containing two base64-encoded integers.
function xtea_encipher( $v0 , $v1 ) {
global $_xtea_num_rounds , $_xtea_key , $_XTEA_DELTA;
$num_rounds = $_xtea_num_rounds;
$sum = 0;
do {
// LSL only has 32 bit integers. However PHP automaticly changes
// 32 bit integers to 64 bit floats as nessesary. This causes
// incompatibilities between the LSL Encryption and the PHP
// counterpart. I got round this by changing all addition to
// binary addition using logical & and ^ and loops to handle bit
// carries. This forces the 32 bit integer to remain 32 bits as
// I mask out any carry over 32 bits. this bring the output of the
// encrypt routine to conform with the output of its LSL counterpart.
// LSL does not have unsigned integers, so when shifting right we
// have to mask out sign-extension bits.
// calculate ((($v1 << 4) ^ (($v1 >> 5) & 0x07FFFFFF)) + $v1)
$v0a = binadd((($v1 << 4) ^ (($v1 >> 5) & 0x07FFFFFF)) , $v1);
// calculate ($sum + $_xtea_key[$sum & 3])
$v0b = binadd($sum , $_xtea_key[$sum & 3]);
// Calculate ($v0 + ((($v1 << 4) ^ (($v1 >> 5) & 0x07FFFFFF)) + $v1)
// ^ ($sum + $_xtea_key[$sum & 3]))
$v0 = binadd($v0 , ($v0a ^ $v0b));
//Calculate ($sum + $_XTEA_DELTA)
$sum = binadd($sum , $_XTEA_DELTA);
//Calculate ((($v0 << 4) ^ (($v0 >> 5) & 0x07FFFFFF)) + $v0)
$v1a = binadd((($v0 << 4) ^ (($v0 >> 5) & 0x07FFFFFF)) , $v0);
// Calculate ($sum + $_xtea_key[($sum >>11) & 3])
$v1b = binadd($sum , $_xtea_key[($sum >>11) & 3]);
//Calculate ($v1 + ((($v0 << 4) ^ (($v0 >> 5) & 0x07FFFFFF)) + $v0
// ^ ($sum & $_xtea_key[($sum >>11) & 3]))
$v1 = binadd($v1 , ($v1a ^ $v1b));
} while( $num_rounds = ~-$num_rounds );
//return only first 6 chars to remove "=="'s and compact encrypted text.
return substr(integer_base64($v0),0,6) . substr(integer_base64($v1),0,6);
}
// Decipher two base64-encoded integers and return the FIRST 30 BITS of
// each as one 10-byte base64-encoded string.
function xtea_decipher( $v0, $v1 ) {
global $_xtea_num_rounds , $_xtea_key , $_XTEA_DELTA;
$num_rounds = $_xtea_num_rounds;
$sum = 0; // $_XTEA_DELTA * $_xtea_num_rounds;
$tda = $_XTEA_DELTA;
do{ // Binary multiplication using binary manipulation
if($num_rounds & 1){
$sum = binadd($sum , $tda);
}
$num_rounds = $num_rounds >> 1;
$tda = ($tda << 1) & 0x0FFFFFFFF;
}while($num_rounds);
$num_rounds = $_xtea_num_rounds; // reset $num_rounds back to its propper setting;
do {
// LSL only has 32 bit integers. However PHP automaticly changes
// 32 bit integers to 64 bit floats as nessesary. This causes
// incompatibilities between the LSL Encryption and the PHP
// counterpart. I got round this by changing all addition to
// binary addition using logical & and ^ and loops to handle bit
// carries. This forces the 32 bit integer to remain 32 bits as
// I mask out any carry over 32 bits. this bring the output of the
// decrypt routine to conform with the output of its LSL counterpart.
// Subtrations are handled by using 2's compliment
// LSL does not have unsigned integers, so when shifting right we
// have to mask out sign-extension bits.
// calculate ((($v0 << 4) ^ (($v0 >> 5) & 0x07FFFFFF)) + $v0)
$v1a = binadd((($v0 << 4) ^ (($v0 >> 5) & 0x07FFFFFF)) , $v0);
// calculate ($sum + $_xtea_key[($sum>>11) & 3])
$v1b = binadd($sum , $_xtea_key[($sum>>11) & 3]);
//Calculate 2's compliment of ($v1a ^ $v1b) for subtraction
$v1c = binadd((~($v1a ^ $v1b)) , 1);
//Calculate ($v1 - ((($v0 << 4) ^ (($v0 >> 5) & 0x07FFFFFF)) + $v0)
// ^ ($sum + $_xtea_key[($sum>>11) & 3]))
$v1 = binadd($v1 , $v1c);
// Calculate new $sum based on $num_rounds - 1
$tnr = $num_rounds - 1; // Temp $num_rounds
$sum = 0; // $_XTEA_DELTA * ($num_rounds - 1);
$tda = $_XTEA_DELTA;
do{ // Binary multiplication using binary manipulation
if($tnr & 1){
$sum = binadd($sum , $tda);
}
$tnr = $tnr >> 1;
$tda = ($tda << 1) & 0x0FFFFFFFF;
}while($tnr);
//Calculate ((($v1 << 4) ^ (($v1 >> 5) & 0x07FFFFFF)) + $v1)
$v0a = binadd((($v1 << 4) ^ (($v1 >> 5) & 0x07FFFFFF)) , $v1);
//Calculate ($sum + $_xtea_key[$sum & 3])
$v0b = binadd($sum , $_xtea_key[$sum & 3]);
//Calculate 2's compliment of ($v0a ^ $v0b) for subtraction
$v0c = binadd((~($v0a ^ $v0b)) , 1);
//Calculate ($v0 - ((($v1 << 4) ^ (($v1 >> 5) & 0x07FFFFFF)) + $v1
// ^ ($sum + $_xtea_key[$sum & 3]))
$v0 = binadd($v0 , $v0c);
} while ( $num_rounds = ~-$num_rounds );
return substr(integer_base64($v0), 0, 5) . substr(integer_base64($v1), 0, 5);
}
// Encrypt a full string using XTEA.
function xtea_encrypt_string( $str ) {
// encode Binany string to Base64
$str = base64_encode($str);
// remove trailing =s so we can do our own 0 padding
$i = strpos($str, '=', 0);
if ( $i !== FALSE ){
$str = substr( $str, 0, $i);
}
// we don't want to process padding, so get length before adding it
$len = strlen($str);
// zero pad
$str .= "AAAAAAAAAA=";
$result = "";
$i = 0;
do {
// encipher 30 (5*6) bits at a time.
$enc1 = base64_integer(substr($str , $i , 5) . "A==");
$i += 5;
$enc2 = base64_integer(substr($str , $i , 5) . "A==");
$i += 5;
$result .= xtea_encipher($enc1, $enc2);
} while ( $i < $len );
return $result; //Return Encrypted string
}
// Decrypt a full string using XTEA
function xtea_decrypt_string( $str ) {
global $_base64 ;
$len = strlen($str);
$i;
$result;
do {
$dec1 = base64_integer(substr($str , $i , 6)."==");
$i += 6;
$dec2 = base64_integer(substr($str , $i , 6)."==");
$i += 6;
$result .= xtea_decipher( $dec1, $dec2);
} while ( $i < $len );
// Replace multiple trailing zeroes with a single one
$i = strlen($result);
while ( substr($result, --$i, 1) == "A" );
$result = substr($result, 0, $i+1);
$i = strlen($result);
$mod = $i%4; //Depending on encoded length diffrent appends are needed
if($mod == 1) return base64_decode($result . "A==");
else if($mod == 2 ){
if((strpos($_base64,substr($result, -1,1))) & 0x0F) return base64_decode($result . "A=");
else return base64_decode($result . "==");
}
else if($mod == 3){
if((strpos($_base64,substr($result, -1,1))) & 0x03) return base64_decode($result . "A");
else return base64_decode($result . "=");
}
return base64_decode( $result );
}
// Only works with PHP compiled as an Apache module
$headers = apache_request_headers();
$objectName = $headers["X-SecondLife-Object-Name"];
$objectKey = $headers["X-SecondLife-Object-Key"];
$ownerKey = $headers["X-SecondLife-Owner-Key"];
$ownerName = $headers["X-SecondLife-Owner-Name"];
$region = $headers["X-SecondLife-Region"];
// and so on for getting all the other variables ...
xtea_key_from_string("this is a test key");
// get things from $_POST[]
// Naturally enough, if this is empty, you won't get anything
$parameter1 = xtea_decrypt_string($_POST["parameter1"]);
echo xtea_encrypt_string($ownerName . " just said " . $parameter1) . "\n";
?>
This should result in the following output as this is what was output by my object.
CODE
Object whispers: Message to Send = this is a message to send
Object whispers: Message to Server = JSdgCA0FDyhgLlUnSgqMQWkAxz1AzA1vr9zwSEDnCgwJ6GNQ
Object whispers: Web server sent: SVbqNQ5XdkngeUI3bgP+s6eAT6GM4AWnYCYApcfxagrPbxmwiY 7WXA4J+gEQ1AYhRQNvcnEwfZSo/AuKVtIw
Object whispers: Cleaned : SVbqNQ5XdkngeUI3bgP+s6eAT6GM4AWnYCYApcfxagrPbxmwiY 7WXA4J+gEQ1AYhRQNvcnEwfZSo/AuKVtIw
Object whispers: Web server said: SleightOf Hand just said this is a message to send