Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Looking for 'real' encryption? Start here.

Tobia Forcella
Registered User
Join date: 4 Mar 2007
Posts: 30
04-20-2007 05:42
Nobody still working on this project? :(:(
Sys Slade
Registered User
Join date: 15 Feb 2007
Posts: 626
04-20-2007 05:51
No posts in 24 hours and you think it's dead?
/me hands Tobia a glass of patience

Both Robby and Newgate are tackling new languages, and have RL stuff to do. Give it some time.
Tobia Forcella
Registered User
Join date: 4 Mar 2007
Posts: 30
04-20-2007 06:06
hey no problem Syd, only to know :)

i'm working on it and can't find a solution; i can pay for it and share with the community! :)
Newgate Ludd
Out of Chesse Error
Join date: 8 Apr 2005
Posts: 2,103
04-20-2007 08:06
From: Tobia Forcella
Nobody still working on this project? :(:(


As has already been posted there are other things demanding my attention I'm afraid.
I will however endeavour to revisit this problem when I have a few moments to spare.

Can you confirm that the different PHP implementations you have used return the same encrypted values for the same key?
Tobia Forcella
Registered User
Join date: 4 Mar 2007
Posts: 30
04-20-2007 08:32
From: someone
Can you confirm that the different PHP implementations you have used return the same encrypted values for the same key?


the mcrypt version of Xtea give a different result than the pear package:

word to encrypt: test
key: 0123456789abcdef

Pear: 03e3fc60351a3fdd
mcrypt: 6c302719dd265d3f

but i tested it on various server, always the same results.
Some posts ago there is the code i used.

I can use pear or mcrypt in my project, i don't have a preference ;)

Thank you very much.
Newgate Ludd
Out of Chesse Error
Join date: 8 Apr 2005
Posts: 2,103
04-20-2007 12:46
From: Tobia Forcella
the mcrypt version of Xtea give a different result than the pear package:

word to encrypt: test
key: 0123456789abcdef

Pear: 03e3fc60351a3fdd
mcrypt: 6c302719dd265d3f

but i tested it on various server, always the same results.
Some posts ago there is the code i used.

I can use pear or mcrypt in my project, i don't have a preference ;)

Thank you very much.



Each installation gave the same results with each package, and was platform/os independant? Thats good to know, it shows that the two packages use different implementations of XTEA. Probably just the number of rounds but could also be some other subtle difference like parenthasis.

I have a shed load of work that I am commited to finishing this weekend, both RL and SL, but will hopefully have time to play with this problem at some point.
jefferey Heart
Registered User
Join date: 25 Jan 2006
Posts: 45
Optimized version not working
04-21-2007 08:09
Anyone else get this Optimized version working right?
Newgate Ludd
Out of Chesse Error
Join date: 8 Apr 2005
Posts: 2,103
04-25-2007 00:42
Another thought has occurred to me but I have not had time to test.
It was previously mentioned that LSL doesnt allow unsigned ints and also that PHP is teh same. Looking at the posted PHP code it supplies its own functions for shifting and adding to by pass PHP's signed function. I think we may need to implement something similar. In fact I think I will try and implement a near direct translation of the PHP script and see if that works.
RobbyRacoon Olmstead
Red warrior is hungry!
Join date: 20 Sep 2006
Posts: 1,821
04-25-2007 07:44
From: Newgate Ludd
Another thought has occurred to me but I have not had time to test.
It was previously mentioned that LSL doesnt allow unsigned ints and also that PHP is teh same. Looking at the posted PHP code it supplies its own functions for shifting and adding to by pass PHP's signed function. I think we may need to implement something similar. In fact I think I will try and implement a near direct translation of the PHP script and see if that works.


I was under the impression that the LSL versions did that as well, but it's been a while since I looked at the code and I am not certain.

That code bounty I offered is still open if you succeed :)


.
_____________________
Newgate Ludd
Out of Chesse Error
Join date: 8 Apr 2005
Posts: 2,103
04-25-2007 08:08
From: RobbyRacoon Olmstead
I was under the impression that the LSL versions did that as well, but it's been a while since I looked at the code and I am not certain.

That code bounty I offered is still open if you succeed :)


