Difference between revisions of "Simple Encryption"

From Second Life Wiki
Jump to navigation Jump to search
m (→‎Encryptor: error in the hex function, could result in an extra character and invalid value.)
m (<lsl> tag to <source>)
 
(10 intermediate revisions by 5 users not shown)
Line 4: Line 4:
== Encryptor ==
== Encryptor ==


<lsl>
<source lang="lsl2">
//Chibiusa lings shiz
string ProtocolSignature = "ENC"; // your own signature
string ProtocolSignature = "ENC"; // your own signature
float ProtocolVersion = 0.3; // can range from 0.0 to 255.255
float ProtocolVersion = 0.3; // can range from 0.0 to 255.255
string Password = "P@ssw0rd"; // change this to your own password
string Password = "P@ssw0rd"; // change this to your own password
integer communicationsChannel = PUBLIC_CHANNEL;
integer communicationsChannel = PUBLIC_CHANNEL;
string Header;
string strHex = "0123456789ABCDEF";


string hex(integer value)
string hex(integer value)
{
{
    string hex = "0123456789ABCDEF";
     integer digit = value & 0xF;
     integer digit = value & 0xF;
     string text = llGetSubString(hex, digit, digit);
     string text = llGetSubString(strHex, digit, digit);
     value = (value >> 4) & 0x3FFFFFFF;
     value = (value >> 4) & 0xfffFFFF;
     integer odd = 1;
     integer odd = TRUE;
     while(value)
     while(value)
     {
     {
         digit = value & 0xF;
         digit = value & 0xF;
         text = llGetSubString(hex, digit, digit) + text;
         text = llGetSubString(strHex, digit, digit) + text;
         odd++;
         odd = !odd;
         value = value >> 4;
         value = value >> 4;
     }  
     }
     if(odd % 2)
     if(odd)
         text = "0" + text;
         text = "0" + text;
     return text;
     return text;
Line 31: Line 33:
{
{
     // get a random value
     // get a random value
     integer nonce = llFloor(llFrand(0x7FFFFFFF));
     integer nonce = (integer)llFrand(0x7FFFFFFF);
   
     // generate session password
     // generate digest and prepend it to message
     string passKey = llMD5String(password, nonce);
     message = llMD5String(message, nonce) + message;
   
     // generate digest
     // generate one time pad
     string digest = llMD5String(message, nonce);
     string oneTimePad = llMD5String(password, nonce);
   
     // prepend message with digest
     // append pad until length matches or exceeds message
     message = digest + message;
     integer count = (llStringLength(message) - 1) / 32;
      
     if(count)
     // encrypt message
        do
     message = llXorBase64StringsCorrect(llStringToBase64(message), llStringToBase64(passKey));
            oneTimePad += llMD5String(oneTimePad, nonce);
   
        while(--count);
     // build header
    string header = ProtocolSignature;
     // return the header, nonce and encrypted message
   
     return Header + llGetSubString("00000000" + hex(nonce), -8, -1) + llXorBase64StringsCorrect(llStringToBase64(message), llStringToBase64(oneTimePad));
    // append major version
}
init()
{
     //build the header, it never changes.
     list versions = llParseString2List((string)ProtocolVersion, ["."], []);
     list versions = llParseString2List((string)ProtocolVersion, ["."], []);
     header += hex(llList2Integer(versions, 0));
     string minor = llList2String(versions, 1);
      
     integer p = 0;
    // append minor version
     while(llGetSubString(minor, --p, p) == "0");
    string minor;
    Header = ProtocolSignature + hex(llList2Integer(versions, 0)) + hex((integer)llGetSubString(minor, 0xFF000000, p));
     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
default
{
{
     state_entry()
     state_entry()
     {
     {
        init();
         llSay(communicationsChannel, encrypt(Password, "Hello, Avatar!"));
         llSay(communicationsChannel, encrypt(Password, "Hello, Avatar!"));
        llSay(communicationsChannel, encrypt(Password, "This is a very long text that I hope to be able to create a long one time pad to decrypt for it."));
     }
     }
 
     touch_start(integer total_number)
     touch_start(integer total_number)
     {
     {
         llSay(communicationsChannel, encrypt(Password, "Touched."));
         llSay(communicationsChannel, encrypt(Password, "Touched."));
     }
     }
}
}</source>
</lsl>


== Decryptor ==
== Decryptor ==
<lsl>
<source lang="lsl2">
string ProtocolSignature = "ENC"; // your own signature
string ProtocolSignature = "ENC"; // your own signature
float ProtocolVersion = 0.3; // can range from 0.0 to 255.255
float ProtocolVersion = 0.3; // can range from 0.0 to 255.255
Line 112: Line 105:
      
      
     // verify length of encrypted message
     // verify length of encrypted message
     if(llStringLength(message) < headerLength + 44) // digest = 32 (base64 of digest + 1 character = 44)
     if(llStringLength(message) < signatureLength + 44) // digest = 32 (base64 = 44) + at least one character
         return error("Too small for secret message.");
         return error("Too small for secret message.");
          
          
Line 131: Line 124:
     // parse nonce from header
     // parse nonce from header
     integer nonce = (integer)("0x" + llGetSubString(message, ++index, index + 7));
     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
     // remove header from message
     message = llGetSubString(message, headerLength, -1);
     message = llGetSubString(message, headerLength, -1);
   
    // create one time pad from password and nonce
    string oneTimePad = llMD5String(password, nonce);
    // append pad until length matches or exceeds message
    while(llStringLength(oneTimePad) < (llStringLength(message) / 2 * 3))
        oneTimePad += llMD5String(oneTimePad, nonce);
      
      
     // decrypt message
     // decrypt message
     message = llXorBase64StringsCorrect(message, passKey);
    oneTimePad = llStringToBase64(oneTimePad);
     message = llXorBase64StringsCorrect(message, oneTimePad);
      
      
     // decode message
     // decode message
Line 174: Line 171:
     }
     }
}
}
</lsl>
</source>


