Difference between revisions of "AES LSL+ Implementation"

From Second Life Wiki
Jump to navigation Jump to search
Line 1: Line 1:
= Description =
= Description =
The following is an [http://lslplus.sourceforge.net/ LSL+] version of the [[AES LSL Implementation|LSL AES Engine]] by [[Haravikk Mistral]]. It allows a developer to generate an optimised AES Engine using [http://en.wikipedia.org/wiki/Eclipse_(software) The Eclipse IDE].
The following is an [http://lslplus.sourceforge.net/ LSL+] version of the [[AES LSL Implementation|LSL AES Engine]] by [[Haravikk Mistral]]. It allows a developer to generate an optimised AES Engine using [http://en.wikipedia.org/wiki/Eclipse_(software) the Eclipse IDE].


This version has a number of advantages including over 8kb of memory right-away, and up to a further 12kb of memory through the use of the <code>SUPPORTED_MODES()</code>, <code>SUPPORTED_PADS()</code>, and <code>SUPPORTS_SETUP()</code> constants, which can be adjusted to enabled/disable modes of operation, padding schemes, and dynamic set-up.
This version has a number of advantages including over 8kb of memory right-away, and up to a further 12kb of memory through the use of the <code>SUPPORTED_MODES()</code>, <code>SUPPORTED_PADS()</code>, and <code>SUPPORTS_SETUP()</code> constants, which can be adjusted to enabled/disable modes of operation, padding schemes, and dynamic set-up.


With this amount of free-memory it is possible to integrate some scripts directly within the broker, eliminating the need to send it link-messages, such optimisations may be made in future to more easily facilitate this.
With this amount of free-memory it is possible to integrate AES directly into a script, without the use of a broker which you would communicate with to perform encryption/decryption.


= Required Modules =
= Project structure =
The LSL Plus project as constructed here uses a common module for constants, and one for helper-functions, to make things as easy-to-use as possible. It assumes the following folder structure:
While not a requirement, here is the structure of the LSL+ project from which the following code is derived, if you choose to use a different structure then you'll need to change the <code>$import</code> declarations accordingly.
 
The code you are mainly interested in is AES_Core.lslm, and AES_Constants.lslm. By importing these you can quickly start using AES in your examples, please refer to the examples to see how.


* AES
* AES
** Broker
** Broker
*** AES_Broker_Constants.lslm
*** AES_Broker_Helper.lslm
*** AES_Broker.lslp
*** AES_Broker.lslp
*** AES_Constants.lslm
** AES_Constants.lslm
** AES_Helper.lslm
** AES_Core.lslm


= Core Scripts =
== AES_Constants.lslm ==
== AES_Constants.lslm ==
<lsl>$module ()
<lsl>$module ()


// These variables are used to build communications. Commands are sent as
integer LSLAES_COMMAND_PRIME() { return 1; }
// combined bits in the integer argument of a link-message, and are
integer LSLAES_COMMAND_INIT() { return 2; }
// recovered using masks, you may wish to read about bit-masks before
integer LSLAES_COMMAND_ENCRYPT() { return 3; }
// editing these values. These are used so the string argument is
integer LSLAES_COMMAND_DECRYPT() { return 4; }
// kept free for data only.
 
//
integer LSLAES_DATA_HEX() { return 1; }
// Commands take the following form (in hex):
integer LSLAES_DATA_BASE64() { return 2; }
//      0xFFMMIOvv
// Where the letters are:
//      F  Filter, used to quickly determine if a message is for us.
//      C  Command; encrypt/decrypt etc.
//      I  Type of data provided (hex, base64, etc.).
//      O  Desired type of data to be returned (hex, base64, etc.),
//          this is unused in replies as the reply's value for I will
//          be the request's value for O.
//      v  Variable, depends on mode.
// This mask allows the filter byte to be retrieved quickly
integer LSLAES_FILTER_MASK() { return 0xFF000000; }
// This mask allows the mask byte to be retrieved quickly
integer LSLAES_COMMAND_MASK() { return 0x00FF0000; }
// This mask allows the input type to be retrieved quickly
integer LSLAES_INPUT_TYPE_MASK() { return 0x0000F000; }
// This mask allows the output type to be retireved quickly
integer LSLAES_OUTPUT_TYPE_MASK() { return 0x00000F00; }
// This mask allows the variable to retrieved quickly
integer LSLAES_VARIABLE_MASK() { return 0x000000FF; }
// How many bits right variable must be shifted
integer LSLAES_VARIABLE_SHIFT() { return 0; }
// A request
integer LSLAES_FILTER_REQUEST() { return 0x81000000; }
// A reply
integer LSLAES_FILTER_REPLY() { return 0x82000000; }
// An error occurred
integer LSLAES_COMMAND_ERROR() { return 0x00000000; }
// Prime engine with key
integer LSLAES_COMMAND_PRIME() { return 0x00010000; }
// Encrypt message using expanded key
integer LSLAES_COMMAND_ENCRYPT() { return 0x00020000; }
// Decrypt message using expanded key
integer LSLAES_COMMAND_DECRYPT() { return 0x00030000; }
// Sets-up the engine by specifying comma-separated flags
integer LSLAES_COMMAND_SETUP() { return 0x00050000; }
// Initialise the engine with an input-vector
integer LSLAES_COMMAND_INIT() { return 0x00060000; }
// Input type is hex
integer LSLAES_INPUT_HEX() { return 0x00000000; }
// Input type is base64
integer LSLAES_INPUT_BASE64() { return 0x00001000; }
// Output type is hex
integer LSLAES_OUTPUT_HEX() { return 0x00000000; }
// Output type is base64
integer LSLAES_OUTPUT_BASE64() { return 0x00000100; }
// Refuse any data longer than this many characters
integer LSLAES_MAX_SIZE() { return 1536; }
   
   
string  LSLAES_HEX_CHARS() { return "0123456789abcdef"; }
string  LSLAES_HEX_CHARS() { return "0123456789abcdef"; }
Line 160: Line 112:
integer LSLAES_PAD_SIZE_DEFAULT() { return 512; }</lsl>
integer LSLAES_PAD_SIZE_DEFAULT() { return 512; }</lsl>


== AES_Helper.lslm ==
== AES_Core.lslm ==
<lsl>$module ()
<lsl>$module()
 
$import AES.Broker.AES_Constants.lslm();
 
// The following extra variables are used to track our messages
key    requestID              = NULL_KEY;
// Sets-up the AES engine. Flags is a comma-separated list with the
// following possible entries:
//  MODE_ECB    - Sets Electronic Code-Book mode, a little faster but
//                not especially secure
//  MODE_CBC    - Cipher-Block-Chaining mode, most commonly used, good
//                security.
//  MODE_CFB    - Ciphertext Feed-Back mode. Similar to CBC, but does
//                not require an inverse-cipher to decrypt.
//  MODE_NOFB  - Output Feed-Back mode. Similar to CFB.
//
//  PAD_RBT    - Residual Block Termination padding is a method of
//                encrypting data that does not fit correctly within
//                into blocks.
//  PAD_NULLS  - Mainly added to provide support for PHP's mcrypt
//                library. Null-characters (zero-bytes) are added to
//                pad the length. ALL nulls are removed from the end
//                after decryption, so be careful if null-characters
//                occur within the text naturally.
//  PAD_ZEROES  - Adds zero-bytes, with the final byte describing the
//                number of bytes added. If data fits within padSize
//                then an extra padSize bits is added.
//  PAD_RANDOM  - Identical to PAD_ZEROES except that random bytes are
//                generated for padding.
//
//  PAD_SIZE    - Defines the length of padding for NULLS, ZEROES, and
//                random to align on. After this should be an integer
//                value defining the size. Must be a multiple of 128.
// pragma inline
lslAESSetup(integer targetLink, string flags, key id) {
    llMessageLinked(
        targetLink,
        LSLAES_FILTER_REQUEST() | LSLAES_COMMAND_SETUP(),
        (flags = "") + flags,
        requestID = id
    );
}
// Sends a link message to targetLink, requesting that aesKey be used to
// prime the AES engine. aesKey should be a hexadecimal string representing
// a value that is 128, 192, or 256-bits in length.
// pragma inline
lslAESPrimeHexKey(integer targetLink, string aesKey, key id) {
    llMessageLinked(
        targetLink,
        LSLAES_FILTER_REQUEST() | LSLAES_COMMAND_PRIME() | LSLAES_INPUT_HEX(),
        (aesKey = "") + aesKey,
        requestID = id
    );
}
// Initialises a 128-bit input-vector to be used by the AES engine
// pragma inline
lslAESInitHexIV(integer targetLink, string iv, key id) {
    llMessageLinked(
        targetLink,
        LSLAES_FILTER_REQUEST() | LSLAES_COMMAND_INIT() | LSLAES_INPUT_HEX(),
        (iv = "") + iv,
        requestID = id
    );
}
// Sends hexadecimal data and gets encrypted hexadecimal data back
// pragma inline
lslAESEncryptHexToHex(integer targetLink, string hexData, key id) {
    llMessageLinked(
        targetLink,
        LSLAES_FILTER_REQUEST() | LSLAES_COMMAND_ENCRYPT() |
            LSLAES_INPUT_HEX() | LSLAES_OUTPUT_HEX(),
        (hexData = "") + hexData,
        requestID = id
    );
}
// Sends hexadecimal data and gets encrypted base64 data back
// pragma inline
lslAESEncryptHexToBase64(integer targetLink, string hexData, key id) {
    llMessageLinked(
        targetLink,
        LSLAES_FILTER_REQUEST() | LSLAES_COMMAND_ENCRYPT() |
            LSLAES_INPUT_HEX() | LSLAES_OUTPUT_BASE64(),
        (hexData = "") + hexData,
        requestID = id
    );
}
// Send base64 data and gets encrypted hexadecimal data back
// pragma inline
lslAESEncryptBase64ToHex(integer targetLink, string b64Data, key id) {
    llMessageLinked(
        targetLink,
        LSLAES_FILTER_REQUEST() | LSLAES_COMMAND_ENCRYPT() |
            LSLAES_INPUT_BASE64() | LSLAES_OUTPUT_HEX(),
        (b64Data = "") + b64Data,
        requestID = id
    );   
}
// Send base64 data and gets encrypted hexadecimal data back
// pragma inline
lslAESEncryptBase64ToBase64(integer targetLink, string b64Data, key id) {
    llMessageLinked(
        targetLink,
        LSLAES_FILTER_REQUEST() | LSLAES_COMMAND_ENCRYPT() |
            LSLAES_INPUT_BASE64() | LSLAES_OUTPUT_BASE64(),
        (b64Data = "") + b64Data,
        requestID = id
    );   
}
// Sends hexadecimal data and gets decrypted hexadecimal data back
// pragma inline
lslAESDecryptHexToHex(integer targetLink, string hexData, key id) {
    llMessageLinked(
        targetLink,
        LSLAES_FILTER_REQUEST() | LSLAES_COMMAND_DECRYPT() |
            LSLAES_INPUT_HEX() | LSLAES_OUTPUT_HEX(),
        (hexData = "") + hexData,
        requestID = id
    );
}
// Sends hexadecimal data and gets decrypted base64 data back
// pragma inline
lslAESDecryptHexToBase64(integer targetLink, string hexData, key id) {
    llMessageLinked(
        targetLink,
        LSLAES_FILTER_REQUEST() | LSLAES_COMMAND_DECRYPT() |
            LSLAES_INPUT_HEX() | LSLAES_OUTPUT_BASE64(),
        (hexData = "") + hexData,
        requestID = id
    );
}
// Send base64 data and gets decrypted hexadecimal data back
// pragma inline
lslAESDecryptBase64ToHex(integer targetLink, string b64Data, key id) {
    llMessageLinked(
        targetLink,
        LSLAES_FILTER_REQUEST() | LSLAES_COMMAND_DECRYPT() |
            LSLAES_INPUT_BASE64() | LSLAES_OUTPUT_HEX(),
        (b64Data = "") + b64Data,
        requestID = id
    );   
}
// Send base64 data and gets decrypted hexadecimal data back
// pragma inline
lslAESDecryptBase64ToBase64(integer targetLink, string b64Data, key id) {
    llMessageLinked(
        targetLink,
        LSLAES_FILTER_REQUEST() | LSLAES_COMMAND_DECRYPT() |
            LSLAES_INPUT_BASE64() | LSLAES_OUTPUT_BASE64(),
        (b64Data = "") + b64Data,
        requestID = id
    );   
}
// Tests to see if a message is a reply or not (TRUE/FALSE)
// pragma inline
integer lslAESIsReply(integer int, key id) {
    return (
        ((int & LSLAES_FILTER_MASK()) == LSLAES_FILTER_REPLY()) &&
        (id == requestID)
    );
}
// Grabs the mode of this reply. Should be one of the LSLAES_COMMAND_* constants
// pragma inline
integer lslAESGetReplyMode(integer int) {
    return (int & LSLAES_COMMAND_MASK());
}
// Grabs the data type of this reply. Should be one of the LSLAES_INPUT_*
// constants.
// pragma inline
integer lslAESGetReplyDataType(integer int) {
    return (int & LSLAES_INPUT_TYPE_MASK());
}</lsl>
 
= AES_Broker.lslp =
<lsl>$import AES.Broker.AES_Constants.lslm();


integer SUPPORTS_SETUP() { return TRUE; }
$import AES.AES_Constants.lslm();


list SUPPORTED_MODES() {
list SUPPORTED_MODES() {
Line 385: Line 150:


// Treats the above list as a byte-array, retrieving the desired byte value.
// Treats the above list as a byte-array, retrieving the desired byte value.
integer lslAESGetSBoxInvertedByte(integer n) {{
integer _lslAESGetSBoxInvertedByte(integer n) {{
     return lslAESMultInverse(lslAESInverseAffine(n));
     return _lslAESMultInverse(_lslAESInverseAffine(n));
}}
}}
   
   
// Treats the above list as a byte-array, retrieving the desired byte value.
// Treats the above list as a byte-array, retrieving the desired byte value.
integer lslAESGetSBoxByte(integer n) {{
integer _lslAESGetSBoxByte(integer n) {{
     return lslAESAffine(lslAESMultInverse(n));
     return _lslAESAffine(_lslAESMultInverse(n));
}}
}}
   
   
// Calculates high-bit of x / 2 in a finite field
// Calculates high-bit of x / 2 in a finite field
integer lslAESHibit(integer x) {{
integer _lslAESHibit(integer x) {{
     x = (x >> 1) | (x >> 2);
     x = (x >> 1) | (x >> 2);
     x = x | (x >> 2);
     x = x | (x >> 2);
Line 403: Line 168:
   
   
// Calculates a multipilicative inverse in a finite field
// Calculates a multipilicative inverse in a finite field
integer lslAESMultInverse(integer p1) {{
integer _lslAESMultInverse(integer p1) {{
     if(p1 < 2) return p1;
     if(p1 < 2) return p1;
   
   
     integer p2 = 0x1b;
     integer p2 = 0x1b;
     integer n1 = lslAESHibit(p1);
     integer n1 = _lslAESHibit(p1);
     integer n2 = 0x80;
     integer n2 = 0x80;
     integer v1 = 1;
     integer v1 = 1;
Line 418: Line 183:
                 p2 = p2 ^ ((p1 * n2) & 0xFF); // and remove from larger one
                 p2 = p2 ^ ((p1 * n2) & 0xFF); // and remove from larger one
                 v2 = v2 ^ ((v1 * n2) & 0xFF); // shift accumulated value and
                 v2 = v2 ^ ((v1 * n2) & 0xFF); // shift accumulated value and
                 n2 = lslAESHibit(p2);              // add into result
                 n2 = _lslAESHibit(p2);              // add into result
             }
             }
         else return v1;
         else return v1;
Line 427: Line 192:
                 p1 = p1 ^ ((p2 * n1) & 0xFF);
                 p1 = p1 ^ ((p2 * n1) & 0xFF);
                 v1 = v1 ^ ((v2 * n1) & 0xFF);
                 v1 = v1 ^ ((v2 * n1) & 0xFF);
                 n1 = lslAESHibit(p1);
                 n1 = _lslAESHibit(p1);
             }
             }
         else return v2;
         else return v2;
Line 435: Line 200:


// Affine function for sbox
// Affine function for sbox
integer lslAESAffine(integer x) {{
integer _lslAESAffine(integer x) {{
     x = x ^ (x << 1) ^ (x << 2) ^ (x << 3) ^ (x << 4);
     x = x ^ (x << 1) ^ (x << 2) ^ (x << 3) ^ (x << 4);
     return 0x63 ^ ((x ^ (x >> 8)) & 0xFF);
     return 0x63 ^ ((x ^ (x >> 8)) & 0xFF);
Line 441: Line 206:
   
   
// Inverse affine function for sbox inversion
// Inverse affine function for sbox inversion
integer lslAESInverseAffine(integer x) {{
integer _lslAESInverseAffine(integer x) {{
     x = (x << 1) ^ (x << 3) ^ (x << 6);
     x = (x << 1) ^ (x << 3) ^ (x << 6);
     return 0x05 ^ ((x ^ (x >> 8)) & 0xFF);
     return 0x05 ^ ((x ^ (x >> 8)) & 0xFF);
}}
}}
   
   
integer lslAESMode; // Set in default state_entry()
integer _lslAESMode; // Set in default state_entry()
integer lslAESPad; // Set in default state_entry()
integer _lslAESPad; // Set in default state_entry()
integer lslAESPadSize; // Set in default state_entry()
integer _lslAESPadSize; // Set in default state_entry()
   
   
// Used for the actual encryption, generated from Key
// Used for the actual encryption, generated from Key
list    lslAESRoundKey         = [];
list    _lslAESRoundKey         = [];
// The number of rounds to perform (bigger key == more rounds)
// The number of rounds to perform (bigger key == more rounds)
integer lslAESRounds           = 0;
integer _lslAESRounds           = 0;
   
   
// The following are used for the state instead of a list
// The following are used for the state instead of a list
integer lslAESStateX0Y0         = 0;
integer _lslAESStateX0Y0         = 0;
integer lslAESStateX0Y1         = 0;
integer _lslAESStateX0Y1         = 0;
integer lslAESStateX0Y2         = 0;
integer _lslAESStateX0Y2         = 0;
integer lslAESStateX0Y3         = 0;
integer _lslAESStateX0Y3         = 0;
integer lslAESStateX1Y0         = 0;
integer _lslAESStateX1Y0         = 0;
integer lslAESStateX1Y1         = 0;
integer _lslAESStateX1Y1         = 0;
integer lslAESStateX1Y2         = 0;
integer _lslAESStateX1Y2         = 0;
integer lslAESStateX1Y3         = 0;
integer _lslAESStateX1Y3         = 0;
integer lslAESStateX2Y0         = 0;
integer _lslAESStateX2Y0         = 0;
integer lslAESStateX2Y1         = 0;
integer _lslAESStateX2Y1         = 0;
integer lslAESStateX2Y2         = 0;
integer _lslAESStateX2Y2         = 0;
integer lslAESStateX2Y3         = 0;
integer _lslAESStateX2Y3         = 0;
integer lslAESStateX3Y0         = 0;
integer _lslAESStateX3Y0         = 0;
integer lslAESStateX3Y1         = 0;
integer _lslAESStateX3Y1         = 0;
integer lslAESStateX3Y2         = 0;
integer _lslAESStateX3Y2         = 0;
integer lslAESStateX3Y3         = 0;
integer _lslAESStateX3Y3         = 0;
   
   
// Used to initialise state for CBC and other mode
// Used to initialise state for CBC and other mode
integer lslAESInputVector0     = 0;
integer _lslAESInputVector0     = 0;
integer lslAESInputVector1     = 0;
integer _lslAESInputVector1     = 0;
integer lslAESInputVector2     = 0;
integer _lslAESInputVector2     = 0;
integer lslAESInputVector3     = 0;
integer _lslAESInputVector3     = 0;
 
integer _lslAESProcessCommandError = TRUE;
   
   
//##########################################################################//
//##########################################################################//
Line 486: Line 253:
// Performs a cipher with necessary padding performed before execution
// Performs a cipher with necessary padding performed before execution
// pragma inline
// pragma inline
list lslAESPadCipher(list data) {{
list _lslAESPadCipher(list data) {{
     integer bits = llList2Integer(data, 0);
     integer bits = llList2Integer(data, 0);
     data = llDeleteSubList((data = []) + data, 0, 0);
     data = llDeleteSubList((data = []) + data, 0, 0);
   
   
     integer padding = lslAESPad;
     integer padding = _lslAESPad;
     if (padding == LSLAES_PAD_NONE_ID()) {
     if (padding == LSLAES_PAD_NONE_ID()) {
         if (lslAESMode == LSLAES_MODE_CFB_ID())  
         if (_lslAESMode == LSLAES_MODE_CFB_ID())  
             return [bits] + lslAESCipher((data = []) + data);
             return [bits] + _lslAESCipher((data = []) + data);
         padding = LSLAES_PAD_RBT_ID();
         padding = LSLAES_PAD_RBT_ID();
     }
     }
   
   
     integer blockSize = lslAESPadSize;
     integer blockSize = _lslAESPadSize;
     if (padding == LSLAES_PAD_RBT_ID()) blockSize = 128;
     if (padding == LSLAES_PAD_RBT_ID()) blockSize = 128;
   
   
Line 521: Line 288:
                // If not enough for a block, we generate lb using  
                // If not enough for a block, we generate lb using  
                // a double cipher of input vector.
                // a double cipher of input vector.
                lb = lslAESCipher(
                lb = _lslAESCipher(
                    lslAESCipher((data = []) + [
                    _lslAESCipher((data = []) + [
                        lslAESInputVector0, lslAESInputVector1,  
                        _lslAESInputVector0, _lslAESInputVector1,  
                        lslAESInputVector2, lslAESInputVector3
                        _lslAESInputVector2, _lslAESInputVector3
                    ])
                    ])
                );
                );
Line 530: Line 297:
                // If there are blocks, we encrypt normally, then  
                // If there are blocks, we encrypt normally, then  
                // double-encrypt the final block for lb
                // double-encrypt the final block for lb
                data = lslAESCipher(
                data = _lslAESCipher(
                    llDeleteSubList((data = []) + data, -words, -1)
                    llDeleteSubList((data = []) + data, -words, -1)
                );
                );
                lb = lslAESCipher(llList2List(data, -4, -1));
                lb = _lslAESCipher(llList2List(data, -4, -1));
            }
            }
 
 
Line 545: Line 312:
            return [bits] + (data = final = []) + data + final;
            return [bits] + (data = final = []) + data + final;
        }  
        }  
        return [bits] + lslAESCipher((data = []) + data);
        return [bits] + _lslAESCipher((data = []) + data);
     }
     }
     } else if (SUPPORTS_PAD(LSLAES_PAD_NULLS()) ||  
     } else if (SUPPORTS_PAD(LSLAES_PAD_NULLS()) ||  
Line 552: Line 319:
       SUPPORTS_PAD(LSLAES_PAD_ZEROES())) {
       SUPPORTS_PAD(LSLAES_PAD_ZEROES())) {
         // This scheme works by adding bytes until the data is a  
         // This scheme works by adding bytes until the data is a  
         // multiple of lslAESPadSize bits long. In the case of  
         // multiple of _lslAESPadSize bits long. In the case of  
         // PAD_NULLS this will only add extra data if needed,  
         // PAD_NULLS this will only add extra data if needed,  
         // while the other types must always add at least one  
         // while the other types must always add at least one  
Line 642: Line 409:
   
   
         @skip;
         @skip;
         return [bits] + lslAESCipher((data = []) + data);
         return [bits] + _lslAESCipher((data = []) + data);
     }
     }
     return [];
     return [];
Line 649: Line 416:
// Performs an inverse cipher with appropriate padding handling performed
// Performs an inverse cipher with appropriate padding handling performed
// pragma inline
// pragma inline
list lslAESInvertPadCipher(list data) {{
list _lslAESInvertPadCipher(list data) {{
     integer bits = llList2Integer(data, 0);
     integer bits = llList2Integer(data, 0);
     data = llDeleteSubList((data = []) + data, 0, 0);
     data = llDeleteSubList((data = []) + data, 0, 0);
   
   
     integer padding = lslAESPad;
     integer padding = _lslAESPad;
     if (padding == LSLAES_PAD_NONE_ID()) {
     if (padding == LSLAES_PAD_NONE_ID()) {
         if (lslAESMode == LSLAES_MODE_CFB_ID())  
         if (_lslAESMode == LSLAES_MODE_CFB_ID())  
             return [bits] + lslAESInvertCipher((data = []) + data);
             return [bits] + _lslAESInvertCipher((data = []) + data);
         padding = LSLAES_PAD_RBT_ID();
         padding = LSLAES_PAD_RBT_ID();
     }
     }
   
   
     integer blockSize = lslAESPadSize;
     integer blockSize = _lslAESPadSize;
     if (padding == LSLAES_PAD_RBT_ID()) blockSize = 128;
     if (padding == LSLAES_PAD_RBT_ID()) blockSize = 128;
   
   
Line 684: Line 451:
                // If not enough for a block, we generate lb using  
                // If not enough for a block, we generate lb using  
                // a double cipher of input vector.
                // a double cipher of input vector.
                lb = lslAESCipher(
                lb = _lslAESCipher(
                    lslAESCipher((data = []) + [
                    _lslAESCipher((data = []) + [
                        lslAESInputVector0, lslAESInputVector1,  
                        _lslAESInputVector0, _lslAESInputVector1,  
                        lslAESInputVector2, lslAESInputVector3
                        _lslAESInputVector2, _lslAESInputVector3
                    ])
                    ])
                );
                );
Line 693: Line 460:
                // If there are blocks, then we double-encrypt the  
                // If there are blocks, then we double-encrypt the  
                // last full block to generate lb, then decrypt normally
                // last full block to generate lb, then decrypt normally
                lb = lslAESCipher(
                lb = _lslAESCipher(
                    llList2List(data, -(4 + words), -(words + 1))
                    llList2List(data, -(4 + words), -(words + 1))
                );
                );
                data = lslAESInvertCipher(
                data = _lslAESInvertCipher(
                    llDeleteSubList((data = []) + data, -words, -1)
                    llDeleteSubList((data = []) + data, -words, -1)
                );
                );
Line 710: Line 477:
            return [bits] + (data = final = []) + data + final;
            return [bits] + (data = final = []) + data + final;
        }
        }
        return [bits] + lslAESInvertCipher((data = []) + data);
        return [bits] + _lslAESInvertCipher((data = []) + data);
     }
     }
     } else if (SUPPORTS_PAD(LSLAES_PAD_NULLS()) ||  
     } else if (SUPPORTS_PAD(LSLAES_PAD_NULLS()) ||  
Line 717: Line 484:
       SUPPORTS_PAD(LSLAES_PAD_ZEROES())) {
       SUPPORTS_PAD(LSLAES_PAD_ZEROES())) {
         // This scheme works by adding bytes until the data is a  
         // This scheme works by adding bytes until the data is a  
         // multiple of lslAESPadSize bits long. In the case of  
         // multiple of _lslAESPadSize bits long. In the case of  
         // PAD_NULLS this will only add extra data if needed,  
         // PAD_NULLS this will only add extra data if needed,  
         // while the other types must always add at least one  
         // while the other types must always add at least one  
Line 741: Line 508:
   
   
         // Perform the decryption
         // Perform the decryption
         data = lslAESInvertCipher((data = []) + data);
         data = _lslAESInvertCipher((data = []) + data);
   
   
         integer bytes = 0; integer words = 0; integer excessBits = 0;
         integer bytes = 0; integer words = 0; integer excessBits = 0;
Line 808: Line 575:
// Padding adjustment must be performed as this function will only except data  
// Padding adjustment must be performed as this function will only except data  
// that is a multiple of 128-bits long.
// that is a multiple of 128-bits long.
list lslAESInvertCipher(list data) {{
list _lslAESInvertCipher(list data) {{
     // The following are used to pass blocks forward     
     // The following are used to pass blocks forward     
     integer prevBlock0 = lslAESInputVector0;
     integer prevBlock0 = _lslAESInputVector0;
     integer prevBlock1 = lslAESInputVector1;
     integer prevBlock1 = _lslAESInputVector1;
     integer prevBlock2 = lslAESInputVector2;
     integer prevBlock2 = _lslAESInputVector2;
     integer prevBlock3 = lslAESInputVector3;
     integer prevBlock3 = _lslAESInputVector3;
   
   
     integer nextBlock0 = 0;
     integer nextBlock0 = 0;
Line 825: Line 592:
     while (l > 0) {
     while (l > 0) {
         // Different modes treat blocks differently
         // Different modes treat blocks differently
         if (lslAESMode == LSLAES_MODE_CBC_ID()) {
         if (_lslAESMode == LSLAES_MODE_CBC_ID()) {
         if (SUPPORTS_MODE(LSLAES_MODE_CBC())) {
         if (SUPPORTS_MODE(LSLAES_MODE_CBC())) {
            // For CBC we load it, and must keep a copy
            // For CBC we load it, and must keep a copy
            nextBlock0 = llList2Integer(data, 0);
            nextBlock0 = llList2Integer(data, 0);
            lslAESStateX0Y0 = ((nextBlock0 >> 24) & 0xFF);
            _lslAESStateX0Y0 = ((nextBlock0 >> 24) & 0xFF);
            lslAESStateX0Y1 = ((nextBlock0 >> 16) & 0xFF);
            _lslAESStateX0Y1 = ((nextBlock0 >> 16) & 0xFF);
            lslAESStateX0Y2 = ((nextBlock0 >> 8 ) & 0xFF);
            _lslAESStateX0Y2 = ((nextBlock0 >> 8 ) & 0xFF);
            lslAESStateX0Y3 = ((nextBlock0      ) & 0xFF);
            _lslAESStateX0Y3 = ((nextBlock0      ) & 0xFF);
            nextBlock1 = llList2Integer(data, 1);
            nextBlock1 = llList2Integer(data, 1);
            lslAESStateX1Y0 = ((nextBlock1 >> 24) & 0xFF);
            _lslAESStateX1Y0 = ((nextBlock1 >> 24) & 0xFF);
            lslAESStateX1Y1 = ((nextBlock1 >> 16) & 0xFF);
            _lslAESStateX1Y1 = ((nextBlock1 >> 16) & 0xFF);
            lslAESStateX1Y2 = ((nextBlock1 >> 8 ) & 0xFF);
            _lslAESStateX1Y2 = ((nextBlock1 >> 8 ) & 0xFF);
            lslAESStateX1Y3 = ((nextBlock1      ) & 0xFF);
            _lslAESStateX1Y3 = ((nextBlock1      ) & 0xFF);
            nextBlock2 = llList2Integer(data, 2);
            nextBlock2 = llList2Integer(data, 2);
            lslAESStateX2Y0 = ((nextBlock2 >> 24) & 0xFF);
            _lslAESStateX2Y0 = ((nextBlock2 >> 24) & 0xFF);
            lslAESStateX2Y1 = ((nextBlock2 >> 16) & 0xFF);
            _lslAESStateX2Y1 = ((nextBlock2 >> 16) & 0xFF);
            lslAESStateX2Y2 = ((nextBlock2 >> 8 ) & 0xFF);
            _lslAESStateX2Y2 = ((nextBlock2 >> 8 ) & 0xFF);
            lslAESStateX2Y3 = ((nextBlock2      ) & 0xFF);
            _lslAESStateX2Y3 = ((nextBlock2      ) & 0xFF);
            nextBlock3 = llList2Integer(data, 3);
            nextBlock3 = llList2Integer(data, 3);
            lslAESStateX3Y0 = ((nextBlock3 >> 24) & 0xFF);
            _lslAESStateX3Y0 = ((nextBlock3 >> 24) & 0xFF);
            lslAESStateX3Y1 = ((nextBlock3 >> 16) & 0xFF);
            _lslAESStateX3Y1 = ((nextBlock3 >> 16) & 0xFF);
            lslAESStateX3Y2 = ((nextBlock3 >> 8 ) & 0xFF);
            _lslAESStateX3Y2 = ((nextBlock3 >> 8 ) & 0xFF);
            lslAESStateX3Y3 = ((nextBlock3      ) & 0xFF);
            _lslAESStateX3Y3 = ((nextBlock3      ) & 0xFF);
         }
         }
         } else if (lslAESMode == LSLAES_MODE_CFB_ID()) {
         } else if (_lslAESMode == LSLAES_MODE_CFB_ID()) {
         if (SUPPORTS_MODE(LSLAES_MODE_CFB())) {
         if (SUPPORTS_MODE(LSLAES_MODE_CFB())) {
            lslAESStateX0Y0 = ((prevBlock0 >> 24) & 0xFF);
            _lslAESStateX0Y0 = ((prevBlock0 >> 24) & 0xFF);
            lslAESStateX0Y1 = ((prevBlock0 >> 16) & 0xFF);
            _lslAESStateX0Y1 = ((prevBlock0 >> 16) & 0xFF);
            lslAESStateX0Y2 = ((prevBlock0 >> 8 ) & 0xFF);
            _lslAESStateX0Y2 = ((prevBlock0 >> 8 ) & 0xFF);
            lslAESStateX0Y3 = ((prevBlock0      ) & 0xFF);
            _lslAESStateX0Y3 = ((prevBlock0      ) & 0xFF);
 
 
            lslAESStateX1Y0 = ((prevBlock1 >> 24) & 0xFF);
            _lslAESStateX1Y0 = ((prevBlock1 >> 24) & 0xFF);
            lslAESStateX1Y1 = ((prevBlock1 >> 16) & 0xFF);
            _lslAESStateX1Y1 = ((prevBlock1 >> 16) & 0xFF);
            lslAESStateX1Y2 = ((prevBlock1 >> 8 ) & 0xFF);
            _lslAESStateX1Y2 = ((prevBlock1 >> 8 ) & 0xFF);
            lslAESStateX1Y3 = ((prevBlock1      ) & 0xFF);
            _lslAESStateX1Y3 = ((prevBlock1      ) & 0xFF);
 
 
            lslAESStateX2Y0 = ((prevBlock2 >> 24) & 0xFF);
            _lslAESStateX2Y0 = ((prevBlock2 >> 24) & 0xFF);
            lslAESStateX2Y1 = ((prevBlock2 >> 16) & 0xFF);
            _lslAESStateX2Y1 = ((prevBlock2 >> 16) & 0xFF);
            lslAESStateX2Y2 = ((prevBlock2 >> 8 ) & 0xFF);
            _lslAESStateX2Y2 = ((prevBlock2 >> 8 ) & 0xFF);
            lslAESStateX2Y3 = ((prevBlock2      ) & 0xFF);
            _lslAESStateX2Y3 = ((prevBlock2      ) & 0xFF);
 
 
            lslAESStateX3Y0 = ((prevBlock3 >> 24) & 0xFF);
            _lslAESStateX3Y0 = ((prevBlock3 >> 24) & 0xFF);
            lslAESStateX3Y1 = ((prevBlock3 >> 16) & 0xFF);
            _lslAESStateX3Y1 = ((prevBlock3 >> 16) & 0xFF);
            lslAESStateX3Y2 = ((prevBlock3 >> 8 ) & 0xFF);
            _lslAESStateX3Y2 = ((prevBlock3 >> 8 ) & 0xFF);
            lslAESStateX3Y3 = ((prevBlock3      ) & 0xFF);
            _lslAESStateX3Y3 = ((prevBlock3      ) & 0xFF);
         }
         }
         }
         }
   
   
         if (lslAESMode == LSLAES_MODE_CFB_ID()) {
         if (_lslAESMode == LSLAES_MODE_CFB_ID()) {
         if (SUPPORTS_MODE(LSLAES_MODE_CFB())) {
         if (SUPPORTS_MODE(LSLAES_MODE_CFB())) {
            lslAESPerformCipher(); // CFB doesn't need inverse cipher
            _lslAESPerformCipher(); // CFB doesn't need inverse cipher
         }
         }
         } else if (SUPPORTS_MODE(LSLAES_MODE_CBC())) {
         } else if (SUPPORTS_MODE(LSLAES_MODE_CBC())) {
             j = lslAESRounds;
             j = _lslAESRounds;
             do {
             do {
                 if (j < lslAESRounds) {
                 if (j < _lslAESRounds) {
                 lslAESInvertShiftRows();
                 _lslAESInvertShiftRows();
                 lslAESInvertSubBytes();
                 _lslAESInvertSubBytes();
                 }
                 }
                 lslAESAddRoundKey(j);
                 _lslAESAddRoundKey(j);
                 if (j && (j < lslAESRounds)) {
                 if (j && (j < _lslAESRounds)) {
                 lslAESInvertMixColumns();
                 _lslAESInvertMixColumns();
                 }
                 }
             } while ((--j) >= 0);
             } while ((--j) >= 0);
Line 892: Line 659:
   
   
         // Ciphertext is generated differently by different modes
         // Ciphertext is generated differently by different modes
         if (lslAESMode == LSLAES_MODE_CBC_ID()) {
         if (_lslAESMode == LSLAES_MODE_CBC_ID()) {
         if (SUPPORTS_MODE(LSLAES_MODE_CBC())) {
         if (SUPPORTS_MODE(LSLAES_MODE_CBC())) {
            // For CBC we XOR with previous block before output
            // For CBC we XOR with previous block before output
            output = (output = []) + output + [
            output = (output = []) + output + [
                prevBlock0 ^  
                prevBlock0 ^  
                ((lslAESStateX0Y0 << 24) | (lslAESStateX0Y1 << 16) |  
                ((_lslAESStateX0Y0 << 24) | (_lslAESStateX0Y1 << 16) |  
                    (lslAESStateX0Y2 << 8) | (lslAESStateX0Y3)),
                    (_lslAESStateX0Y2 << 8) | (_lslAESStateX0Y3)),
                prevBlock1 ^  
                prevBlock1 ^  
                ((lslAESStateX1Y0 << 24) | (lslAESStateX1Y1 << 16) |  
                ((_lslAESStateX1Y0 << 24) | (_lslAESStateX1Y1 << 16) |  
                    (lslAESStateX1Y2 << 8) | (lslAESStateX1Y3)),
                    (_lslAESStateX1Y2 << 8) | (_lslAESStateX1Y3)),
                prevBlock2 ^  
                prevBlock2 ^  
                ((lslAESStateX2Y0 << 24) | (lslAESStateX2Y1 << 16) |  
                ((_lslAESStateX2Y0 << 24) | (_lslAESStateX2Y1 << 16) |  
                    (lslAESStateX2Y2 << 8) | (lslAESStateX2Y3)),
                    (_lslAESStateX2Y2 << 8) | (_lslAESStateX2Y3)),
                prevBlock3 ^  
                prevBlock3 ^  
                ((lslAESStateX3Y0 << 24) | (lslAESStateX3Y1 << 16) |  
                ((_lslAESStateX3Y0 << 24) | (_lslAESStateX3Y1 << 16) |  
                    (lslAESStateX3Y2 << 8) | (lslAESStateX3Y3))
                    (_lslAESStateX3Y2 << 8) | (_lslAESStateX3Y3))
            ];
            ];
 
 
Line 925: Line 692:
             output = (output = []) + output + [
             output = (output = []) + output + [
                 prevBlock0 ^  
                 prevBlock0 ^  
                 ((lslAESStateX0Y0 << 24) | (lslAESStateX0Y1 << 16) |  
                 ((_lslAESStateX0Y0 << 24) | (_lslAESStateX0Y1 << 16) |  
                     (lslAESStateX0Y2 << 8) | (lslAESStateX0Y3)),
                     (_lslAESStateX0Y2 << 8) | (_lslAESStateX0Y3)),
                 prevBlock1 ^  
                 prevBlock1 ^  
                 ((lslAESStateX1Y0 << 24) | (lslAESStateX1Y1 << 16) |  
                 ((_lslAESStateX1Y0 << 24) | (_lslAESStateX1Y1 << 16) |  
                     (lslAESStateX1Y2 << 8) | (lslAESStateX1Y3)),
                     (_lslAESStateX1Y2 << 8) | (_lslAESStateX1Y3)),
                 prevBlock2 ^  
                 prevBlock2 ^  
                 ((lslAESStateX2Y0 << 24) | (lslAESStateX2Y1 << 16) |  
                 ((_lslAESStateX2Y0 << 24) | (_lslAESStateX2Y1 << 16) |  
                     (lslAESStateX2Y2 << 8) | (lslAESStateX2Y3)),
                     (_lslAESStateX2Y2 << 8) | (_lslAESStateX2Y3)),
                 prevBlock3 ^  
                 prevBlock3 ^  
                 ((lslAESStateX3Y0 << 24) | (lslAESStateX3Y1 << 16) |  
                 ((_lslAESStateX3Y0 << 24) | (_lslAESStateX3Y1 << 16) |  
                     (lslAESStateX3Y2 << 8) | (lslAESStateX3Y3))
                     (_lslAESStateX3Y2 << 8) | (_lslAESStateX3Y3))
             ];
             ];
         }
         }
Line 952: Line 719:
// Padding must be performed before being called so that data is a multiple of  
// Padding must be performed before being called so that data is a multiple of  
// 128-bits long.
// 128-bits long.
list lslAESCipher(list data) {{
list _lslAESCipher(list data) {{
     // We must prime the state with the input vector
     // We must prime the state with the input vector
     lslAESLoadInputVector();
     _lslAESLoadInputVector();
   
   
     integer l = (data != []);
     integer l = (data != []);
Line 962: Line 729:
     while (l > 0) {
     while (l > 0) {
         // Different modes treat blocks differently
         // Different modes treat blocks differently
         if (lslAESMode == LSLAES_MODE_CBC_ID()) {
         if (_lslAESMode == LSLAES_MODE_CBC_ID()) {
         if (SUPPORTS_MODE(LSLAES_MODE_CBC())) {
         if (SUPPORTS_MODE(LSLAES_MODE_CBC())) {
            // For CBC we XOR with the previous block to reduce  
            // For CBC we XOR with the previous block to reduce  
            // chances of patterns occurring
            // chances of patterns occurring
            j = llList2Integer(data, 0);
            j = llList2Integer(data, 0);
            lslAESStateX0Y0 = lslAESStateX0Y0 ^ ((j >> 24) & 0xFF);
            _lslAESStateX0Y0 = _lslAESStateX0Y0 ^ ((j >> 24) & 0xFF);
            lslAESStateX0Y1 = lslAESStateX0Y1 ^ ((j >> 16) & 0xFF);
            _lslAESStateX0Y1 = _lslAESStateX0Y1 ^ ((j >> 16) & 0xFF);
            lslAESStateX0Y2 = lslAESStateX0Y2 ^ ((j >> 8 ) & 0xFF);
            _lslAESStateX0Y2 = _lslAESStateX0Y2 ^ ((j >> 8 ) & 0xFF);
            lslAESStateX0Y3 = lslAESStateX0Y3 ^ ((j      ) & 0xFF);
            _lslAESStateX0Y3 = _lslAESStateX0Y3 ^ ((j      ) & 0xFF);
            j = llList2Integer(data, 1);
            j = llList2Integer(data, 1);
            lslAESStateX1Y0 = lslAESStateX1Y0 ^ ((j >> 24) & 0xFF);
            _lslAESStateX1Y0 = _lslAESStateX1Y0 ^ ((j >> 24) & 0xFF);
            lslAESStateX1Y1 = lslAESStateX1Y1 ^ ((j >> 16) & 0xFF);
            _lslAESStateX1Y1 = _lslAESStateX1Y1 ^ ((j >> 16) & 0xFF);
            lslAESStateX1Y2 = lslAESStateX1Y2 ^ ((j >> 8 ) & 0xFF);
            _lslAESStateX1Y2 = _lslAESStateX1Y2 ^ ((j >> 8 ) & 0xFF);
            lslAESStateX1Y3 = lslAESStateX1Y3 ^ ((j      ) & 0xFF);
            _lslAESStateX1Y3 = _lslAESStateX1Y3 ^ ((j      ) & 0xFF);
            j = llList2Integer(data, 2);
            j = llList2Integer(data, 2);
            lslAESStateX2Y0 = lslAESStateX2Y0 ^ ((j >> 24) & 0xFF);
            _lslAESStateX2Y0 = _lslAESStateX2Y0 ^ ((j >> 24) & 0xFF);
            lslAESStateX2Y1 = lslAESStateX2Y1 ^ ((j >> 16) & 0xFF);
            _lslAESStateX2Y1 = _lslAESStateX2Y1 ^ ((j >> 16) & 0xFF);
            lslAESStateX2Y2 = lslAESStateX2Y2 ^ ((j >> 8 ) & 0xFF);
            _lslAESStateX2Y2 = _lslAESStateX2Y2 ^ ((j >> 8 ) & 0xFF);
            lslAESStateX2Y3 = lslAESStateX2Y3 ^ ((j      ) & 0xFF);
            _lslAESStateX2Y3 = _lslAESStateX2Y3 ^ ((j      ) & 0xFF);
            j = llList2Integer(data, 3);
            j = llList2Integer(data, 3);
            lslAESStateX3Y0 = lslAESStateX3Y0 ^ ((j >> 24) & 0xFF);
            _lslAESStateX3Y0 = _lslAESStateX3Y0 ^ ((j >> 24) & 0xFF);
            lslAESStateX3Y1 = lslAESStateX3Y1 ^ ((j >> 16) & 0xFF);
            _lslAESStateX3Y1 = _lslAESStateX3Y1 ^ ((j >> 16) & 0xFF);
            lslAESStateX3Y2 = lslAESStateX3Y2 ^ ((j >> 8 ) & 0xFF);
            _lslAESStateX3Y2 = _lslAESStateX3Y2 ^ ((j >> 8 ) & 0xFF);
            lslAESStateX3Y3 = lslAESStateX3Y3 ^ ((j      ) & 0xFF);
            _lslAESStateX3Y3 = _lslAESStateX3Y3 ^ ((j      ) & 0xFF);
         }
         }
         }
         }
   
   
         lslAESPerformCipher();
         _lslAESPerformCipher();
   
   
         if (lslAESMode == LSLAES_MODE_CFB_ID()) {
         if (_lslAESMode == LSLAES_MODE_CFB_ID()) {
         if (SUPPORTS_MODE(LSLAES_MODE_CFB())) {
         if (SUPPORTS_MODE(LSLAES_MODE_CFB())) {
            // For CFB we XOR blocks and carry them to the next  
            // For CFB we XOR blocks and carry them to the next  
            // stage (by keeping the result in state)
            // stage (by keeping the result in state)
            j = llList2Integer(data, 0);
            j = llList2Integer(data, 0);
            lslAESStateX0Y0 = lslAESStateX0Y0 ^ ((j >> 24) & 0xFF);
            _lslAESStateX0Y0 = _lslAESStateX0Y0 ^ ((j >> 24) & 0xFF);
            lslAESStateX0Y1 = lslAESStateX0Y1 ^ ((j >> 16) & 0xFF);
            _lslAESStateX0Y1 = _lslAESStateX0Y1 ^ ((j >> 16) & 0xFF);
            lslAESStateX0Y2 = lslAESStateX0Y2 ^ ((j >> 8 ) & 0xFF);
            _lslAESStateX0Y2 = _lslAESStateX0Y2 ^ ((j >> 8 ) & 0xFF);
            lslAESStateX0Y3 = lslAESStateX0Y3 ^ ((j      ) & 0xFF);
            _lslAESStateX0Y3 = _lslAESStateX0Y3 ^ ((j      ) & 0xFF);
            j = llList2Integer(data, 1);
            j = llList2Integer(data, 1);
            lslAESStateX1Y0 = lslAESStateX1Y0 ^ ((j >> 24) & 0xFF);
            _lslAESStateX1Y0 = _lslAESStateX1Y0 ^ ((j >> 24) & 0xFF);
            lslAESStateX1Y1 = lslAESStateX1Y1 ^ ((j >> 16) & 0xFF);
            _lslAESStateX1Y1 = _lslAESStateX1Y1 ^ ((j >> 16) & 0xFF);
            lslAESStateX1Y2 = lslAESStateX1Y2 ^ ((j >> 8 ) & 0xFF);
            _lslAESStateX1Y2 = _lslAESStateX1Y2 ^ ((j >> 8 ) & 0xFF);
            lslAESStateX1Y3 = lslAESStateX1Y3 ^ ((j      ) & 0xFF);
            _lslAESStateX1Y3 = _lslAESStateX1Y3 ^ ((j      ) & 0xFF);
            j = llList2Integer(data, 2);
            j = llList2Integer(data, 2);
            lslAESStateX2Y0 = lslAESStateX2Y0 ^ ((j >> 24) & 0xFF);
            _lslAESStateX2Y0 = _lslAESStateX2Y0 ^ ((j >> 24) & 0xFF);
            lslAESStateX2Y1 = lslAESStateX2Y1 ^ ((j >> 16) & 0xFF);
            _lslAESStateX2Y1 = _lslAESStateX2Y1 ^ ((j >> 16) & 0xFF);
            lslAESStateX2Y2 = lslAESStateX2Y2 ^ ((j >> 8 ) & 0xFF);
            _lslAESStateX2Y2 = _lslAESStateX2Y2 ^ ((j >> 8 ) & 0xFF);
            lslAESStateX2Y3 = lslAESStateX2Y3 ^ ((j      ) & 0xFF);
            _lslAESStateX2Y3 = _lslAESStateX2Y3 ^ ((j      ) & 0xFF);
            j = llList2Integer(data, 3);
            j = llList2Integer(data, 3);
            lslAESStateX3Y0 = lslAESStateX3Y0 ^ ((j >> 24) & 0xFF);
            _lslAESStateX3Y0 = _lslAESStateX3Y0 ^ ((j >> 24) & 0xFF);
            lslAESStateX3Y1 = lslAESStateX3Y1 ^ ((j >> 16) & 0xFF);
            _lslAESStateX3Y1 = _lslAESStateX3Y1 ^ ((j >> 16) & 0xFF);
            lslAESStateX3Y2 = lslAESStateX3Y2 ^ ((j >> 8 ) & 0xFF);
            _lslAESStateX3Y2 = _lslAESStateX3Y2 ^ ((j >> 8 ) & 0xFF);
            lslAESStateX3Y3 = lslAESStateX3Y3 ^ ((j      ) & 0xFF);
            _lslAESStateX3Y3 = _lslAESStateX3Y3 ^ ((j      ) & 0xFF);
         }
         }
         }
         }
   
   
         output = (output = []) + output + [
         output = (output = []) + output + [
             (lslAESStateX0Y0 << 24) | (lslAESStateX0Y1 << 16) |  
             (_lslAESStateX0Y0 << 24) | (_lslAESStateX0Y1 << 16) |  
                 (lslAESStateX0Y2 << 8) | lslAESStateX0Y3,
                 (_lslAESStateX0Y2 << 8) | _lslAESStateX0Y3,
             (lslAESStateX1Y0 << 24) | (lslAESStateX1Y1 << 16) |  
             (_lslAESStateX1Y0 << 24) | (_lslAESStateX1Y1 << 16) |  
                 (lslAESStateX1Y2 << 8) | lslAESStateX1Y3,
                 (_lslAESStateX1Y2 << 8) | _lslAESStateX1Y3,
             (lslAESStateX2Y0 << 24) | (lslAESStateX2Y1 << 16) |  
             (_lslAESStateX2Y0 << 24) | (_lslAESStateX2Y1 << 16) |  
                 (lslAESStateX2Y2 << 8) | lslAESStateX2Y3,
                 (_lslAESStateX2Y2 << 8) | _lslAESStateX2Y3,
             (lslAESStateX3Y0 << 24) | (lslAESStateX3Y1 << 16) |  
             (_lslAESStateX3Y0 << 24) | (_lslAESStateX3Y1 << 16) |  
                 (lslAESStateX3Y2 << 8) | lslAESStateX3Y3
                 (_lslAESStateX3Y2 << 8) | _lslAESStateX3Y3
         ];
         ];
   
   
Line 1,042: Line 809:
// for convenience with CBF and OBF modes (which perform a cipher in  
// for convenience with CBF and OBF modes (which perform a cipher in  
// order to decrypt data).
// order to decrypt data).
lslAESPerformCipher() {{
_lslAESPerformCipher() {{
integer j = 0;
integer j = 0;
do {
do {
if (j) {
if (j) {
         lslAESSubBytes();
         _lslAESSubBytes();
     lslAESShiftRows();
     _lslAESShiftRows();
     if (j < lslAESRounds) {
     if (j < _lslAESRounds) {
         lslAESMixColumns();
         _lslAESMixColumns();
     }
     }
}
}
     lslAESAddRoundKey(j);
     _lslAESAddRoundKey(j);
} while ((++j) <= lslAESRounds);
} while ((++j) <= _lslAESRounds);
}}
}}
   
   
// Expands the input vector for use in block differentiation
// Expands the input vector for use in block differentiation
// pragma inline
// pragma inline
lslAESLoadInputVector() {{
_lslAESLoadInputVector() {{
     lslAESStateX0Y0 = (lslAESInputVector0 >> 24) & 0xFF;
     _lslAESStateX0Y0 = (_lslAESInputVector0 >> 24) & 0xFF;
     lslAESStateX0Y1 = (lslAESInputVector0 >> 16) & 0xFF;
     _lslAESStateX0Y1 = (_lslAESInputVector0 >> 16) & 0xFF;
     lslAESStateX0Y2 = (lslAESInputVector0 >> 8 ) & 0xFF;
     _lslAESStateX0Y2 = (_lslAESInputVector0 >> 8 ) & 0xFF;
     lslAESStateX0Y3 = (lslAESInputVector0     ) & 0xFF;
     _lslAESStateX0Y3 = (_lslAESInputVector0     ) & 0xFF;
   
   
     lslAESStateX1Y0 = (lslAESInputVector1 >> 24) & 0xFF;
     _lslAESStateX1Y0 = (_lslAESInputVector1 >> 24) & 0xFF;
     lslAESStateX1Y1 = (lslAESInputVector1 >> 16) & 0xFF;
     _lslAESStateX1Y1 = (_lslAESInputVector1 >> 16) & 0xFF;
     lslAESStateX1Y2 = (lslAESInputVector1 >> 8 ) & 0xFF;
     _lslAESStateX1Y2 = (_lslAESInputVector1 >> 8 ) & 0xFF;
     lslAESStateX1Y3 = (lslAESInputVector1     ) & 0xFF;
     _lslAESStateX1Y3 = (_lslAESInputVector1     ) & 0xFF;
   
   
     lslAESStateX2Y0 = (lslAESInputVector2 >> 24) & 0xFF;
     _lslAESStateX2Y0 = (_lslAESInputVector2 >> 24) & 0xFF;
     lslAESStateX2Y1 = (lslAESInputVector2 >> 16) & 0xFF;
     _lslAESStateX2Y1 = (_lslAESInputVector2 >> 16) & 0xFF;
     lslAESStateX2Y2 = (lslAESInputVector2 >> 8 ) & 0xFF;
     _lslAESStateX2Y2 = (_lslAESInputVector2 >> 8 ) & 0xFF;
     lslAESStateX2Y3 = (lslAESInputVector2     ) & 0xFF;
     _lslAESStateX2Y3 = (_lslAESInputVector2     ) & 0xFF;
   
   
     lslAESStateX3Y0 = (lslAESInputVector3 >> 24) & 0xFF;
     _lslAESStateX3Y0 = (_lslAESInputVector3 >> 24) & 0xFF;
     lslAESStateX3Y1 = (lslAESInputVector3 >> 16) & 0xFF;
     _lslAESStateX3Y1 = (_lslAESInputVector3 >> 16) & 0xFF;
     lslAESStateX3Y2 = (lslAESInputVector3 >> 8 ) & 0xFF;
     _lslAESStateX3Y2 = (_lslAESInputVector3 >> 8 ) & 0xFF;
     lslAESStateX3Y3 = (lslAESInputVector3     ) & 0xFF;
     _lslAESStateX3Y3 = (_lslAESInputVector3     ) & 0xFF;
}}
}}
   
   
Line 1,088: Line 855:
// XORs the value with RoundKey values
// XORs the value with RoundKey values
// pragma inline
// pragma inline
lslAESAddRoundKey(integer round) {{
_lslAESAddRoundKey(integer round) {{
     round = round << 2;
     round = round << 2;
   
   
     integer t = llList2Integer(lslAESRoundKey, round);
     integer t = llList2Integer(_lslAESRoundKey, round);
     lslAESStateX0Y0 = lslAESStateX0Y0 ^ ((t >> 24) & 0xFF);
     _lslAESStateX0Y0 = _lslAESStateX0Y0 ^ ((t >> 24) & 0xFF);
     lslAESStateX0Y1 = lslAESStateX0Y1 ^ ((t >> 16) & 0xFF);
     _lslAESStateX0Y1 = _lslAESStateX0Y1 ^ ((t >> 16) & 0xFF);
     lslAESStateX0Y2 = lslAESStateX0Y2 ^ ((t >> 8 ) & 0xFF);
     _lslAESStateX0Y2 = _lslAESStateX0Y2 ^ ((t >> 8 ) & 0xFF);
     lslAESStateX0Y3 = lslAESStateX0Y3 ^ ((t      ) & 0xFF);
     _lslAESStateX0Y3 = _lslAESStateX0Y3 ^ ((t      ) & 0xFF);
   
   
     t = llList2Integer(lslAESRoundKey, ++round);
     t = llList2Integer(_lslAESRoundKey, ++round);
     lslAESStateX1Y0 = lslAESStateX1Y0 ^ ((t >> 24) & 0xFF);
     _lslAESStateX1Y0 = _lslAESStateX1Y0 ^ ((t >> 24) & 0xFF);
     lslAESStateX1Y1 = lslAESStateX1Y1 ^ ((t >> 16) & 0xFF);
     _lslAESStateX1Y1 = _lslAESStateX1Y1 ^ ((t >> 16) & 0xFF);
     lslAESStateX1Y2 = lslAESStateX1Y2 ^ ((t >> 8 ) & 0xFF);
     _lslAESStateX1Y2 = _lslAESStateX1Y2 ^ ((t >> 8 ) & 0xFF);
     lslAESStateX1Y3 = lslAESStateX1Y3 ^ ((t      ) & 0xFF);
     _lslAESStateX1Y3 = _lslAESStateX1Y3 ^ ((t      ) & 0xFF);
   
   
     t = llList2Integer(lslAESRoundKey, ++round);
     t = llList2Integer(_lslAESRoundKey, ++round);
     lslAESStateX2Y0 = lslAESStateX2Y0 ^ ((t >> 24) & 0xFF);
     _lslAESStateX2Y0 = _lslAESStateX2Y0 ^ ((t >> 24) & 0xFF);
     lslAESStateX2Y1 = lslAESStateX2Y1 ^ ((t >> 16) & 0xFF);
     _lslAESStateX2Y1 = _lslAESStateX2Y1 ^ ((t >> 16) & 0xFF);
     lslAESStateX2Y2 = lslAESStateX2Y2 ^ ((t >> 8 ) & 0xFF);
     _lslAESStateX2Y2 = _lslAESStateX2Y2 ^ ((t >> 8 ) & 0xFF);
     lslAESStateX2Y3 = lslAESStateX2Y3 ^ ((t      ) & 0xFF);
     _lslAESStateX2Y3 = _lslAESStateX2Y3 ^ ((t      ) & 0xFF);
   
   
     t = llList2Integer(lslAESRoundKey, ++round);
     t = llList2Integer(_lslAESRoundKey, ++round);
     lslAESStateX3Y0 = lslAESStateX3Y0 ^ ((t >> 24) & 0xFF);
     _lslAESStateX3Y0 = _lslAESStateX3Y0 ^ ((t >> 24) & 0xFF);
     lslAESStateX3Y1 = lslAESStateX3Y1 ^ ((t >> 16) & 0xFF);
     _lslAESStateX3Y1 = _lslAESStateX3Y1 ^ ((t >> 16) & 0xFF);
     lslAESStateX3Y2 = lslAESStateX3Y2 ^ ((t >> 8 ) & 0xFF);
     _lslAESStateX3Y2 = _lslAESStateX3Y2 ^ ((t >> 8 ) & 0xFF);
     lslAESStateX3Y3 = lslAESStateX3Y3 ^ ((t      ) & 0xFF);
     _lslAESStateX3Y3 = _lslAESStateX3Y3 ^ ((t      ) & 0xFF);
}}
}}
   
   
// Performs a substitution using SBox
// Performs a substitution using SBox
// pragma inline
// pragma inline
lslAESSubBytes() {{
_lslAESSubBytes() {{
     lslAESStateX0Y0 = lslAESGetSBoxByte(lslAESStateX0Y0);
     _lslAESStateX0Y0 = _lslAESGetSBoxByte(_lslAESStateX0Y0);
     lslAESStateX0Y1 = lslAESGetSBoxByte(lslAESStateX0Y1);
     _lslAESStateX0Y1 = _lslAESGetSBoxByte(_lslAESStateX0Y1);
     lslAESStateX0Y2 = lslAESGetSBoxByte(lslAESStateX0Y2);
     _lslAESStateX0Y2 = _lslAESGetSBoxByte(_lslAESStateX0Y2);
     lslAESStateX0Y3 = lslAESGetSBoxByte(lslAESStateX0Y3);
     _lslAESStateX0Y3 = _lslAESGetSBoxByte(_lslAESStateX0Y3);
     lslAESStateX1Y0 = lslAESGetSBoxByte(lslAESStateX1Y0);
     _lslAESStateX1Y0 = _lslAESGetSBoxByte(_lslAESStateX1Y0);
     lslAESStateX1Y1 = lslAESGetSBoxByte(lslAESStateX1Y1);
     _lslAESStateX1Y1 = _lslAESGetSBoxByte(_lslAESStateX1Y1);
     lslAESStateX1Y2 = lslAESGetSBoxByte(lslAESStateX1Y2);
     _lslAESStateX1Y2 = _lslAESGetSBoxByte(_lslAESStateX1Y2);
     lslAESStateX1Y3 = lslAESGetSBoxByte(lslAESStateX1Y3);
     _lslAESStateX1Y3 = _lslAESGetSBoxByte(_lslAESStateX1Y3);
     lslAESStateX2Y0 = lslAESGetSBoxByte(lslAESStateX2Y0);
     _lslAESStateX2Y0 = _lslAESGetSBoxByte(_lslAESStateX2Y0);
     lslAESStateX2Y1 = lslAESGetSBoxByte(lslAESStateX2Y1);
     _lslAESStateX2Y1 = _lslAESGetSBoxByte(_lslAESStateX2Y1);
     lslAESStateX2Y2 = lslAESGetSBoxByte(lslAESStateX2Y2);
     _lslAESStateX2Y2 = _lslAESGetSBoxByte(_lslAESStateX2Y2);
     lslAESStateX2Y3 = lslAESGetSBoxByte(lslAESStateX2Y3);
     _lslAESStateX2Y3 = _lslAESGetSBoxByte(_lslAESStateX2Y3);
     lslAESStateX3Y0 = lslAESGetSBoxByte(lslAESStateX3Y0);
     _lslAESStateX3Y0 = _lslAESGetSBoxByte(_lslAESStateX3Y0);
     lslAESStateX3Y1 = lslAESGetSBoxByte(lslAESStateX3Y1);
     _lslAESStateX3Y1 = _lslAESGetSBoxByte(_lslAESStateX3Y1);
     lslAESStateX3Y2 = lslAESGetSBoxByte(lslAESStateX3Y2);
     _lslAESStateX3Y2 = _lslAESGetSBoxByte(_lslAESStateX3Y2);
     lslAESStateX3Y3 = lslAESGetSBoxByte(lslAESStateX3Y3);
     _lslAESStateX3Y3 = _lslAESGetSBoxByte(_lslAESStateX3Y3);
}}
}}
   
   
// Performs a substition using SBoxInverted
// Performs a substition using SBoxInverted
// pragma inline
// pragma inline
lslAESInvertSubBytes() {{
_lslAESInvertSubBytes() {{
     lslAESStateX0Y0 = lslAESGetSBoxInvertedByte(lslAESStateX0Y0);
     _lslAESStateX0Y0 = _lslAESGetSBoxInvertedByte(_lslAESStateX0Y0);
     lslAESStateX0Y1 = lslAESGetSBoxInvertedByte(lslAESStateX0Y1);
     _lslAESStateX0Y1 = _lslAESGetSBoxInvertedByte(_lslAESStateX0Y1);
     lslAESStateX0Y2 = lslAESGetSBoxInvertedByte(lslAESStateX0Y2);
     _lslAESStateX0Y2 = _lslAESGetSBoxInvertedByte(_lslAESStateX0Y2);
     lslAESStateX0Y3 = lslAESGetSBoxInvertedByte(lslAESStateX0Y3);
     _lslAESStateX0Y3 = _lslAESGetSBoxInvertedByte(_lslAESStateX0Y3);
     lslAESStateX1Y0 = lslAESGetSBoxInvertedByte(lslAESStateX1Y0);
     _lslAESStateX1Y0 = _lslAESGetSBoxInvertedByte(_lslAESStateX1Y0);
     lslAESStateX1Y1 = lslAESGetSBoxInvertedByte(lslAESStateX1Y1);
     _lslAESStateX1Y1 = _lslAESGetSBoxInvertedByte(_lslAESStateX1Y1);
     lslAESStateX1Y2 = lslAESGetSBoxInvertedByte(lslAESStateX1Y2);
     _lslAESStateX1Y2 = _lslAESGetSBoxInvertedByte(_lslAESStateX1Y2);
     lslAESStateX1Y3 = lslAESGetSBoxInvertedByte(lslAESStateX1Y3);
     _lslAESStateX1Y3 = _lslAESGetSBoxInvertedByte(_lslAESStateX1Y3);
     lslAESStateX2Y0 = lslAESGetSBoxInvertedByte(lslAESStateX2Y0);
     _lslAESStateX2Y0 = _lslAESGetSBoxInvertedByte(_lslAESStateX2Y0);
     lslAESStateX2Y1 = lslAESGetSBoxInvertedByte(lslAESStateX2Y1);
     _lslAESStateX2Y1 = _lslAESGetSBoxInvertedByte(_lslAESStateX2Y1);
     lslAESStateX2Y2 = lslAESGetSBoxInvertedByte(lslAESStateX2Y2);
     _lslAESStateX2Y2 = _lslAESGetSBoxInvertedByte(_lslAESStateX2Y2);
     lslAESStateX2Y3 = lslAESGetSBoxInvertedByte(lslAESStateX2Y3);
     _lslAESStateX2Y3 = _lslAESGetSBoxInvertedByte(_lslAESStateX2Y3);
     lslAESStateX3Y0 = lslAESGetSBoxInvertedByte(lslAESStateX3Y0);
     _lslAESStateX3Y0 = _lslAESGetSBoxInvertedByte(_lslAESStateX3Y0);
     lslAESStateX3Y1 = lslAESGetSBoxInvertedByte(lslAESStateX3Y1);
     _lslAESStateX3Y1 = _lslAESGetSBoxInvertedByte(_lslAESStateX3Y1);
     lslAESStateX3Y2 = lslAESGetSBoxInvertedByte(lslAESStateX3Y2);
     _lslAESStateX3Y2 = _lslAESGetSBoxInvertedByte(_lslAESStateX3Y2);
     lslAESStateX3Y3 = lslAESGetSBoxInvertedByte(lslAESStateX3Y3);
     _lslAESStateX3Y3 = _lslAESGetSBoxInvertedByte(_lslAESStateX3Y3);
}}
}}
   
   
Line 1,161: Line 928:
// Performs row shifts
// Performs row shifts
// pragma inline
// pragma inline
lslAESShiftRows() {{
_lslAESShiftRows() {{
     // Rotate first row 1 columns to left
     // Rotate first row 1 columns to left
     integer t = lslAESStateX0Y1;
     integer t = _lslAESStateX0Y1;
     lslAESStateX0Y1 = lslAESStateX1Y1;
     _lslAESStateX0Y1 = _lslAESStateX1Y1;
     lslAESStateX1Y1 = lslAESStateX2Y1;
     _lslAESStateX1Y1 = _lslAESStateX2Y1;
     lslAESStateX2Y1 = lslAESStateX3Y1;
     _lslAESStateX2Y1 = _lslAESStateX3Y1;
     lslAESStateX3Y1 = t;
     _lslAESStateX3Y1 = t;
   
   
     // Rotate second row 2 columns to left
     // Rotate second row 2 columns to left
     t = lslAESStateX0Y2;
     t = _lslAESStateX0Y2;
     lslAESStateX0Y2 = lslAESStateX2Y2;
     _lslAESStateX0Y2 = _lslAESStateX2Y2;
     lslAESStateX2Y2 = t;
     _lslAESStateX2Y2 = t;
   
   
     t = lslAESStateX1Y2;
     t = _lslAESStateX1Y2;
     lslAESStateX1Y2 = lslAESStateX3Y2;
     _lslAESStateX1Y2 = _lslAESStateX3Y2;
     lslAESStateX3Y2 = t;
     _lslAESStateX3Y2 = t;
   
   
     // Rotate third row 3 columns to left
     // Rotate third row 3 columns to left
     t = lslAESStateX0Y3;
     t = _lslAESStateX0Y3;
     lslAESStateX0Y3 = lslAESStateX3Y3;
     _lslAESStateX0Y3 = _lslAESStateX3Y3;
     lslAESStateX3Y3 = lslAESStateX2Y3;
     _lslAESStateX3Y3 = _lslAESStateX2Y3;
     lslAESStateX2Y3 = lslAESStateX1Y3;
     _lslAESStateX2Y3 = _lslAESStateX1Y3;
     lslAESStateX1Y3 = t;
     _lslAESStateX1Y3 = t;
}}
}}
   
   
// Undoes a set of row shifts
// Undoes a set of row shifts
// pragma inline
// pragma inline
lslAESInvertShiftRows() {{
_lslAESInvertShiftRows() {{
     // Rotate first row 1 columns to right
     // Rotate first row 1 columns to right
     integer t = lslAESStateX3Y1;
     integer t = _lslAESStateX3Y1;
     lslAESStateX3Y1 = lslAESStateX2Y1;
     _lslAESStateX3Y1 = _lslAESStateX2Y1;
     lslAESStateX2Y1 = lslAESStateX1Y1;
     _lslAESStateX2Y1 = _lslAESStateX1Y1;
     lslAESStateX1Y1 = lslAESStateX0Y1;
     _lslAESStateX1Y1 = _lslAESStateX0Y1;
     lslAESStateX0Y1 = t;
     _lslAESStateX0Y1 = t;
   
   
     // Rotate second row 2 columns to right
     // Rotate second row 2 columns to right
     t = lslAESStateX0Y2;
     t = _lslAESStateX0Y2;
     lslAESStateX0Y2 = lslAESStateX2Y2;
     _lslAESStateX0Y2 = _lslAESStateX2Y2;
     lslAESStateX2Y2 = t;
     _lslAESStateX2Y2 = t;
   
   
     t = lslAESStateX1Y2;
     t = _lslAESStateX1Y2;
     lslAESStateX1Y2 = lslAESStateX3Y2;
     _lslAESStateX1Y2 = _lslAESStateX3Y2;
     lslAESStateX3Y2 = t;
     _lslAESStateX3Y2 = t;
   
   
     // Rotate third row 3 columns to right
     // Rotate third row 3 columns to right
     t = lslAESStateX0Y3;
     t = _lslAESStateX0Y3;
     lslAESStateX0Y3 = lslAESStateX1Y3;
     _lslAESStateX0Y3 = _lslAESStateX1Y3;
     lslAESStateX1Y3 = lslAESStateX2Y3;
     _lslAESStateX1Y3 = _lslAESStateX2Y3;
     lslAESStateX2Y3 = lslAESStateX3Y3;
     _lslAESStateX2Y3 = _lslAESStateX3Y3;
     lslAESStateX3Y3 = t;
     _lslAESStateX3Y3 = t;
}}
}}
   
   
// Mixes columns of the state
// Mixes columns of the state
// pragma inline
// pragma inline
lslAESMixColumns() {{
_lslAESMixColumns() {{
     integer t = lslAESStateX0Y0;
     integer t = _lslAESStateX0Y0;
     integer t1 = lslAESStateX0Y0 ^ lslAESStateX0Y1 ^  
     integer t1 = _lslAESStateX0Y0 ^ _lslAESStateX0Y1 ^  
         lslAESStateX0Y2 ^ lslAESStateX0Y3;
         _lslAESStateX0Y2 ^ _lslAESStateX0Y3;
   
   
     integer t2 = lslAESXTimes(lslAESStateX0Y0 ^ lslAESStateX0Y1);
     integer t2 = _lslAESXTimes(_lslAESStateX0Y0 ^ _lslAESStateX0Y1);
     lslAESStateX0Y0 = lslAESStateX0Y0 ^ t2 ^ t1;
     _lslAESStateX0Y0 = _lslAESStateX0Y0 ^ t2 ^ t1;
   
   
     t2 = lslAESXTimes(lslAESStateX0Y1 ^ lslAESStateX0Y2);
     t2 = _lslAESXTimes(_lslAESStateX0Y1 ^ _lslAESStateX0Y2);
     lslAESStateX0Y1 = lslAESStateX0Y1 ^ t2 ^ t1;
     _lslAESStateX0Y1 = _lslAESStateX0Y1 ^ t2 ^ t1;
   
   
     t2 = lslAESXTimes(lslAESStateX0Y2 ^ lslAESStateX0Y3);
     t2 = _lslAESXTimes(_lslAESStateX0Y2 ^ _lslAESStateX0Y3);
     lslAESStateX0Y2 = lslAESStateX0Y2 ^ t2 ^ t1;
     _lslAESStateX0Y2 = _lslAESStateX0Y2 ^ t2 ^ t1;
   
   
     t2 = lslAESXTimes(lslAESStateX0Y3 ^ t);
     t2 = _lslAESXTimes(_lslAESStateX0Y3 ^ t);
     lslAESStateX0Y3 = lslAESStateX0Y3 ^ t2 ^ t1;
     _lslAESStateX0Y3 = _lslAESStateX0Y3 ^ t2 ^ t1;
   
   
     t = lslAESStateX1Y0;
     t = _lslAESStateX1Y0;
     t1 = lslAESStateX1Y0 ^ lslAESStateX1Y1 ^ lslAESStateX1Y2 ^ lslAESStateX1Y3;
     t1 = _lslAESStateX1Y0 ^ _lslAESStateX1Y1 ^ _lslAESStateX1Y2 ^ _lslAESStateX1Y3;
   
   
     t2 = lslAESXTimes(lslAESStateX1Y0 ^ lslAESStateX1Y1);
     t2 = _lslAESXTimes(_lslAESStateX1Y0 ^ _lslAESStateX1Y1);
     lslAESStateX1Y0 = lslAESStateX1Y0 ^ t2 ^ t1;
     _lslAESStateX1Y0 = _lslAESStateX1Y0 ^ t2 ^ t1;
   
   
     t2 = lslAESXTimes(lslAESStateX1Y1 ^ lslAESStateX1Y2);
     t2 = _lslAESXTimes(_lslAESStateX1Y1 ^ _lslAESStateX1Y2);
     lslAESStateX1Y1 = lslAESStateX1Y1 ^ t2 ^ t1;
     _lslAESStateX1Y1 = _lslAESStateX1Y1 ^ t2 ^ t1;
   
   
     t2 = lslAESXTimes(lslAESStateX1Y2 ^ lslAESStateX1Y3);
     t2 = _lslAESXTimes(_lslAESStateX1Y2 ^ _lslAESStateX1Y3);
     lslAESStateX1Y2 = lslAESStateX1Y2 ^ t2 ^ t1;
     _lslAESStateX1Y2 = _lslAESStateX1Y2 ^ t2 ^ t1;
   
   
     t2 = lslAESXTimes(lslAESStateX1Y3 ^ t);
     t2 = _lslAESXTimes(_lslAESStateX1Y3 ^ t);
     lslAESStateX1Y3 = lslAESStateX1Y3 ^ t2 ^ t1;
     _lslAESStateX1Y3 = _lslAESStateX1Y3 ^ t2 ^ t1;
   
   
     t = lslAESStateX2Y0;
     t = _lslAESStateX2Y0;
     t1 = lslAESStateX2Y0 ^ lslAESStateX2Y1 ^ lslAESStateX2Y2 ^ lslAESStateX2Y3;
     t1 = _lslAESStateX2Y0 ^ _lslAESStateX2Y1 ^ _lslAESStateX2Y2 ^ _lslAESStateX2Y3;
   
   
     t2 = lslAESXTimes(lslAESStateX2Y0 ^ lslAESStateX2Y1);
     t2 = _lslAESXTimes(_lslAESStateX2Y0 ^ _lslAESStateX2Y1);
     lslAESStateX2Y0 = lslAESStateX2Y0 ^ t2 ^ t1;
     _lslAESStateX2Y0 = _lslAESStateX2Y0 ^ t2 ^ t1;
   
   
     t2 = lslAESXTimes(lslAESStateX2Y1 ^ lslAESStateX2Y2);
     t2 = _lslAESXTimes(_lslAESStateX2Y1 ^ _lslAESStateX2Y2);
     lslAESStateX2Y1 = lslAESStateX2Y1 ^ t2 ^ t1;
     _lslAESStateX2Y1 = _lslAESStateX2Y1 ^ t2 ^ t1;
   
   
     t2 = lslAESXTimes(lslAESStateX2Y2 ^ lslAESStateX2Y3);
     t2 = _lslAESXTimes(_lslAESStateX2Y2 ^ _lslAESStateX2Y3);
     lslAESStateX2Y2 = lslAESStateX2Y2 ^ t2 ^ t1;
     _lslAESStateX2Y2 = _lslAESStateX2Y2 ^ t2 ^ t1;
   
   
     t2 = lslAESXTimes(lslAESStateX2Y3 ^ t);
     t2 = _lslAESXTimes(_lslAESStateX2Y3 ^ t);
     lslAESStateX2Y3 = lslAESStateX2Y3 ^ t2 ^ t1;
     _lslAESStateX2Y3 = _lslAESStateX2Y3 ^ t2 ^ t1;
   
   
     t = lslAESStateX3Y0;
     t = _lslAESStateX3Y0;
     t1 = lslAESStateX3Y0 ^ lslAESStateX3Y1 ^ lslAESStateX3Y2 ^ lslAESStateX3Y3;
     t1 = _lslAESStateX3Y0 ^ _lslAESStateX3Y1 ^ _lslAESStateX3Y2 ^ _lslAESStateX3Y3;
   
   
     t2 = lslAESXTimes(lslAESStateX3Y0 ^ lslAESStateX3Y1);
     t2 = _lslAESXTimes(_lslAESStateX3Y0 ^ _lslAESStateX3Y1);
     lslAESStateX3Y0 = lslAESStateX3Y0 ^ t2 ^ t1;
     _lslAESStateX3Y0 = _lslAESStateX3Y0 ^ t2 ^ t1;
   
   
     t2 = lslAESXTimes(lslAESStateX3Y1 ^ lslAESStateX3Y2);
     t2 = _lslAESXTimes(_lslAESStateX3Y1 ^ _lslAESStateX3Y2);
     lslAESStateX3Y1 = lslAESStateX3Y1 ^ t2 ^ t1;
     _lslAESStateX3Y1 = _lslAESStateX3Y1 ^ t2 ^ t1;
   
   
     t2 = lslAESXTimes(lslAESStateX3Y2 ^ lslAESStateX3Y3);
     t2 = _lslAESXTimes(_lslAESStateX3Y2 ^ _lslAESStateX3Y3);
     lslAESStateX3Y2 = lslAESStateX3Y2 ^ t2 ^ t1;
     _lslAESStateX3Y2 = _lslAESStateX3Y2 ^ t2 ^ t1;
   
   
     t2 = lslAESXTimes(lslAESStateX3Y3 ^ t);
     t2 = _lslAESXTimes(_lslAESStateX3Y3 ^ t);
     lslAESStateX3Y3 = lslAESStateX3Y3 ^ t2 ^ t1;
     _lslAESStateX3Y3 = _lslAESStateX3Y3 ^ t2 ^ t1;
}}
}}
   
   
// Used when column mixing
// Used when column mixing
// pragma inline
// pragma inline
integer lslAESXTimes(integer x) {{
integer _lslAESXTimes(integer x) {{
     return ((x << 1) ^ (((x >> 7) & 1) * 0x1b)) & 0xFF;
     return ((x << 1) ^ (((x >> 7) & 1) * 0x1b)) & 0xFF;
}}
}}
   
   
// Used when column mixing
// Used when column mixing
integer lslAESMultiply(integer x, integer y) {{
integer _lslAESMultiply(integer x, integer y) {{
     integer xT  = lslAESXTimes(x);
     integer xT  = _lslAESXTimes(x);
     integer xT2 = lslAESXTimes(xT);
     integer xT2 = _lslAESXTimes(xT);
     integer xT3 = lslAESXTimes(xT2);
     integer xT3 = _lslAESXTimes(xT2);
   
   
     return (((y & 1) * x) ^ (((y >> 1) & 1) * xT) ^  
     return (((y & 1) * x) ^ (((y >> 1) & 1) * xT) ^  
             (((y >> 2) & 1) * xT2) ^ (((y >> 3) & 1) * xT3) ^  
             (((y >> 2) & 1) * xT2) ^ (((y >> 3) & 1) * xT3) ^  
             (((y >> 4) & 1) * lslAESXTimes(xT3))) & 0xFF;
             (((y >> 4) & 1) * _lslAESXTimes(xT3))) & 0xFF;
}}
}}
   
   
// Try to understand this at your own peril!
// Try to understand this at your own peril!
// pragma inline
// pragma inline
lslAESInvertMixColumns() {{
_lslAESInvertMixColumns() {{
     integer a = lslAESStateX0Y0;
     integer a = _lslAESStateX0Y0;
     integer b = lslAESStateX0Y1;
     integer b = _lslAESStateX0Y1;
     integer c = lslAESStateX0Y2;
     integer c = _lslAESStateX0Y2;
     integer d = lslAESStateX0Y3;
     integer d = _lslAESStateX0Y3;
   
   
     lslAESStateX0Y0 = lslAESMultiply(a, 0x0e) ^ lslAESMultiply(b, 0x0b) ^  
     _lslAESStateX0Y0 = _lslAESMultiply(a, 0x0e) ^ _lslAESMultiply(b, 0x0b) ^  
         lslAESMultiply(c, 0x0d) ^ lslAESMultiply(d, 0x09);
         _lslAESMultiply(c, 0x0d) ^ _lslAESMultiply(d, 0x09);
     lslAESStateX0Y1 = lslAESMultiply(a, 0x09) ^ lslAESMultiply(b, 0x0e) ^  
     _lslAESStateX0Y1 = _lslAESMultiply(a, 0x09) ^ _lslAESMultiply(b, 0x0e) ^  
         lslAESMultiply(c, 0x0b) ^ lslAESMultiply(d, 0x0d);
         _lslAESMultiply(c, 0x0b) ^ _lslAESMultiply(d, 0x0d);
     lslAESStateX0Y2 = lslAESMultiply(a, 0x0d) ^ lslAESMultiply(b, 0x09) ^  
     _lslAESStateX0Y2 = _lslAESMultiply(a, 0x0d) ^ _lslAESMultiply(b, 0x09) ^  
         lslAESMultiply(c, 0x0e) ^ lslAESMultiply(d, 0x0b);
         _lslAESMultiply(c, 0x0e) ^ _lslAESMultiply(d, 0x0b);
     lslAESStateX0Y3 = lslAESMultiply(a, 0x0b) ^ lslAESMultiply(b, 0x0d) ^  
     _lslAESStateX0Y3 = _lslAESMultiply(a, 0x0b) ^ _lslAESMultiply(b, 0x0d) ^  
         lslAESMultiply(c, 0x09) ^ lslAESMultiply(d, 0x0e);
         _lslAESMultiply(c, 0x09) ^ _lslAESMultiply(d, 0x0e);
   
   
     a = lslAESStateX1Y0;
     a = _lslAESStateX1Y0;
     b = lslAESStateX1Y1;
     b = _lslAESStateX1Y1;
     c = lslAESStateX1Y2;
     c = _lslAESStateX1Y2;
     d = lslAESStateX1Y3;
     d = _lslAESStateX1Y3;
   
   
     lslAESStateX1Y0 = lslAESMultiply(a, 0x0e) ^ lslAESMultiply(b, 0x0b) ^  
     _lslAESStateX1Y0 = _lslAESMultiply(a, 0x0e) ^ _lslAESMultiply(b, 0x0b) ^  
         lslAESMultiply(c, 0x0d) ^ lslAESMultiply(d, 0x09);
         _lslAESMultiply(c, 0x0d) ^ _lslAESMultiply(d, 0x09);
     lslAESStateX1Y1 = lslAESMultiply(a, 0x09) ^ lslAESMultiply(b, 0x0e) ^  
     _lslAESStateX1Y1 = _lslAESMultiply(a, 0x09) ^ _lslAESMultiply(b, 0x0e) ^  
         lslAESMultiply(c, 0x0b) ^ lslAESMultiply(d, 0x0d);
         _lslAESMultiply(c, 0x0b) ^ _lslAESMultiply(d, 0x0d);
     lslAESStateX1Y2 = lslAESMultiply(a, 0x0d) ^ lslAESMultiply(b, 0x09) ^  
     _lslAESStateX1Y2 = _lslAESMultiply(a, 0x0d) ^ _lslAESMultiply(b, 0x09) ^  
         lslAESMultiply(c, 0x0e) ^ lslAESMultiply(d, 0x0b);
         _lslAESMultiply(c, 0x0e) ^ _lslAESMultiply(d, 0x0b);
     lslAESStateX1Y3 = lslAESMultiply(a, 0x0b) ^ lslAESMultiply(b, 0x0d) ^  
     _lslAESStateX1Y3 = _lslAESMultiply(a, 0x0b) ^ _lslAESMultiply(b, 0x0d) ^  
         lslAESMultiply(c, 0x09) ^ lslAESMultiply(d, 0x0e);
         _lslAESMultiply(c, 0x09) ^ _lslAESMultiply(d, 0x0e);
   
   
     a = lslAESStateX2Y0;
     a = _lslAESStateX2Y0;
     b = lslAESStateX2Y1;
     b = _lslAESStateX2Y1;
     c = lslAESStateX2Y2;
     c = _lslAESStateX2Y2;
     d = lslAESStateX2Y3;
     d = _lslAESStateX2Y3;
   
   
     lslAESStateX2Y0 = lslAESMultiply(a, 0x0e) ^ lslAESMultiply(b, 0x0b) ^  
     _lslAESStateX2Y0 = _lslAESMultiply(a, 0x0e) ^ _lslAESMultiply(b, 0x0b) ^  
         lslAESMultiply(c, 0x0d) ^ lslAESMultiply(d, 0x09);
         _lslAESMultiply(c, 0x0d) ^ _lslAESMultiply(d, 0x09);
     lslAESStateX2Y1 = lslAESMultiply(a, 0x09) ^ lslAESMultiply(b, 0x0e) ^  
     _lslAESStateX2Y1 = _lslAESMultiply(a, 0x09) ^ _lslAESMultiply(b, 0x0e) ^  
         lslAESMultiply(c, 0x0b) ^ lslAESMultiply(d, 0x0d);
         _lslAESMultiply(c, 0x0b) ^ _lslAESMultiply(d, 0x0d);
     lslAESStateX2Y2 = lslAESMultiply(a, 0x0d) ^ lslAESMultiply(b, 0x09) ^  
     _lslAESStateX2Y2 = _lslAESMultiply(a, 0x0d) ^ _lslAESMultiply(b, 0x09) ^  
         lslAESMultiply(c, 0x0e) ^ lslAESMultiply(d, 0x0b);
         _lslAESMultiply(c, 0x0e) ^ _lslAESMultiply(d, 0x0b);
     lslAESStateX2Y3 = lslAESMultiply(a, 0x0b) ^ lslAESMultiply(b, 0x0d) ^  
     _lslAESStateX2Y3 = _lslAESMultiply(a, 0x0b) ^ _lslAESMultiply(b, 0x0d) ^  
         lslAESMultiply(c, 0x09) ^ lslAESMultiply(d, 0x0e);
         _lslAESMultiply(c, 0x09) ^ _lslAESMultiply(d, 0x0e);
   
   
     a = lslAESStateX3Y0;
     a = _lslAESStateX3Y0;
     b = lslAESStateX3Y1;
     b = _lslAESStateX3Y1;
     c = lslAESStateX3Y2;
     c = _lslAESStateX3Y2;
     d = lslAESStateX3Y3;
     d = _lslAESStateX3Y3;
   
   
     lslAESStateX3Y0 = lslAESMultiply(a, 0x0e) ^ lslAESMultiply(b, 0x0b) ^  
     _lslAESStateX3Y0 = _lslAESMultiply(a, 0x0e) ^ _lslAESMultiply(b, 0x0b) ^  
         lslAESMultiply(c, 0x0d) ^ lslAESMultiply(d, 0x09);
         _lslAESMultiply(c, 0x0d) ^ _lslAESMultiply(d, 0x09);
     lslAESStateX3Y1 = lslAESMultiply(a, 0x09) ^ lslAESMultiply(b, 0x0e) ^  
     _lslAESStateX3Y1 = _lslAESMultiply(a, 0x09) ^ _lslAESMultiply(b, 0x0e) ^  
         lslAESMultiply(c, 0x0b) ^ lslAESMultiply(d, 0x0d);
         _lslAESMultiply(c, 0x0b) ^ _lslAESMultiply(d, 0x0d);
     lslAESStateX3Y2 = lslAESMultiply(a, 0x0d) ^ lslAESMultiply(b, 0x09) ^  
     _lslAESStateX3Y2 = _lslAESMultiply(a, 0x0d) ^ _lslAESMultiply(b, 0x09) ^  
         lslAESMultiply(c, 0x0e) ^ lslAESMultiply(d, 0x0b);
         _lslAESMultiply(c, 0x0e) ^ _lslAESMultiply(d, 0x0b);
     lslAESStateX3Y3 = lslAESMultiply(a, 0x0b) ^ lslAESMultiply(b, 0x0d) ^  
     _lslAESStateX3Y3 = _lslAESMultiply(a, 0x0b) ^ _lslAESMultiply(b, 0x0d) ^  
         lslAESMultiply(c, 0x09) ^ lslAESMultiply(d, 0x0e);
         _lslAESMultiply(c, 0x09) ^ _lslAESMultiply(d, 0x0e);
}}
}}
   
   
Line 1,365: Line 1,132:
// Thanks to Strife Onizuka for providing optimisations to this function.
// Thanks to Strife Onizuka for providing optimisations to this function.
// pragma inline
// pragma inline
list lslAESKeyExpansion(list keyBytes) {{
list _lslAESKeyExpansion(list keyBytes) {{
     // Don't need the bit-count and the first round key is the key itself
     // Don't need the bit-count and the first round key is the key itself
     integer len = (
     integer len = (
         (
         (
             lslAESRoundKey = llDeleteSubList( // Remove header, copy into rounds
             _lslAESRoundKey = llDeleteSubList( // Remove header, copy into rounds
                 (lslAESRoundKey = keyBytes = []) + keyBytes,  
                 (_lslAESRoundKey = keyBytes = []) + keyBytes,  
                 0,  
                 0,  
                 0
                 0
Line 1,378: Line 1,145:
     // Check that we are within reasonable limits
     // Check that we are within reasonable limits
     if ((len < 4) || (len > 8)) {
     if ((len < 4) || (len > 8)) {
         lslAESRoundKey = [];
         _lslAESRoundKey = [];
         return ["Invalid key size; must be 128, 192, or 256 bits!"];
         return ["Invalid key size; must be 128, 192, or 256 bits!"];
     }
     }
   
   
     // Calculate the number of required rounds
     // Calculate the number of required rounds
     lslAESRounds = len + 6;
     _lslAESRounds = len + 6;
   
   
     // All others are found from previous keys
     // All others are found from previous keys
Line 1,389: Line 1,156:
     integer x = (len * 3) + 28;
     integer x = (len * 3) + 28;
   
   
     integer t = llList2Integer(lslAESRoundKey, -1);
     integer t = llList2Integer(_lslAESRoundKey, -1);
   
   
     do {
     do {
Line 1,395: Line 1,162:
             // Rotate by 1, SubWord and Nudge  
             // Rotate by 1, SubWord and Nudge  
             // [0x01020408, 0x01020408, 0x1b366cd8]
             // [0x01020408, 0x01020408, 0x1b366cd8]
             t = ((lslAESGetSBoxByte((t >> 16) & 0xFF) ^  
             t = ((_lslAESGetSBoxByte((t >> 16) & 0xFF) ^  
                     (0x000D8080 >> (7 ^ (i / len)))) << 24) |  
                     (0x000D8080 >> (7 ^ (i / len)))) << 24) |  
                 (lslAESGetSBoxByte((t >>  8) & 0xFF) << 16) |  
                 (_lslAESGetSBoxByte((t >>  8) & 0xFF) << 16) |  
                 (lslAESGetSBoxByte((t      ) & 0xFF) <<  8) |
                 (_lslAESGetSBoxByte((t      ) & 0xFF) <<  8) |
                   lslAESGetSBoxByte((t >> 24) & 0xFF);
                   _lslAESGetSBoxByte((t >> 24) & 0xFF);
         } else if ((len > 6) && (i % len) == 4) {
         } else if ((len > 6) && (i % len) == 4) {
             // SubWord
             // SubWord
             t = (lslAESGetSBoxByte((t >> 24) & 0xFF) << 24) |  
             t = (_lslAESGetSBoxByte((t >> 24) & 0xFF) << 24) |  
                 (lslAESGetSBoxByte((t >> 16) & 0xFF) << 16) |  
                 (_lslAESGetSBoxByte((t >> 16) & 0xFF) << 16) |  
                 (lslAESGetSBoxByte((t >>  8) & 0xFF) <<  8) |
                 (_lslAESGetSBoxByte((t >>  8) & 0xFF) <<  8) |
                 (lslAESGetSBoxByte((t      ) & 0xFF)      );
                 (_lslAESGetSBoxByte((t      ) & 0xFF)      );
         }
         }
   
   
         // XOR k with four previous RoundKey values And add the  
         // XOR k with four previous RoundKey values And add the  
         // new entries, yay!
         // new entries, yay!
         lslAESRoundKey = (lslAESRoundKey = []) + lslAESRoundKey +  
         _lslAESRoundKey = (_lslAESRoundKey = []) + _lslAESRoundKey +  
             (t = (t ^ llList2Integer(lslAESRoundKey, i)));
             (t = (t ^ llList2Integer(_lslAESRoundKey, i)));
     } while ((i = -~i) < x);
     } while ((i = -~i) < x);
   
   
Line 1,422: Line 1,189:
// at least 128-bits of data (all else is discarded)
// at least 128-bits of data (all else is discarded)
// pragma inline
// pragma inline
list lslAESSetInputVector(list data) {{
list _lslAESSetInputVector(list data) {{
     if ((data != []) < 5)  
     if ((data != []) < 5)  
         return ["Input vector must be at least 128-bits long"];
         return ["Input vector must be at least 128-bits long"];
   
   
     // Ignore index 0 (the header)
     // Ignore index 0 (the header)
     lslAESInputVector0 = llList2Integer(data, 1);
     _lslAESInputVector0 = llList2Integer(data, 1);
     lslAESInputVector1 = llList2Integer(data, 2);
     _lslAESInputVector1 = llList2Integer(data, 2);
     lslAESInputVector2 = llList2Integer(data, 3);
     _lslAESInputVector2 = llList2Integer(data, 3);
     lslAESInputVector3 = llList2Integer(data, 4);
     _lslAESInputVector3 = llList2Integer(data, 4);
   
   
     return [1];
     return [1];
Line 1,443: Line 1,210:
// Converts a binary-string into a list of 32-bit integers, using the provided  
// Converts a binary-string into a list of 32-bit integers, using the provided  
// alphabet and character width (in bits). See the helper functions  
// alphabet and character width (in bits). See the helper functions  
// lslAESBase64ToBytes and lslAESHexToBytes for examples of this function's  
// _lslAESBase64ToBytes and _lslAESHexToBytes for examples of this function's  
// usage. The list returned will contain as its first-entry an integer count  
// usage. The list returned will contain as its first-entry an integer count  
// of the number of bits represented by the input string  
// of the number of bits represented by the input string  
Line 1,450: Line 1,217:
// Thanks to Strife Onizuka for providing optimisations to this function.
// Thanks to Strife Onizuka for providing optimisations to this function.
// pragma inline
// pragma inline
list lslAESStringToBytes(string s, integer width, string alphabet) {{
list _lslAESStringToBytes(string s, integer width, string alphabet) {{
     integer l = llStringLength(s);
     integer l = llStringLength(s);
   
   
Line 1,488: Line 1,255:
// it as a string using characters from the given alphabet, where each character  
// it as a string using characters from the given alphabet, where each character  
// represents a number of bits as described by width. Please refer to the helper  
// represents a number of bits as described by width. Please refer to the helper  
// functions lslAESBytesToBase64 and lslAESBytesToHex for examples of this  
// functions _lslAESBytesToBase64 and _lslAESBytesToHex for examples of this  
// function's usage.
// function's usage.
//
//
// Thanks to Strife Onizuka for providing optimisations to this function.
// Thanks to Strife Onizuka for providing optimisations to this function.
// pragma inline
// pragma inline
string lslAESBytesToString(list b, integer width, string alphabet) {{
string _lslAESBytesToString(list b, integer width, string alphabet) {{
     integer bits = llList2Integer(b, 0);
     integer bits = llList2Integer(b, 0);
   
   
Line 1,508: Line 1,275:
     string s = "";
     string s = "";
   
   
     @lslAESBytesToStringLoop;
     @_lslAESBytesToStringLoop;
     if((bits -= 32) > -32) {
     if((bits -= 32) > -32) {
         available += 32 + (bits * (0 > bits));
         available += 32 + (bits * (0 > bits));
Line 1,539: Line 1,306:
             if (prev = available) // Update prev
             if (prev = available) // Update prev
                 extra = (buf >> shift) & mask;
                 extra = (buf >> shift) & mask;
             jump lslAESBytesToStringLoop;
             jump _lslAESBytesToStringLoop;
         }
         }
     }
     }
Line 1,557: Line 1,324:
     return (s = "") + s;
     return (s = "") + s;
}}
}}
/* Sets the operating mode of the AES engine. Returns TRUE on success. */
// pragma inline
integer lslAESSetMode(integer mode) {{
if (~llListFindList(
llList2ListStrided(
llList2List(SUPPORTED_MODES(), 1, -1), 0, -1, 2), [mode])) {
_lslAESMode = mode;
return TRUE;
}
return FALSE;
}}
/* Sets the padding mode of the AES engine. Returns TRUE on success. */
// pragma inline
integer lslAESSetPadding(integer pad) {{
if (~llListFindList(
llList2ListStrided(
llList2List(SUPPORTED_PADS(), 1, -1), 0, -1, 2), [pad])) {
_lslAESPad = pad;
return TRUE;
}
return FALSE;
}}
/*
* Sets the padding block-size (in bits) for this AES engine.
* Valid sizes are greater than zero, and a multiple of 128.
* Returns TRUE on success.
*/
// pragma inline
integer lslAESSetPaddingSize(integer padSize) {{
if ((padSize > 0) && !(padSize % 128)) {
_lslAESPadSize = padSize;
return TRUE;
}
return FALSE;
}}
/** Returns TRUE if an error occur during the last lslAESProcessCommand() call */
// pragma inline
integer lslAESProcessCommandError() {
return _lslAESProcessCommandError;
}
/**
* Executes an LSLAES_COMMAND_* with given input-type, desired output-type, and
* provided string-data.
*
* Returns string data.
* To test for an error in the function, call lslAESProcessComamndError(), if
* the value of that is TRUE, then the string-data will be an error message.
*/
string lslAESProcessCommand(
integer command,
integer inputType,
integer outputType,
string  str) {// Special case for COMMAND_SETUP
    // What type of data do we have?
    list data = [];
    if ((LSLAES_DATA_HEX() == inputType) || (LSLAES_DATA_BASE64() == inputType)) {
    string alphabet = LSLAES_BASE64_CHARS();
    integer width  = 6;
   
    if (LSLAES_DATA_BASE64() == inputType) {
    integer e = llSubStringIndex(str, "=");
    if (e > 0)
        str = llDeleteSubString(
            (str = "") + str,
            e,
            -1
        );
    } else {
    str = llToLower((str = "") + str);
    if (llGetSubString(str, 0, 1) == "0x")
        str = llDeleteSubString((str = "") + str, 0, 1);
       
    alphabet = LSLAES_HEX_CHARS();
    width    = 4;
    }
        data = _lslAESStringToBytes(
        (str = "") + str,
        width,
        (alphabet = "") + alphabet
        );
    } else data = [(str = "") + "Unsupported input-type"];
    // Was data parsed successfully?
    if (llGetListEntryType(data, 0) != TYPE_INTEGER) {
    _lslAESProcessCommandError = TRUE;
        return llList2String(data, 0);
    }
    // Now determine mode of operation
    if (command == LSLAES_COMMAND_PRIME())
        data = _lslAESKeyExpansion((data = []) + data);
    else if (command == LSLAES_COMMAND_ENCRYPT())
        data = _lslAESPadCipher((data = []) + data);
    else if (command == LSLAES_COMMAND_DECRYPT())
        data = _lslAESInvertPadCipher((data = []) + data);
    else if (command == LSLAES_COMMAND_INIT())
        data = _lslAESSetInputVector((data = []) + data);
    else data = ["Unsupported mode"];
    // Was mode executed successfully?
    if (llGetListEntryType(data, 0) != TYPE_INTEGER) {
    _lslAESProcessCommandError = TRUE;
        return llList2String(data, 0);
    }
    // Convert into requested output type
    if ((command != LSLAES_COMMAND_PRIME()) && (command != LSLAES_COMMAND_INIT())) {
        if ((LSLAES_DATA_BASE64() == outputType) || (LSLAES_DATA_HEX() == outputType)) {
        string alphabet = LSLAES_BASE64_CHARS();
        integer width  = 6;
       
        if (LSLAES_DATA_HEX() == outputType) {
        alphabet = LSLAES_HEX_CHARS();
        width = 4;
        }
       
        str = _lslAESBytesToString(
        (data = []) + data,
        width,
        (alphabet = "") + alphabet
        );
       
        if (LSLAES_DATA_BASE64() == outputType) {
    integer l = llStringLength(str) % 4;
    if (l && (l < 3)) {
    string add = "";
        if (l == 2) add = "==";
        else if (l == 1) add = "=";
       
        str = (str = add = "") + str + add;
    }
        } else str = (str = "") + "0x" + str;
        } else {
        _lslAESProcessCommandError = TRUE;
        return "Invalid output type";
        }
    }
   
    _lslAESProcessCommandError = FALSE;
    return (str = "") + str;
}
/** Encrypts the provided data using the current settings. */
// pragma inline
string lslAESEncrypt(integer inputType, integer outputType, string str) {{
return lslAESProcessCommand(
LSLAES_COMMAND_ENCRYPT(), inputType, outputType, (str = "") + str);
}}
/** Decrypts the provided data using the current settings. */
// pragma inline
string lslAESDecrypt(integer inputType, integer outputType, string str) {{
return lslAESProcessCommand(
LSLAES_COMMAND_DECRYPT(), inputType, outputType, (str = "") + str);
}}
/** Encrypts the provided data using the current settings. */
// pragma inline
string lslAESSetKey(integer inputType, string str) {{
return lslAESProcessCommand(
LSLAES_COMMAND_PRIME(), inputType, 0, (str = "") + str);
}}
/** Encrypts the provided data using the current settings. */
// pragma inline
string lslAESSetIV(integer inputType, string str) {{
return lslAESProcessCommand(
LSLAES_COMMAND_INIT(), inputType, 0, (str = "") + str);
}}
/** Sets engine defaults. */
// pragma inline
lslAESSetDefaults() {{
_lslAESMode = LSLAES_MODE_DEFAULT();
_lslAESPad = LSLAES_PAD_DEFAULT();
_lslAESPadSize = LSLAES_PAD_SIZE_DEFAULT();
}}</lsl>
== Examples ==
=== Encrypt ===
<lsl>$import AES.AES_Core.lslm();
string  myKey  = "1234567890ABCDEF0123456789ABCDEF"; // 128-bit key in hex
string  myMsg  = "Hello world! I am a lovely message waiting to be encrypted!";
string  myIV    = "89ABCDEF0123456789ABCDEF01234567";
default {
    state_entry() {
    // Set defaults, not needed if mode, padding, and pad-size are set
    lslAESSetDefaults();
   
    // Set-up the AES engine's operating mode
    lslAESSetMode(LSLAES_MODE_CFB_ID());
    lslAESSetPadding(LSLAES_PAD_NULLS_SAFE_ID());
    lslAESSetPaddingSize(512);
   
    // "Prime" the engine with a key and input-vector
    lslAESSetKey(LSLAES_DATA_HEX(), myKey);
    lslAESSetIV(LSLAES_DATA_HEX(), myIV);
   
    // Encrypt the message
    string data = lslAESEncrypt(
    LSLAES_DATA_BASE64(),
    LSLAES_DATA_BASE64(),
    llStringToBase64(myMsg)
    );
   
    // Process the result
    string msg = "";
    if (lslAESProcessCommandError()) msg = "ERROR: ";
    else msg = "Encrypted: ";
    llOwnerSay(msg + data);
    }
}</lsl>
=== Decrypt ===
<lsl>$import AES.AES_Core.lslm();
string  myKey  = "1234567890ABCDEF0123456789ABCDEF"; // 128-bit key in hex
string  myMsg  = "Mdn6jGTwRPMOKTYTTdDKGm9KScz26LIz96KVOGAeMw3hpwByPfa07PDRHxRW4TIh5dmu5LlhKpTQChiFLJJYDw==";
string  myIV    = "89ABCDEF0123456789ABCDEF01234567";
default {
    state_entry() {
    // Set defaults, not needed if mode, padding, and pad-size are set
    lslAESSetDefaults();
   
    // Set-up the AES engine's operating mode
    lslAESSetMode(LSLAES_MODE_CFB_ID());
    lslAESSetPadding(LSLAES_PAD_NULLS_SAFE_ID());
    lslAESSetPaddingSize(512);
   
    // "Prime" the engine with a key and input-vector
    lslAESSetKey(LSLAES_DATA_HEX(), myKey);
    lslAESSetIV(LSLAES_DATA_HEX(), myIV);
   
    // Encrypt the message
    string data = lslAESDecrypt(
    LSLAES_DATA_BASE64(),
    LSLAES_DATA_BASE64(),
    myMsg
    );
   
    // Process the result
    string msg = "";
    if (lslAESProcessCommandError()) msg = "ERROR: ";
    else {
    msg = "Decrypted: ";
    data = llBase64ToString(data);
    }
    llOwnerSay(msg + data);
    }
}</lsl>
= Broker =
The broker is a script that implements the AES engine, and which you query in order to encrypt strings. This is intended for use when your program logic is too large to fit within the free-memory of a script importing AES_Core.lslm. AES_Broker_Helper.lslm contains functions that aid you in communicating with the broker.
== AES_Broker_Constants.lslm ==
<lsl>$module ()
// These variables are used to build communications. Commands are sent as
// combined bits in the integer argument of a link-message, and are
// recovered using masks, you may wish to read about bit-masks before
// editing these values. These are used so the string argument is
// kept free for data only.
//
// Commands take the following form (in hex):
//      0xFFMMIOvv
// Where the letters are:
//      F  Filter, used to quickly determine if a message is for us.
//      C  Command; encrypt/decrypt etc.
//      I  Type of data provided (hex, base64, etc.).
//      O  Desired type of data to be returned (hex, base64, etc.),
//          this is unused in replies as the reply's value for I will
//          be the request's value for O.
//      v  Variable, depends on mode.
// This mask allows the filter byte to be retrieved quickly
integer LSLAES_BROKER_FILTER_MASK() { return 0xFF000000; }
// This mask allows the mask byte to be retrieved quickly
integer LSLAES_BROKER_COMMAND_MASK() { return 0x00FF0000; }
// This mask allows the input type to be retrieved quickly
integer LSLAES_BROKER_INPUT_TYPE_MASK() { return 0x0000F000; }
// This mask allows the output type to be retireved quickly
integer LSLAES_BROKER_OUTPUT_TYPE_MASK() { return 0x00000F00; }
// This mask allows the variable to retrieved quickly
integer LSLAES_BROKER_VARIABLE_MASK() { return 0x000000FF; }
// How many bits right variable must be shifted
integer LSLAES_BROKER_VARIABLE_SHIFT() { return 0; }
// A request
integer LSLAES_BROKER_FILTER_REQUEST() { return 0x81000000; }
// A reply
integer LSLAES_BROKER_FILTER_REPLY() { return 0x82000000; }
// An error occurred
integer LSLAES_BROKER_COMMAND_ERROR() { return 0x00000000; }
// Prime engine with key
integer LSLAES_BROKER_COMMAND_PRIME() { return 0x00010000; }
// Encrypt message using expanded key
integer LSLAES_BROKER_COMMAND_ENCRYPT() { return 0x00020000; }
// Decrypt message using expanded key
integer LSLAES_BROKER_COMMAND_DECRYPT() { return 0x00030000; }
// Sets-up the engine by specifying comma-separated flags
integer LSLAES_BROKER_COMMAND_SETUP() { return 0x00050000; }
// Initialise the engine with an input-vector
integer LSLAES_BROKER_COMMAND_INIT() { return 0x00060000; }
// Input type is hex
integer LSLAES_BROKER_INPUT_HEX() { return 0x00000000; }
// Input type is base64
integer LSLAES_BROKER_INPUT_BASE64() { return 0x00001000; }
// Output type is hex
integer LSLAES_BROKER_OUTPUT_HEX() { return 0x00000000; }
// Output type is base64
integer LSLAES_BROKER_OUTPUT_BASE64() { return 0x00000100; }</lsl>
== AES_Broker_Helper.lslm ==
<lsl>$module ()
$import AES.Broker.AES_Broker_Constants.lslm();
$import AES.AES_Constants.lslm();
// The following extra variables are used to track our messages
key    requestID              = NULL_KEY;
// Sets-up the AES engine. Flags is a comma-separated list with the
// following possible entries:
//  MODE_ECB    - Sets Electronic Code-Book mode, a little faster but
//                not especially secure
//  MODE_CBC    - Cipher-Block-Chaining mode, most commonly used, good
//                security.
//  MODE_CFB    - Ciphertext Feed-Back mode. Similar to CBC, but does
//                not require an inverse-cipher to decrypt.
//  MODE_NOFB  - Output Feed-Back mode. Similar to CFB.
//
//  PAD_RBT    - Residual Block Termination padding is a method of
//                encrypting data that does not fit correctly within
//                into blocks.
//  PAD_NULLS  - Mainly added to provide support for PHP's mcrypt
//                library. Null-characters (zero-bytes) are added to
//                pad the length. ALL nulls are removed from the end
//                after decryption, so be careful if null-characters
//                occur within the text naturally.
//  PAD_ZEROES  - Adds zero-bytes, with the final byte describing the
//                number of bytes added. If data fits within padSize
//                then an extra padSize bits is added.
//  PAD_RANDOM  - Identical to PAD_ZEROES except that random bytes are
//                generated for padding.
//
//  PAD_SIZE    - Defines the length of padding for NULLS, ZEROES, and
//                random to align on. After this should be an integer
//                value defining the size. Must be a multiple of 128.
// pragma inline
lslAESSetup(integer targetLink, string flags, key id) {
    llMessageLinked(
        targetLink,
        LSLAES_BROKER_FILTER_REQUEST() | LSLAES_BROKER_COMMAND_SETUP(),
        (flags = "") + flags,
        requestID = id
    );
}
// Sends a link message to targetLink, requesting that aesKey be used to
// prime the AES engine. aesKey should be a hexadecimal string representing
// a value that is 128, 192, or 256-bits in length.
// pragma inline
lslAESPrimeHexKey(integer targetLink, string aesKey, key id) {
    llMessageLinked(
        targetLink,
        LSLAES_BROKER_FILTER_REQUEST() | LSLAES_BROKER_COMMAND_PRIME() | LSLAES_BROKER_INPUT_HEX(),
        (aesKey = "") + aesKey,
        requestID = id
    );
}
// Initialises a 128-bit input-vector to be used by the AES engine
// pragma inline
lslAESInitHexIV(integer targetLink, string iv, key id) {
    llMessageLinked(
        targetLink,
        LSLAES_BROKER_FILTER_REQUEST() | LSLAES_BROKER_COMMAND_INIT() | LSLAES_BROKER_INPUT_HEX(),
        (iv = "") + iv,
        requestID = id
    );
}
// Sends hexadecimal data and gets encrypted hexadecimal data back
// pragma inline
lslAESEncryptHexToHex(integer targetLink, string hexData, key id) {
    llMessageLinked(
        targetLink,
        LSLAES_BROKER_FILTER_REQUEST() | LSLAES_BROKER_COMMAND_ENCRYPT() |
            LSLAES_BROKER_INPUT_HEX() | LSLAES_BROKER_OUTPUT_HEX(),
        (hexData = "") + hexData,
        requestID = id
    );
}
// Sends hexadecimal data and gets encrypted base64 data back
// pragma inline
lslAESEncryptHexToBase64(integer targetLink, string hexData, key id) {
    llMessageLinked(
        targetLink,
        LSLAES_BROKER_FILTER_REQUEST() | LSLAES_BROKER_COMMAND_ENCRYPT() |
            LSLAES_BROKER_INPUT_HEX() | LSLAES_BROKER_OUTPUT_BASE64(),
        (hexData = "") + hexData,
        requestID = id
    );
}
// Send base64 data and gets encrypted hexadecimal data back
// pragma inline
lslAESEncryptBase64ToHex(integer targetLink, string b64Data, key id) {
    llMessageLinked(
        targetLink,
        LSLAES_BROKER_FILTER_REQUEST() | LSLAES_BROKER_COMMAND_ENCRYPT() |
            LSLAES_BROKER_INPUT_BASE64() | LSLAES_BROKER_OUTPUT_HEX(),
        (b64Data = "") + b64Data,
        requestID = id
    );   
}
// Send base64 data and gets encrypted hexadecimal data back
// pragma inline
lslAESEncryptBase64ToBase64(integer targetLink, string b64Data, key id) {
    llMessageLinked(
        targetLink,
        LSLAES_BROKER_FILTER_REQUEST() | LSLAES_BROKER_COMMAND_ENCRYPT() |
            LSLAES_BROKER_INPUT_BASE64() | LSLAES_BROKER_OUTPUT_BASE64(),
        (b64Data = "") + b64Data,
        requestID = id
    );   
}
// Sends hexadecimal data and gets decrypted hexadecimal data back
// pragma inline
lslAESDecryptHexToHex(integer targetLink, string hexData, key id) {
    llMessageLinked(
        targetLink,
        LSLAES_BROKER_FILTER_REQUEST() | LSLAES_BROKER_COMMAND_DECRYPT() |
            LSLAES_BROKER_INPUT_HEX() | LSLAES_BROKER_OUTPUT_HEX(),
        (hexData = "") + hexData,
        requestID = id
    );
}
// Sends hexadecimal data and gets decrypted base64 data back
// pragma inline
lslAESDecryptHexToBase64(integer targetLink, string hexData, key id) {
    llMessageLinked(
        targetLink,
        LSLAES_BROKER_FILTER_REQUEST() | LSLAES_BROKER_COMMAND_DECRYPT() |
            LSLAES_BROKER_INPUT_HEX() | LSLAES_BROKER_OUTPUT_BASE64(),
        (hexData = "") + hexData,
        requestID = id
    );
}
// Send base64 data and gets decrypted hexadecimal data back
// pragma inline
lslAESDecryptBase64ToHex(integer targetLink, string b64Data, key id) {
    llMessageLinked(
        targetLink,
        LSLAES_BROKER_FILTER_REQUEST() | LSLAES_BROKER_COMMAND_DECRYPT() |
            LSLAES_BROKER_INPUT_BASE64() | LSLAES_BROKER_OUTPUT_HEX(),
        (b64Data = "") + b64Data,
        requestID = id
    );   
}
// Send base64 data and gets decrypted hexadecimal data back
// pragma inline
lslAESDecryptBase64ToBase64(integer targetLink, string b64Data, key id) {
    llMessageLinked(
        targetLink,
        LSLAES_BROKER_FILTER_REQUEST() | LSLAES_BROKER_COMMAND_DECRYPT() |
            LSLAES_BROKER_INPUT_BASE64() | LSLAES_BROKER_OUTPUT_BASE64(),
        (b64Data = "") + b64Data,
        requestID = id
    );   
}
// Tests to see if a message is a reply or not (TRUE/FALSE)
// pragma inline
integer lslAESIsReply(integer int, key id) {
    return (
        ((int & LSLAES_BROKER_FILTER_MASK()) == LSLAES_BROKER_FILTER_REPLY()) &&
        (id == requestID)
    );
}
// Grabs the mode of this reply. Should be one of the LSLAES_BROKER_COMMAND_* constants
// pragma inline
integer lslAESGetReplyMode(integer int) {
    return (int & LSLAES_BROKER_COMMAND_MASK());
}
// Grabs the data type of this reply. Should be one of the LSLAES_BROKER_INPUT_*
// constants.
// pragma inline
integer lslAESGetReplyDataType(integer int) {
    return (int & LSLAES_BROKER_INPUT_TYPE_MASK());
}</lsl>
== AES_Broker.lslp ==
<lsl>$import AES.AES_Core.lslm();
$import AES.Broker.AES_Broker_Constants.lslm();
integer SUPPORTS_SETUP() { return TRUE; }
integer MAX_SIZE() { return 1536; }
   
   
// pragma inline
// pragma inline
Line 1,562: Line 1,847:
     llMessageLinked(
     llMessageLinked(
         link,
         link,
         LSLAES_FILTER_REPLY() | LSLAES_COMMAND_ERROR(),
         LSLAES_BROKER_FILTER_REPLY() | LSLAES_BROKER_COMMAND_ERROR(),
         str,
         str,
         id
         id
Line 1,570: Line 1,855:
default {
default {
state_entry() {
state_entry() {
lslAESMode = LSLAES_MODE_DEFAULT();
lslAESSetDefaults();
lslAESPad = LSLAES_PAD_DEFAULT();
lslAESPadSize = LSLAES_PAD_SIZE_DEFAULT();
llOwnerSay((string)llGetFreeMemory() + " bytes free.");
}
}
 
    link_message(integer x, integer y, string msg, key id) {         
link_message(integer link, integer channel, string msg, key id) {         
        // Is the message for us?
// Is the message for us?
        if ((y & LSLAES_FILTER_MASK()) == LSLAES_FILTER_REQUEST()) {
if ((channel & LSLAES_BROKER_FILTER_MASK()) == LSLAES_BROKER_FILTER_REQUEST()) {
            // Refuse overly large messages
// Refuse overly large messages
            if (llStringLength(msg) > LSLAES_MAX_SIZE()) {
if (llStringLength(msg) > MAX_SIZE()) {
                error(
    error(
                    x,  
        link,  
                    "Maxmimum message length is " +  
        "Maxmimum message length is " +  
                    (string)LSLAES_MAX_SIZE() +  
        (string)MAX_SIZE() +  
                    " characters",  
        " characters",  
                    id
        id
                );
    );
                return;
    return;
            }
}
   
   
             // Special case for COMMAND_SETUP
             // Special case for COMMAND_SETUP
             if ((y & LSLAES_COMMAND_MASK()) == LSLAES_COMMAND_SETUP()) {
             if ((channel & LSLAES_BROKER_COMMAND_MASK()) == LSLAES_BROKER_COMMAND_SETUP()) {
            if (SUPPORTS_SETUP()) {
      if (SUPPORTS_SETUP()) {
                // Break up flags
                // Break up flags
                if (msg != "") {
                if (msg != "") {
                    list flags = llCSV2List((msg = "") + msg);
                    list flags = llCSV2List((msg = "") + msg);
                    integer i = 0; integer l = (flags != []);
                    integer i = 0; integer l = (flags != []);
                      integer j = 0; list flag = [];
integer j = 0; list flag = [];
                      do {
do {
                          flag = [llToUpper(llList2String(flags, i))];
flag = [llToUpper(llList2String(flags, i))];
                         
                          if (~(j = llListFindList(LSLAES_MODES(), flag)))  
if (~(j = llListFindList(SUPPORTED_MODES(), flag))) {
                              lslAESMode = j;
if (!lslAESSetMode(llList2Integer(SUPPORTED_MODES(), ++j))) {
                          else if (~(j = llListFindList(LSLAES_PADS(), flag)))  
error(link, "Unsupported mode", id);
                              lslAESPad  = j;
return;
                          else if ((string)flag == LSLAES_PAD_SIZE()) {
}
                              j = llList2Integer(flags, ++i); // Next value should be pad-size
} else if (~(j = llListFindList(SUPPORTED_PADS(), flag))) {
                              if (j <= 0) j = LSLAES_PAD_SIZE_DEFAULT();
if (!lslAESSetPadding(llList2Integer(SUPPORTED_PADS(), ++j))) {
                              else if (j > LSLAES_PAD_SIZE_DEFAULT()) {
error(link, "Unsupported padding scheme", id);
                                  error(x, "Maximum pad-size is "+(string)LSLAES_PAD_SIZE_DEFAULT()+" bits", id);
return;
                                  return;
}
                              } else if (j % 128) {
} else if ((string)flag == LSLAES_PAD_SIZE()) {
                                  error(x, "Pad-size must be a multiple of 128-bits", id);
j = llList2Integer(flags, ++i); // Next value should be pad-size
                                  return;
if (!lslAESSetPaddingSize(j)) {
                              }
error(link, "Invalid padding size", id);
return;
                              lslAESPadSize = j;
}
                          } else {
} else {
                              error(x, "Unsupported flag '"+(string)flag+"'", id);
error(link, "Unsupported flag '"+(string)flag+"'", id);
                              return;
return;
                          }
}
                      } while ((++i) < l);
} while ((++i) < l);
                }
                }
 
 
                  // Construct reply
                  // Construct reply
                llMessageLinked(
                llMessageLinked(
                    x,
                    link,
                    LSLAES_FILTER_REPLY() | LSLAES_COMMAND_SETUP(),
                    LSLAES_BROKER_FILTER_REPLY() | LSLAES_BROKER_COMMAND_SETUP(),
                    "",
                    "",
                    id
                    id
                );
                );
            } else error(x, "Set-up not supported (single-mode and pad available)", id);
            } else error(link, "Set-up not supported", id);
           
            return;
            return;
             }
             }
   
   
             // What type of data do we have?
             // What type of data do we have?
             integer type = y & LSLAES_INPUT_TYPE_MASK();
             integer inputType = channel & LSLAES_BROKER_INPUT_TYPE_MASK();
            list data = [];
             if (inputType == LSLAES_BROKER_INPUT_HEX())  
             if ((type == LSLAES_INPUT_HEX()) || (type == LSLAES_INPUT_BASE64())) {
             inputType = LSLAES_DATA_HEX();
             string alphabet = LSLAES_BASE64_CHARS();
            else if (inputType == LSLAES_BROKER_INPUT_BASE64())  
            integer width  = 6;
            inputType = LSLAES_DATA_BASE64();
           
            else {
            if (type == LSLAES_INPUT_BASE64()) {
             error(link, "Unsupported input-type", id);
    integer e = llSubStringIndex(msg, "=");
            return;
    if (e > 0)
        msg = llDeleteSubString(
            (msg = "") + msg,
            e,
            -1
        );
            } else {
    if (llGetSubString(msg, 0, 1) == "0x")
        msg = llDeleteSubString((msg = "") + msg, 0, 1);
    msg = llToLower((msg = "") + msg);
       
    alphabet = LSLAES_HEX_CHARS();
    width    = 4;
             }
           
                data = lslAESStringToBytes(
                (msg = "") + msg,  
                width,
                (alphabet = "") + alphabet
                );
            } else data = [(msg = "") + "Unsupported input-type"];
            // Was data parsed successfully?
            if (llGetListEntryType(data, 0) != TYPE_INTEGER) {
                error(x, llList2String((data = []) + data, 0), id);
                return;
             }
             }
           
            // What type of data do we want?
            integer outputType = channel & LSLAES_BROKER_OUTPUT_TYPE_MASK();
            integer output = 0;
            if (outputType == LSLAES_BROKER_OUTPUT_HEX()) {
            outputType = LSLAES_DATA_HEX();
            output = LSLAES_BROKER_INPUT_HEX();
            } else if (outputType == LSLAES_BROKER_OUTPUT_BASE64()) {
            outputType = LSLAES_DATA_BASE64();
            output = LSLAES_BROKER_INPUT_BASE64();
            } else outputType = -1;
   
   
             // Now determine mode of operation
             // Now determine mode of operation
             type = y & LSLAES_COMMAND_MASK();
             integer command = channel & LSLAES_BROKER_COMMAND_MASK();
             if (type == LSLAES_COMMAND_PRIME())  
            list data = [];
                 data = lslAESKeyExpansion((data = []) + data);
           
             else if (type == LSLAES_COMMAND_ENCRYPT())  
             if (command == LSLAES_BROKER_COMMAND_PRIME())  
                data = lslAESPadCipher((data = []) + data);
                 msg = lslAESSetKey(inputType, (msg = "") + msg);
             else if (type == LSLAES_COMMAND_DECRYPT())  
             else if (command == LSLAES_BROKER_COMMAND_ENCRYPT()) {
                data = lslAESInvertPadCipher((data = []) + data);
            if (~outputType)
             else if (type == LSLAES_COMMAND_INIT())  
                msg = lslAESEncrypt(inputType, outputType, (msg = "") + msg);
                 data = lslAESSetInputVector((data = []) + data);
            else {
             else data = ["Unsupported mode"];
            error(link, (msg = "") + "Unsupported output-type", id);
            return;
            }
             } else if (command == LSLAES_BROKER_COMMAND_DECRYPT()) {
            if (~outputType)
                msg = lslAESDecrypt(inputType, outputType, (msg = "") + msg);
            else {
            error(link, (msg = "") + "Unsupported output-type", id);
            return;
            }
             } else if (command == LSLAES_BROKER_COMMAND_INIT())  
                 msg = lslAESSetIV(inputType, (msg = "") + msg);
             else {
            error(link, (msg = "") + "Unsupported mode", id);
            return;
            }
   
   
             // Was mode executed successfully?
             // Was command executed successfully?
             if (llGetListEntryType(data, 0) != TYPE_INTEGER) {
             if (lslAESProcessCommandError()) {
                 error(x, llList2String((data = []) + data, 0), id);
                 error(link, (msg = "") + msg, id);
                 return;
                 return;
            }
            // Convert into requested output type
            integer output = 0;
            if ((type != LSLAES_COMMAND_PRIME()) && (type != LSLAES_COMMAND_INIT())) {
                output = y & LSLAES_OUTPUT_TYPE_MASK();
                if ((output == LSLAES_OUTPUT_BASE64()) || (output == LSLAES_OUTPUT_HEX())) {
                string alphabet = LSLAES_BASE64_CHARS();
                integer width  = 6;
               
                if (output == LSLAES_OUTPUT_HEX()) {
                alphabet = LSLAES_HEX_CHARS();
                width = 4;
                }
               
                msg = lslAESBytesToString(
                (data = []) + data,
                width,
                (alphabet = "") + alphabet
                );
               
                if (output == LSLAES_OUTPUT_BASE64()) {
    integer l = llStringLength(msg) % 4;
    if (l && (l < 3)) {
    string add = "";
        if (l == 2) add = "==";
        else if (l == 1) add = "=";
       
        msg = (msg = add = "") + msg + add;
    }
    output = LSLAES_INPUT_BASE64();
                } else {
                msg = (msg = "") + "0x" + msg;
                output = LSLAES_INPUT_HEX();
                }
                } else {
                    error(x, "Invalid output type", id);
                    return;
                }
             }
             }
   
   
             // Construct reply
             // Construct reply
             llMessageLinked(
             llMessageLinked(
                 x,
                 link,
                 LSLAES_FILTER_REPLY() | type | output,
                 LSLAES_BROKER_FILTER_REPLY() | command | output,
                 (msg = "") + msg,
                 (msg = "") + msg,
                 id
                 id
Line 1,744: Line 1,984:
}</lsl>
}</lsl>


= Examples =
== Examples ==
== Encryption ==
=== Encryption (AES_Broker_Encrypt.lslp) ===
<lsl>$import AES.AES_Helper.lslm();
<lsl>$import AES.Broker.AES_Broker_Helper.lslm();


integer aesLink = LINK_THIS;
integer aesLink = LINK_THIS;
Line 1,761: Line 2,001:
             [
             [
            LSLAES_MODE_CFB(), // CFB requires a less complex broker
            LSLAES_MODE_CFB(), // CFB requires a less complex broker
            LSLAES_PAD_NONE(), // No padding
            LSLAES_PAD_NULLS_SAFE(),// Safe null-padding (preserves bits)
            LSLAES_PAD_SIZE(), // Pad into blocks of 512-bits
            LSLAES_PAD_SIZE(), // Pad into blocks of 512-bits
            512
            512
Line 1,775: Line 2,015:
   
   
         y = lslAESGetReplyMode(y);
         y = lslAESGetReplyMode(y);
         if (y == LSLAES_COMMAND_ERROR())  
         if (y == LSLAES_BROKER_COMMAND_ERROR())  
             llOwnerSay("SETUP ERROR: "+msg);
             llOwnerSay("SETUP ERROR: "+msg);
         else if (y == LSLAES_COMMAND_SETUP())  
         else if (y == LSLAES_BROKER_COMMAND_SETUP())  
             state prime;
             state prime;
     }
     }
Line 1,795: Line 2,035:
   
   
         y = lslAESGetReplyMode(y);
         y = lslAESGetReplyMode(y);
         if (y == LSLAES_COMMAND_ERROR())  
         if (y == LSLAES_BROKER_COMMAND_ERROR())  
             llOwnerSay("PRIME ERROR: "+msg);
             llOwnerSay("PRIME ERROR: "+msg);
         else if (y == LSLAES_COMMAND_PRIME())  
         else if (y == LSLAES_BROKER_COMMAND_PRIME())  
             state init;
             state init;
     }
     }
Line 1,815: Line 2,055:
   
   
         y = lslAESGetReplyMode(y);
         y = lslAESGetReplyMode(y);
         if (y == LSLAES_COMMAND_ERROR())  
         if (y == LSLAES_BROKER_COMMAND_ERROR())  
             llOwnerSay("INIT ERROR: "+msg);
             llOwnerSay("INIT ERROR: "+msg);
         else if (y == LSLAES_COMMAND_INIT())  
         else if (y == LSLAES_BROKER_COMMAND_INIT())  
             state encrypt;
             state encrypt;
     }
     }
Line 1,835: Line 2,075:
   
   
         y = lslAESGetReplyMode(y);
         y = lslAESGetReplyMode(y);
         if (y == LSLAES_COMMAND_ERROR())  
         if (y == LSLAES_BROKER_COMMAND_ERROR())  
             llOwnerSay("ENCRYPT ERROR: "+msg);
             llOwnerSay("ENCRYPT ERROR: "+msg);
         else if (y == LSLAES_COMMAND_ENCRYPT())  
         else if (y == LSLAES_BROKER_COMMAND_ENCRYPT())  
             llOwnerSay("Encrypted: "+msg);
             llOwnerSay("Encrypted: "+msg);
     }
     }
}</lsl>
}</lsl>


= Decryption =
=== Decryption (AES_Broker_Decrypt.lslp) ===
<lsl>$import AES.AES_Helper.lslm();
<lsl>$import AES.Broker.AES_Broker_Helper.lslm();


integer aesLink = LINK_THIS;
integer aesLink = LINK_THIS;


string  myKey  = "1234567890ABCDEF0123456789ABCDEF"; // 128-bit key in hex
string  myKey  = "1234567890ABCDEF0123456789ABCDEF"; // 128-bit key in hex
string  myMsg  = "Mdn6jGTwRPMOKTYTTdDKGm9KScz26LIz96KVOGAeMw3hpwByPfa07PDRHxRW4TIh5dmu5LlhKpTQChi=";
string  myMsg  = "Mdn6jGTwRPMOKTYTTdDKGm9KScz26LIz96KVOGAeMw3hpwByPfa07PDRHxRW4TIh5dmu5LlhKpTQChilKJZcCw==";
string  myIV    = "89ABCDEF0123456789ABCDEF01234567";
string  myIV    = "89ABCDEF0123456789ABCDEF01234567";
   
   
default {
default {
     state_entry() { // Setup the engine for use
     state_entry() { // Setup the engine for use
    state prime;
         lslAESSetup(
         lslAESSetup(
             aesLink,
             aesLink,
Line 1,859: Line 2,098:
             [
             [
            LSLAES_MODE_CFB(), // CFB requires a less complex broker
            LSLAES_MODE_CFB(), // CFB requires a less complex broker
            LSLAES_PAD_NONE(), // No padding
            LSLAES_PAD_NULLS_SAFE(),// Safe null-padding (preserves bits)
            LSLAES_PAD_SIZE(), // Pad into blocks of 512-bits
            LSLAES_PAD_SIZE(), // Pad into blocks of 512-bits
            512
            512
Line 1,873: Line 2,112:
   
   
         y = lslAESGetReplyMode(y);
         y = lslAESGetReplyMode(y);
         if (y == LSLAES_COMMAND_ERROR())  
         if (y == LSLAES_BROKER_COMMAND_ERROR())  
             llOwnerSay("SETUP ERROR: "+msg);
             llOwnerSay("SETUP ERROR: "+msg);
         else if (y == LSLAES_COMMAND_SETUP())  
         else if (y == LSLAES_BROKER_COMMAND_SETUP())  
             state prime;
             state prime;
     }
     }
Line 1,893: Line 2,132:
   
   
         y = lslAESGetReplyMode(y);
         y = lslAESGetReplyMode(y);
         if (y == LSLAES_COMMAND_ERROR())  
         if (y == LSLAES_BROKER_COMMAND_ERROR())  
             llOwnerSay("PRIME ERROR: "+msg);
             llOwnerSay("PRIME ERROR: "+msg);
         else if (y == LSLAES_COMMAND_PRIME())  
         else if (y == LSLAES_BROKER_COMMAND_PRIME())  
             state init;
             state init;
     }
     }
Line 1,913: Line 2,152:
   
   
         y = lslAESGetReplyMode(y);
         y = lslAESGetReplyMode(y);
         if (y == LSLAES_COMMAND_ERROR())  
         if (y == LSLAES_BROKER_COMMAND_ERROR())  
             llOwnerSay("INIT ERROR: "+msg);
             llOwnerSay("INIT ERROR: "+msg);
         else if (y == LSLAES_COMMAND_INIT())  
         else if (y == LSLAES_BROKER_COMMAND_INIT())  
             state decrypt;
             state decrypt;
     }
     }
Line 1,933: Line 2,172:
   
   
         y = lslAESGetReplyMode(y);
         y = lslAESGetReplyMode(y);
         if (y == LSLAES_COMMAND_ERROR())  
         if (y == LSLAES_BROKER_COMMAND_ERROR())  
             llOwnerSay("DECRYPT ERROR: "+msg);
             llOwnerSay("DECRYPT ERROR: "+msg);
         else if (y == LSLAES_COMMAND_DECRYPT())  
         else if (y == LSLAES_BROKER_COMMAND_DECRYPT())  
             llOwnerSay("Decrypted: "+llBase64ToString(msg));
             llOwnerSay("Decrypted: "+llBase64ToString(msg));
     }
     }
}</lsl>
}</lsl>

Revision as of 12:52, 20 August 2009

Description

The following is an LSL+ version of the LSL AES Engine by Haravikk Mistral. It allows a developer to generate an optimised AES Engine using the Eclipse IDE.

This version has a number of advantages including over 8kb of memory right-away, and up to a further 12kb of memory through the use of the SUPPORTED_MODES(), SUPPORTED_PADS(), and SUPPORTS_SETUP() constants, which can be adjusted to enabled/disable modes of operation, padding schemes, and dynamic set-up.

With this amount of free-memory it is possible to integrate AES directly into a script, without the use of a broker which you would communicate with to perform encryption/decryption.

Project structure

While not a requirement, here is the structure of the LSL+ project from which the following code is derived, if you choose to use a different structure then you'll need to change the $import declarations accordingly.

The code you are mainly interested in is AES_Core.lslm, and AES_Constants.lslm. By importing these you can quickly start using AES in your examples, please refer to the examples to see how.

  • AES
    • Broker
      • AES_Broker_Constants.lslm
      • AES_Broker_Helper.lslm
      • AES_Broker.lslp
    • AES_Constants.lslm
    • AES_Core.lslm

Core Scripts

AES_Constants.lslm

<lsl>$module ()

integer LSLAES_COMMAND_PRIME() { return 1; } integer LSLAES_COMMAND_INIT() { return 2; } integer LSLAES_COMMAND_ENCRYPT() { return 3; } integer LSLAES_COMMAND_DECRYPT() { return 4; }

integer LSLAES_DATA_HEX() { return 1; } integer LSLAES_DATA_BASE64() { return 2; }

string LSLAES_HEX_CHARS() { return "0123456789abcdef"; } string LSLAES_BASE64_CHARS() { return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; }

// The following constants define modes of operation string LSLAES_MODE_CBC() { return "MODE_CBC"; } string LSLAES_MODE_CFB() { return "MODE_CFB"; }

// Used to set mode list LSLAES_MODES() { return [ LSLAES_MODE_CBC(), LSLAES_MODE_CFB() ]; }

// pragma inline integer LSLAES_MODE_LOOKUP(string mode) { return llListFindList(LSLAES_MODES(), [mode]); }

integer LSLAES_MODE_CBC_ID() { return LSLAES_MODE_LOOKUP(LSLAES_MODE_CBC()); } integer LSLAES_MODE_CFB_ID() { return LSLAES_MODE_LOOKUP(LSLAES_MODE_CFB()); }

// The following contstants define types of padding string LSLAES_PAD_NONE() { return "PAD_NONE"; } string LSLAES_PAD_RBT() { return "PAD_RBT"; } string LSLAES_PAD_NULLS() { return "PAD_NULLS"; } string LSLAES_PAD_NULLS_SAFE() { return "PAD_NULLS_SAFE"; } string LSLAES_PAD_RANDOM() { return "PAD_RANDOM"; } string LSLAES_PAD_ZEROES() { return "PAD_ZEROES"; }

// Used to set padding type list LSLAES_PADS() { return [ LSLAES_PAD_NONE(), LSLAES_PAD_RBT(), LSLAES_PAD_NULLS(), LSLAES_PAD_NULLS_SAFE(), LSLAES_PAD_RANDOM(), LSLAES_PAD_ZEROES() ]; }

// pragma inline integer LSLAES_PAD_LOOKUP(string pad) { return llListFindList(LSLAES_PADS(), [pad]); }

integer LSLAES_PAD_NONE_ID() { // Only compatible with CBF and OBF modes return LSLAES_PAD_LOOKUP(LSLAES_PAD_NONE()); } integer LSLAES_PAD_RBT_ID() { // XOR leftover bytes with re-encrypted

                               	// first-block. Length remains the same

return LSLAES_PAD_LOOKUP(LSLAES_PAD_RBT()); } integer LSLAES_PAD_NULLS_ID() { // Adds zeroes (null characters) to the

                               	// end, which are trimmed afterwards.
                               	// Padding creates blocks of lslAESPadSize

return LSLAES_PAD_LOOKUP(LSLAES_PAD_NULLS()); } integer LSLAES_PAD_NULLS_SAFE_ID() {// Adds a single '1' bit before padding // with zero-bytes to the block-boundary. // This method is safer than normal PAD_NULLS return LSLAES_PAD_LOOKUP(LSLAES_PAD_NULLS_SAFE()); } integer LSLAES_PAD_RANDOM_ID() { // Adds random bytes to the end of the

                               	// data until it reaches a multiple of 
                               	// lslAESPadSize in length. Final byte 
                               	// identifies how many were added. This 
                               	// scheme causes padding to ALWAYS be 
                               	// added.

return LSLAES_PAD_LOOKUP(LSLAES_PAD_RANDOM()); } integer LSLAES_PAD_ZEROES_ID() { // Identical to LSLAES_PAD_RANDOM_ID() except

                               	// that zero-bytes are added.

return LSLAES_PAD_LOOKUP(LSLAES_PAD_ZEROES()); }

string LSLAES_PAD_SIZE() { return "PAD_SIZE"; } integer LSLAES_PAD_SIZE_DEFAULT() { return 512; }</lsl>

AES_Core.lslm

<lsl>$module()

$import AES.AES_Constants.lslm();

list SUPPORTED_MODES() { return [ LSLAES_MODE_CBC(), LSLAES_MODE_CBC_ID(), LSLAES_MODE_CFB(), LSLAES_MODE_CFB_ID() ]; }

integer LSLAES_MODE_DEFAULT() { return llList2Integer(SUPPORTED_MODES(), 1); }

// pragma inline integer SUPPORTS_MODE(string mode) { return (~llListFindList(SUPPORTED_MODES(), [mode])); }

list SUPPORTED_PADS() { return [ LSLAES_PAD_NONE(), LSLAES_PAD_NONE_ID(), LSLAES_PAD_RBT(), LSLAES_PAD_RBT_ID(), LSLAES_PAD_NULLS(), LSLAES_PAD_NULLS_ID(), LSLAES_PAD_NULLS_SAFE(),LSLAES_PAD_NULLS_SAFE_ID(), LSLAES_PAD_RANDOM(), LSLAES_PAD_RANDOM_ID(), LSLAES_PAD_ZEROES(), LSLAES_PAD_ZEROES_ID() ]; }

integer LSLAES_PAD_DEFAULT() { return llList2Integer(SUPPORTED_PADS(), 1); }

// pragma inline integer SUPPORTS_PAD(string pad) { return (~llListFindList(SUPPORTED_PADS(), [pad])); }

// Treats the above list as a byte-array, retrieving the desired byte value. integer _lslAESGetSBoxInvertedByte(integer n) Template:Return lslAESMultInverse( lslAESInverseAffine(n));

// Treats the above list as a byte-array, retrieving the desired byte value. integer _lslAESGetSBoxByte(integer n) Template:Return lslAESAffine( lslAESMultInverse(n));

// Calculates high-bit of x / 2 in a finite field integer _lslAESHibit(integer x) {{

   x = (x >> 1) | (x >> 2);
   x = x | (x >> 2);
   x = x | (x >> 4);
   return (++x) >> 1;

}}

// Calculates a multipilicative inverse in a finite field integer _lslAESMultInverse(integer p1) {{

   if(p1 < 2) return p1;

   integer p2 = 0x1b;
   integer n1 = _lslAESHibit(p1);
   integer n2 = 0x80;
   integer v1 = 1;
   integer v2 = 0;

   do {
       if(n1)
           while(n2 >= n1) {                 // Divide polynomial p2 by p1
               n2 /= n1;                     // shift smaller polynomial left 
               p2 = p2 ^ ((p1 * n2) & 0xFF); // and remove from larger one
               v2 = v2 ^ ((v1 * n2) & 0xFF); // shift accumulated value and
               n2 = _lslAESHibit(p2);               // add into result
           }
       else return v1;

       if(n2)                                // repeat with values swapped 
           while(n1 >= n2) {
               n1 /= n2;
               p1 = p1 ^ ((p2 * n1) & 0xFF);
               v1 = v1 ^ ((v2 * n1) & 0xFF);
               n1 = _lslAESHibit(p1);
           }
       else return v2;
   } while (TRUE);
   return 0;

}}

// Affine function for sbox integer _lslAESAffine(integer x) {{

   x = x ^ (x << 1) ^ (x << 2) ^ (x << 3) ^ (x << 4);
   return 0x63 ^ ((x ^ (x >> 8)) & 0xFF);

}}

// Inverse affine function for sbox inversion integer _lslAESInverseAffine(integer x) {{

   x = (x << 1) ^ (x << 3) ^ (x << 6);
   return 0x05 ^ ((x ^ (x >> 8)) & 0xFF);

}}

integer _lslAESMode; // Set in default state_entry() integer _lslAESPad; // Set in default state_entry() integer _lslAESPadSize; // Set in default state_entry()

// Used for the actual encryption, generated from Key list _lslAESRoundKey = []; // The number of rounds to perform (bigger key == more rounds) integer _lslAESRounds = 0;

// The following are used for the state instead of a list integer _lslAESStateX0Y0 = 0; integer _lslAESStateX0Y1 = 0; integer _lslAESStateX0Y2 = 0; integer _lslAESStateX0Y3 = 0; integer _lslAESStateX1Y0 = 0; integer _lslAESStateX1Y1 = 0; integer _lslAESStateX1Y2 = 0; integer _lslAESStateX1Y3 = 0; integer _lslAESStateX2Y0 = 0; integer _lslAESStateX2Y1 = 0; integer _lslAESStateX2Y2 = 0; integer _lslAESStateX2Y3 = 0; integer _lslAESStateX3Y0 = 0; integer _lslAESStateX3Y1 = 0; integer _lslAESStateX3Y2 = 0; integer _lslAESStateX3Y3 = 0;

// Used to initialise state for CBC and other mode integer _lslAESInputVector0 = 0; integer _lslAESInputVector1 = 0; integer _lslAESInputVector2 = 0; integer _lslAESInputVector3 = 0;

integer _lslAESProcessCommandError = TRUE;

//##########################################################################// // HIGH-LEVEL FUNCTIONS // //##########################################################################// // The following functions are the ones to call to encrypt/decrypt // //##########################################################################// // Performs a cipher with necessary padding performed before execution // pragma inline list _lslAESPadCipher(list data) {{

   integer bits = llList2Integer(data, 0);
   data = llDeleteSubList((data = []) + data, 0, 0);

   integer padding = _lslAESPad;
   if (padding == LSLAES_PAD_NONE_ID()) {
       if (_lslAESMode == LSLAES_MODE_CFB_ID()) 
           return [bits] + _lslAESCipher((data = []) + data);
       padding = LSLAES_PAD_RBT_ID();
   }

   integer blockSize = _lslAESPadSize;
   if (padding == LSLAES_PAD_RBT_ID()) blockSize = 128;

   integer blocks = bits / blockSize;
   integer extra  = bits % blockSize;

   if (padding == LSLAES_PAD_RBT_ID()) {
   	if (SUPPORTS_PAD(LSLAES_PAD_RBT())) {

// This scheme takes the last encrypted block, encrypts it again and // XORs it with any leftover data, maintaining data-length. If input // is less than a block in size then the current input-vector is used. list final = []; if (extra > 0) { integer words = extra / 32; if ((words * 32) < extra) ++words;

// Grab leftover words list t = llList2List(data, -words, -1);

// Encrypt all other data list lb = []; if (blocks < 1) { // If not enough for a block, we generate lb using // a double cipher of input vector. lb = _lslAESCipher( _lslAESCipher((data = []) + [ _lslAESInputVector0, _lslAESInputVector1, _lslAESInputVector2, _lslAESInputVector3 ]) ); } else { // If there are blocks, we encrypt normally, then // double-encrypt the final block for lb data = _lslAESCipher( llDeleteSubList((data = []) + data, -words, -1) ); lb = _lslAESCipher(llList2List(data, -4, -1)); }

// XOR lb with t integer i = 0; integer l = (t != []); do final = (final = []) + final + [llList2Integer(t, i) ^ llList2Integer(lb, i)]; while ((++i) < l);

return [bits] + (data = final = []) + data + final; } return [bits] + _lslAESCipher((data = []) + data);

   	}
   } else if (SUPPORTS_PAD(LSLAES_PAD_NULLS()) || 
   		   SUPPORTS_PAD(LSLAES_PAD_NULLS_SAFE()) || 
   		   SUPPORTS_PAD(LSLAES_PAD_RANDOM()) || 
   		   SUPPORTS_PAD(LSLAES_PAD_ZEROES())) {
       // This scheme works by adding bytes until the data is a 
       // multiple of _lslAESPadSize bits long. In the case of 
       // PAD_NULLS this will only add extra data if needed, 
       // while the other types must always add at least one 
       // byte, as they also leave a note of bytes added in the 
       // final byte.
       extra = blockSize - extra; // Bits to add
       
		if (SUPPORTS_PAD(LSLAES_PAD_NULLS_SAFE())) {

if (padding == LSLAES_PAD_NULLS_SAFE_ID()) { // We want to add an extra '1' bit to halt unsafe null-trimming // Does an extra bit exist? ++bits; integer words = bits / 32; integer bit = bits % 32;

if (words < (data != [])) { integer word = llList2Integer(data, words); data = llListReplaceList( (data = []) + data, [word | (1 << (32 - bit))], words, words ); } else data += [0x80000000];

if ((--extra) < 0) extra += blockSize; // Now just let the function pad nulls as normal padding = LSLAES_PAD_NULLS_ID(); }

		}
       
       integer bytes = extra / 8; // Bytes to add
       if (bytes <= 0) {
           if (padding == LSLAES_PAD_NULLS_ID()) 
               jump skip; // Doesn't need to add anything

           bytes = blockSize / 8;
           extra += blockSize;
       }
       bits += extra;

       integer words = bytes / 4; // Words to add

       // First add bytes to end-word
       extra = bytes % 4;
       if (extra > 0) {
           integer i = 0; integer v = llList2Integer(data, -1);
           integer byte = 0;
           if ((extra == bytes) && (padding != LSLAES_PAD_NULLS_ID())) 
               byte = bytes;

           while (i < extra) {
               if (padding == LSLAES_PAD_RANDOM_ID()) {
                   byte = (integer)llFrand(256.0) & 0xFF;

v = v | (byte << (i << 3));

               }
               ++i;
           }

           data = llListReplaceList((data = []) + data, [v], -1, -1);
       }

       // Now, if needed, add words to end of data
       if (words > 0) {
           integer final = -1;
           if (padding != LSLAES_PAD_NULLS_ID())
               final = words - 1;

           integer word = 0; integer byte = 0;
           integer i = 0;
           integer j = 0; list w = [];
           do {
               word = j = 0; // New word
               do {
                   if ((padding != LSLAES_PAD_NULLS_ID()) && 
                       (i == final) && !j) 
                       byte = bytes;
                   else if (padding == LSLAES_PAD_RANDOM_ID()) 
                       byte = (integer)llFrand(256.0) & 0xFF;

                   word = word | (byte << (j << 3));
               } while ((++j) < 4);

               w = (w = []) + w + [word];
           } while ((++i) < words);

           data = (data = w = []) + data + w;
       }

       @skip;
       return [bits] + _lslAESCipher((data = []) + data);
   }
   return [];

}}

// Performs an inverse cipher with appropriate padding handling performed // pragma inline list _lslAESInvertPadCipher(list data) {{

   integer bits = llList2Integer(data, 0);
   data = llDeleteSubList((data = []) + data, 0, 0);

   integer padding = _lslAESPad;
   if (padding == LSLAES_PAD_NONE_ID()) {
       if (_lslAESMode == LSLAES_MODE_CFB_ID()) 
           return [bits] + _lslAESInvertCipher((data = []) + data);
       padding = LSLAES_PAD_RBT_ID();
   }

   integer blockSize = _lslAESPadSize;
   if (padding == LSLAES_PAD_RBT_ID()) blockSize = 128;

   integer blocks = bits / blockSize;
   integer extra  = bits % blockSize;

   if (padding == LSLAES_PAD_RBT_ID()) {
   	if (SUPPORTS_PAD(LSLAES_PAD_RBT())) {

// This scheme takes the last encrypted block, encrypts it again and // XORs it with any leftover data, maintaining data-length. If input // is less than a block in size then the current input-vector is used. list final = []; if (extra > 0) { integer words = extra / 32; if ((words * 32) < extra) ++words;

// Grab leftover words list t = llList2List(data, -words, -1);

// Decrypt all other data list lb = []; if (blocks < 1) { // If not enough for a block, we generate lb using // a double cipher of input vector. lb = _lslAESCipher( _lslAESCipher((data = []) + [ _lslAESInputVector0, _lslAESInputVector1, _lslAESInputVector2, _lslAESInputVector3 ]) ); } else { // If there are blocks, then we double-encrypt the // last full block to generate lb, then decrypt normally lb = _lslAESCipher( llList2List(data, -(4 + words), -(words + 1)) ); data = _lslAESInvertCipher( llDeleteSubList((data = []) + data, -words, -1) ); }

// XOR lb with t integer i = 0; integer l = (t != []); do final = (final = []) + final + [llList2Integer(t, i) ^ llList2Integer(lb, i)]; while ((++i) < l);

return [bits] + (data = final = []) + data + final; } return [bits] + _lslAESInvertCipher((data = []) + data);

   	}
   } else if (SUPPORTS_PAD(LSLAES_PAD_NULLS()) || 
   		   SUPPORTS_PAD(LSLAES_PAD_NULLS_SAFE()) || 
   		   SUPPORTS_PAD(LSLAES_PAD_RANDOM()) || 
   		   SUPPORTS_PAD(LSLAES_PAD_ZEROES())) {
       // This scheme works by adding bytes until the data is a 
       // multiple of _lslAESPadSize bits long. In the case of 
       // PAD_NULLS this will only add extra data if needed, 
       // while the other types must always add at least one 
       // byte, as they also leave a note of bytes added in the 
       // final byte.

       // If the data is not on a block boundary, then extra bits 
       // have snuck in (usually due to base64 conversion). We 
       // assume here that padding was done correctly, and ignore 
       // extra bits.
       if (extra > 0) {
           bits -= extra;
           
           integer e = extra / 32;
           if ((e * 32) < extra) ++e;
           extra = e;
           
           if (extra <= 0) extra = 1;

           if (extra > (data != [])) return [0];
           data = llDeleteSubList((data = []) + data, -extra, -1);
       }

       // Perform the decryption
       data = _lslAESInvertCipher((data = []) + data);

       integer bytes = 0; integer words = 0; integer excessBits = 0;

       // Remove extra bytes as required
       if ((padding == LSLAES_PAD_NULLS_ID()) || 
       	(padding == LSLAES_PAD_NULLS_SAFE_ID())) {
       	if (SUPPORTS_PAD(LSLAES_PAD_NULLS()) || 
       		SUPPORTS_PAD(LSLAES_PAD_NULLS_SAFE())) {

// We remove all zero-bytes at the end of the data integer l = data != []; integer v = 0; integer j = 0;

while (words < l) { v = llList2Integer(data, -(words + 1));

if (v == 0) { // Four null-bytes ++words; bytes += 4; } else { integer byte = j = 0; do { byte = (v >> (j << 3)) & 0xFF;

if (byte == 0) ++bytes; else jump skip; } while ((++j) < 4); } } @skip;

if (SUPPORTS_PAD(LSLAES_PAD_NULLS_SAFE())) { if (padding == LSLAES_PAD_NULLS_SAFE_ID()) { // Now correct the bit-count of the final byte integer byte = (v >> (j << 3)) & 0xFF; integer i = 1; while (i < 0xFF) { ++excessBits; if (byte & i) jump skip2; i = i << 1; } @skip2; } }

       	}
       } else {
           // Get the number of bytes to remove from the final byte
           bytes = llList2Integer(data, -1) & 0xFF;
           if ((bytes << 3) >= bits) return [0];
           words = bytes / 4;
       }

       // Lop-off words, excess bytes are accounted for later
       if (words > 0) 
           data = llDeleteSubList((data = []) + data, -words, -1);

       // Correct bit-header for output
       bits -= (bytes << 3) + excessBits;

       return [bits] + (data = []) + data;
   }
   return [];

}}

// Decrypts a list of integers into a list of decrypted integers. // Padding adjustment must be performed as this function will only except data // that is a multiple of 128-bits long. list _lslAESInvertCipher(list data) {{

   // The following are used to pass blocks forward    
   integer prevBlock0 = _lslAESInputVector0;
   integer prevBlock1 = _lslAESInputVector1;
   integer prevBlock2 = _lslAESInputVector2;
   integer prevBlock3 = _lslAESInputVector3;

   integer nextBlock0 = 0;
   integer nextBlock1 = 0;
   integer nextBlock2 = 0;
   integer nextBlock3 = 0;

   integer j = 0;
   integer l = (data != []);
   list output = [];
   while (l > 0) {
       // Different modes treat blocks differently
       if (_lslAESMode == LSLAES_MODE_CBC_ID()) {
       	if (SUPPORTS_MODE(LSLAES_MODE_CBC())) {

// For CBC we load it, and must keep a copy nextBlock0 = llList2Integer(data, 0); _lslAESStateX0Y0 = ((nextBlock0 >> 24) & 0xFF); _lslAESStateX0Y1 = ((nextBlock0 >> 16) & 0xFF); _lslAESStateX0Y2 = ((nextBlock0 >> 8 ) & 0xFF); _lslAESStateX0Y3 = ((nextBlock0 ) & 0xFF); nextBlock1 = llList2Integer(data, 1); _lslAESStateX1Y0 = ((nextBlock1 >> 24) & 0xFF); _lslAESStateX1Y1 = ((nextBlock1 >> 16) & 0xFF); _lslAESStateX1Y2 = ((nextBlock1 >> 8 ) & 0xFF); _lslAESStateX1Y3 = ((nextBlock1 ) & 0xFF); nextBlock2 = llList2Integer(data, 2); _lslAESStateX2Y0 = ((nextBlock2 >> 24) & 0xFF); _lslAESStateX2Y1 = ((nextBlock2 >> 16) & 0xFF); _lslAESStateX2Y2 = ((nextBlock2 >> 8 ) & 0xFF); _lslAESStateX2Y3 = ((nextBlock2 ) & 0xFF); nextBlock3 = llList2Integer(data, 3); _lslAESStateX3Y0 = ((nextBlock3 >> 24) & 0xFF); _lslAESStateX3Y1 = ((nextBlock3 >> 16) & 0xFF); _lslAESStateX3Y2 = ((nextBlock3 >> 8 ) & 0xFF); _lslAESStateX3Y3 = ((nextBlock3 ) & 0xFF);

       	}
       } else if (_lslAESMode == LSLAES_MODE_CFB_ID()) {
       	if (SUPPORTS_MODE(LSLAES_MODE_CFB())) {

_lslAESStateX0Y0 = ((prevBlock0 >> 24) & 0xFF); _lslAESStateX0Y1 = ((prevBlock0 >> 16) & 0xFF); _lslAESStateX0Y2 = ((prevBlock0 >> 8 ) & 0xFF); _lslAESStateX0Y3 = ((prevBlock0 ) & 0xFF);

_lslAESStateX1Y0 = ((prevBlock1 >> 24) & 0xFF); _lslAESStateX1Y1 = ((prevBlock1 >> 16) & 0xFF); _lslAESStateX1Y2 = ((prevBlock1 >> 8 ) & 0xFF); _lslAESStateX1Y3 = ((prevBlock1 ) & 0xFF);

_lslAESStateX2Y0 = ((prevBlock2 >> 24) & 0xFF); _lslAESStateX2Y1 = ((prevBlock2 >> 16) & 0xFF); _lslAESStateX2Y2 = ((prevBlock2 >> 8 ) & 0xFF); _lslAESStateX2Y3 = ((prevBlock2 ) & 0xFF);

_lslAESStateX3Y0 = ((prevBlock3 >> 24) & 0xFF); _lslAESStateX3Y1 = ((prevBlock3 >> 16) & 0xFF); _lslAESStateX3Y2 = ((prevBlock3 >> 8 ) & 0xFF); _lslAESStateX3Y3 = ((prevBlock3 ) & 0xFF);

       	}
       }

       if (_lslAESMode == LSLAES_MODE_CFB_ID()) {
       	if (SUPPORTS_MODE(LSLAES_MODE_CFB())) {

_lslAESPerformCipher(); // CFB doesn't need inverse cipher

       	}
       } else if (SUPPORTS_MODE(LSLAES_MODE_CBC())) {
           j = _lslAESRounds;
           do {
               if (j < _lslAESRounds) {
               	_lslAESInvertShiftRows();
               	_lslAESInvertSubBytes();
               }
               _lslAESAddRoundKey(j);
               if (j && (j < _lslAESRounds)) {
               	_lslAESInvertMixColumns();
               }
           } while ((--j) >= 0);
       }

       // Ciphertext is generated differently by different modes
       if (_lslAESMode == LSLAES_MODE_CBC_ID()) {
       	if (SUPPORTS_MODE(LSLAES_MODE_CBC())) {

// For CBC we XOR with previous block before output output = (output = []) + output + [ prevBlock0 ^ ((_lslAESStateX0Y0 << 24) | (_lslAESStateX0Y1 << 16) | (_lslAESStateX0Y2 << 8) | (_lslAESStateX0Y3)), prevBlock1 ^ ((_lslAESStateX1Y0 << 24) | (_lslAESStateX1Y1 << 16) | (_lslAESStateX1Y2 << 8) | (_lslAESStateX1Y3)), prevBlock2 ^ ((_lslAESStateX2Y0 << 24) | (_lslAESStateX2Y1 << 16) | (_lslAESStateX2Y2 << 8) | (_lslAESStateX2Y3)), prevBlock3 ^ ((_lslAESStateX3Y0 << 24) | (_lslAESStateX3Y1 << 16) | (_lslAESStateX3Y2 << 8) | (_lslAESStateX3Y3)) ];

prevBlock0 = nextBlock0; prevBlock1 = nextBlock1; prevBlock2 = nextBlock2; prevBlock3 = nextBlock3;

       	}
       } else if (SUPPORTS_MODE(LSLAES_MODE_CFB())) { // CFB
           // For CBF we XOR input block for output and carry 
           // input for encryption next-block
           prevBlock0 = llList2Integer(data, 0);
           prevBlock1 = llList2Integer(data, 1);
           prevBlock2 = llList2Integer(data, 2);
           prevBlock3 = llList2Integer(data, 3);

           output = (output = []) + output + [
               prevBlock0 ^ 
               ((_lslAESStateX0Y0 << 24) | (_lslAESStateX0Y1 << 16) | 
                   (_lslAESStateX0Y2 << 8) | (_lslAESStateX0Y3)),
               prevBlock1 ^ 
               ((_lslAESStateX1Y0 << 24) | (_lslAESStateX1Y1 << 16) | 
                   (_lslAESStateX1Y2 << 8) | (_lslAESStateX1Y3)),
               prevBlock2 ^ 
               ((_lslAESStateX2Y0 << 24) | (_lslAESStateX2Y1 << 16) | 
                   (_lslAESStateX2Y2 << 8) | (_lslAESStateX2Y3)),
               prevBlock3 ^ 
               ((_lslAESStateX3Y0 << 24) | (_lslAESStateX3Y1 << 16) | 
                   (_lslAESStateX3Y2 << 8) | (_lslAESStateX3Y3))
           ];
       }

        // Reduce input
       if (l > 4) 
           data = llList2List((data = []) + data, 4, -1);
       else data = [];
       l -= 4;
   }

   return (output = []) + output;

}}

// Encrypts a list of integers into a list of encrypted integers. // Padding must be performed before being called so that data is a multiple of // 128-bits long. list _lslAESCipher(list data) {{

   // We must prime the state with the input vector
   _lslAESLoadInputVector();

   integer l = (data != []);
   integer j = 0;
   list output = [];

   while (l > 0) {
       // Different modes treat blocks differently
       if (_lslAESMode == LSLAES_MODE_CBC_ID()) {
       	if (SUPPORTS_MODE(LSLAES_MODE_CBC())) {

// For CBC we XOR with the previous block to reduce // chances of patterns occurring j = llList2Integer(data, 0); _lslAESStateX0Y0 = _lslAESStateX0Y0 ^ ((j >> 24) & 0xFF); _lslAESStateX0Y1 = _lslAESStateX0Y1 ^ ((j >> 16) & 0xFF); _lslAESStateX0Y2 = _lslAESStateX0Y2 ^ ((j >> 8 ) & 0xFF); _lslAESStateX0Y3 = _lslAESStateX0Y3 ^ ((j ) & 0xFF); j = llList2Integer(data, 1); _lslAESStateX1Y0 = _lslAESStateX1Y0 ^ ((j >> 24) & 0xFF); _lslAESStateX1Y1 = _lslAESStateX1Y1 ^ ((j >> 16) & 0xFF); _lslAESStateX1Y2 = _lslAESStateX1Y2 ^ ((j >> 8 ) & 0xFF); _lslAESStateX1Y3 = _lslAESStateX1Y3 ^ ((j ) & 0xFF); j = llList2Integer(data, 2); _lslAESStateX2Y0 = _lslAESStateX2Y0 ^ ((j >> 24) & 0xFF); _lslAESStateX2Y1 = _lslAESStateX2Y1 ^ ((j >> 16) & 0xFF); _lslAESStateX2Y2 = _lslAESStateX2Y2 ^ ((j >> 8 ) & 0xFF); _lslAESStateX2Y3 = _lslAESStateX2Y3 ^ ((j ) & 0xFF); j = llList2Integer(data, 3); _lslAESStateX3Y0 = _lslAESStateX3Y0 ^ ((j >> 24) & 0xFF); _lslAESStateX3Y1 = _lslAESStateX3Y1 ^ ((j >> 16) & 0xFF); _lslAESStateX3Y2 = _lslAESStateX3Y2 ^ ((j >> 8 ) & 0xFF); _lslAESStateX3Y3 = _lslAESStateX3Y3 ^ ((j ) & 0xFF);

       	}
       }

       _lslAESPerformCipher();

       if (_lslAESMode == LSLAES_MODE_CFB_ID()) {
       	if (SUPPORTS_MODE(LSLAES_MODE_CFB())) {

// For CFB we XOR blocks and carry them to the next // stage (by keeping the result in state) j = llList2Integer(data, 0); _lslAESStateX0Y0 = _lslAESStateX0Y0 ^ ((j >> 24) & 0xFF); _lslAESStateX0Y1 = _lslAESStateX0Y1 ^ ((j >> 16) & 0xFF); _lslAESStateX0Y2 = _lslAESStateX0Y2 ^ ((j >> 8 ) & 0xFF); _lslAESStateX0Y3 = _lslAESStateX0Y3 ^ ((j ) & 0xFF); j = llList2Integer(data, 1); _lslAESStateX1Y0 = _lslAESStateX1Y0 ^ ((j >> 24) & 0xFF); _lslAESStateX1Y1 = _lslAESStateX1Y1 ^ ((j >> 16) & 0xFF); _lslAESStateX1Y2 = _lslAESStateX1Y2 ^ ((j >> 8 ) & 0xFF); _lslAESStateX1Y3 = _lslAESStateX1Y3 ^ ((j ) & 0xFF); j = llList2Integer(data, 2); _lslAESStateX2Y0 = _lslAESStateX2Y0 ^ ((j >> 24) & 0xFF); _lslAESStateX2Y1 = _lslAESStateX2Y1 ^ ((j >> 16) & 0xFF); _lslAESStateX2Y2 = _lslAESStateX2Y2 ^ ((j >> 8 ) & 0xFF); _lslAESStateX2Y3 = _lslAESStateX2Y3 ^ ((j ) & 0xFF); j = llList2Integer(data, 3); _lslAESStateX3Y0 = _lslAESStateX3Y0 ^ ((j >> 24) & 0xFF); _lslAESStateX3Y1 = _lslAESStateX3Y1 ^ ((j >> 16) & 0xFF); _lslAESStateX3Y2 = _lslAESStateX3Y2 ^ ((j >> 8 ) & 0xFF); _lslAESStateX3Y3 = _lslAESStateX3Y3 ^ ((j ) & 0xFF);

       	}
       }

       output = (output = []) + output + [
           (_lslAESStateX0Y0 << 24) | (_lslAESStateX0Y1 << 16) | 
               (_lslAESStateX0Y2 << 8) | _lslAESStateX0Y3,
           (_lslAESStateX1Y0 << 24) | (_lslAESStateX1Y1 << 16) | 
               (_lslAESStateX1Y2 << 8) | _lslAESStateX1Y3,
           (_lslAESStateX2Y0 << 24) | (_lslAESStateX2Y1 << 16) | 
               (_lslAESStateX2Y2 << 8) | _lslAESStateX2Y3,
           (_lslAESStateX3Y0 << 24) | (_lslAESStateX3Y1 << 16) | 
               (_lslAESStateX3Y2 << 8) | _lslAESStateX3Y3
       ];

        // Reduce input
       if (l > 4) 
           data = llList2List((data = []) + data, 4, -1);
       else data = [];
       l -= 4;
   }

   return (output = []) + output;

}}

// Simply performs the cipher operation on current state, separated // for convenience with CBF and OBF modes (which perform a cipher in // order to decrypt data). _lslAESPerformCipher() {{ integer j = 0; do { if (j) {

       	_lslAESSubBytes();
   		_lslAESShiftRows();
   		if (j < _lslAESRounds) {
       		_lslAESMixColumns();
   		}

}

   	_lslAESAddRoundKey(j);

} while ((++j) <= _lslAESRounds); }}

// Expands the input vector for use in block differentiation // pragma inline _lslAESLoadInputVector() {{

   _lslAESStateX0Y0 = (_lslAESInputVector0 >> 24) & 0xFF;
   _lslAESStateX0Y1 = (_lslAESInputVector0 >> 16) & 0xFF;
   _lslAESStateX0Y2 = (_lslAESInputVector0 >> 8 ) & 0xFF;
   _lslAESStateX0Y3 = (_lslAESInputVector0      ) & 0xFF;

   _lslAESStateX1Y0 = (_lslAESInputVector1 >> 24) & 0xFF;
   _lslAESStateX1Y1 = (_lslAESInputVector1 >> 16) & 0xFF;
   _lslAESStateX1Y2 = (_lslAESInputVector1 >> 8 ) & 0xFF;
   _lslAESStateX1Y3 = (_lslAESInputVector1      ) & 0xFF;

   _lslAESStateX2Y0 = (_lslAESInputVector2 >> 24) & 0xFF;
   _lslAESStateX2Y1 = (_lslAESInputVector2 >> 16) & 0xFF;
   _lslAESStateX2Y2 = (_lslAESInputVector2 >> 8 ) & 0xFF;
   _lslAESStateX2Y3 = (_lslAESInputVector2      ) & 0xFF;

   _lslAESStateX3Y0 = (_lslAESInputVector3 >> 24) & 0xFF;
   _lslAESStateX3Y1 = (_lslAESInputVector3 >> 16) & 0xFF;
   _lslAESStateX3Y2 = (_lslAESInputVector3 >> 8 ) & 0xFF;
   _lslAESStateX3Y3 = (_lslAESInputVector3      ) & 0xFF;

}}

//##########################################################################// // PROCESSING FUNCTIONS // //##########################################################################// // The following functions are used to process data that is being // // encrypted or decrypted. // //##########################################################################// // XORs the value with RoundKey values // pragma inline _lslAESAddRoundKey(integer round) {{

   round = round << 2;

   integer t = llList2Integer(_lslAESRoundKey, round);
   _lslAESStateX0Y0 = _lslAESStateX0Y0 ^ ((t >> 24) & 0xFF);
   _lslAESStateX0Y1 = _lslAESStateX0Y1 ^ ((t >> 16) & 0xFF);
   _lslAESStateX0Y2 = _lslAESStateX0Y2 ^ ((t >> 8 ) & 0xFF);
   _lslAESStateX0Y3 = _lslAESStateX0Y3 ^ ((t      ) & 0xFF);

   t = llList2Integer(_lslAESRoundKey, ++round);
   _lslAESStateX1Y0 = _lslAESStateX1Y0 ^ ((t >> 24) & 0xFF);
   _lslAESStateX1Y1 = _lslAESStateX1Y1 ^ ((t >> 16) & 0xFF);
   _lslAESStateX1Y2 = _lslAESStateX1Y2 ^ ((t >> 8 ) & 0xFF);
   _lslAESStateX1Y3 = _lslAESStateX1Y3 ^ ((t      ) & 0xFF);

   t = llList2Integer(_lslAESRoundKey, ++round);
   _lslAESStateX2Y0 = _lslAESStateX2Y0 ^ ((t >> 24) & 0xFF);
   _lslAESStateX2Y1 = _lslAESStateX2Y1 ^ ((t >> 16) & 0xFF);
   _lslAESStateX2Y2 = _lslAESStateX2Y2 ^ ((t >> 8 ) & 0xFF);
   _lslAESStateX2Y3 = _lslAESStateX2Y3 ^ ((t      ) & 0xFF);

   t = llList2Integer(_lslAESRoundKey, ++round);
   _lslAESStateX3Y0 = _lslAESStateX3Y0 ^ ((t >> 24) & 0xFF);
   _lslAESStateX3Y1 = _lslAESStateX3Y1 ^ ((t >> 16) & 0xFF);
   _lslAESStateX3Y2 = _lslAESStateX3Y2 ^ ((t >> 8 ) & 0xFF);
   _lslAESStateX3Y3 = _lslAESStateX3Y3 ^ ((t      ) & 0xFF);

}}

// Performs a substitution using SBox // pragma inline _lslAESSubBytes() {{

   _lslAESStateX0Y0 = _lslAESGetSBoxByte(_lslAESStateX0Y0);
   _lslAESStateX0Y1 = _lslAESGetSBoxByte(_lslAESStateX0Y1);
   _lslAESStateX0Y2 = _lslAESGetSBoxByte(_lslAESStateX0Y2);
   _lslAESStateX0Y3 = _lslAESGetSBoxByte(_lslAESStateX0Y3);
   _lslAESStateX1Y0 = _lslAESGetSBoxByte(_lslAESStateX1Y0);
   _lslAESStateX1Y1 = _lslAESGetSBoxByte(_lslAESStateX1Y1);
   _lslAESStateX1Y2 = _lslAESGetSBoxByte(_lslAESStateX1Y2);
   _lslAESStateX1Y3 = _lslAESGetSBoxByte(_lslAESStateX1Y3);
   _lslAESStateX2Y0 = _lslAESGetSBoxByte(_lslAESStateX2Y0);
   _lslAESStateX2Y1 = _lslAESGetSBoxByte(_lslAESStateX2Y1);
   _lslAESStateX2Y2 = _lslAESGetSBoxByte(_lslAESStateX2Y2);
   _lslAESStateX2Y3 = _lslAESGetSBoxByte(_lslAESStateX2Y3);
   _lslAESStateX3Y0 = _lslAESGetSBoxByte(_lslAESStateX3Y0);
   _lslAESStateX3Y1 = _lslAESGetSBoxByte(_lslAESStateX3Y1);
   _lslAESStateX3Y2 = _lslAESGetSBoxByte(_lslAESStateX3Y2);
   _lslAESStateX3Y3 = _lslAESGetSBoxByte(_lslAESStateX3Y3);

}}

// Performs a substition using SBoxInverted // pragma inline _lslAESInvertSubBytes() {{

   _lslAESStateX0Y0 = _lslAESGetSBoxInvertedByte(_lslAESStateX0Y0);
   _lslAESStateX0Y1 = _lslAESGetSBoxInvertedByte(_lslAESStateX0Y1);
   _lslAESStateX0Y2 = _lslAESGetSBoxInvertedByte(_lslAESStateX0Y2);
   _lslAESStateX0Y3 = _lslAESGetSBoxInvertedByte(_lslAESStateX0Y3);
   _lslAESStateX1Y0 = _lslAESGetSBoxInvertedByte(_lslAESStateX1Y0);
   _lslAESStateX1Y1 = _lslAESGetSBoxInvertedByte(_lslAESStateX1Y1);
   _lslAESStateX1Y2 = _lslAESGetSBoxInvertedByte(_lslAESStateX1Y2);
   _lslAESStateX1Y3 = _lslAESGetSBoxInvertedByte(_lslAESStateX1Y3);
   _lslAESStateX2Y0 = _lslAESGetSBoxInvertedByte(_lslAESStateX2Y0);
   _lslAESStateX2Y1 = _lslAESGetSBoxInvertedByte(_lslAESStateX2Y1);
   _lslAESStateX2Y2 = _lslAESGetSBoxInvertedByte(_lslAESStateX2Y2);
   _lslAESStateX2Y3 = _lslAESGetSBoxInvertedByte(_lslAESStateX2Y3);
   _lslAESStateX3Y0 = _lslAESGetSBoxInvertedByte(_lslAESStateX3Y0);
   _lslAESStateX3Y1 = _lslAESGetSBoxInvertedByte(_lslAESStateX3Y1);
   _lslAESStateX3Y2 = _lslAESGetSBoxInvertedByte(_lslAESStateX3Y2);
   _lslAESStateX3Y3 = _lslAESGetSBoxInvertedByte(_lslAESStateX3Y3);

}}


// Performs row shifts // pragma inline _lslAESShiftRows() {{

   // Rotate first row 1 columns to left
   integer t = _lslAESStateX0Y1;
   _lslAESStateX0Y1 = _lslAESStateX1Y1;
   _lslAESStateX1Y1 = _lslAESStateX2Y1;
   _lslAESStateX2Y1 = _lslAESStateX3Y1;
   _lslAESStateX3Y1 = t;

   // Rotate second row 2 columns to left
   t = _lslAESStateX0Y2;
   _lslAESStateX0Y2 = _lslAESStateX2Y2;
   _lslAESStateX2Y2 = t;

   t = _lslAESStateX1Y2;
   _lslAESStateX1Y2 = _lslAESStateX3Y2;
   _lslAESStateX3Y2 = t;

   // Rotate third row 3 columns to left
   t = _lslAESStateX0Y3;
   _lslAESStateX0Y3 = _lslAESStateX3Y3;
   _lslAESStateX3Y3 = _lslAESStateX2Y3;
   _lslAESStateX2Y3 = _lslAESStateX1Y3;
   _lslAESStateX1Y3 = t;

}}

// Undoes a set of row shifts // pragma inline _lslAESInvertShiftRows() {{

   // Rotate first row 1 columns to right
   integer t = _lslAESStateX3Y1;
   _lslAESStateX3Y1 = _lslAESStateX2Y1;
   _lslAESStateX2Y1 = _lslAESStateX1Y1;
   _lslAESStateX1Y1 = _lslAESStateX0Y1;
   _lslAESStateX0Y1 = t;

   // Rotate second row 2 columns to right
   t = _lslAESStateX0Y2;
   _lslAESStateX0Y2 = _lslAESStateX2Y2;
   _lslAESStateX2Y2 = t;

   t = _lslAESStateX1Y2;
   _lslAESStateX1Y2 = _lslAESStateX3Y2;
   _lslAESStateX3Y2 = t;

   // Rotate third row 3 columns to right
   t = _lslAESStateX0Y3;
   _lslAESStateX0Y3 = _lslAESStateX1Y3;
   _lslAESStateX1Y3 = _lslAESStateX2Y3;
   _lslAESStateX2Y3 = _lslAESStateX3Y3;
   _lslAESStateX3Y3 = t;

}}

// Mixes columns of the state // pragma inline _lslAESMixColumns() {{

   integer t = _lslAESStateX0Y0;
   integer t1 = _lslAESStateX0Y0 ^ _lslAESStateX0Y1 ^ 
       _lslAESStateX0Y2 ^ _lslAESStateX0Y3;

   integer t2 = _lslAESXTimes(_lslAESStateX0Y0 ^ _lslAESStateX0Y1);
   _lslAESStateX0Y0 = _lslAESStateX0Y0 ^ t2 ^ t1;

   t2 = _lslAESXTimes(_lslAESStateX0Y1 ^ _lslAESStateX0Y2);
   _lslAESStateX0Y1 = _lslAESStateX0Y1 ^ t2 ^ t1;

   t2 = _lslAESXTimes(_lslAESStateX0Y2 ^ _lslAESStateX0Y3);
   _lslAESStateX0Y2 = _lslAESStateX0Y2 ^ t2 ^ t1;

   t2 = _lslAESXTimes(_lslAESStateX0Y3 ^ t);
   _lslAESStateX0Y3 = _lslAESStateX0Y3 ^ t2 ^ t1;

   t = _lslAESStateX1Y0;
   t1 = _lslAESStateX1Y0 ^ _lslAESStateX1Y1 ^ _lslAESStateX1Y2 ^ _lslAESStateX1Y3;

   t2 = _lslAESXTimes(_lslAESStateX1Y0 ^ _lslAESStateX1Y1);
   _lslAESStateX1Y0 = _lslAESStateX1Y0 ^ t2 ^ t1;

   t2 = _lslAESXTimes(_lslAESStateX1Y1 ^ _lslAESStateX1Y2);
   _lslAESStateX1Y1 = _lslAESStateX1Y1 ^ t2 ^ t1;

   t2 = _lslAESXTimes(_lslAESStateX1Y2 ^ _lslAESStateX1Y3);
   _lslAESStateX1Y2 = _lslAESStateX1Y2 ^ t2 ^ t1;

   t2 = _lslAESXTimes(_lslAESStateX1Y3 ^ t);
   _lslAESStateX1Y3 = _lslAESStateX1Y3 ^ t2 ^ t1;

   t = _lslAESStateX2Y0;
   t1 = _lslAESStateX2Y0 ^ _lslAESStateX2Y1 ^ _lslAESStateX2Y2 ^ _lslAESStateX2Y3;

   t2 = _lslAESXTimes(_lslAESStateX2Y0 ^ _lslAESStateX2Y1);
   _lslAESStateX2Y0 = _lslAESStateX2Y0 ^ t2 ^ t1;

   t2 = _lslAESXTimes(_lslAESStateX2Y1 ^ _lslAESStateX2Y2);
   _lslAESStateX2Y1 = _lslAESStateX2Y1 ^ t2 ^ t1;

   t2 = _lslAESXTimes(_lslAESStateX2Y2 ^ _lslAESStateX2Y3);
   _lslAESStateX2Y2 = _lslAESStateX2Y2 ^ t2 ^ t1;

   t2 = _lslAESXTimes(_lslAESStateX2Y3 ^ t);
   _lslAESStateX2Y3 = _lslAESStateX2Y3 ^ t2 ^ t1;

   t = _lslAESStateX3Y0;
   t1 = _lslAESStateX3Y0 ^ _lslAESStateX3Y1 ^ _lslAESStateX3Y2 ^ _lslAESStateX3Y3;

   t2 = _lslAESXTimes(_lslAESStateX3Y0 ^ _lslAESStateX3Y1);
   _lslAESStateX3Y0 = _lslAESStateX3Y0 ^ t2 ^ t1;

   t2 = _lslAESXTimes(_lslAESStateX3Y1 ^ _lslAESStateX3Y2);
   _lslAESStateX3Y1 = _lslAESStateX3Y1 ^ t2 ^ t1;

   t2 = _lslAESXTimes(_lslAESStateX3Y2 ^ _lslAESStateX3Y3);
   _lslAESStateX3Y2 = _lslAESStateX3Y2 ^ t2 ^ t1;

   t2 = _lslAESXTimes(_lslAESStateX3Y3 ^ t);
   _lslAESStateX3Y3 = _lslAESStateX3Y3 ^ t2 ^ t1;

}}

// Used when column mixing // pragma inline integer _lslAESXTimes(integer x) {{

   return ((x << 1) ^ (((x >> 7) & 1) * 0x1b)) & 0xFF;

}}