.


The library script referenced in the OP doesnt.
If I can clear my current (over due) workload I'll have a play.
ViktorScorich Villota
Registered User
Join date: 15 Apr 2007
Posts: 4
'Real' Encryption
04-25-2007 08:28
Asymmetric Encryption Anyone? On top of that... Replace llFrand https://wiki.secondlife.com/wiki/LlFrandom https://jira.secondlife.com/browse/SVC-134

The Primes and might be an issue....
SleightOf Hand
Registered User
Join date: 4 Apr 2006
Posts: 21
PHP and LSL compatible XTEA and Code
05-22-2007 00:01
Masakazu Kojima gave a good general method of implimenting the XTEA encryptionm and i based my PHP code from that and modified the LSL code to make it a more relable with Key generation and Compactness of the encrypted String.

Following is the LSL, PHP code and Results from both for people to view.

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 = 32;
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 );
}
//************************************************//
//* TESTS *//
//************************************************//
integer test_assertions = 0;
integer test_failures = 0;
test_assert( integer condition, string description ) {
++test_assertions;
if ( !condition ) {
++test_failures;
llOwnerSay( "ASSERTION FAILED: " + description );
} else llOwnerSay("ASSERTION SUCCEEDED: ");

}
test_assert_equal( string v1, string v2, string desc ) {
test_assert( v1 == v2, desc + "\nACTUAL=" + v1 + "\nEXPECTED=" + v2 );
}
test_xtea_encipher() {
xtea_num_rounds = 6;
xtea_key = [0x74736574, 0x2c676e69, 0x74736574, 0x2e676e69];
test_assert_equal(
xtea_encipher(0x62626161, 0x64646363),
llIntegerToBase64(0x5117f04b) + llIntegerToBase64(0xb9f38d3c),
"xtea_encipher(rounds=6, string=\"aabbccdd\"," +
"key=\"testing,testing.\") vs std"
);
xtea_num_rounds = 16;
xtea_key = [0x24234021, 0x2a265e25, 0x2b5f2928, 0x5d5b7d7b];
test_assert_equal(
xtea_encipher(0x74536554, 0x23476e49),
llIntegerToBase64(0xe9306ed2) + llIntegerToBase64(0x8f983d5a),
"xtea_encipher(rounds=16, string=\"TeStInG#\"," +
"key=\"!@#$%^&*()_+{}[]\") vs std"
);
xtea_num_rounds = 32;
xtea_key = [0x20202020, 0x20202020, 0x20202020, 0x20202020];
test_assert_equal(
xtea_encipher(0x20202020, 0x20202020),
llIntegerToBase64(0xb63a89e3) + llIntegerToBase64(0x8631c79c),
"xtea_encipher(rounds=32, string=\" \"," +
"key=\" \") vs std"
);
}
test_timed_encrypt(integer num_rounds, string str, string k) {
string encrypted;
string decrypted;
integer len = llStringLength(str);
string info = "rounds=" + (string)num_rounds + ", len=" + (string)len;
xtea_num_rounds = num_rounds;
xtea_key = xtea_key_from_string(k);
llOwnerSay("Encrypting : " + str);
llResetTime();
encrypted = xtea_encrypt_string(str);
llOwnerSay( "enc(" + info + "): " + (string)llGetTime() );
llOwnerSay("Encrypted to : " + encrypted);
llResetTime();
decrypted = xtea_decrypt_string(encrypted);
llOwnerSay( "dec(" + info + "): " + (string)llGetTime() );
llOwnerSay("Decrypted to : " + decrypted );
test_assert(
str == decrypted,
"test_timed_encrypt(" + (string)num_rounds + "," +
"\"" + str + "\", \"" + k + "\") -- \"" + decrypted + "\""
);
}
test_xtea_encrypt_string() {
test_timed_encrypt(64, llUnescapeURL("%E4%BD%95"), "unicode test");
test_timed_encrypt(64, llUnescapeURL("%E6%94%BF%E5%92%8C%E5%B0%8F%E5%B3%B6"),
"unicode test 2" );
test_timed_encrypt(64, "hello", "test");
test_timed_encrypt(64, "small test", "small key");
test_timed_encrypt(64, llEscapeURL(",xaYGp:?iThL *+\"I8!6qGA0eSXCUG1fXxNl'\"T0_" +
"Un.P:u/= N{2{!L -]'mg-89p.on9zjfEJ<lZW;gJ;d" +
"3:u CFK+|qMqmhaI0"), "here is a key");
test_timed_encrypt(32, "hello", "test");
test_timed_encrypt(32, "small test", "small key");
test_timed_encrypt(32, llEscapeURL(",xaYGp:?iThL *+\"I8!6qGA0eSXCUG1fXxNl'\"T0_" +
"Un.P:u/= N{2{!L -]'mg-89p.on9zjfEJ<lZW;gJ;d" +
"3:u CFK+|qMqmhaI0"), "here is a key");
test_timed_encrypt( 6, "hello", "test");
test_timed_encrypt( 6, "small test", "small key");
test_timed_encrypt( 6, llEscapeURL(",xaYGp:?iThL *+\"I8!6qGA0eSXCUG1fXxNl'\"T0_" +
"Un.P:u/= N{2{!L -]'mg-89p.on9zjfEJ<lZW;gJ;d" +
"3:u CFK+|qMqmhaI0"), "here is a key");
}
//************************************************//
//* TEST DRIVER *//
//************************************************//
default {
state_entry() {
// test_xtea_encipher();
test_xtea_encrypt_string();
llOwnerSay( "assertions: " + (string)test_assertions + " / " +
"failures: " + (string)test_failures );
llListen(0, "", llGetOwner(), "" );
}
listen(integer channel, string name, key id, string msg) {
test_timed_encrypt( 64, msg, id );
test_timed_encrypt( 32, msg, id );
test_timed_encrypt( 6, msg, id );
}
}



