Difference between revisions of "XTEA Strong Encryption Implementation"
Jump to navigation
Jump to search
Morse Dillon (talk | contribs) m |
|||
Line 1: | Line 1: | ||
{{LSL Header}} | {{LSL Header}} | ||
= Original = | |||
<pre> | <pre> | ||
//XTEA Strong Encryption Implementation - Linden Scripting Language (LSL) | //XTEA Strong Encryption Implementation - Linden Scripting Language (LSL) | ||
Line 424: | Line 424: | ||
} | } | ||
</pre> | |||
= Optimized = | |||
This version is untested but if it works should run faster (and be able to handle larger strings). | |||
<pre> | |||
//XTEA Strong Encryption Implementation - Linden Scripting Language (LSL) | |||
//Version 1.0a Alpha | |||
//Copyright (C) 2007 by Strife Onizuka (blindwandererATgmail.com) | |||
// | |||
//Version 1.0 | |||
//Copyright (C) 2007 by Morse Dillon (morseATmorsedillon.com) | |||
// | |||
//This program is free software; you can redistribute it and/or | |||
//modify it under the terms of the GNU General Public License | |||
//as published by the Free Software Foundation; either version 2 | |||
//of the License, or (at your option) any later version. | |||
// | |||
//This program is distributed in the hope that it will be useful, | |||
//but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
//GNU General Public License for more details. | |||
// | |||
//You should have received a copy of the GNU General Public License | |||
//along with this program; if not, write to the Free Software | |||
//Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |||
//02110-1301, USA. | |||
//======================================================================== | |||
// | |||
//Included at the end of this source listing is a small bit of example | |||
//code that shows the usage. If you wish to include this implementation | |||
//in your own work, just replace the example code with your own. Also, | |||
//please do not reuse or redistribute this work without including the | |||
//above text attributing this code to its author Morse Dillon, the above | |||
//GPL statement, and this documentation. | |||
// | |||
//This is an implentation of the XTEA (eXtended Tiny Encryption Algorithm) | |||
//block cypher. (X)TEA is a very good choice of cipher when security | |||
//is important but computational power is limited. Although I did a | |||
//lot of work on this implementation, enormous amounts of credit must | |||
//be given to the creators of the algorithm and those who came before | |||
//me to implement it in other languages and computing environments. | |||
// | |||
//***If you do decide to use this code in a project, I'd appreciate | |||
//hearing about it. You can reach me by e-mail at: | |||
//morseATmorsedillon.com | |||
// | |||
// | |||
//ABOUT TEA AND XTEA | |||
//------------------ | |||
//TEA was originally designed by David Wheeler and Roger Needham | |||
//of the Cambridge Computer Laboratory. The algorithm itself is not | |||
//subject to any patents. While the original TEA was found to have | |||
//some minor weaknesses, XTEA (implemented herein) addresses these. | |||
// | |||
//TEA and its derivatives consist of 64-bit block Feistel network | |||
//with a 128-bit key. This implementation uses six cycles, or rounds, | |||
//which is less than one would like but still provides a reasonable | |||
//level of security (16 is sufficient while 8 is enough for most | |||
//applications). Six is said to achieve theoretically good dispersion, | |||
//but should more security be desired the number of cycles can easily be | |||
//modified by changing the CYCLES global variable. Due to the low | |||
//execution speed of LSL scripts, it's suggested to make this as low as | |||
//your comfort level allows. Encryption time scales linearly with the | |||
//number of cycles. | |||
// | |||
//For more information about XTEA, see the following: | |||
// | |||
//Original Paper by Walker and Needham | |||
//http://www.ftp.cl.cam.ac.uk/ftp/papers/djw-rmn/djw-rmn-tea.html | |||
// | |||
//Wikipedia on TEA | |||
//http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm | |||
// | |||
// | |||
//ABOUT THIS IMPLEMENTATION | |||
//------------------------- | |||
//This is a barebones implementation, and is meant to be included in | |||
//the body of the script needing encryption facilities or wrapped | |||
//in a link message handler. If the latter approach is desired, care | |||
//should be taken to only send link messages to the prim containing | |||
//this implementation. If ALL_PRIMS is used as the destination, | |||
//one could link a link message listener to the object and intercept | |||
//cleartext communications. | |||
// | |||
//If you plan to place this code into the same script as that needing | |||
//encryption facilities, you need only call the following functions: | |||
// | |||
//string Encrypt(string cleartext) | |||
//string Decrypt(string cyphertext) | |||
// | |||
//Simple as that. | |||
// | |||
//This implementation does not provide any secure key exchange, so in | |||
//terms of key generation and exchange you're on your own. | |||
// | |||
//The 128-bit key is contained in four LSL integers: KEY1, KEY2, KEY3, | |||
//and KEY4. These are global variables at the beginning of the source | |||
//and can be set using a method that works for you. | |||
// | |||
// | |||
//CHANGES | |||
//------- | |||
// | |||
//1.0a - Alpha | |||
//*General optimization to run faster and use less bytecode. | |||
//*Encrypt: Pad works differently, no longer extra characters appended to the output. | |||
//*TEAEncrypt: Changed the return type | |||
//*ord: Added null support. | |||
// | |||
//1.0 | |||
//*Initial Release | |||
// | |||
// | |||
//FUTURE CHANGES | |||
//-------------- | |||
// | |||
//It would be nice if it supported UTF-8; but adding that would be alot | |||
//of work. The main issue is the decoding, the bytes would have to be | |||
//reassembled into characters. It would be time consuming. Another possibility | |||
//would be to implement XTEA to output to BASE64 instead of hex strings (also | |||
//time consuming to implement). | |||
// | |||
// | |||
//**************IF YOU READ ONE THING IN HERE, READ THIS******************* | |||
//It is VERY important to remember that there is no such thing as | |||
//'cookbook cryptography'! Simply using this cypher does not guarantee | |||
//security. Security is an end-to-end concern and responsibility lies | |||
//with you to thoroughly examine your project from all possible angles | |||
//if valuable data is at risk. If you doubt this, ask any thief how they'd | |||
//rather break into your house - futzing about with picking a high-security | |||
//deadbolt on the front door or walking in through the back door that you | |||
//left open. | |||
//******************USER-CONFIGURABLE GLOBALS BEGIN HERE******************* | |||
//ENCRYPTION KEYS KEY[1-4] | |||
//These together make up the 128-bit XTEA encryption key. See the above | |||
//documentation for details. Whatever you do, don't leave them as the default. | |||
//Don't be stupid and make it obvious like your av's key. | |||
integer KEY1 = 11111111; | |||
integer KEY2 = 22222222; | |||
integer KEY3 = 33333333; | |||
integer KEY4 = 44444444; | |||
//COMM_CHANNEL | |||
//Specifies which channel should be used for debug and test harness communication. | |||
integer COMM_CHANNEL = 0; | |||
//CYCLES | |||
//Specifies the number of rounds to be used. See the above documentation for | |||
//details. | |||
integer CYCLES = 6; | |||
//******************USER-CONFIGURABLE GLOBALS END HERE********************* | |||
//Other Globals | |||
list cypherkey = []; | |||
integer delta = 0x9E3779B9; | |||
string ASCII = " \n !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; | |||
string characters = "0123456789ABCDEF"; | |||
//Function: ord | |||
//Returns the index of an ASCII character | |||
integer ord(string chr) | |||
{ | |||
if(chr) | |||
{ | |||
if(llStringLength(chr) > 1) return -1; | |||
if(chr == " ") return 32; | |||
return llSubStringIndex(ASCII, chr); | |||
} | |||
return 0; | |||
} | |||
//Function: chr | |||
//Returns the ASCII character correspondent to index i | |||
string chr(integer i) | |||
{ | |||
if(i) | |||
return llGetSubString(ASCII, i %= 127, i); | |||
return ""; | |||
} | |||
//Function: DWord2Hex | |||
//Converts a dword contained in a LSL integer to hexadecimal format. | |||
string DWord2Hex(integer m) | |||
{ | |||
string result; | |||
integer i = 0; | |||
//Define character string [0-F] for use in building the hex. | |||
//Step through 8 times, for a total of 32 bits, 8 nibbles, and 8 hexadecimal digits. | |||
do{ | |||
integer index = (m >> i) & 0xF; | |||
result = llGetSubString(characters, index, index) + result; | |||
}while((i += 4) < 32); | |||
return result; | |||
} | |||
//Function: Encrypt | |||
//Takes cleartext string, pads and bitpacks it, then encrypts it using TEAEncrypt(). | |||
string Encrypt(string cleartext) | |||
{ | |||
string cyphertext = ""; | |||
integer i = llStringLength(cleartext); | |||
if((i += (0x7 & -i)))//Pad cleartext string to the nearest multiple of 8. | |||
{ | |||
//Step through cleartext string backwords, encrypting it in 64-bit (8 character) blocks. | |||
do{ | |||
//i=~-i is the same as --i, just a bit faster and lighter on bytecode; requires one less stack manipulation. | |||
//Pack dword1 with 4 bytes. Do so by bit-shifting in each character. | |||
//4th byte winds up in the most-significant position. | |||
integer dword2 = ( ord(llGetSubString(cleartext,i=~-i,i)) ) | | |||
( ord(llGetSubString(cleartext,i=~-i,i)) << 8 ) | | |||
( ord(llGetSubString(cleartext,i=~-i,i)) << 16) | | |||
( ord(llGetSubString(cleartext,i=~-i,i)) << 24) ; | |||
//Do it again, this time for dword1 | |||
integer dword1 = ( ord(llGetSubString(cleartext,i=~-i,i)) ) | | |||
( ord(llGetSubString(cleartext,i=~-i,i)) << 8 ) | | |||
( ord(llGetSubString(cleartext,i=~-i,i)) << 16) | | |||
( ord(llGetSubString(cleartext,i=~-i,i)) << 24) ; | |||
//Call TEAencrypt() with dword1, dword2, and the cypher key and store result in cypherblock. | |||
//Convert dword values from cypherblock to hex and append to cyphertext. | |||
cyphertext = TEAEncrypt(dword1,dword2,cypherkey) + cyphertext; | |||
}while(i); | |||
} | |||
return cyphertext; | |||
} | |||
//Function: Decrypt | |||
//Takes cyphertext, decrypts it with TEADecrypt(), and unpacks it into a string. | |||
string Decrypt(string cyphertext){ | |||
//Initialize variables. | |||
string cleartext = ""; | |||
integer i = -llStringLength(cyphertext); | |||
//Step through cyphertext string, decrypting it block by block. | |||
if((i -= (0xF & i)))//Pad cyphertext string to the nearest multiple of 16. | |||
{ | |||
do | |||
{ | |||
//Convert hexvalues to dwords contained in LSL integers. | |||
//Call TEADecrypt() with dword1, dword2, and the cypher key and store result in clearblock list. | |||
list clearblock = TEADecrypt((integer)("0x"+llGetSubString(cyphertext,i, ~-(i -= 8))), | |||
(integer)("0x"+llGetSubString(cyphertext,i, ~-(i -= 8))), cypherkey); | |||
//Append first 4 characters of ASCII to cleartext string. | |||
//This is done by pulling the decrypted dwords from the clearblock list and looking up their ASCII values. | |||
integer t = llList2Integer(clearblock,1); | |||
cleartext += chr( (t ) & 0xFF) + | |||
chr( (t >> 8 ) & 0xFF) + | |||
chr( (t >> 16) & 0xFF) + | |||
chr( (t = llList2Integer(clearblock,0) >> 24) & 0xFF) + | |||
chr( (t ) & 0xFF) + | |||
chr( (t >> 8 ) & 0xFF) + | |||
chr( (t >> 16) & 0xFF) + | |||
chr( (t >> 24) & 0xFF) ; | |||
}while(i); | |||
} | |||
return cleartext; | |||
} | |||
//Function: TEADecrypt | |||
//This is the implementation of XTEA proper. It takes a block of cleartext | |||
//consisting of two dwords contained in LSL integers and a 128-bit key | |||
//contained in an LSL list of 4 integers. The function then returns | |||
//the cyphertext in an LSL list of two integers. | |||
string TEAEncrypt(integer dword1, integer dword2, list cypherkey_) | |||
{ | |||
if(CYCLES > 0)//$[E20011] /*lslint ignore*/ | |||
{ | |||
//Set n to the number of cycles given in the CYCLES global variable | |||
integer n = CYCLES; | |||
integer sum = 0; | |||
//Operate for the specified number of cycles. | |||
do{ | |||
dword1 = dword1 + ( ( dword2 << 4 ^ dword2 >> 5 ) + dword2 ^ sum + llList2Integer(cypherkey_, (sum & 3) ) ); | |||
dword2 = dword2 + ( ( dword1 << 4 ^ dword1 >> 5 ) + dword1 ^ sum + llList2Integer(cypherkey_, ((sum += delta) >> 11 & 3) ) ); | |||
}while (n = ~-n); | |||
} | |||
return DWord2Hex(dword1) + DWord2Hex(dword2); | |||
} | |||
//Function: TEADecrypt | |||
//This is the implementation of XTEA proper. It takes a block of cyphertext | |||
//consisting of two dwords contained in LSL integers and a 128-bit key | |||
//contained in an LSL list of 4 integers. The function then returns | |||
//the cleartext in an LSL list of two integers. | |||
list TEADecrypt(integer dword1, integer dword2,list cypherkey_) | |||
{ | |||
if(CYCLES > 0)//$[E20011] /*lslint ignore*/ | |||
{ | |||
//Set n to the number of cycles given in the CYCLES global variable | |||
integer n = CYCLES; | |||
integer sum = delta * CYCLES; | |||
//Operate for the specified number of cycles. | |||
do{ | |||
dword2 = dword2 - ( ( dword1 << 4 ^ dword1 >> 5 ) + dword1 ^ sum + llList2Integer(cypherkey_, (sum >> 11 & 3) ) ); | |||
dword1 = dword1 - ( ( dword2 << 4 ^ dword2 >> 5 ) + dword2 ^ sum + llList2Integer(cypherkey_, ((sum -= delta) & 3) ) ); | |||
}while (n = ~-n); | |||
} | |||
return [dword1,dword2]; | |||
} | |||
//XTEA Usage Example | |||
//Listens on COMM_CHANNEL for a message and encrypts it, then turns around and decrypts the resultant cyphertext. | |||
//Object than says the encrypted and decrypted messages to the owner. | |||
default | |||
{ | |||
state_entry() | |||
{ | |||
llListen(COMM_CHANNEL, "", NULL_KEY, ""); | |||
cypherkey = [KEY1,KEY2,KEY3,KEY4]; | |||
} | |||
listen(integer channel, string name, key id, string message) | |||
{ | |||
string temp_cyphertext = Encrypt(message); | |||
string temp_cleartext = Decrypt(temp_cyphertext); | |||
llOwnerSay("\nOriginal Cleartext: " + message + "\nCyphertext: " + temp_cyphertext + "\nDecrypted Cleartext: " + temp_cleartext); | |||
} | |||
} | |||
</pre> | </pre> | ||
{{#vardefine:sort|XTEA Strong Encryption Implementation}}{{LSLC|Library}}{{LSLC|Examples}} | {{#vardefine:sort|XTEA Strong Encryption Implementation}}{{LSLC|Library}}{{LSLC|Examples}} |
Revision as of 21:08, 14 March 2007
LSL Portal | Functions | Events | Types | Operators | Constants | Flow Control | Script Library | Categorized Library | Tutorials |
Original
//XTEA Strong Encryption Implementation - Linden Scripting Language (LSL) //Version 1.0 //Copyright (C) 2007 by Morse Dillon (morseATmorsedillon.com) // //This program is free software; you can redistribute it and/or //modify it under the terms of the GNU General Public License //as published by the Free Software Foundation; either version 2 //of the License, or (at your option) any later version. // //This program is distributed in the hope that it will be useful, //but WITHOUT ANY WARRANTY; without even the implied warranty of //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //GNU General Public License for more details. // //You should have received a copy of the GNU General Public License //along with this program; if not, write to the Free Software //Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA //02110-1301, USA. //======================================================================== // //Included at the end of this source listing is a small bit of example //code that shows the usage. If you wish to include this implementation //in your own work, just replace the example code with your own. Also, //please do not reuse or redistribute this work without including the //above text attributing this code to its author Morse Dillon, the above //GPL statement, and this documentation. // //This is an implentation of the XTEA (eXtended Tiny Encryption Algorithm) //block cypher. (X)TEA is a very good choice of cipher when security //is important but computational power is limited. Although I did a //lot of work on this implementation, enormous amounts of credit must //be given to the creators of the algorithm and those who came before //me to implement it in other languages and computing environments. // //***If you do decide to use this code in a project, I'd appreciate //hearing about it. You can reach me by e-mail at: //morseATmorsedillon.com // // //ABOUT TEA AND XTEA //------------------ //TEA was originally designed by David Wheeler and Roger Needham //of the Cambridge Computer Laboratory. The algorithm itself is not //subject to any patents. While the original TEA was found to have //some minor weaknesses, XTEA (implemented herein) addresses these. // //TEA and its derivatives consist of 64-bit block Feistel network //with a 128-bit key. This implementation uses six cycles, or rounds, //which is less than one would like but still provides a reasonable //level of security (16 is sufficient while 8 is enough for most //applications). Six is said to achieve theoretically good dispersion, //but should more security be desired the number of cycles can easily be //modified by changing the CYCLES global variable. Due to the low //execution speed of LSL scripts, it's suggested to make this as low as //your comfort level allows. Encryption time scales linearly with the //number of cycles. // //For more information about XTEA, see the following: // //Original Paper by Walker and Needham //http://www.ftp.cl.cam.ac.uk/ftp/papers/djw-rmn/djw-rmn-tea.html // //Wikipedia on TEA //http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm // // //ABOUT THIS IMPLEMENTATION //------------------------- //This is a barebones implementation, and is meant to be included in //the body of the script needing encryption facilities or wrapped //in a link message handler. If the latter approach is desired, care //should be taken to only send link messages to the prim containing //this implementation. If ALL_PRIMS is used as the destination, //one could link a link message listener to the object and intercept //cleartext communications. // //If you plan to place this code into the same script as that needing //encryption facilities, you need only call the following functions: // //string Encrypt(string cleartext) //string Decrypt(string cyphertext) // //Simple as that. // //This implementation does not provide any secure key exchange, so in //terms of key generation and exchange you're on your own. // //The 128-bit key is contained in four LSL integers: KEY1, KEY2, KEY3, //and KEY4. These are global variables at the beginning of the source //and can be set using a method that works for you. // // //**************IF YOU READ ONE THING IN HERE, READ THIS******************* //It is VERY important to remember that there is no such thing as //'cookbook cryptography'! Simply using this cypher does not guarantee //security. Security is an end-to-end concern and responsibility lies //with you to thoroughly examine your project from all possible angles //if valuable data is at risk. If you doubt this, ask any thief how they'd //rather break into your house - futzing about with picking a high-security //deadbolt on the front door or walking in through the back door that you //left open. //******************USER-CONFIGURABLE GLOBALS BEGIN HERE******************* //ENCRYPTION KEYS KEY[1-4] //These together make up the 128-bit XTEA encryption key. See the above //documentation for details. Whatever you do, don't leave them as the default. integer KEY1 = 11111111; integer KEY2 = 22222222; integer KEY3 = 33333333; integer KEY4 = 44444444; //DEBUG_FLAG //If set to 1, will cause debug text to be printed containing some //intermediate cleartext/cyphertext and the resultant cyphertext/cleartext. //Do not leave this enabled in production environments!!!! integer DEBUG_FLAG = 0; //COMM_CHANNEL //Specifies which channel should be used for debug and test harness communication. integer COMM_CHANNEL = 0; //CYCLES //Specifies the number of rounds to be used. See the above documentation for //details. integer CYCLES = 6; //******************USER-CONFIGURABLE GLOBALS END HERE********************* //Other Globals list cypherkey = []; integer delta = 0x9E3779B9; //Function: ord //Returns the index of an ASCII character integer ord(string chr) { string ASCII = " \n !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; if(llStringLength(chr) != 1) return -1; if(chr == " ") return 32; return llSubStringIndex(ASCII, chr); } //Function: chr //Returns the ASCII character correspondent to index i string chr(integer i) { string ASCII = " \n !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; i %= 127; return llGetSubString(ASCII, i, i); } //Function: DWord2Hex //Converts a dword containted in a LSL integer to hexadecimal format. string DWord2Hex(integer m){ string result; integer i = 0; integer index = 0; //Define character string [0-F] for use in building the hex. string characters = "0123456789ABCDEF"; //Step through 8 times, for a total of 32 bits, 8 nibbles, and 8 hexadecimal digits. for (i = 0; i < 8; i++){ //Get a nibble by right-shifting and masking off 4 bits. index = (m >> (i * 4)) & 0xF; //Grab character from the characters string at index position and add it to the result string. result = llInsertString(result, 0, llGetSubString(characters,index,index)); } return result; } //Function: Hex2DWword //Converts a string containing a hexadecimal number to a dword contained in a LSL integer. integer Hex2DWord(string m){ integer result = 0; integer i = 0; string digit; integer value; integer index; string characters = "0123456789ABCDEF"; for (i = 0; i < 8; i++){ index = 8 - (i + 1); digit = llGetSubString(m,index,index); value = llSubStringIndex(characters, digit); result = result | value << (i * 4); } return result; } //Function: Encrypt //Takes cleartext string, pads and bitpacks it, then encrypts it using TEAEncrypt(). string Encrypt(string cleartext){ //Initialize variables. integer dword1 = 0; integer dword2 = 0; integer cyphertext_numeric; list cypherblock; string cyphertext = ""; //Pad cleartext string to the nearest multiple of 8. while(llStringLength(cleartext) & 0x7) { cleartext += " "; } //Define more variables pertaining to while loop. integer stringlength = llStringLength(cleartext); integer i=0; integer character; //Step through cleartext string, encrypting it in 64-bit (8 character) blocks. while (i < stringlength){ //Pack dword1 with 4 bytes. Do so by bit-shifting in each character. //4th byte winds up in the most-significant position. dword1 = ord(llGetSubString(cleartext,i,i)); i++; dword1 = dword1 | (ord(llGetSubString(cleartext,i,i)) << 8); i++; dword1 = dword1 | (ord(llGetSubString(cleartext,i,i)) << 16); i++; dword1 = dword1 | (ord(llGetSubString(cleartext,i,i)) << 24); i++; //Do it again, this time for dword2 dword2 = ord(llGetSubString(cleartext,i,i)); i++; dword2 = dword2 | ord(llGetSubString(cleartext,i,i)) << 8; i++; dword2 = dword2 | ord(llGetSubString(cleartext,i,i)) << 16; i++; dword2 = dword2 | ord(llGetSubString(cleartext,i,i)) << 24; i++; //Call TEAencrypt() with dword1, dword2, and the cypher key and store result in cypherblock. cypherblock = TEAEncrypt(dword1,dword2,cypherkey); //Convert dword values from cypherblock to hex and append to cyphertext. cyphertext = cyphertext + DWord2Hex(llList2Integer(cypherblock,0)) + DWord2Hex(llList2Integer(cypherblock,1)); //Reset variables for the next round, just to be safe. dword1 = 0; dword2 = 0; cypherblock = []; if(DEBUG_FLAG){ llOwnerSay("Pre-Crypt DWords: " + (string)dword1 + "," + (string)dword2); llOwnerSay("Post-Crypt DWords: " + (string)llList2Integer(cypherblock,1) + "," + (string)llList2Integer(cypherblock,2)); llOwnerSay("Post-Crypt Hex: " + DWord2Hex(llList2Integer(cypherblock,1)) + "," + DWord2Hex(llList2Integer(cypherblock,2))); } } return cyphertext; } //Function: Decrypt //Takes cyphertext, decrypts it with TEADecrypt(), and unpacks it into a string. string Decrypt(string cyphertext){ //Initialize variables. string hexvalue1 = ""; string hexvalue2 = ""; integer dword1 = 0; integer dword2 = 0; list clearblock = []; //res string cleartext = ""; integer i; //Step through cyphertext string, descrypting it block by block. while (i < llStringLength(cyphertext)){ //Pull first 32 bits worth of hexadecimal into hexvalue1 hexvalue1 += llGetSubString(cyphertext,i,i + 7); i = i + 8; //Pull second 32 bits worth of hexadecimal into hexvalue2 hexvalue2 += llGetSubString(cyphertext,i,i + 7); i = i + 8; //Convert hexvalues to dwords contained in LSL integers. dword1 = Hex2DWord(hexvalue1); dword2 = Hex2DWord(hexvalue2); //Call TEADecrypt() with dword1, dword2, and the cypher key and store result in clearblock list. clearblock = TEADecrypt(dword1, dword2, cypherkey); //Append first 4 characters of ASCII to cleartext string. //This is done by pulling the decrypted dwords from the clearblock list and looking up their ASCII values. cleartext += chr( llList2Integer(clearblock,0) & 0x000000FF); cleartext += chr( (llList2Integer(clearblock,0) & 0x0000FF00) >> 8); cleartext += chr( (llList2Integer(clearblock,0) & 0x00FF0000) >> 16); cleartext += chr( (llList2Integer(clearblock,0) & 0xFF000000) >> 24); //Append second 4 characters of ASCII to cleartext string. cleartext += chr( llList2Integer(clearblock,1) & 0x000000FF); cleartext += chr( (llList2Integer(clearblock,1) & 0x0000FF00) >> 8); cleartext += chr( (llList2Integer(clearblock,1) & 0x00FF0000) >> 16); cleartext += chr( (llList2Integer(clearblock,1) & 0xFF000000) >> 24); //Reset variables for the next two blocks of decrypt. hexvalue1 = ""; hexvalue2 = ""; dword1 = 0; dword2 = 0; clearblock = []; if(DEBUG_FLAG){ llOwnerSay("Pre-Decrypt Hex: " + hexvalue1 + "," + hexvalue2); llOwnerSay("Pre-Decrypt DWords: " + (string)dword1 + "," + (string)dword2); llOwnerSay("Post-Decrypt DWords: " + (string)llList2Integer(clearblock,1) + "," + (string)llList2Integer(clearblock,2)); } } return cleartext; } //Function: TEADecrypt //This is the implementation of XTEA proper. It takes a block of cleartext //consisting of two dwords contained in LSL integers and a 128-bit key //contained in an LSL list of 4 integers. The function then returns //the cyphertext in an LSL list of two integers. list TEAEncrypt(integer dword1, integer dword2,list cypherkey){ list cryptlist = []; //Set n to the number of cycles given in the CYCLES global variable integer n = CYCLES; integer sum = 0; //Operate for the specified number of cycles. while (n-- > 0){ dword1 = dword1 + ( ( dword2 << 4 ^ dword2 >> 5 ) + dword2 ^ sum + llList2Integer(cypherkey, (sum & 3) ) ); sum += delta; dword2 = dword2 + ( ( dword1 << 4 ^ dword1 >> 5 ) + dword1 ^ sum + llList2Integer(cypherkey, (sum >> 11 & 3) ) ); } cryptlist = [dword1,dword2]; return cryptlist; } //Function: TEADecrypt //This is the implementation of XTEA proper. It takes a block of cyphertext //consisting of two dwords contained in LSL integers and a 128-bit key //contained in an LSL list of 4 integers. The function then returns //the cleartext in an LSL list of two integers. list TEADecrypt(integer dword1, integer dword2,list cypherkey){ list cryptlist = []; //Set n to the number of cycles given in the CYCLES global variable integer n = CYCLES; integer sum = delta * CYCLES; //Operate for the specified number of cycles. while (n-- > 0){ dword2 = dword2 - ( ( dword1 << 4 ^ dword1 >> 5 ) + dword1 ^ sum + llList2Integer(cypherkey, (sum >> 11 & 3) ) ); sum -= delta; dword1 = dword1 - ( ( dword2 << 4 ^ dword2 >> 5 ) + dword2 ^ sum + llList2Integer(cypherkey, (sum & 3) ) ); } cryptlist = [dword1,dword2]; return cryptlist; } //XTEA Usage Example //Listens on COMM_CHANNEL for a message and encrypts it, then turns around and decrypts the resultant cyphertext. //Object than says the encrypted and decrypted messages to the owner. default { state_entry() { llListen(COMM_CHANNEL, "", NULL_KEY, ""); cypherkey = [KEY1,KEY2,KEY3,KEY4]; } listen(integer channel, string name, key id, string message) { string temp_cyphertext = Encrypt(message); string temp_cleartext = Decrypt(temp_cyphertext); llOwnerSay("\nOriginal Cleartext: " + message + "\nCyphertext: " + temp_cyphertext + "\nDecrypted Cleartext: " + temp_cleartext); } }
Optimized
This version is untested but if it works should run faster (and be able to handle larger strings).
//XTEA Strong Encryption Implementation - Linden Scripting Language (LSL) //Version 1.0a Alpha //Copyright (C) 2007 by Strife Onizuka (blindwandererATgmail.com) // //Version 1.0 //Copyright (C) 2007 by Morse Dillon (morseATmorsedillon.com) // //This program is free software; you can redistribute it and/or //modify it under the terms of the GNU General Public License //as published by the Free Software Foundation; either version 2 //of the License, or (at your option) any later version. // //This program is distributed in the hope that it will be useful, //but WITHOUT ANY WARRANTY; without even the implied warranty of //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //GNU General Public License for more details. // //You should have received a copy of the GNU General Public License //along with this program; if not, write to the Free Software //Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA //02110-1301, USA. //======================================================================== // //Included at the end of this source listing is a small bit of example //code that shows the usage. If you wish to include this implementation //in your own work, just replace the example code with your own. Also, //please do not reuse or redistribute this work without including the //above text attributing this code to its author Morse Dillon, the above //GPL statement, and this documentation. // //This is an implentation of the XTEA (eXtended Tiny Encryption Algorithm) //block cypher. (X)TEA is a very good choice of cipher when security //is important but computational power is limited. Although I did a //lot of work on this implementation, enormous amounts of credit must //be given to the creators of the algorithm and those who came before //me to implement it in other languages and computing environments. // //***If you do decide to use this code in a project, I'd appreciate //hearing about it. You can reach me by e-mail at: //morseATmorsedillon.com // // //ABOUT TEA AND XTEA //------------------ //TEA was originally designed by David Wheeler and Roger Needham //of the Cambridge Computer Laboratory. The algorithm itself is not //subject to any patents. While the original TEA was found to have //some minor weaknesses, XTEA (implemented herein) addresses these. // //TEA and its derivatives consist of 64-bit block Feistel network //with a 128-bit key. This implementation uses six cycles, or rounds, //which is less than one would like but still provides a reasonable //level of security (16 is sufficient while 8 is enough for most //applications). Six is said to achieve theoretically good dispersion, //but should more security be desired the number of cycles can easily be //modified by changing the CYCLES global variable. Due to the low //execution speed of LSL scripts, it's suggested to make this as low as //your comfort level allows. Encryption time scales linearly with the //number of cycles. // //For more information about XTEA, see the following: // //Original Paper by Walker and Needham //http://www.ftp.cl.cam.ac.uk/ftp/papers/djw-rmn/djw-rmn-tea.html // //Wikipedia on TEA //http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm // // //ABOUT THIS IMPLEMENTATION //------------------------- //This is a barebones implementation, and is meant to be included in //the body of the script needing encryption facilities or wrapped //in a link message handler. If the latter approach is desired, care //should be taken to only send link messages to the prim containing //this implementation. If ALL_PRIMS is used as the destination, //one could link a link message listener to the object and intercept //cleartext communications. // //If you plan to place this code into the same script as that needing //encryption facilities, you need only call the following functions: // //string Encrypt(string cleartext) //string Decrypt(string cyphertext) // //Simple as that. // //This implementation does not provide any secure key exchange, so in //terms of key generation and exchange you're on your own. // //The 128-bit key is contained in four LSL integers: KEY1, KEY2, KEY3, //and KEY4. These are global variables at the beginning of the source //and can be set using a method that works for you. // // //CHANGES //------- // //1.0a - Alpha //*General optimization to run faster and use less bytecode. //*Encrypt: Pad works differently, no longer extra characters appended to the output. //*TEAEncrypt: Changed the return type //*ord: Added null support. // //1.0 //*Initial Release // // //FUTURE CHANGES //-------------- // //It would be nice if it supported UTF-8; but adding that would be alot //of work. The main issue is the decoding, the bytes would have to be //reassembled into characters. It would be time consuming. Another possibility //would be to implement XTEA to output to BASE64 instead of hex strings (also //time consuming to implement). // // //**************IF YOU READ ONE THING IN HERE, READ THIS******************* //It is VERY important to remember that there is no such thing as //'cookbook cryptography'! Simply using this cypher does not guarantee //security. Security is an end-to-end concern and responsibility lies //with you to thoroughly examine your project from all possible angles //if valuable data is at risk. If you doubt this, ask any thief how they'd //rather break into your house - futzing about with picking a high-security //deadbolt on the front door or walking in through the back door that you //left open. //******************USER-CONFIGURABLE GLOBALS BEGIN HERE******************* //ENCRYPTION KEYS KEY[1-4] //These together make up the 128-bit XTEA encryption key. See the above //documentation for details. Whatever you do, don't leave them as the default. //Don't be stupid and make it obvious like your av's key. integer KEY1 = 11111111; integer KEY2 = 22222222; integer KEY3 = 33333333; integer KEY4 = 44444444; //COMM_CHANNEL //Specifies which channel should be used for debug and test harness communication. integer COMM_CHANNEL = 0; //CYCLES //Specifies the number of rounds to be used. See the above documentation for //details. integer CYCLES = 6; //******************USER-CONFIGURABLE GLOBALS END HERE********************* //Other Globals list cypherkey = []; integer delta = 0x9E3779B9; string ASCII = " \n !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; string characters = "0123456789ABCDEF"; //Function: ord //Returns the index of an ASCII character integer ord(string chr) { if(chr) { if(llStringLength(chr) > 1) return -1; if(chr == " ") return 32; return llSubStringIndex(ASCII, chr); } return 0; } //Function: chr //Returns the ASCII character correspondent to index i string chr(integer i) { if(i) return llGetSubString(ASCII, i %= 127, i); return ""; } //Function: DWord2Hex //Converts a dword contained in a LSL integer to hexadecimal format. string DWord2Hex(integer m) { string result; integer i = 0; //Define character string [0-F] for use in building the hex. //Step through 8 times, for a total of 32 bits, 8 nibbles, and 8 hexadecimal digits. do{ integer index = (m >> i) & 0xF; result = llGetSubString(characters, index, index) + result; }while((i += 4) < 32); return result; } //Function: Encrypt //Takes cleartext string, pads and bitpacks it, then encrypts it using TEAEncrypt(). string Encrypt(string cleartext) { string cyphertext = ""; integer i = llStringLength(cleartext); if((i += (0x7 & -i)))//Pad cleartext string to the nearest multiple of 8. { //Step through cleartext string backwords, encrypting it in 64-bit (8 character) blocks. do{ //i=~-i is the same as --i, just a bit faster and lighter on bytecode; requires one less stack manipulation. //Pack dword1 with 4 bytes. Do so by bit-shifting in each character. //4th byte winds up in the most-significant position. integer dword2 = ( ord(llGetSubString(cleartext,i=~-i,i)) ) | ( ord(llGetSubString(cleartext,i=~-i,i)) << 8 ) | ( ord(llGetSubString(cleartext,i=~-i,i)) << 16) | ( ord(llGetSubString(cleartext,i=~-i,i)) << 24) ; //Do it again, this time for dword1 integer dword1 = ( ord(llGetSubString(cleartext,i=~-i,i)) ) | ( ord(llGetSubString(cleartext,i=~-i,i)) << 8 ) | ( ord(llGetSubString(cleartext,i=~-i,i)) << 16) | ( ord(llGetSubString(cleartext,i=~-i,i)) << 24) ; //Call TEAencrypt() with dword1, dword2, and the cypher key and store result in cypherblock. //Convert dword values from cypherblock to hex and append to cyphertext. cyphertext = TEAEncrypt(dword1,dword2,cypherkey) + cyphertext; }while(i); } return cyphertext; } //Function: Decrypt //Takes cyphertext, decrypts it with TEADecrypt(), and unpacks it into a string. string Decrypt(string cyphertext){ //Initialize variables. string cleartext = ""; integer i = -llStringLength(cyphertext); //Step through cyphertext string, decrypting it block by block. if((i -= (0xF & i)))//Pad cyphertext string to the nearest multiple of 16. { do { //Convert hexvalues to dwords contained in LSL integers. //Call TEADecrypt() with dword1, dword2, and the cypher key and store result in clearblock list. list clearblock = TEADecrypt((integer)("0x"+llGetSubString(cyphertext,i, ~-(i -= 8))), (integer)("0x"+llGetSubString(cyphertext,i, ~-(i -= 8))), cypherkey); //Append first 4 characters of ASCII to cleartext string. //This is done by pulling the decrypted dwords from the clearblock list and looking up their ASCII values. integer t = llList2Integer(clearblock,1); cleartext += chr( (t ) & 0xFF) + chr( (t >> 8 ) & 0xFF) + chr( (t >> 16) & 0xFF) + chr( (t = llList2Integer(clearblock,0) >> 24) & 0xFF) + chr( (t ) & 0xFF) + chr( (t >> 8 ) & 0xFF) + chr( (t >> 16) & 0xFF) + chr( (t >> 24) & 0xFF) ; }while(i); } return cleartext; } //Function: TEADecrypt //This is the implementation of XTEA proper. It takes a block of cleartext //consisting of two dwords contained in LSL integers and a 128-bit key //contained in an LSL list of 4 integers. The function then returns //the cyphertext in an LSL list of two integers. string TEAEncrypt(integer dword1, integer dword2, list cypherkey_) { if(CYCLES > 0)//$[E20011] /*lslint ignore*/ { //Set n to the number of cycles given in the CYCLES global variable integer n = CYCLES; integer sum = 0; //Operate for the specified number of cycles. do{ dword1 = dword1 + ( ( dword2 << 4 ^ dword2 >> 5 ) + dword2 ^ sum + llList2Integer(cypherkey_, (sum & 3) ) ); dword2 = dword2 + ( ( dword1 << 4 ^ dword1 >> 5 ) + dword1 ^ sum + llList2Integer(cypherkey_, ((sum += delta) >> 11 & 3) ) ); }while (n = ~-n); } return DWord2Hex(dword1) + DWord2Hex(dword2); } //Function: TEADecrypt //This is the implementation of XTEA proper. It takes a block of cyphertext //consisting of two dwords contained in LSL integers and a 128-bit key //contained in an LSL list of 4 integers. The function then returns //the cleartext in an LSL list of two integers. list TEADecrypt(integer dword1, integer dword2,list cypherkey_) { if(CYCLES > 0)//$[E20011] /*lslint ignore*/ { //Set n to the number of cycles given in the CYCLES global variable integer n = CYCLES; integer sum = delta * CYCLES; //Operate for the specified number of cycles. do{ dword2 = dword2 - ( ( dword1 << 4 ^ dword1 >> 5 ) + dword1 ^ sum + llList2Integer(cypherkey_, (sum >> 11 & 3) ) ); dword1 = dword1 - ( ( dword2 << 4 ^ dword2 >> 5 ) + dword2 ^ sum + llList2Integer(cypherkey_, ((sum -= delta) & 3) ) ); }while (n = ~-n); } return [dword1,dword2]; } //XTEA Usage Example //Listens on COMM_CHANNEL for a message and encrypts it, then turns around and decrypts the resultant cyphertext. //Object than says the encrypted and decrypted messages to the owner. default { state_entry() { llListen(COMM_CHANNEL, "", NULL_KEY, ""); cypherkey = [KEY1,KEY2,KEY3,KEY4]; } listen(integer channel, string name, key id, string message) { string temp_cyphertext = Encrypt(message); string temp_cleartext = Decrypt(temp_cyphertext); llOwnerSay("\nOriginal Cleartext: " + message + "\nCyphertext: " + temp_cyphertext + "\nDecrypted Cleartext: " + temp_cleartext); } }