// Used when column mixing integer _lslAESMultiply(integer x, integer y) {{

   integer xT  = _lslAESXTimes(x);
   integer xT2 = _lslAESXTimes(xT);
   integer xT3 = _lslAESXTimes(xT2);

   return (((y & 1) * x) ^ (((y >> 1) & 1) * xT) ^ 
           (((y >> 2) & 1) * xT2) ^ (((y >> 3) & 1) * xT3) ^ 
           (((y >> 4) & 1) * _lslAESXTimes(xT3))) & 0xFF;

}}

// Try to understand this at your own peril! // pragma inline _lslAESInvertMixColumns() {{

   integer a = _lslAESStateX0Y0;
   integer b = _lslAESStateX0Y1;
   integer c = _lslAESStateX0Y2;
   integer d = _lslAESStateX0Y3;

   _lslAESStateX0Y0 = _lslAESMultiply(a, 0x0e) ^ _lslAESMultiply(b, 0x0b) ^ 
       _lslAESMultiply(c, 0x0d) ^ _lslAESMultiply(d, 0x09);
   _lslAESStateX0Y1 = _lslAESMultiply(a, 0x09) ^ _lslAESMultiply(b, 0x0e) ^ 
       _lslAESMultiply(c, 0x0b) ^ _lslAESMultiply(d, 0x0d);
   _lslAESStateX0Y2 = _lslAESMultiply(a, 0x0d) ^ _lslAESMultiply(b, 0x09) ^ 
       _lslAESMultiply(c, 0x0e) ^ _lslAESMultiply(d, 0x0b);
   _lslAESStateX0Y3 = _lslAESMultiply(a, 0x0b) ^ _lslAESMultiply(b, 0x0d) ^ 
       _lslAESMultiply(c, 0x09) ^ _lslAESMultiply(d, 0x0e);

   a = _lslAESStateX1Y0;
   b = _lslAESStateX1Y1;
   c = _lslAESStateX1Y2;
   d = _lslAESStateX1Y3;

   _lslAESStateX1Y0 = _lslAESMultiply(a, 0x0e) ^ _lslAESMultiply(b, 0x0b) ^ 
       _lslAESMultiply(c, 0x0d) ^ _lslAESMultiply(d, 0x09);
   _lslAESStateX1Y1 = _lslAESMultiply(a, 0x09) ^ _lslAESMultiply(b, 0x0e) ^ 
       _lslAESMultiply(c, 0x0b) ^ _lslAESMultiply(d, 0x0d);
   _lslAESStateX1Y2 = _lslAESMultiply(a, 0x0d) ^ _lslAESMultiply(b, 0x09) ^ 
       _lslAESMultiply(c, 0x0e) ^ _lslAESMultiply(d, 0x0b);
   _lslAESStateX1Y3 = _lslAESMultiply(a, 0x0b) ^ _lslAESMultiply(b, 0x0d) ^ 
       _lslAESMultiply(c, 0x09) ^ _lslAESMultiply(d, 0x0e);

   a = _lslAESStateX2Y0;
   b = _lslAESStateX2Y1;
   c = _lslAESStateX2Y2;
   d = _lslAESStateX2Y3;

   _lslAESStateX2Y0 = _lslAESMultiply(a, 0x0e) ^ _lslAESMultiply(b, 0x0b) ^ 
       _lslAESMultiply(c, 0x0d) ^ _lslAESMultiply(d, 0x09);
   _lslAESStateX2Y1 = _lslAESMultiply(a, 0x09) ^ _lslAESMultiply(b, 0x0e) ^ 
       _lslAESMultiply(c, 0x0b) ^ _lslAESMultiply(d, 0x0d);
   _lslAESStateX2Y2 = _lslAESMultiply(a, 0x0d) ^ _lslAESMultiply(b, 0x09) ^ 
       _lslAESMultiply(c, 0x0e) ^ _lslAESMultiply(d, 0x0b);
   _lslAESStateX2Y3 = _lslAESMultiply(a, 0x0b) ^ _lslAESMultiply(b, 0x0d) ^ 
       _lslAESMultiply(c, 0x09) ^ _lslAESMultiply(d, 0x0e);

   a = _lslAESStateX3Y0;
   b = _lslAESStateX3Y1;
   c = _lslAESStateX3Y2;
   d = _lslAESStateX3Y3;

   _lslAESStateX3Y0 = _lslAESMultiply(a, 0x0e) ^ _lslAESMultiply(b, 0x0b) ^ 
       _lslAESMultiply(c, 0x0d) ^ _lslAESMultiply(d, 0x09);
   _lslAESStateX3Y1 = _lslAESMultiply(a, 0x09) ^ _lslAESMultiply(b, 0x0e) ^ 
       _lslAESMultiply(c, 0x0b) ^ _lslAESMultiply(d, 0x0d);
   _lslAESStateX3Y2 = _lslAESMultiply(a, 0x0d) ^ _lslAESMultiply(b, 0x09) ^ 
       _lslAESMultiply(c, 0x0e) ^ _lslAESMultiply(d, 0x0b);
   _lslAESStateX3Y3 = _lslAESMultiply(a, 0x0b) ^ _lslAESMultiply(b, 0x0d) ^ 
       _lslAESMultiply(c, 0x09) ^ _lslAESMultiply(d, 0x0e);

}}

