Jump to content

XTEA symmetric-key encryption algorithm


Quistess Alpha
 Share

You are about to reply to a thread that has been inactive for 525 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

This might be a bit niche, but I thought I'd post it anyway.

Most modern encryption algorithms are a bit too big and cumbersome to implement in LSL, and often use large tables of numbers which would be infeasible to store in an efficiently busy script. so I was quite happy to eventually stumble upon a cipher that was simple enouhg to implement in LSL and doesn't use a lookup table.

For my use-case (Identifying users of an XHTML enabled menu) I just need to encrypt and decrypt key values, so I modified the algorithm slightly, and LSL 'arithmetic shifts' also make the implementation different from the standard, but surprisingly it still works, so I thought I'd pass it along for anyone who might find it interesting or useful.

list gPrivateKey; // set in state_entry()

// based on wikipedia specification of XTEA
// https://en.wikipedia.org/wiki/XTEA
key encipher(integer n_rounds, key data)
{   integer v0 = (integer)("0x"+llGetSubString(data,0,7));
    integer v1 = (integer)("0x"+llGetSubString(data, 9,12)+llGetSubString(data,14,17));
    integer v2 = (integer)("0x"+llGetSubString(data,19,22)+llGetSubString(data,24,27));
    integer v3 = (integer)("0x"+llGetSubString(data,28,35));
    integer sum;
    integer delta = 0x9E3779B9;
    do{
        integer X0 = (sum + llList2Integer(gPrivateKey,(sum & 3)));
        v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ X0;
        v2 += (((v3 << 4) ^ (v3 >> 5)) + v3) ^ X0;
        sum += delta;
        integer X1 = (sum + llList2Integer(gPrivateKey,((sum>>11) & 3)));
        v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ X1;
        v3 += (((v2 << 4) ^ (v2 >> 5)) + v2) ^ X1;
    }while(--n_rounds);
    // convert to key format.
    string ret = int2hex(v0);
    string r = int2hex(v1);
    ret+="-"+llGetSubString(r,0,3)+"-"+llGetSubString(r,4,7);
    r = int2hex(v2);
    ret+="-"+llGetSubString(r,0,3)+"-"+llGetSubString(r,4,7)+int2hex(v3);
    return ret; // automatic string to key conversion.
}
key decipher(integer n_rounds, key data)
{   integer v0 = (integer)("0x"+llGetSubString(data,0,7));
    integer v1 = (integer)("0x"+llGetSubString(data, 9,12)+llGetSubString(data,14,17));
    integer v2 = (integer)("0x"+llGetSubString(data,19,22)+llGetSubString(data,24,27));
    integer v3 = (integer)("0x"+llGetSubString(data,28,35));
    integer delta = 0x9E3779B9;
    integer sum = delta*n_rounds;
    do{
        integer X1 = (sum + llList2Integer(gPrivateKey,((sum>>11) & 3)));
        v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ X1;
        v3 -= (((v2 << 4) ^ (v2 >> 5)) + v2) ^ X1;
        sum -= delta;
        integer X0 = (sum + llList2Integer(gPrivateKey,(sum & 3)));
        v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ X0;
        v2 -= (((v3 << 4) ^ (v3 >> 5)) + v3) ^ X0;
    }while(--n_rounds);
    // convert to key format.
    string ret = int2hex(v0);
    string r = int2hex(v1);
    ret+="-"+llGetSubString(r,0,3)+"-"+llGetSubString(r,4,7);
    r = int2hex(v2);
    ret+="-"+llGetSubString(r,0,3)+"-"+llGetSubString(r,4,7)+int2hex(v3);
    return ret; // automatic string to key conversion.
}
string int2hex(integer i)
{   // lowercase. replace all 39's with 7's for UPPERCASE.
    string ret;
    integer w;
    w = (i&0x70000000)>>28;
    w+= 8*(i<0); // correct for LSL 'arithmetic shift'.
    ret += llChar(0x30+w+39*(w>=10));
    w = (i&0x0F000000)>>24;
    ret += llChar(0x30+w+39*(w>=10));
    w = (i&0x00F00000)>>20;
    ret += llChar(0x30+w+39*(w>=10));
    w = (i&0x000F0000)>>16;
    ret += llChar(0x30+w+39*(w>=10));
    w = (i&0x0000F000)>>12;
    ret += llChar(0x30+w+39*(w>=10));
    w = (i&0x00000F00)>>8;
    ret += llChar(0x30+w+39*(w>=10));
    w = (i&0x000000F0)>>4;
    ret += llChar(0x30+w+39*(w>=10));
    w = (i&0x0000000F);
    ret += llChar(0x30+w+39*(w>=10));
    return ret;
}

default
{
    state_entry()
    {   key k = llGenerateKey(); // a random key. DO NOT USE THE KEY OF THE ROOT PRIM!
        gPrivateKey =
        [   (integer)("0x"+llGetSubString(k,0,7)),
            (integer)("0x"+llGetSubString(k, 9,12)+llGetSubString(k,14,17)),
            (integer)("0x"+llGetSubString(k,19,22)+llGetSubString(k,24,27)),
            (integer)("0x"+llGetSubString(k,28,35))
        ];
    }

    touch_start(integer total_number)
    {
        //llOwnerSay(int2hex(0x123ABC2A));
        key data = llGenerateKey();
        llOwnerSay((string)data);
        key crypt = encipher(32,data);
        llOwnerSay((string)crypt);
        llOwnerSay(decipher(32,crypt));
    }
}

 

If you're curious how that's related to menus, the basic idea is to send users their encrypted key when they open the menu, so they can send it back whenever they access a menu item. Then if we need to know their key, (say, to give them an inventory offer) we just decrypt the key they send back. Because the 'private key' is secret, nobody can impersonate someone else to the menu, unless that someone else had shared the encrypted key they were given. I might share that menu script some time when I get a chance to work this in and really polish it off (linkset data is another game-changer that will probably need to be factored in. . .).

  • Like 1
Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 525 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...