PHP Code:

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 = 32;
$_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 );


}
//************************************************//
//* TESTS *//
//************************************************//
$_test_assertions = 0;
$_test_failures = 0;
function test_assert($condition, $description ) {
global $_test_failures , $_test_assertions;
++$_test_assertions;
if ( !$condition ) {
++$_test_failures;
echo ( "ASSERTION FAILED: " . $description . "<p>");
}
else echo ( "ASSERTION SUCCEEDED: <p>" );
}
function test_assert_equal( $v1, $v2, $desc ) {
test_assert( $v1 == $v2, $desc . "<br>ACTUAL=" . $v1 . "<br>EXPECTED=" . $v2 );
}
function test_timed_encrypt($num_rounds, $str, $k) {
global $_xtea_num_rounds, $_xtea_key;
$encrypted;
$decrypted;
$len = strlen($str);
$info = "rounds=" . (string) $num_rounds . ", len=" . (string) $len;
$_xtea_num_rounds = $num_rounds;
xtea_key_from_string($k);
$CurrTime = time();
echo "Encrypting : " . $str . "<p>";
$encrypted = xtea_encrypt_string($str);
echo "Encrypted to : " . $encrypted . "<p>";
$CurrTime = time();
$decrypted = xtea_decrypt_string($encrypted);
echo "Decrypted to : " . $decrypted . "<p>";
test_assert( !strcmp($str,$decrypted), "test_timed_encrypt(" . $num_rounds . "," .
"\"" . $str . "\", \"" . $k . "\") -- \"" . $decrypted . "\""
);
}
function test_xtea_encrypt_string() {
test_timed_encrypt(64, urldecode("%E4%BD%95"), "unicode test");
test_timed_encrypt(64, urldecode("%E6%94%BF%E5%92%8C%E5%B0%8F%E5%B3%B6"),
"unicode test 2" );
test_timed_encrypt(64, "hello", "test");
test_timed_encrypt(64, "small test", "small key");
test_timed_encrypt(64, urlencode(",xaYGp:?iThL *+\"I8!6qGA0eSXCUG1fXxNl'\"T0_" .
"Un.P:u/= N{2{!L -]'mg-89p.on9zjfEJ<lZW;gJ;d" .
"3:u CFK+|qMqmhaI0"), "here is a key");
test_timed_encrypt(32, "hello", "test");
test_timed_encrypt(32, "small test", "small key");
test_timed_encrypt(32, urlencode(",xaYGp:?iThL *+\"I8!6qGA0eSXCUG1fXxNl'\"T0_" .
"Un.P:u/= N{2{!L -]'mg-89p.on9zjfEJ<lZW;gJ;d" .
"3:u CFK+|qMqmhaI0"), "here is a key");
test_timed_encrypt( 6, "hello", "test");
test_timed_encrypt( 6, "small test", "small key");
test_timed_encrypt( 6, urlencode(",xaYGp:?iThL *+\"I8!6qGA0eSXCUG1fXxNl'\"T0_" .
"Un.P:u/= N{2{!L -]'mg-89p.on9zjfEJ<lZW;gJ;d" .
"3:u CFK+|qMqmhaI0"), "here is a key");
}
//************************************************//
//* TEST DRIVER *//
//************************************************//
test_xtea_encrypt_string();
echo ( "assertions: " . (string)$_test_assertions . " / " .
"failures: " . (string)($_test_failures ));
?>