//##########################################################################// // ENCRYPTION SET-UP FUNCTIONS // //##########################################################################// // The following functions are used to set-up the AES encryption engine. // //##########################################################################// // Takes the key bytes provided and sets up the engine ready to encrypt or // decrypt using them. // // Thanks to Strife Onizuka for providing optimisations to this function. // pragma inline list _lslAESKeyExpansion(list keyBytes) {{

   // Don't need the bit-count and the first round key is the key itself
   integer len = (
       (
           _lslAESRoundKey = llDeleteSubList( // Remove header, copy into rounds
               (_lslAESRoundKey = keyBytes = []) + keyBytes, 
               0, 
               0
           )
       ) != []); // Get the length

   // Check that we are within reasonable limits
   if ((len < 4) || (len > 8)) {
       _lslAESRoundKey = [];
       return ["Invalid key size; must be 128, 192, or 256 bits!"];
   }

   // Calculate the number of required rounds
   _lslAESRounds = len + 6;

   // All others are found from previous keys
   integer i = 0;
   integer x = (len * 3) + 28;

   integer t = llList2Integer(_lslAESRoundKey, -1);

   do {
       if (!(i % len)) {
           // Rotate by 1, SubWord and Nudge 
           // [0x01020408, 0x01020408, 0x1b366cd8]
           t = ((_lslAESGetSBoxByte((t >> 16) & 0xFF) ^ 
                    (0x000D8080 >> (7 ^ (i / len)))) << 24) | 
                (_lslAESGetSBoxByte((t >>  8) & 0xFF) << 16) | 
                (_lslAESGetSBoxByte((t      ) & 0xFF) <<  8) |
                 _lslAESGetSBoxByte((t >> 24) & 0xFF);
       } else if ((len > 6) && (i % len) == 4) {
           // SubWord
           t = (_lslAESGetSBoxByte((t >> 24) & 0xFF) << 24) | 
               (_lslAESGetSBoxByte((t >> 16) & 0xFF) << 16) | 
               (_lslAESGetSBoxByte((t >>  8) & 0xFF) <<  8) |
               (_lslAESGetSBoxByte((t      ) & 0xFF)      );
       }

       // XOR k with four previous RoundKey values And add the 
       // new entries, yay!
       _lslAESRoundKey = (_lslAESRoundKey = []) + _lslAESRoundKey + 
           (t = (t ^ llList2Integer(_lslAESRoundKey, i)));
   } while ((i = -~i) < x);

   // On success no error message is returned
   return [1];

}}

