Simple Encryption
| LSL Portal | Functions | Events | Types | Operators | Constants | Flow Control | Script Library | Categorized Library | Tutorials |
Here's a function to pass a secret message from one object to another. Using XOR, this is perhaps the weakest form of encryption. I have taken steps to make it harder to break using random nonce values with the password. If someone is able to decrypt one message, it will be easy for them to decrypt any other message. I've also added version support so that you can upgrade the script later and still have compatibility with older scripts using the same protocol.
Encryptor
<lsl> string ProtocolSignature = "ENC"; // your own signature float ProtocolVersion = 0.3; // can range from 0.0 to 255.255 string Password = "P@ssw0rd"; // change this to your own password integer communicationsChannel = PUBLIC_CHANNEL;
string hex(integer value) {
string hex = "0123456789ABCDEF";
integer digit = value & 0xF;
string text = llGetSubString(hex, digit, digit);
value = (value >> 4) & 0x3FFFFFFF;
integer odd = 1;
while(value)
{
digit = value & 0xF;
text = llGetSubString(hex, digit, digit) + text;
odd++;
value = value >> 4;
}
if(odd % 2)
text = "0" + text;
return text;
} string encrypt(string password, string message) {
// get a random value
integer nonce = llFloor(llFrand(0x7FFFFFFF));
// generate session password
string passKey = llMD5String(password, nonce);
// generate digest
string digest = llMD5String(message, nonce);
// prepend message with digest
message = digest + message;
// encrypt message
message = llXorBase64StringsCorrect(llStringToBase64(message), llStringToBase64(passKey));
// build header
string header = ProtocolSignature;
// append major version
list versions = llParseString2List((string)ProtocolVersion, ["."], []);
header += hex(llList2Integer(versions, 0));
// append minor version
string minor;
for(minor = llList2String(versions, 1);
llGetSubString(minor, -1, -1) == "0";
minor = llGetSubString(minor, 0, -2))
;
header += hex((integer)minor);
// append nonce to header
string nonceH = hex(nonce);
while(llStringLength(nonceH) < 8)
nonceH = "0" + nonceH;
header += nonceH;
// return the header and encrypted message
return header + message;
} default {
state_entry()
{
llSay(communicationsChannel, encrypt(Password, "Hello, Avatar!"));
}
touch_start(integer total_number)
{
llSay(communicationsChannel, encrypt(Password, "Touched."));
}
} </lsl>
Decryptor
<lsl> string ProtocolSignature = "ENC"; // your own signature float ProtocolVersion = 0.3; // can range from 0.0 to 255.255 string Password = "P@ssw0rd"; // change this to your own password integer communicationsChannel = PUBLIC_CHANNEL; integer Debug = TRUE; // Set this to false for production integer listener;
init() {
if(listener != 0)
{
llListenRemove(listener);
listener = 0;
}
listener = llListen(communicationsChannel, "", NULL_KEY, "");
} string error(string message) {
if(Debug) llSay(DEBUG_CHANNEL, message); return "";
} string decrypt(string password, string message) {
integer signatureLength = llStringLength(ProtocolSignature);
integer headerLength = signatureLength + 12; // version = 4, nonce = 8
// verify length of encrypted message
if(llStringLength(message) < headerLength + 44) // digest = 32 (base64 of digest + 1 character = 44)
return error("Too small for secret message.");
// look for protocol signature in message header
if(llSubStringIndex(message, ProtocolSignature) != 0)
return error("Unknown protocol.");
// Parse version information from header
integer index = signatureLength; // determine where to start parsing
string major = "0x" + llGetSubString(message, index, ++index);
string minor = "0x" + llGetSubString(message, ++index, ++index);
float version = (float)((string)((integer)major) + "." + (string)((integer)minor));
// verify version is supported
if(version != ProtocolVersion)
return error("Unknown version.");
// parse nonce from header
integer nonce = (integer)("0x" + llGetSubString(message, ++index, index + 7));
// create passkey from password and nonce
string passKey = llStringToBase64(llMD5String(password, nonce));
// remove header from message
message = llGetSubString(message, headerLength, -1);
// decrypt message
message = llXorBase64StringsCorrect(message, passKey);
// decode message
message = llBase64ToString(message);
// get digest
string digest = llGetSubString(message, 0, 31);
// remove digest from message
message = llGetSubString(message, 32, -1);
// verify digest is valid
if(llMD5String(message, nonce) != digest)
return error("Message digest was not valid.");
// return decrypted message
return message;
} default {
state_entry()
{
init();
}
on_rez(integer start_param)
{
init();
}
listen(integer channel, string name, key id, string message)
{
string message = decrypt(Password, message);
if(message != "")
llSay(0, message);
}
} </lsl>
Note: The Hex and Efficient Hex examples were used to create the hex method.