Results from LSL :

CODE
 
Encrypting : 何
enc(rounds=64, len=1): 2.517058
Encrypted to : 8HwqOQkyYGWA
dec(rounds=64, len=1): 2.492023
Decrypted to : 何
ASSERTION SUCCEEDED:
Encrypting : 政和小島
enc(rounds=64, len=4): 4.739208
Encrypted to : 1b34tA6OFuLQlcsltAV8MJEw
dec(rounds=64, len=4): 4.731294
Decrypted to : 政和小島
ASSERTION SUCCEEDED:
Encrypting : hello
enc(rounds=64, len=5): 2.335077
Encrypted to : yMYYiQL9v5JQ
dec(rounds=64, len=5): 2.429809
Decrypted to : hello
ASSERTION SUCCEEDED:
Encrypting : small test
enc(rounds=64, len=10): 4.581894
Encrypted to : +xuQagkp0FmQFQUtfQHbISsA
dec(rounds=64, len=10): 4.835964
Decrypted to : small test
ASSERTION SUCCEEDED:
Encrypting : %2CxaYGp%3A%3FiThL%20%2A%2B%22I8%216qGA0eSXCUG1fXxNl%27%22T0%5FUn%2EP%3Au%2F%3D%20N%7B2%7B%21L%20%2D%5D%27mg%2D89p%2Eon9zjfEJ%3ClZW%3BgJ%3Bd3%3Au%20CFK%2B%7CqMqmhaI0
enc(rounds=64, len=165): 54.701614
Encrypted to : forJbQQRunRQtRc1xgAKHgwQ7q8QkQrwFtgAbE5RVANKKZLAtDql5QItcjpQP065bgxQ+XcAc3m07QSTZPgAEdEKRQfqwoBQICSOBARzr5LQmw/UHQ0mAK0QEwuoHQ/PbwrQPRXbuwkO51jQwq+uHQt2JS0Q0pCN2A4G73SwjUbvIwWHFVLg3XvRPgCEJiFgE3duuAKwlBqQojEF8Qk6pQeA/8l/cAXtBSVQ92P93wmH762QThu/HApJzfNA0X/VvgSeIfsQ
dec(rounds=64, len=165): 54.852505
Decrypted to : %2CxaYGp%3A%3FiThL%20%2A%2B%22I8%216qGA0eSXCUG1fXxNl%27%22T0%5FUn%2EP%3Au%2F%3D%20N%7B2%7B%21L%20%2D%5D%27mg%2D89p%2Eon9zjfEJ%3ClZW%3BgJ%3Bd3%3Au%20CFK%2B%7CqMqmhaI0
ASSERTION SUCCEEDED:
Encrypting : hello
enc(rounds=32, len=5): 1.166722
Encrypted to : OtvxrQO/zCMQ
dec(rounds=32, len=5): 1.516466
Decrypted to : hello
ASSERTION SUCCEEDED:
Encrypting : small test
enc(rounds=32, len=10): 2.642615
Encrypted to : L29pOwiRNMAASDdpZgYOKXtw
dec(rounds=32, len=10): 2.712204
Decrypted to : small test
ASSERTION SUCCEEDED:
Encrypting : %2CxaYGp%3A%3FiThL%20%2A%2B%22I8%216qGA0eSXCUG1fXxNl%27%22T0%5FUn%2EP%3Au%2F%3D%20N%7B2%7B%21L%20%2D%5D%27mg%2D89p%2Eon9zjfEJ%3ClZW%3BgJ%3Bd3%3Au%20CFK%2B%7CqMqmhaI0
enc(rounds=32, len=165): 28.061316
Encrypted to : XAbCDwIM3+Dg3dQB0ApFhWtww3ee0wnn81KgYVh+vgn4LZdQhGqzKgkBziMAOBtFWAntMolg3a/PewDQNYIwwXZZYwjLJJbg8Zx7mAFBcD8wGWAMMQyzUyHQqqT5lwBaxOhgjeigqAB/pz1gmWDvxQhefwKgm6gRAw/JqCIwMr6KEQCfjCEAPK6QoAChnrCA9UGtYwuYxUlAUT3uigp7KhgAxuXSrw92bmSgrXZofwmPZZlgvjLltAH5915wSGWHuw5lWN5Q
dec(rounds=32, len=165): 27.892733
Decrypted to : %2CxaYGp%3A%3FiThL%20%2A%2B%22I8%216qGA0eSXCUG1fXxNl%27%22T0%5FUn%2EP%3Au%2F%3D%20N%7B2%7B%21L%20%2D%5D%27mg%2D89p%2Eon9zjfEJ%3ClZW%3BgJ%3Bd3%3Au%20CFK%2B%7CqMqmhaI0
ASSERTION SUCCEEDED:
Encrypting : hello
enc(rounds=6, len=5): 0.494484
Encrypted to : zBE6gwElLiOQ
dec(rounds=6, len=5): 0.618669
Decrypted to : hello
ASSERTION SUCCEEDED:
Encrypting : small test
enc(rounds=6, len=10): 0.940793
Encrypted to : g6Yd4w8iJULAykugogyLKRAA
dec(rounds=6, len=10): 1.111868
Decrypted to : small test
ASSERTION SUCCEEDED:
Encrypting : %2CxaYGp%3A%3FiThL%20%2A%2B%22I8%216qGA0eSXCUG1fXxNl%27%22T0%5FUn%2EP%3Au%2F%3D%20N%7B2%7B%21L%20%2D%5D%27mg%2D89p%2Eon9zjfEJ%3ClZW%3BgJ%3Bd3%3Au%20CFK%2B%7CqMqmhaI0
enc(rounds=6, len=165): 8.037796
Encrypted to : T/F8GAVZe64QM9BrSAfh0tDAKOXyZQiIcqjQVjaoRw5P3l0wqPKbYArc2CjQg+0BQgjbtu9wwJes2gQ9iyfwHamm8AFC4bUw1a4EOgAOwVoQfU/CXQT9j7iQNYh8QAfwy/0g6yYxmQ6emSjA2ZATFgqNmB3g6IqaogFMfn1QRFjq7AiVjK8ApH3MEQ+IFTqwJcxONQgQHZpwdyEl8g6tMq9QmlFzjwnNx8zQRsOVSAXb9y3AW22gaw6eJj7wRBeWbAHS9a6A
dec(rounds=6, len=165): 8.228614
Decrypted to : %2CxaYGp%3A%3FiThL%20%2A%2B%22I8%216qGA0eSXCUG1fXxNl%27%22T0%5FUn%2EP%3Au%2F%3D%20N%7B2%7B%21L%20%2D%5D%27mg%2D89p%2Eon9zjfEJ%3ClZW%3BgJ%3Bd3%3Au%20CFK%2B%7CqMqmhaI0
ASSERTION SUCCEEDED:
assertions: 11 / failures: 0