// Takes a list of 32-bit words and uses them to initialise the // input vector used by CBC and similar modes. Data must contain // at least 128-bits of data (all else is discarded) // pragma inline list _lslAESSetInputVector(list data) {{

   if ((data != []) < 5) 
       return ["Input vector must be at least 128-bits long"];

   // Ignore index 0 (the header)
   _lslAESInputVector0 = llList2Integer(data, 1);
   _lslAESInputVector1 = llList2Integer(data, 2);
   _lslAESInputVector2 = llList2Integer(data, 3);
   _lslAESInputVector3 = llList2Integer(data, 4);

   return [1];

}}

//##########################################################################// // SERIALISATION FUNCTIONS // //##########################################################################// // The following functions are used to serialise a string into a list of // // byte data for use as a key, or to encrypt/decrypt. // //##########################################################################// // Converts a binary-string into a list of 32-bit integers, using the provided // alphabet and character width (in bits). See the helper functions // _lslAESBase64ToBytes and _lslAESHexToBytes for examples of this function's // usage. The list returned will contain as its first-entry an integer count // of the number of bits represented by the input string // (llStringLength(s) * width). // // Thanks to Strife Onizuka for providing optimisations to this function. // pragma inline list _lslAESStringToBytes(string s, integer width, string alphabet) {{

   integer l = llStringLength(s);

   list n = [l * width]; // Add bit-length
   integer bitbuf = 0;
   integer adjust = 32;

   integer i = 0;
   integer val;
   while (i < l) {
       val = llSubStringIndex(alphabet, llGetSubString(s, i, i));
       if (val < 0) {
           s = "";
           return (n = []) + 
               ["Invalid character at index "+(string)i];
       }

       if ((adjust -= width) <= 0) {
           bitbuf = bitbuf | (val >> -adjust);
           n += [bitbuf];

           adjust += 32;
           if (adjust < 32) bitbuf = (val << adjust);
           else bitbuf = 0;
       } else bitbuf = bitbuf | (val << adjust);

       ++i;
   }

   s = "";
   if (adjust < 32) 
       return (n = []) + n + [bitbuf];
   return (n = []) + n;

}}