Note: The [[Hex]] and [[Efficient Hex]] examples were used to create the hex method.
Note: The [[Hex]] and [[Efficient Hex]] examples were used to create the hex method.


{{LSLC|Examples|Simple Encryption}}
{{LSLC|Examples|Simple Encryption}}
[[Category: LSL Encryption]]

Latest revision as of 17:00, 24 January 2015

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

//Chibiusa lings shiz
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 Header;
string strHex = "0123456789ABCDEF";

string hex(integer value)
{
    integer digit = value & 0xF;
    string text = llGetSubString(strHex, digit, digit);
    value = (value >> 4) & 0xfffFFFF;
    integer odd = TRUE;
    while(value)
    {
        digit = value & 0xF;
        text = llGetSubString(strHex, digit, digit) + text;
        odd = !odd;
        value = value >> 4;
    }
    if(odd)
        text = "0" + text;
    return text;
}
string encrypt(string password, string message)
{
    // get a random value
    integer nonce = (integer)llFrand(0x7FFFFFFF);
 
    // generate digest and prepend it to message
    message = llMD5String(message, nonce) + message;
 
    // generate one time pad
    string oneTimePad = llMD5String(password, nonce);
 
    // append pad until length matches or exceeds message
    integer count = (llStringLength(message) - 1) / 32;
    if(count)
        do
            oneTimePad += llMD5String(oneTimePad, nonce);
        while(--count);
 
    // return the header, nonce and encrypted message
    return Header + llGetSubString("00000000" + hex(nonce), -8, -1) + llXorBase64StringsCorrect(llStringToBase64(message), llStringToBase64(oneTimePad));
}
init()
{
    //build the header, it never changes.
    list versions = llParseString2List((string)ProtocolVersion, ["."], []);
    string minor = llList2String(versions, 1);
    integer p = 0;
    while(llGetSubString(minor, --p, p) == "0");
    Header = ProtocolSignature + hex(llList2Integer(versions, 0)) + hex((integer)llGetSubString(minor, 0xFF000000, p));	
}

default
{
    state_entry()
    {
        init();
        llSay(communicationsChannel, encrypt(Password, "Hello, Avatar!"));
        llSay(communicationsChannel, encrypt(Password, "This is a very long text that I hope to be able to create a long one time pad to decrypt for it."));
    }
 
    touch_start(integer total_number)
    {
        llSay(communicationsChannel, encrypt(Password, "Touched."));
    }
}

Decryptor

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) < signatureLength + 44) // digest = 32 (base64 = 44) + at least one character
        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));
    
    // remove header from message
    message = llGetSubString(message, headerLength, -1);
    
    // create one time pad from password and nonce
    string oneTimePad = llMD5String(password, nonce);
    // append pad until length matches or exceeds message
    while(llStringLength(oneTimePad) < (llStringLength(message) / 2 * 3))
        oneTimePad += llMD5String(oneTimePad, nonce);
    
    // decrypt message
    oneTimePad = llStringToBase64(oneTimePad);
    message = llXorBase64StringsCorrect(message, oneTimePad);
    
    // 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);
    }
}

Note: The Hex and Efficient Hex examples were used to create the hex method.