and Finaly PHP Results :
Discrepencies in the Encrypted strings are a result of diffrences in results from llEscapeURL() and urlencode() in LSL and PHP and not from the actual encryption process.

CODE
 
Encrypting : 何
Encrypted to : 8HwqOQkyYGWA

Decrypted to : 何

ASSERTION SUCCEEDED:

Encrypting : 政和�島

Encrypted to : 1b34tA6OFuLQlcsltAV8MJEw

Decrypted to : 政和�島

ASSERTION SUCCEEDED:

Encrypting : hello

Encrypted to : yMYYiQL9v5JQ

Decrypted to : hello

ASSERTION SUCCEEDED:

Encrypting : small test

Encrypted to : +xuQagkp0FmQFQUtfQHbISsA

Decrypted to : small test

ASSERTION SUCCEEDED:

Encrypting : %2CxaYGp%3A%3FiThL+%2A%2B%22I8%216qGA0eSXCUG1fXxNl%27%22T0_Un.P%3Au%2F%3D+N%7B2%7B%21L+-%5D%27mg-89p.on9zjfEJ%3ClZW%3BgJ%3Bd3%3Au+CFK%2B%7CqMqmhaI0

Encrypted to : forJbQQRunRQtRc1xgAKHgwQT3kvlw6dabjANRFqDgwsqBzA2IFQJwn2gueQmGotYQ0U/J+QZfS50wVLhWfg4QDelQ9Vqp5gJb/XOQgA5cowxHEyaQPIIYzA8f4vLwzA4rJglzErCg9nYBqQUmamAQa4HeRAwYevVQXJSNWA8+3gbwP0DB7QIsYpXA4uqmJg5gJcOgpKYTQwdQnN1wIraZyw964mXgdqpmCAJJMbAgE2Ht3w