// Takes a list of integers (with a bit-count as the first entry) and outputs // it as a string using characters from the given alphabet, where each character // represents a number of bits as described by width. Please refer to the helper // functions _lslAESBytesToBase64 and _lslAESBytesToHex for examples of this // function's usage. // // Thanks to Strife Onizuka for providing optimisations to this function. // pragma inline string _lslAESBytesToString(list b, integer width, string alphabet) {{

   integer bits = llList2Integer(b, 0);

   integer i = 0;
   integer mask = ~(-1 << width);
   integer shift = 32 - width;

   integer available = 0;
   integer prev = 0;
   integer buf;
   integer extra;
   integer value;

   string s = "";

   @_lslAESBytesToStringLoop;
   if((bits -= 32) > -32) {
       available += 32 + (bits * (0 > bits));
       buf = llList2Integer(b, ++i);
       if (available >= width) {
           if (prev) {
               s += llGetSubString(
                   alphabet, 
                   value = (
                       extra | 
                       (
                           (buf >> (shift + prev)) & 
                           ~(-1 << (width - prev))
                       )
                   ), 
                   value
               );
               buf = buf << (width - prev);
               available -= width;
           }
           while(available >= width) {
               s += llGetSubString(
                   alphabet, 
                   value = ((buf >> shift) & mask),
                   value
               );
               buf = buf << width;
               available -= width;
           }
           if (prev = available) // Update prev
               extra = (buf >> shift) & mask;
           jump _lslAESBytesToStringLoop;
       }
   }
   if(available) {
       mask = -1 << (width - prev);
       return (s = "") + s + 
           llGetSubString(
               alphabet, 
               value = ((extra & mask) | 
                       (
                           (buf >> (shift + prev)) & 
                           ((-1 << (width - available)) ^ mask))
                       ), 
               value
           );
   }
   return (s = "") + s;

}}

