llXorBase64StringsCorrect

From Second Life Wiki
Revision as of 14:06, 19 January 2010 by Strife Onizuka (talk | contribs)
Jump to navigation Jump to search

Summary

Function: string llXorBase64StringsCorrect( string str1, string str2 );

Correctly performs an exclusive or on two Base 64 strings.
Returns a string that is a Base64 XOR of str1 and str2.

• string str1 Base64 string
• string str2 Base64 string

str2 repeats if it is shorter than str1. If the inputs are not Base64 strings the result will be erratic.
Be sure to read the Cryptography section before designing a cryptographic algorithm.

Caveats

  • During the conversion to a byte array the last (bitcount % 8) are discarded from both str1 and str2. See Implementation for details.
All Issues ~ Search JIRA for related Bugs

Examples

<lsl>default {

   state_entry(){
       
       // Use a HARD password ! with caps nocaps numbers and symbols !
       string pass = "P4s5Wo_rD";
       
       string data = "I am some ver important data.";
       
       // Enccrypting the data:
       string crypt = llXorBase64StringsCorrect(llStringToBase64(data), llStringToBase64(pass));
       
       // Say the mess you made to Owner
       llOwnerSay(crypt);
       
       // DeCrypting the data and say back to owner:
       llOwnerSay(llBase64ToString(llXorBase64StringsCorrect(crypt, llStringToBase64(pass))));
       
   }

}</lsl>

Notes

Implementation

The XOR is performed by converting the Base64 strings into a byte arrays str1 and str2 and then XORing the two byte arrays. Finally converting the resulting byte array back into Base64 and returning it to the user.

However during the conversion to byte arrays the last (bitcount % 8) are discard. LSL treats Base64 strings as 8-bit byte arrays, not arrays of 6-bit bytes.

Cryptography

While the information provided in this section is by no means exhaustive, it should give the reader enough information that they can ask the right questions and guide their future reading. Writing cryptographic algorithms should not be attempted without an understanding of cryptography as the results may otherwise be disastrous.

In cryptography, a secret is a bit of input information that is used to transform the cryptographic algorithm. The secret is not mutated with subsequent runs of the algorithm. A seed is also used to transform the algorithm but unlike the secret it does mutate; the method of mutation is part of the algorithm.

To effectively use a secret and a seed you need to keep secret at-least two of the following: 1) the algorithm, 2) the seed, or 3) the secret.

Believe it (or not) that keeping your algorithm secret will not protect you. The attack vectors that can be used against these algorithms do not require little or no knowledge of the algorithm. The best protection is a strong algorithm that uses multiple secrets/seeds. In this way you can still satisfy the prior precondition by interpreting the numbered items as categories. Keep in mind how the secrets and seeds are used, an attacker need not determine the secrets, only intermediate static values and the relationship between intermediate values for the algorithm to be broken. Do not give the attacker secrets and seeds that render blocks of living code, static. The more information provide to the attacker, the simpler your algorithm becomes.

Best Practices

As a cryptographic technique, XOR is weak and there are several attacks that can be leveraged to determine the XOR inputs. Depending upon how the secrets are used cracking a single message could expose the input secrets, resulting in the derived algorithm being broken.

Keep your secrets secret. Use a seeded trap door function to shake up the bits of the secret before using with the XOR and change the seed often.

Do not XOR a value by two differing length values without knowing the implications. It may seem like a good idea but what it actually does is link the fields. While it will give you a longer key value (the Smallest Common Multiple in length), the fields will be linked such that there are really only as many fields as the Greatest Common Divisor. The number of unique fields determines the theoretical maximum number of keys an attacker has to try.

Unique_Key_Fields = Greatest_Common_Divisor(lengths_of_keys) * number_of_keys

Attack Vectors

First thing you need to know is that XOR is limited poly-alphabetic cipher. The attack vectors that work for poly-alphabetic ciphers work for XOR.

  • Probability: In English, letters have different probabilities of occurring because of grammar and spelling rules. XOR does not hide the letter probabilities. This attack only works when the keys is many times smaller than the message.
  • UTF-8 Rules: When you convert a string to Base64, UTF-8 encoding is used first. If you assume the inputs are valid UTF-8 encodes some bits can be determined purely upon examination.
  • Plain Text: The user captures outputs for known inputs can expose weaknesses in the key.
  • Brute force: Attacking the key, secret and/or seed

How to decode with php

PHP script can be found in LSL Wiki. An older version of the code can be found here: llXorBase64StringsCorrect in PHP

How to decode with java

Remember to URLEncode your BASE64 hash if you transfer it vie GET...

<java>

      String BASE64datahash = "error";
      String passhash = "error";
      try {
       //URLDecode the URL encoded encrypted data
       BASE64datahash = java.net.URLDecoder.decode("KhoFRRYaAUMbEVU%3D", "UTF-8"); //KhoFRRYaAUMbEVU%3D
       System.out.println("BASE64datahash: " + BASE64datahash); //KhoFRRYaAUMbEVU=
       //create an array of BASE64 data
       char[] BASE64data = BASE64datahash.toCharArray();
       char[] dataUB = new String(new BASE64Decoder().decodeBuffer(new String(BASE64data))).toCharArray(); //BASE64 decode the data
       System.out.println("encrypted data (but base64 decoded) [dataUB]: " + new String(dataUB));


       //Encode the secred key/password to BASE64 (Just to show how to use BASE64Encoder)
       //String BASE64password = new String(new BASE64Encoder().encodeBuffer("supersecretpassword".getBytes()));
       //System.out.println("BASE64password: " + new String(BASE64password));
       //create array of BASE64 key/password
       //char[] key = BASE64password.toCharArray();
       //char[] keyUB = new String(new BASE64Decoder().decodeBuffer(new String(key))).toCharArray();
       char[] keyUB = "supersecretpassword".toCharArray(); 
       System.out.println("plaintext key/password [keyUB]: " + new String(keyUB));
       //XOR data array chars with corresponding key/password array chars
       int k=0;
       for (int i = 0; i < dataUB.length; i++) {
           dataUB[i] = (char) (dataUB[i] ^ keyUB[k]);
           k++;
           //Loop to start of the key if the key is too short
           if (k == keyUB.length)
              k=0;

}

       System.out.println("Decoded data [dataUB]: " + new String(dataUB));
       
       } catch (Exception ex) {
           System.out.println("Oops!");
       }

</java>

<lsl> </lsl>

Deep Notes

All Issues

~ Search JIRA for related Issues
   llXorBase64StringsCorrect zero out last (bitcount % 8) bits of data.

Signature

function string llXorBase64StringsCorrect( string str1, string str2 );