Decrypted to : %2CxaYGp%3A%3FiThL+%2A%2B%22I8%216qGA0eSXCUG1fXxNl%27%22T0_Un.P%3Au%2F%3D+N%7B2%7B%21L+-%5D%27mg-89p.on9zjfEJ%3ClZW%3BgJ%3Bd3%3Au+CFK%2B%7CqMqmhaI0

ASSERTION SUCCEEDED:

Encrypting : hello

Encrypted to : OtvxrQO/zCMQ

Decrypted to : hello

ASSERTION SUCCEEDED:

Encrypting : small test

Encrypted to : L29pOwiRNMAASDdpZgYOKXtw

Decrypted to : small test

ASSERTION SUCCEEDED:

Encrypting : %2CxaYGp%3A%3FiThL+%2A%2B%22I8%216qGA0eSXCUG1fXxNl%27%22T0_Un.P%3Au%2F%3D+N%7B2%7B%21L+-%5D%27mg-89p.on9zjfEJ%3ClZW%3BgJ%3Bd3%3Au+CFK%2B%7CqMqmhaI0

Encrypted to : XAbCDwIM3+Dg3dQB0ApFhWtw1xcNFAbDXjgAWexMRAhd9L9Qygyt7Q8HBA3gnCNE+Qx/cA2QZnrHfgH+JJBgEY5gvgaw6rUAZqcA+QG0J+YAFPhAcwAXXzIANjwa6QccavoQZ/hLpg8e2qNg40XEog7AbDigbQRQNAXXBK8Q48qamQNUJb1QdD0CtQtLZiXwxrp5/gJ3CiXASmn2ngHyoJMgl/sX1g4RhHog6io2LAGr/w7w