/* Sets the operating mode of the AES engine. Returns TRUE on success. */ // pragma inline integer lslAESSetMode(integer mode) {{ if (~llListFindList( llList2ListStrided( llList2List(SUPPORTED_MODES(), 1, -1), 0, -1, 2), [mode])) { _lslAESMode = mode; return TRUE; } return FALSE; }}

/* Sets the padding mode of the AES engine. Returns TRUE on success. */ // pragma inline integer lslAESSetPadding(integer pad) {{ if (~llListFindList( llList2ListStrided( llList2List(SUPPORTED_PADS(), 1, -1), 0, -1, 2), [pad])) { _lslAESPad = pad; return TRUE; } return FALSE; }}

/*

* Sets the padding block-size (in bits) for this AES engine.
* Valid sizes are greater than zero, and a multiple of 128.
* Returns TRUE on success.
*/

// pragma inline integer lslAESSetPaddingSize(integer padSize) {{ if ((padSize > 0) && !(padSize % 128)) { _lslAESPadSize = padSize; return TRUE; } return FALSE; }}

/** Returns TRUE if an error occur during the last lslAESProcessCommand() call */ // pragma inline integer lslAESProcessCommandError() { return _lslAESProcessCommandError; }

/**

* Executes an LSLAES_COMMAND_* with given input-type, desired output-type, and 
* provided string-data.
*
* Returns string data.
* To test for an error in the function, call lslAESProcessComamndError(), if 
* the value of that is TRUE, then the string-data will be an error message.
*/

