This function has been deprecated
in favour of llXorBase64StringsCorrect
string llXorBase64Strings(string s1, string s2)
Performs an xor
on two Base64
strings and returns a Base64 string. s2
repeats if it is shorter than s1
This function is for encrypting data. Put your data in s1
and your key in s2
to encrypt or put the encrypted data into s1
with the same key in s2
to decrypt again.
for converting to and from Base64 respectively.
While fine for most SL encryption purposes, Xor'ing a string with a password is considered a very weak encryption algorithm. Do not use this for anything that will cost you RL $ if compromised (such as an automated RL - SL currency exchanger). Also, consider carefully how much damage a malicious party might be able to wreak if your encryption is hacked.
This type of encryption is similar to something called a one time pad
that is if s2
is the same length as s1
, is generated randomly (not pseudo randomly), and s2
is used only once. When used in this way this function is provably unbreakable. However implementing this function in this way is difficult to say the least. However with a little ingenuity and some creative problem solving we might be able to create different variations of this with acceptable reductions in security with minimal resource requirements(execution time, memory). IE have a new key created for each message maybe based on some universally changing constant like the server timestamp.
And as it turns out the quickest way to weaken xor type encryption is to use the key more than once, either by repeating a small key across a longer message or to use the same key on more than one message. It is only strong if the key is used only once. So this type of encryption when used with the same key over and over is supposedly rather trivial to break.
Note: this example code always produces the same result as llXorBase64StringsCorrect
, but only the same result as llXorBase64Strings
when s2 is longer than s1 (unless s2 is a multiple of 3 bytes in length -see discussion at end of page).
string data = "I like bananas."; // the data we want to encrypt
string pass = "monkey"; // the encryption key
string crypt; // for storing the encrypted data
// convert both data and key to base64 and encrypt the data with the key
// then store the encrypted data in 'crypt'
crypt = llXorBase64Strings(llStringToBase64(data), llStringToBase64(pass));
llSay(0, crypt); // this could now be used to email the data around
// someone without the correct key wouldn't be able to (easily) get the plaintext
// decrypt it again, using the same key, and convert back to plaintext
llSay(0, llBase64ToString(llXorBase64Strings(crypt, llStringToBase64(pass))));
// as you can see, applying the same key to encrypted data again decrypts it
| Tip: If you see an "=" character in the middle of your encrypted string, you probably forgot to first convert your data to Base64. |
If you want to exchange data that passed through this function from outside of LSL, the following Python snippet might be helpful to you:
from base64 import b64encode, b64decode
def XorBase64Strings(s1, s2):
"""Emulates the LSL function llXorBase64Strings:
Performs an exclusive or on two Base64 strings and returns a Base64 string. s2 repeats if it is shorter than s1."""
s1 = b64decode(s1) # internally this works with
s2 = b64decode(s2) # the decoded strings
while len(s2) < len(s1): s2 += s2 # repeat s2 until it's at least as long as s1
out = ""
for index in range(len(s1)): # take each character from s1
out += chr( ord(s1[index]) ^ ord(s2[index]) ) # and XOR it with one from s2
data = "I like bananas." # the data we want to encrypt
ckey = "monkey" # the encryption key
crypt = XorBase64Strings(b64encode(data), b64encode(ckey)) # encode & encrypt
print crypt # the base64 encoded result
decrypt = b64decode(XorBase64Strings(crypt, b64encode(ckey))) # decrypt & decode
print decrypt # the decrypted and base64 decoded data
if decrypt == data: print "This function seems to work..."
# this string is from calling the LSL function with the same parameters
if crypt == "JE8CAg4cTQ0PBQQXDBxA": print "... in the same way as the LSL function."
This function does the same thing as the one above, only in PHP:
function XorBase64Strings($s1, $s2)
$s1 = base64_decode($s1);
$s2 = base64_decode($s2);
while(strlen($s2) < strlen($s1))
$s2 .= $s2;
return base64_encode($s1 ^ $s2);
'1.9.0(18)' vs 'pre/post-1.9.0(18)' implementation
The 1.9.0(18) Grid update introducted a new implementation of this function. It was re-written to fix a sim crash bug, however, the output deviates from the original pre-update version. The 1.9.0(18) implementation is simpler. The difference is shown below through pseudo-code. The 1.9.0(21) update reverted this function's behavior to the pre-1.9.0(18) behavior and introduced a new llXorBase64StringsCorrect
with the 1.9.0(18) behavior.
1. Decode s1 and s2 from Base64
into byte strings
2. Bit-wise XOR corresponding bytes of s1 and s2 in sequence. If s2 is shorter than s1, it is simply repeated (i.e. the index into s2 is the index into s1 % length of s2).
3. Re-encode the result byte string into Base64
encoding and return as result
This function's original implementation is more efficient, but gives a different result than the new one, only if s2 is shorter than s1 and s2 isn't a multiple of 3 bytes/chars long
. As of 1.9.0(21), this is the behavior of this function.
1. Convert the Base64
encoding of s1 and s2 into a sequence of 6bit values. (by converting each Base64
character into its 6bit index - see Wikipedia Base64
2. Bit-wise XOR corresponding 6bit values of s1 and s2 in sequence. If s2 is shorter than s1, it is simply repeated (i.e. the index into s2 is the index into s1 % length of s2).
3. Re-convert the resulting sequence of 6bit values into their Base64
characters (by using the 6bit values as indices into the Base64
The reason this differs from the new implemenation, is that the length of the byte string represented by s2 may not be a multiple of 3 bytes long. The initial encoding of s2 into Base64
form involves taking each set of 3 bytes (3x8=24bits) 6 bits at a time and converting to 4 Base64
characters (4x6=24bits). However, if not a multiple of 3 bytes there would have been either 2bytes (16bits) or 1byte(8bits) left over at the end. The Base64
encoding scheme dictates padding to a multiple of 6bits with a 0 bit to obtain the final Base64
character. Hence the Base64
encoded form of s2 may have either 4bits (16 - 6x2) or 2 bits (8 - 1x6) of 0 padding at its end. This padding is included when s2 is repeated above
in the case when s2 is shorter than s1. Hence the different output.
Here is an example of different output.
If you XOR these two strings using llXorBase64Strings
the 'pre/post-1.9.0(18)' implementation will produce
the '1.9.0(18)' implementation gave:
(which is the same result you'll get from the new llXorBase64StringsCorrect
(If you really need code compatible with the current ('pre/post-1.9.0(18)') implementation of llXorBase64Strings
, IM Cenji Neutra for a C# implementation)