Decrypted to : %2CxaYGp%3A%3FiThL+%2A%2B%22I8%216qGA0eSXCUG1fXxNl%27%22T0_Un.P%3Au%2F%3D+N%7B2%7B%21L+-%5D%27mg-89p.on9zjfEJ%3ClZW%3BgJ%3Bd3%3Au+CFK%2B%7CqMqmhaI0

ASSERTION SUCCEEDED:

Encrypting : hello

Encrypted to : zBE6gwElLiOQ

Decrypted to : hello

ASSERTION SUCCEEDED:

Encrypting : small test

Encrypted to : g6Yd4w8iJULAykugogyLKRAA

Decrypted to : small test

ASSERTION SUCCEEDED:

Encrypting : %2CxaYGp%3A%3FiThL+%2A%2B%22I8%216qGA0eSXCUG1fXxNl%27%22T0_Un.P%3Au%2F%3D+N%7B2%7B%21L+-%5D%27mg-89p.on9zjfEJ%3ClZW%3BgJ%3Bd3%3Au+CFK%2B%7CqMqmhaI0

Encrypted to : T/F8GAVZe64QM9BrSAfh0tDASwHxSgayh50gnXQtlQIBRo8gyDK27gWYsZKgOXkr5g8rht/wGKH2hw8jQHqAsNSmzQc+SS+QGO+HtgvNcgvwDTYQJwGDYGLgkMoiLwKYoEIgae1mIQhd0mkQ07xjRAn/nwHwCvPSKAissRFgW0gXrwri4XygJGjFRQ3cj9dwYB64tgqrAaEQM2p7nwKK8FigQFUB6wfTr4iwz6vxUwGgsllw

Decrypted to : %2CxaYGp%3A%3FiThL+%2A%2B%22I8%216qGA0eSXCUG1fXxNl%27%22T0_Un.P%3Au%2F%3D+N%7B2%7B%21L+-%5D%27mg-89p.on9zjfEJ%3ClZW%3BgJ%3Bd3%3Au+CFK%2B%7CqMqmhaI0

ASSERTION SUCCEEDED:

assertions: 11 / failures: 0

SleightOf Hand
Registered User
Join date: 4 Apr 2006
Posts: 21
Careful with Cut and Paste.
05-22-2007 00:38
I just noticed (and I dont know how it happened as the code I have is correct) but you may want to check for randon spaces in the code that I cut and pasted from my own editor. For example in the $_base64 string there seems to have been inserted a couple of spaces between the "x" and the "y" that should not be there. I will check for others though that is the only one so far that reall stands out and would affect the running of the code. I cant fix this in the editor as the code shows correctly without spaces but still shows with spaces in the post. Contact me if you need the source code directly.
Newgate Ludd
Out of Chesse Error
Join date: 8 Apr 2005
Posts: 2,103
Dont sweat it
05-22-2007 01:48
From: SleightOf Hand
I just noticed (and I dont know how it happened as the code I have is correct) but you may want to check for randon spaces in the code that I cut and pasted from my own editor. For example in the $_base64 string there seems to have been inserted a couple of spaces between the "x" and the "y" that should not be there. I will check for others though that is the only one so far that reall stands out and would affect the running of the code. I cant fix this in the editor as the code shows correctly without spaces but still shows with spaces in the post. Contact me if you need the source code directly.



The Forum does it all the time.
_____________________
I'm back......
ed44 Gupte
Explorer (Retired)
Join date: 7 Oct 2005
Posts: 638
05-22-2007 04:16
It might force folk to layout their code with a few more spaces to make it more readable.
eg:
CODE

$_base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"abcdefghijklmnopqrstuvwxyz" +
"0123456789+/";

Extra readability sometimes allows you to pick errors more easily!