string lslAESProcessCommand( integer command, integer inputType, integer outputType, string str) {// Special case for COMMAND_SETUP

   // What type of data do we have?
   list data = [];
   if ((LSLAES_DATA_HEX() == inputType) || (LSLAES_DATA_BASE64() == inputType)) {
   	string alphabet = LSLAES_BASE64_CHARS();
   	integer width   = 6;
   	
   	if (LSLAES_DATA_BASE64() == inputType) {

integer e = llSubStringIndex(str, "="); if (e > 0) str = llDeleteSubString( (str = "") + str, e, -1 );

   	} else {

str = llToLower((str = "") + str); if (llGetSubString(str, 0, 1) == "0x") str = llDeleteSubString((str = "") + str, 0, 1);

alphabet = LSLAES_HEX_CHARS(); width = 4;

   	}
       data = _lslAESStringToBytes(
       	(str = "") + str, 
       	width, 
       	(alphabet = "") + alphabet
       );
   } else data = [(str = "") + "Unsupported input-type"];

   // Was data parsed successfully?
   if (llGetListEntryType(data, 0) != TYPE_INTEGER) {
   	_lslAESProcessCommandError = TRUE;
       return llList2String(data, 0);
   }

   // Now determine mode of operation
   if (command == LSLAES_COMMAND_PRIME()) 
       data = _lslAESKeyExpansion((data = []) + data);
   else if (command == LSLAES_COMMAND_ENCRYPT()) 
       data = _lslAESPadCipher((data = []) + data);
   else if (command == LSLAES_COMMAND_DECRYPT()) 
       data = _lslAESInvertPadCipher((data = []) + data);
   else if (command == LSLAES_COMMAND_INIT()) 
       data = _lslAESSetInputVector((data = []) + data);
   else data = ["Unsupported mode"];

   // Was mode executed successfully?
   if (llGetListEntryType(data, 0) != TYPE_INTEGER) {
   	_lslAESProcessCommandError = TRUE;
       return llList2String(data, 0);
   }

   // Convert into requested output type
   if ((command != LSLAES_COMMAND_PRIME()) && (command != LSLAES_COMMAND_INIT())) {
       if ((LSLAES_DATA_BASE64() == outputType) || (LSLAES_DATA_HEX() == outputType)) {
       	string alphabet = LSLAES_BASE64_CHARS();
       	integer width   = 6;
       	
       	if (LSLAES_DATA_HEX() == outputType) {
       		alphabet = LSLAES_HEX_CHARS();
       		width = 4;
       	}
       	
       	str = _lslAESBytesToString(
       		(data = []) + data, 
       		width, 
       		(alphabet = "") + alphabet
       	);
       	
       	if (LSLAES_DATA_BASE64() == outputType) {

integer l = llStringLength(str) % 4; if (l && (l < 3)) { string add = ""; if (l == 2) add = "=="; else if (l == 1) add = "=";

str = (str = add = "") + str + add; }

       	} else str = (str = "") + "0x" + str;
       } else {
       	_lslAESProcessCommandError = TRUE;
       	return "Invalid output type";
       }
   }
   
   _lslAESProcessCommandError = FALSE;
   return (str = "") + str;

}

/** Encrypts the provided data using the current settings. */ // pragma inline string lslAESEncrypt(integer inputType, integer outputType, string str) {{ return lslAESProcessCommand( LSLAES_COMMAND_ENCRYPT(), inputType, outputType, (str = "") + str); }}

/** Decrypts the provided data using the current settings. */ // pragma inline string lslAESDecrypt(integer inputType, integer outputType, string str) {{ return lslAESProcessCommand( LSLAES_COMMAND_DECRYPT(), inputType, outputType, (str = "") + str); }}

/** Encrypts the provided data using the current settings. */ // pragma inline string lslAESSetKey(integer inputType, string str) {{ return lslAESProcessCommand( LSLAES_COMMAND_PRIME(), inputType, 0, (str = "") + str); }}

/** Encrypts the provided data using the current settings. */ // pragma inline string lslAESSetIV(integer inputType, string str) {{ return lslAESProcessCommand( LSLAES_COMMAND_INIT(), inputType, 0, (str = "") + str); }}

/** Sets engine defaults. */ // pragma inline lslAESSetDefaults() {{ _lslAESMode = LSLAES_MODE_DEFAULT(); _lslAESPad = LSLAES_PAD_DEFAULT(); _lslAESPadSize = LSLAES_PAD_SIZE_DEFAULT(); }}</lsl>

Examples

Encrypt

<lsl>$import AES.AES_Core.lslm();

string myKey = "1234567890ABCDEF0123456789ABCDEF"; // 128-bit key in hex string myMsg = "Hello world! I am a lovely message waiting to be encrypted!"; string myIV = "89ABCDEF0123456789ABCDEF01234567";

default {

   state_entry() {
   	// Set defaults, not needed if mode, padding, and pad-size are set
   	lslAESSetDefaults();
   	
   	// Set-up the AES engine's operating mode
   	lslAESSetMode(LSLAES_MODE_CFB_ID());
   	lslAESSetPadding(LSLAES_PAD_NULLS_SAFE_ID());
   	lslAESSetPaddingSize(512);
   	
   	// "Prime" the engine with a key and input-vector
   	lslAESSetKey(LSLAES_DATA_HEX(), myKey);
   	lslAESSetIV(LSLAES_DATA_HEX(), myIV);
   	
   	// Encrypt the message
   	string data = lslAESEncrypt(
   		LSLAES_DATA_BASE64(), 
   		LSLAES_DATA_BASE64(), 
   		llStringToBase64(myMsg)
   	);
   	
   	// Process the result
   	string msg = "";
   	if (lslAESProcessCommandError()) msg = "ERROR: ";
   	else msg = "Encrypted: ";
   	llOwnerSay(msg + data);
   }

}</lsl>

Decrypt

<lsl>$import AES.AES_Core.lslm();

string myKey = "1234567890ABCDEF0123456789ABCDEF"; // 128-bit key in hex string myMsg = "Mdn6jGTwRPMOKTYTTdDKGm9KScz26LIz96KVOGAeMw3hpwByPfa07PDRHxRW4TIh5dmu5LlhKpTQChiFLJJYDw=="; string myIV = "89ABCDEF0123456789ABCDEF01234567";

default {

   state_entry() {
   	// Set defaults, not needed if mode, padding, and pad-size are set
   	lslAESSetDefaults();
   	
   	// Set-up the AES engine's operating mode
   	lslAESSetMode(LSLAES_MODE_CFB_ID());
   	lslAESSetPadding(LSLAES_PAD_NULLS_SAFE_ID());
   	lslAESSetPaddingSize(512);
   	
   	// "Prime" the engine with a key and input-vector
   	lslAESSetKey(LSLAES_DATA_HEX(), myKey);
   	lslAESSetIV(LSLAES_DATA_HEX(), myIV);
   	
   	// Encrypt the message
   	string data = lslAESDecrypt(
   		LSLAES_DATA_BASE64(), 
   		LSLAES_DATA_BASE64(), 
   		myMsg
   	);
   	
   	// Process the result
   	string msg = "";
   	if (lslAESProcessCommandError()) msg = "ERROR: ";
   	else {
   		msg = "Decrypted: ";
   		data = llBase64ToString(data);
   	}
   	llOwnerSay(msg + data);
   }

}</lsl>

Broker

The broker is a script that implements the AES engine, and which you query in order to encrypt strings. This is intended for use when your program logic is too large to fit within the free-memory of a script importing AES_Core.lslm. AES_Broker_Helper.lslm contains functions that aid you in communicating with the broker.

AES_Broker_Constants.lslm

<lsl>$module ()

// These variables are used to build communications. Commands are sent as // combined bits in the integer argument of a link-message, and are // recovered using masks, you may wish to read about bit-masks before // editing these values. These are used so the string argument is // kept free for data only. // // Commands take the following form (in hex): // 0xFFMMIOvv // Where the letters are: // F Filter, used to quickly determine if a message is for us. // C Command; encrypt/decrypt etc. // I Type of data provided (hex, base64, etc.). // O Desired type of data to be returned (hex, base64, etc.), // this is unused in replies as the reply's value for I will // be the request's value for O. // v Variable, depends on mode.

// This mask allows the filter byte to be retrieved quickly integer LSLAES_BROKER_FILTER_MASK() { return 0xFF000000; } // This mask allows the mask byte to be retrieved quickly integer LSLAES_BROKER_COMMAND_MASK() { return 0x00FF0000; } // This mask allows the input type to be retrieved quickly integer LSLAES_BROKER_INPUT_TYPE_MASK() { return 0x0000F000; } // This mask allows the output type to be retireved quickly integer LSLAES_BROKER_OUTPUT_TYPE_MASK() { return 0x00000F00; } // This mask allows the variable to retrieved quickly integer LSLAES_BROKER_VARIABLE_MASK() { return 0x000000FF; } // How many bits right variable must be shifted integer LSLAES_BROKER_VARIABLE_SHIFT() { return 0; }

// A request integer LSLAES_BROKER_FILTER_REQUEST() { return 0x81000000; } // A reply integer LSLAES_BROKER_FILTER_REPLY() { return 0x82000000; }

// An error occurred integer LSLAES_BROKER_COMMAND_ERROR() { return 0x00000000; } // Prime engine with key integer LSLAES_BROKER_COMMAND_PRIME() { return 0x00010000; } // Encrypt message using expanded key integer LSLAES_BROKER_COMMAND_ENCRYPT() { return 0x00020000; } // Decrypt message using expanded key integer LSLAES_BROKER_COMMAND_DECRYPT() { return 0x00030000; } // Sets-up the engine by specifying comma-separated flags integer LSLAES_BROKER_COMMAND_SETUP() { return 0x00050000; } // Initialise the engine with an input-vector integer LSLAES_BROKER_COMMAND_INIT() { return 0x00060000; }

// Input type is hex integer LSLAES_BROKER_INPUT_HEX() { return 0x00000000; } // Input type is base64 integer LSLAES_BROKER_INPUT_BASE64() { return 0x00001000; }

// Output type is hex integer LSLAES_BROKER_OUTPUT_HEX() { return 0x00000000; } // Output type is base64 integer LSLAES_BROKER_OUTPUT_BASE64() { return 0x00000100; }</lsl>

AES_Broker_Helper.lslm

<lsl>$module ()

$import AES.Broker.AES_Broker_Constants.lslm(); $import AES.AES_Constants.lslm();

// The following extra variables are used to track our messages key requestID = NULL_KEY;

// Sets-up the AES engine. Flags is a comma-separated list with the // following possible entries: // MODE_ECB - Sets Electronic Code-Book mode, a little faster but // not especially secure // MODE_CBC - Cipher-Block-Chaining mode, most commonly used, good // security. // MODE_CFB - Ciphertext Feed-Back mode. Similar to CBC, but does // not require an inverse-cipher to decrypt. // MODE_NOFB - Output Feed-Back mode. Similar to CFB. // // PAD_RBT - Residual Block Termination padding is a method of // encrypting data that does not fit correctly within // into blocks. // PAD_NULLS - Mainly added to provide support for PHP's mcrypt // library. Null-characters (zero-bytes) are added to // pad the length. ALL nulls are removed from the end // after decryption, so be careful if null-characters // occur within the text naturally. // PAD_ZEROES - Adds zero-bytes, with the final byte describing the // number of bytes added. If data fits within padSize // then an extra padSize bits is added. // PAD_RANDOM - Identical to PAD_ZEROES except that random bytes are // generated for padding. // // PAD_SIZE - Defines the length of padding for NULLS, ZEROES, and // random to align on. After this should be an integer // value defining the size. Must be a multiple of 128. // pragma inline lslAESSetup(integer targetLink, string flags, key id) {

   llMessageLinked(
       targetLink,
       LSLAES_BROKER_FILTER_REQUEST() | LSLAES_BROKER_COMMAND_SETUP(),
       (flags = "") + flags,
       requestID = id
   );

}

// Sends a link message to targetLink, requesting that aesKey be used to // prime the AES engine. aesKey should be a hexadecimal string representing // a value that is 128, 192, or 256-bits in length. // pragma inline lslAESPrimeHexKey(integer targetLink, string aesKey, key id) {

   llMessageLinked(
       targetLink,
       LSLAES_BROKER_FILTER_REQUEST() | LSLAES_BROKER_COMMAND_PRIME() | LSLAES_BROKER_INPUT_HEX(),
       (aesKey = "") + aesKey,
       requestID = id
   );

}

// Initialises a 128-bit input-vector to be used by the AES engine // pragma inline lslAESInitHexIV(integer targetLink, string iv, key id) {

   llMessageLinked(
       targetLink,
       LSLAES_BROKER_FILTER_REQUEST() | LSLAES_BROKER_COMMAND_INIT() | LSLAES_BROKER_INPUT_HEX(),
       (iv = "") + iv,
       requestID = id
   );

}

// Sends hexadecimal data and gets encrypted hexadecimal data back // pragma inline lslAESEncryptHexToHex(integer targetLink, string hexData, key id) {

   llMessageLinked(
       targetLink,
       LSLAES_BROKER_FILTER_REQUEST() | LSLAES_BROKER_COMMAND_ENCRYPT() | 
           LSLAES_BROKER_INPUT_HEX() | LSLAES_BROKER_OUTPUT_HEX(),
       (hexData = "") + hexData,
       requestID = id
   );

}

// Sends hexadecimal data and gets encrypted base64 data back // pragma inline lslAESEncryptHexToBase64(integer targetLink, string hexData, key id) {

   llMessageLinked(
       targetLink,
       LSLAES_BROKER_FILTER_REQUEST() | LSLAES_BROKER_COMMAND_ENCRYPT() | 
           LSLAES_BROKER_INPUT_HEX() | LSLAES_BROKER_OUTPUT_BASE64(),
       (hexData = "") + hexData,
       requestID = id
   );

}

// Send base64 data and gets encrypted hexadecimal data back // pragma inline lslAESEncryptBase64ToHex(integer targetLink, string b64Data, key id) {

   llMessageLinked(
       targetLink,
       LSLAES_BROKER_FILTER_REQUEST() | LSLAES_BROKER_COMMAND_ENCRYPT() | 
           LSLAES_BROKER_INPUT_BASE64() | LSLAES_BROKER_OUTPUT_HEX(),
       (b64Data = "") + b64Data,
       requestID = id
   );    

}

// Send base64 data and gets encrypted hexadecimal data back // pragma inline lslAESEncryptBase64ToBase64(integer targetLink, string b64Data, key id) {

   llMessageLinked(
       targetLink,
       LSLAES_BROKER_FILTER_REQUEST() | LSLAES_BROKER_COMMAND_ENCRYPT() | 
           LSLAES_BROKER_INPUT_BASE64() | LSLAES_BROKER_OUTPUT_BASE64(),
       (b64Data = "") + b64Data,
       requestID = id
   );    

}

// Sends hexadecimal data and gets decrypted hexadecimal data back // pragma inline lslAESDecryptHexToHex(integer targetLink, string hexData, key id) {

   llMessageLinked(
       targetLink,
       LSLAES_BROKER_FILTER_REQUEST() | LSLAES_BROKER_COMMAND_DECRYPT() | 
           LSLAES_BROKER_INPUT_HEX() | LSLAES_BROKER_OUTPUT_HEX(),
       (hexData = "") + hexData,
       requestID = id
   );

}

// Sends hexadecimal data and gets decrypted base64 data back // pragma inline lslAESDecryptHexToBase64(integer targetLink, string hexData, key id) {

   llMessageLinked(
       targetLink,
       LSLAES_BROKER_FILTER_REQUEST() | LSLAES_BROKER_COMMAND_DECRYPT() | 
           LSLAES_BROKER_INPUT_HEX() | LSLAES_BROKER_OUTPUT_BASE64(),
       (hexData = "") + hexData,
       requestID = id
   );

}

// Send base64 data and gets decrypted hexadecimal data back // pragma inline lslAESDecryptBase64ToHex(integer targetLink, string b64Data, key id) {

   llMessageLinked(
       targetLink,
       LSLAES_BROKER_FILTER_REQUEST() | LSLAES_BROKER_COMMAND_DECRYPT() | 
           LSLAES_BROKER_INPUT_BASE64() | LSLAES_BROKER_OUTPUT_HEX(),
       (b64Data = "") + b64Data,
       requestID = id
   );    

}

// Send base64 data and gets decrypted hexadecimal data back // pragma inline lslAESDecryptBase64ToBase64(integer targetLink, string b64Data, key id) {

   llMessageLinked(
       targetLink,
       LSLAES_BROKER_FILTER_REQUEST() | LSLAES_BROKER_COMMAND_DECRYPT() | 
           LSLAES_BROKER_INPUT_BASE64() | LSLAES_BROKER_OUTPUT_BASE64(),
       (b64Data = "") + b64Data,
       requestID = id
   );    

}

// Tests to see if a message is a reply or not (TRUE/FALSE) // pragma inline integer lslAESIsReply(integer int, key id) {

   return (
       ((int & LSLAES_BROKER_FILTER_MASK()) == LSLAES_BROKER_FILTER_REPLY()) && 
       (id == requestID)
   );

}

// Grabs the mode of this reply. Should be one of the LSLAES_BROKER_COMMAND_* constants // pragma inline integer lslAESGetReplyMode(integer int) {

   return (int & LSLAES_BROKER_COMMAND_MASK());

}

// Grabs the data type of this reply. Should be one of the LSLAES_BROKER_INPUT_* // constants. // pragma inline integer lslAESGetReplyDataType(integer int) {

   return (int & LSLAES_BROKER_INPUT_TYPE_MASK());

}</lsl>

AES_Broker.lslp

<lsl>$import AES.AES_Core.lslm(); $import AES.Broker.AES_Broker_Constants.lslm();

integer SUPPORTS_SETUP() { return TRUE; } integer MAX_SIZE() { return 1536; }

// pragma inline error(integer link, string str, key id) {{

   llMessageLinked(
       link,
       LSLAES_BROKER_FILTER_REPLY() | LSLAES_BROKER_COMMAND_ERROR(),
       str,
       id
   );

}}

default { state_entry() { lslAESSetDefaults(); }

link_message(integer link, integer channel, string msg, key id) { // Is the message for us? if ((channel & LSLAES_BROKER_FILTER_MASK()) == LSLAES_BROKER_FILTER_REQUEST()) { // Refuse overly large messages if (llStringLength(msg) > MAX_SIZE()) { error( link, "Maxmimum message length is " + (string)MAX_SIZE() + " characters", id ); return; }

           // Special case for COMMAND_SETUP
           if ((channel & LSLAES_BROKER_COMMAND_MASK()) == LSLAES_BROKER_COMMAND_SETUP()) {
      			if (SUPPORTS_SETUP()) {

// Break up flags if (msg != "") { list flags = llCSV2List((msg = "") + msg); integer i = 0; integer l = (flags != []); integer j = 0; list flag = []; do { flag = [llToUpper(llList2String(flags, i))];

if (~(j = llListFindList(SUPPORTED_MODES(), flag))) { if (!lslAESSetMode(llList2Integer(SUPPORTED_MODES(), ++j))) { error(link, "Unsupported mode", id); return; } } else if (~(j = llListFindList(SUPPORTED_PADS(), flag))) { if (!lslAESSetPadding(llList2Integer(SUPPORTED_PADS(), ++j))) { error(link, "Unsupported padding scheme", id); return; } } else if ((string)flag == LSLAES_PAD_SIZE()) { j = llList2Integer(flags, ++i); // Next value should be pad-size if (!lslAESSetPaddingSize(j)) { error(link, "Invalid padding size", id); return; } } else { error(link, "Unsupported flag '"+(string)flag+"'", id); return; } } while ((++i) < l); }

// Construct reply llMessageLinked( link, LSLAES_BROKER_FILTER_REPLY() | LSLAES_BROKER_COMMAND_SETUP(), "", id ); } else error(link, "Set-up not supported", id); return;

           }

           // What type of data do we have?
           integer inputType = channel & LSLAES_BROKER_INPUT_TYPE_MASK();
           if (inputType == LSLAES_BROKER_INPUT_HEX()) 
           	inputType = LSLAES_DATA_HEX();
           else if (inputType == LSLAES_BROKER_INPUT_BASE64()) 
           	inputType = LSLAES_DATA_BASE64();
           else {
           	error(link, "Unsupported input-type", id);
           	return;
           }
           
           // What type of data do we want?
           integer outputType = channel & LSLAES_BROKER_OUTPUT_TYPE_MASK();
           integer output = 0;
           if (outputType == LSLAES_BROKER_OUTPUT_HEX()) {
           	outputType = LSLAES_DATA_HEX();
           	output = LSLAES_BROKER_INPUT_HEX();
           } else if (outputType == LSLAES_BROKER_OUTPUT_BASE64()) {
           	outputType = LSLAES_DATA_BASE64();
           	output = LSLAES_BROKER_INPUT_BASE64();
           } else outputType = -1;

           // Now determine mode of operation
           integer command = channel & LSLAES_BROKER_COMMAND_MASK();
           list data = [];
           
           if (command == LSLAES_BROKER_COMMAND_PRIME()) 
               msg = lslAESSetKey(inputType, (msg = "") + msg);
           else if (command == LSLAES_BROKER_COMMAND_ENCRYPT()) {
           	if (~outputType) 

msg = lslAESEncrypt(inputType, outputType, (msg = "") + msg); else { error(link, (msg = "") + "Unsupported output-type", id); return; }

           } else if (command == LSLAES_BROKER_COMMAND_DECRYPT()) {
           	if (~outputType) 
               	msg = lslAESDecrypt(inputType, outputType, (msg = "") + msg);

else { error(link, (msg = "") + "Unsupported output-type", id); return; }

           } else if (command == LSLAES_BROKER_COMMAND_INIT()) 
               msg = lslAESSetIV(inputType, (msg = "") + msg);
           else {
           	error(link, (msg = "") + "Unsupported mode", id);
           	return;
           }

           // Was command executed successfully?
           if (lslAESProcessCommandError()) {
               error(link, (msg = "") + msg, id);
               return;
           }

           // Construct reply
           llMessageLinked(
               link,
               LSLAES_BROKER_FILTER_REPLY() | command | output,
               (msg = "") + msg,
               id
           );
       }
   }

}</lsl>

Examples

Encryption (AES_Broker_Encrypt.lslp)

<lsl>$import AES.Broker.AES_Broker_Helper.lslm();

integer aesLink = LINK_THIS;

string myKey = "1234567890ABCDEF0123456789ABCDEF"; // 128-bit key in hex string myMsg = "Hello world! I am a lovely message waiting to be encrypted!"; string myIV = "89ABCDEF0123456789ABCDEF01234567";

default {

   state_entry() { // Setup the engine for use
       lslAESSetup(
           aesLink,
           llDumpList2String(
           	[

LSLAES_MODE_CFB(), // CFB requires a less complex broker LSLAES_PAD_NULLS_SAFE(),// Safe null-padding (preserves bits) LSLAES_PAD_SIZE(), // Pad into blocks of 512-bits 512 ], "," ),

           llGetKey()
       );
   }

   link_message(integer x, integer y, string msg, key id) {
       if (!lslAESIsReply(y, id)) return;

       y = lslAESGetReplyMode(y);
       if (y == LSLAES_BROKER_COMMAND_ERROR()) 
           llOwnerSay("SETUP ERROR: "+msg);
       else if (y == LSLAES_BROKER_COMMAND_SETUP()) 
           state prime;
   }

}

state prime {

   state_entry() { // First prime the engine with a key
       lslAESPrimeHexKey(
           aesLink,
           myKey,
           llGetKey()
       );
   }

   link_message(integer x, integer y, string msg, key id) {
       if (!lslAESIsReply(y, id)) return;

       y = lslAESGetReplyMode(y);
       if (y == LSLAES_BROKER_COMMAND_ERROR()) 
           llOwnerSay("PRIME ERROR: "+msg);
       else if (y == LSLAES_BROKER_COMMAND_PRIME()) 
           state init;
   }

}

state init {

   state_entry() { // Now init the engine with an input vector
       lslAESInitHexIV(
           aesLink,
           myIV,
           llGetKey()
       );
   }

   link_message(integer x, integer y, string msg, key id) {
       if (!lslAESIsReply(y, id)) return;

       y = lslAESGetReplyMode(y);
       if (y == LSLAES_BROKER_COMMAND_ERROR()) 
           llOwnerSay("INIT ERROR: "+msg);
       else if (y == LSLAES_BROKER_COMMAND_INIT()) 
           state encrypt;
   }

}

state encrypt {

   state_entry() { // Send our message
       lslAESEncryptBase64ToBase64(
           aesLink,
           llStringToBase64(myMsg),
           llGetOwner()
       );
   }

   link_message(integer x, integer y, string msg, key id) {
       if (!lslAESIsReply(y, id)) return;

       y = lslAESGetReplyMode(y);
       if (y == LSLAES_BROKER_COMMAND_ERROR()) 
           llOwnerSay("ENCRYPT ERROR: "+msg);
       else if (y == LSLAES_BROKER_COMMAND_ENCRYPT()) 
           llOwnerSay("Encrypted: "+msg);
   }

}</lsl>

Decryption (AES_Broker_Decrypt.lslp)

<lsl>$import AES.Broker.AES_Broker_Helper.lslm();

integer aesLink = LINK_THIS;

string myKey = "1234567890ABCDEF0123456789ABCDEF"; // 128-bit key in hex string myMsg = "Mdn6jGTwRPMOKTYTTdDKGm9KScz26LIz96KVOGAeMw3hpwByPfa07PDRHxRW4TIh5dmu5LlhKpTQChilKJZcCw=="; string myIV = "89ABCDEF0123456789ABCDEF01234567";

default {

   state_entry() { // Setup the engine for use
       lslAESSetup(
           aesLink,
           llDumpList2String(
           	[

LSLAES_MODE_CFB(), // CFB requires a less complex broker LSLAES_PAD_NULLS_SAFE(),// Safe null-padding (preserves bits) LSLAES_PAD_SIZE(), // Pad into blocks of 512-bits 512 ], "," ),

           llGetKey()
       );
   }

   link_message(integer x, integer y, string msg, key id) {
       if (!lslAESIsReply(y, id)) return;

       y = lslAESGetReplyMode(y);
       if (y == LSLAES_BROKER_COMMAND_ERROR()) 
           llOwnerSay("SETUP ERROR: "+msg);
       else if (y == LSLAES_BROKER_COMMAND_SETUP()) 
           state prime;
   }

}

state prime {

   state_entry() { // First prime the engine with a key
       lslAESPrimeHexKey(
           aesLink,
           myKey,
           llGetKey()
       );
   }

   link_message(integer x, integer y, string msg, key id) {
       if (!lslAESIsReply(y, id)) return;

       y = lslAESGetReplyMode(y);
       if (y == LSLAES_BROKER_COMMAND_ERROR()) 
           llOwnerSay("PRIME ERROR: "+msg);
       else if (y == LSLAES_BROKER_COMMAND_PRIME()) 
           state init;
   }

}

state init {

   state_entry() { // Now init the engine with an input vector
       lslAESInitHexIV(
           aesLink,
           myIV,
           llGetKey()
       );
   }

   link_message(integer x, integer y, string msg, key id) {
       if (!lslAESIsReply(y, id)) return;

       y = lslAESGetReplyMode(y);
       if (y == LSLAES_BROKER_COMMAND_ERROR()) 
           llOwnerSay("INIT ERROR: "+msg);
       else if (y == LSLAES_BROKER_COMMAND_INIT()) 
           state decrypt;
   }

}

state decrypt {

   state_entry() { // Send our message
       lslAESDecryptBase64ToBase64(
           aesLink,
           myMsg,
           llGetOwner()
       );
   }

   link_message(integer x, integer y, string msg, key id) {
       if (!lslAESIsReply(y, id)) return;

       y = lslAESGetReplyMode(y);
       if (y == LSLAES_BROKER_COMMAND_ERROR()) 
           llOwnerSay("DECRYPT ERROR: "+msg);
       else if (y == LSLAES_BROKER_COMMAND_DECRYPT()) 
           llOwnerSay("Decrypted: "+llBase64ToString(msg));
   }

}</lsl>