This script is great, though!
SleightOf Hand
Registered User
Join date: 4 Apr 2006
Posts: 21
Strong XTEA Encryption in action LSL <-> PHP
05-22-2007 13:13
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 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
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+s6eAT6GM4AWnYCYApcfxagrPbxmwiY7WXA4J+gEQ1AYhRQNvcnEwfZSo/AuKVtIw

Object whispers: Cleaned : SVbqNQ5XdkngeUI3bgP+s6eAT6GM4AWnYCYApcfxagrPbxmwiY7WXA4J+gEQ1AYhRQNvcnEwfZSo/AuKVtIw
Object whispers: Web server said: SleightOf Hand just said this is a message to send
RobbyRacoon Olmstead
Red warrior is hungry!
Join date: 20 Sep 2006
Posts: 1,821
05-22-2007 14:47
Couldn't get it to work quite right, I think I missed something on the formatting (extraneous space or sumthin?), but I went ahead and paid you the bounty I mentioned earlier in this thread :)

I'm pretty excited about this. It's not hardened security by any means, but it's way better than many of the approaches I've seen and I can see some immediate uses for something like this in non-mission-critical applications.

Thanks for taking the time on it :)


.
_____________________
SleightOf Hand
Registered User
Join date: 4 Apr 2006
Posts: 21
Fix for HTTP/PHP transfers of encrypted data
05-22-2007 21:05
Just a quick bug fix.

Since HTTP/PHP converts "+" into a " " when transfering parameters like....

"this+is+a+test" would become "this is a test" then the encoded string has to be passed through llEscapeURL to safeguard it from this effect on the +'s that are part of the Base64 string.

CODE

requestid = llHTTPRequest(url,
[HTTP_METHOD, "POST",
HTTP_MIMETYPE, "application/x-www-form-urlencoded"],
"parameter1=" + llEscapeURL(message));
SleightOf Hand
Registered User
Join date: 4 Apr 2006
Posts: 21
Alternate binadd() to try with PHP script.
05-23-2007 00:23
Maybe this will be faster for the Binary addition in PHP....

This seems to work very well in practice so far.

any comments?

CODE


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
}

SleightOf Hand
Registered User
Join date: 4 Apr 2006
Posts: 21
Bug Fix.
05-25-2007 09:23
Another glitch has come to light within the PHP script. This involves the decoding of the final Base64 string to get the plaintext of the message.

Thanks to Tobia Forcella for reporting this bug.

It affected charaters with Hex value patern of 0x?0 and was the last charater in the string when the string length was 2,5,8,11, ...etc. In this situation the last charater was not being decoded propery and was being dropped. This was due to the need for me to manualy add the padding charaters to the end of the string to allow PHP to decode to text. the "==" padding did not work in this case.

I have worked out a fix for this and have updated my code posts to reflect this.

in the "function xtea_decrypt_string()

CODE

$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(strlen(base64_decode($result . "==")) < strlen(base64_decode($result . "A="))) return base64_decode($result . "A=");
else return base64_decode($result . "==");
}
else if($mod == 3) return base64_decode($result . "=");
return base64_decode( $result );
SleightOf Hand
Registered User
Join date: 4 Apr 2006
Posts: 21
Another Base64 Decode fix
05-28-2007 16:28
After the discovery of the Base64 Decode bug I decided to test it more thoroughly. I discovered that the decode needed a little more tweaking as it was not handling the control charaters properly (Chars < 0x20).

This is another fix I have texted over time with Chars 0x01 > 0x7F on multiple lengh strings. This Fix has to be applied to both the PHP script and the LSL Script.

I am also updating my previous posts with this code.

PHP Script in the xtea_decrypt_string() function

CODE

$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 );


LSL Script in the xtea_decrypt_string() function

CODE

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 );
Bobbyb30 Zohari
SL Mentor Coach
Join date: 11 Nov 2006
Posts: 466
03-22-2008 07:05
Is there an optimized version that works? The one on the wiki currently has the decrypt portion broken.=(
_____________________
1 2 3 4