Difference between revisions of "Talk:MD5"

From Second Life Wiki
Jump to navigation Jump to search
m (Created page with " : The UTF8_MD5 seem to work OK, only as long as the string contains only letters. : For example UTF8_MD5("Anylyn Hax") returns "4af17d386f8a3ea9cb861afdf8dbae00", and thats corr…")
 
m
 
(4 intermediate revisions by 2 users not shown)
Line 1: Line 1:
: The UTF8_MD5 seem to work OK, only as long as the string contains only letters.
: The UTF8_MD5 seem to work OK, only as long as the string contains only letters.
: For example UTF8_MD5("Anylyn Hax") returns "4af17d386f8a3ea9cb861afdf8dbae00", and thats correct.
: For example UTF8_MD5("Anylyn Hax") returns "4af17d386f8a3ea9cb861afdf8dbae00", and thats correct.
Line 11: Line 10:


:At this point I'm inclined to believe it to be an LSL issue. Likely there is a known bug/caveat that I've overlooked that LSLEditor doesn't abide by. Until I can get in world to confirm your findings and debug I am at a loose as to where to start. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 17:34, 28 December 2011 (PST)
:At this point I'm inclined to believe it to be an LSL issue. Likely there is a known bug/caveat that I've overlooked that LSLEditor doesn't abide by. Until I can get in world to confirm your findings and debug I am at a loose as to where to start. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 17:34, 28 December 2011 (PST)
:Try this version, I've compiled the ESL with a flag to pad llBase64ToInteger calls out to 8 bytes. I don't think it's needed but see if it solves your problem. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 17:50, 28 December 2011 (PST)
:: I don't know what you changed but now UTF8_MD5 works with all UTF8 Strings. :)) You can replace the function on the main site. Maybe you explain us where the problem was. So we learn something :)) Anylyn Hax 11:04, 11 January 2012 (PST)
:::To summarize, calls like <code>llBase64ToInteger(llGetSubString(str + "AAAAAA",0, 5))</code> are now <code>llBase64ToInteger(llGetSubString(str + "AAAAAAAA",0, 7))</code>.
:::An integer is comprised of 32 bits (4 bytes), and base64 uses 6 bits per character, so the minimum number of characters needed to store an integer is 6 (with 4 left over bits). The Base64 standard however requires everything to be padded out to byte boundaries (with "=" characters) which means the length of a Base64 string must be a multiple of 4. llBase64ToInteger historically didn't bother to verify inputs and was buggy, a description of this functionality can be found here: {{Jira|SVC-104}}. llBase64ToInteger would take anything that was between 6 and 8 characters without complaining and give the correct answer. This seems to have changed (at least in Mono). It looks like it requires that the string be padded out to 8 characters.
:::Not a big deal since this is one of the flaws that the Combined Library is intended to address. The CL provides not just functions but Macros that make it easier to address the quirks of various LSL runtimes (Mono, LSO, LSLEditor). It require more of the coder to use the CL Macros but it pays off in the long run as supporting multiple VMs just requires defining a few flags. I'll have a new version on the main page in a few days (I found a few places I could optimize which should increase speed and reduce memory requirements). I'll also be recompiling every other encryption function of mine (since they all use this method). -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 12:10, 11 January 2012 (PST)
<lsl>//////////////////////////////////////////////////////////////////////////////////////
//
// UTF-8 MD5
// Version 1.1a Beta
// ESL Compiled: "Dec 28 2011", "20:50:56"
// Copyright (C) 2012  Strife Onizuka
// Based on Pseudo-code from http://en.wikipedia.org/wiki/MD5
// llBase64ToInteger 8 character padding activated
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation;
// version 3 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library.  If not, see <http://www.gnu.org/licenses/>
// or write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
// Boston, MA  02111-1307  USA
//
//////////////////////////////////////////////////////////////////////////////////////
//===================================================//
//              Combined Library v1.0              //
//            "Dec 28 2011", "20:50:56"            //
//  Copyright (C) 2004-2012, Strife Onizuka (cc-by)  //
//    http://creativecommons.org/licenses/by/3.0/    //
//===================================================//
//{
string TrimRight(string src, string chrs)//LSLEditor Unsafe, LSO Safe
{
    integer i = llStringLength(src);
    do ; while(~llSubStringIndex(chrs, llGetSubString(src, i = ~-i, i)) && i);
    return llDeleteSubString(src, -~(i), 0x7FFFFFF0);
}
string hexc="0123456789abcdef";
//} Combined Library
list r1 = [7, 12, 17, 22];
list r2 = [5,  9, 14, 20];
list r3 = [4, 11, 16, 23];
list r4 = [6, 10, 15, 21];
list k1 = [
    0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
    0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821];
list k2 = [
    0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
    0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a];
list k3 = [
    0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
    0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665];
list k4 = [
    0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
    0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391];
string UTF8_MD5(string plain) {
    integer H1 = 1732584193;
    integer H2 = -271733879;
    integer H3 = -1732584194;
    integer H4 = 271733878;
    //OR on the extra bit.
    integer j = llStringLength(plain = llStringToBase64(plain));
    integer T = 0x80000000;
    if (j) {
        do ; while (llGetSubString(plain, (j = ~-j), j) == "=");
        j = (-6 * ~j) & -8;
        T = llBase64ToInteger(llGetSubString((llGetSubString(plain, -4, j / 6)) + "AAAAAAAA", 0, 7)) | (0x00000080 << ((j % 3) << 3));
    }
    integer b = ((j + 40) >> 5) | 15;
    string buf = "AAA";
    integer i = -5;
    do buf += buf; while((i = -~i));
//    llOwnerSay(llList2CSV([i,j]));
    plain = llGetSubString( llDeleteSubString(plain, -4, -1) +
                            llGetSubString(llIntegerToBase64(T), 0, 5) +
                            buf, 0, ((b << 4) / 3) - 7) +
            llGetSubString(llIntegerToBase64((((j & 0xFF) << 20) | ((j & 0xFF00) << 4) | ((j >> 12) & 0xFF0) | ((j >> 28) & 0xF)) >> ((b % 3) << 1)), 0, 5) +
            "AAAAAAAA";
    integer S = 0;
    list x;
    do
    {
        integer A = H1;
        integer B = H2;
        integer C = H3;
        integer D = H4;
        j = 0;
        x = [];
        do
        {
            T = llBase64ToInteger((buf = llGetSubString(plain, T = (((i + j) << 4) / 3), T+6)) + "A") << (S = (((i + j) % 3) << 1));
            if(S)
                T = T | (llBase64ToInteger("A" + (llDeleteSubString(buf, 0, 1)) + "AA") >> (6 - S));
            x += (T = ((T << 24) | ((T & 0xFF00) << 8) | ((T >> 8) & 0xFF00) | ((T >> 24) & 0xFF)));
            S = A + llList2Integer(k1, j) + T + (D ^ (B & (C ^ D)));
            T = llList2Integer(r1, j & 3);
            A = D;
            D = C;
            C = B;
            B += (S << T) | ((S >> (32 - T)) & ~(0xFFFFFFFF << T));
        }
        while(16 > (j = -~j));
        do
        {
            S = A + llList2Integer(k2, j & 15) + (C ^ (D & (B ^ C))) + llList2Integer(x, (-~(5 * j)) & 15);
            T = llList2Integer(r2, j & 3);
            A = D;
            D = C;
            C = B;
            B += (S << T) | ((S >> (32 - T)) & ~(0xFFFFFFFF << T));
        }
        while(32 > (j = -~j));
        do
        {
            S = A + llList2Integer(k3, j & 15) + (B ^ C ^ D) + llList2Integer(x, (3 * j + 5) & 15);
            T = llList2Integer(r3, j & 3);
            A = D;
            D = C;
            C = B;
            B += (S << T) | ((S >> (32 - T)) & ~(0xFFFFFFFF << T));
        }
        while(48 > (j = -~j));
        do
        {
            S = A + llList2Integer(k4, j & 15) + (C ^ (B | (~D))) + llList2Integer(x, (7 * j) & 15);
            T = llList2Integer(r4, j & 3);
            A = D;
            D = C;
            C = B;
            B += (S << T) | ((S >> (32 - T)) & ~(0xFFFFFFFF << T));
        }
        while(64 > (j = -~j));
//        llOwnerSay(llList2CSV(x));
        H1 += A;
        H2 += B;
        H3 += C;
        H4 += D;
    }while(b > (i += 16));
    x = [H4, H3, H2, H1];
    i = -4;
    buf = "";
    do
    {
        T = llList2Integer(x,i);
        j = 32;
        do
            buf = llGetSubString(hexc, b = ((T >> (j - 4)) & 0xF), b) + llGetSubString(hexc, b = ((T >> (j - 8)) & 0xF), b) + buf;
        while ((j -= 8));
    }while ((i = -~i));
    return buf;
}
string Base64_MD5(string plain, integer bit_length) { //$[E20009]
    integer H1 = 1732584193;
    integer H2 = -271733879;
    integer H3 = -1732584194;
    integer H4 = 271733878;
    //OR on the extra bit.
    integer b = (~-(((bit_length + 552) & -512) >> 5));
    integer T = llBase64ToInteger(llGetSubString((TrimRight(llGetSubString(plain = llStringToBase64(plain), -4, -1),"=")) + "AAAAAAAA", 0, 7));
    string buf = "AAA";
    integer i = -5;
    do buf += buf; while((i = -~i));
    if(bit_length)
    {
        i = 0x800000;
        if(T & 0xFF00)
            i = 0x00000080;
        else if(T & 0xFF0000)
            i = 0x00008000;
    }
    else
        T = 0x80000000;//T is corrupt because of https://jira.secondlife.com/browse/SVC-104
//    llOwnerSay(llList2CSV([i,j]));
    plain = llGetSubString( llDeleteSubString(plain, -4, -1) +
                            llGetSubString(llIntegerToBase64(T | i), 0, 5) +
                            buf, 0, ((b << 4) / 3) - 7) +
            llGetSubString(llIntegerToBase64((((bit_length & 0xFF) << 20) | ((bit_length & 0xFF00) << 4) | ((bit_length >> 12) & 0xFF0) | ((bit_length >> 28) & 0xF)) >> ((b % 3) << 1)), 0, 5) +
            "AAAAAAAA";
    integer S = i = 0;
    list x;
    do
    {
        integer A = H1;
        integer B = H2;
        integer C = H3;
        integer D = H4;
        bit_length = 0;
        x = [];
        do
        {
            T = llBase64ToInteger((buf = llGetSubString(plain, T = (((i + bit_length) << 4) / 3), T+6)) + "A") << (S = (((i + bit_length) % 3) << 1));
            if(S)
                T = T | (llBase64ToInteger("A" + (llDeleteSubString(buf, 0, 1)) + "AA") >> (6 - S));
            x += (T = ((T << 24) | ((T & 0xFF00) << 8) | ((T >> 8) & 0xFF00) | ((T >> 24) & 0xFF)));
            S = A + llList2Integer(k1, bit_length) + T + (D ^ (B & (C ^ D)));
            T = llList2Integer(r1, bit_length & 3);
            A = D;
            D = C;
            C = B;
            B += (S << T) | ((S >> (32 - T)) & ~(0xFFFFFFFF << T));
        }
        while(16 > (bit_length = -~bit_length));
        do
        {
            S = A + llList2Integer(k2, bit_length & 15) + (C ^ (D & (B ^ C))) + llList2Integer(x, (-~(5 * bit_length)) & 15);
            T = llList2Integer(r2, bit_length & 3);
            A = D;
            D = C;
            C = B;
            B += (S << T) | ((S >> (32 - T)) & ~(0xFFFFFFFF << T));
        }
        while(32 > (bit_length = -~bit_length));
        do
        {
            S = A + llList2Integer(k3, bit_length & 15) + (B ^ C ^ D) + llList2Integer(x, (3 * bit_length + 5) & 15);
            T = llList2Integer(r3, bit_length & 3);
            A = D;
            D = C;
            C = B;
            B += (S << T) | ((S >> (32 - T)) & ~(0xFFFFFFFF << T));
        }
        while(48 > (bit_length = -~bit_length));
        do
        {
            S = A + llList2Integer(k4, bit_length & 15) + (C ^ (B | (~D))) + llList2Integer(x, (7 * bit_length) & 15);
            T = llList2Integer(r4, bit_length & 3);
            A = D;
            D = C;
            C = B;
            B += (S << T) | ((S >> (32 - T)) & ~(0xFFFFFFFF << T));
        }
        while(64 > (bit_length = -~bit_length));
//        llOwnerSay(llList2CSV(x));
        H1 += A;
        H2 += B;
        H3 += C;
        H4 += D;
    }while(b > (i += 16));
    x = [H4, H3, H2, H1];
    i = -4;
    buf = "";
    do
    {
        T = llList2Integer(x,i);
        bit_length = 32;
        do
            buf = llGetSubString(hexc, b = ((T >> (bit_length - 4)) & 0xF), b) + llGetSubString(hexc, b = ((T >> (bit_length - 8)) & 0xF), b) + buf;
        while ((bit_length -= 8));
    }while ((i = -~i));
    return buf;
}
integer go(string in, string answer)
{
    llOwnerSay("");
    llResetTime();
    string out = UTF8_MD5(in);
    float t = llGetTime();
    llOwnerSay(llDumpList2String(([out,t,llStringLength(in)]),","));
    if((answer = llToLower(answer)))
    {
        llOwnerSay(answer);
        return answer == out;
    }
    return TRUE;
}
integer secret;
default
{
    state_entry()
    {
        llListen(0, "", "", "");
        llListen(1, "", "", "");
        if(go("","D41D8CD98F00B204E9800998ECF8427E"))
            if(go("abc","900150983CD24FB0D6963F7D28E17F72"))
                go("The quick brown fox jumps over the lazy dog","9E107D9D372BB6826BD81D3542A419D6");
//        llOwnerSay((string)llGetTime());
    }
    listen(integer a, string b, key c, string d)
    {
        if(a)
            secret = (integer)d;
        else
        {
            llOwnerSay(UTF8_MD5(d));
            llOwnerSay(UTF8_MD5(d + ":" + (string)secret));
            llOwnerSay(llMD5String(d,secret));
        }
    }
}</lsl>

Latest revision as of 12:10, 11 January 2012

The UTF8_MD5 seem to work OK, only as long as the string contains only letters.
For example UTF8_MD5("Anylyn Hax") returns "4af17d386f8a3ea9cb861afdf8dbae00", and thats correct.
But if I feed it a String containing numbers like UTF8_MD5("Hf0jUQFz32pIVRa") this should return "d06d41d2f783f39934bfc3c1969a30b2", but it returns "d998312450ba64589563cc563a6cc0cf", same with UTF8_MD5("666") it returns "693e9af84d3dfcc71e640e005bdc5e2e" instead of "fae0b27c451c728867a567e8c1bb4e53"
Can you explain me this ?
--Anylyn Hax 17:19, 27 December 2011 (PST)
It must be something to do with the order of operations as I get the correct results in LSLEditor. -- Strife (talk|contribs) 16:54, 28 December 2011 (PST)
I haven't spotted any instances of optimization that could be causing this. I have spotted one operation where parentheses weren't used to remove all ambiguity but it's excedingly unlikely to be the cause. -- Strife (talk|contribs) 17:27, 28 December 2011 (PST)
At this point I'm inclined to believe it to be an LSL issue. Likely there is a known bug/caveat that I've overlooked that LSLEditor doesn't abide by. Until I can get in world to confirm your findings and debug I am at a loose as to where to start. -- Strife (talk|contribs) 17:34, 28 December 2011 (PST)
Try this version, I've compiled the ESL with a flag to pad llBase64ToInteger calls out to 8 bytes. I don't think it's needed but see if it solves your problem. -- Strife (talk|contribs) 17:50, 28 December 2011 (PST)
I don't know what you changed but now UTF8_MD5 works with all UTF8 Strings. :)) You can replace the function on the main site. Maybe you explain us where the problem was. So we learn something :)) Anylyn Hax 11:04, 11 January 2012 (PST)
To summarize, calls like llBase64ToInteger(llGetSubString(str + "AAAAAA",0, 5)) are now llBase64ToInteger(llGetSubString(str + "AAAAAAAA",0, 7)).
An integer is comprised of 32 bits (4 bytes), and base64 uses 6 bits per character, so the minimum number of characters needed to store an integer is 6 (with 4 left over bits). The Base64 standard however requires everything to be padded out to byte boundaries (with "=" characters) which means the length of a Base64 string must be a multiple of 4. llBase64ToInteger historically didn't bother to verify inputs and was buggy, a description of this functionality can be found here: SVC-104. llBase64ToInteger would take anything that was between 6 and 8 characters without complaining and give the correct answer. This seems to have changed (at least in Mono). It looks like it requires that the string be padded out to 8 characters.
Not a big deal since this is one of the flaws that the Combined Library is intended to address. The CL provides not just functions but Macros that make it easier to address the quirks of various LSL runtimes (Mono, LSO, LSLEditor). It require more of the coder to use the CL Macros but it pays off in the long run as supporting multiple VMs just requires defining a few flags. I'll have a new version on the main page in a few days (I found a few places I could optimize which should increase speed and reduce memory requirements). I'll also be recompiling every other encryption function of mine (since they all use this method). -- Strife (talk|contribs) 12:10, 11 January 2012 (PST)

<lsl>////////////////////////////////////////////////////////////////////////////////////// // // UTF-8 MD5 // Version 1.1a Beta // ESL Compiled: "Dec 28 2011", "20:50:56" // Copyright (C) 2012 Strife Onizuka // Based on Pseudo-code from http://en.wikipedia.org/wiki/MD5 // llBase64ToInteger 8 character padding activated // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public License // as published by the Free Software Foundation; // version 3 of the License. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this library. If not, see <http://www.gnu.org/licenses/> // or write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////////////

//===================================================// // Combined Library v1.0 // // "Dec 28 2011", "20:50:56" // // Copyright (C) 2004-2012, Strife Onizuka (cc-by) // // http://creativecommons.org/licenses/by/3.0/ // //===================================================// //{

string TrimRight(string src, string chrs)//LSLEditor Unsafe, LSO Safe {

   integer i = llStringLength(src);
   do ; while(~llSubStringIndex(chrs, llGetSubString(src, i = ~-i, i)) && i);
   return llDeleteSubString(src, -~(i), 0x7FFFFFF0);

}

string hexc="0123456789abcdef";

//} Combined Library

list r1 = [7, 12, 17, 22]; list r2 = [5, 9, 14, 20]; list r3 = [4, 11, 16, 23]; list r4 = [6, 10, 15, 21];

list k1 = [

   0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
   0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821];

list k2 = [

   0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
   0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a];

list k3 = [

   0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
   0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665];

list k4 = [

   0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
   0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391];

string UTF8_MD5(string plain) {

   integer H1 = 1732584193;
   integer H2 = -271733879;
   integer H3 = -1732584194;
   integer H4 = 271733878;
   //OR on the extra bit.
   integer j = llStringLength(plain = llStringToBase64(plain));
   integer T = 0x80000000;
   if (j) {
       do ; while (llGetSubString(plain, (j = ~-j), j) == "=");
       j = (-6 * ~j) & -8;
       T = llBase64ToInteger(llGetSubString((llGetSubString(plain, -4, j / 6)) + "AAAAAAAA", 0, 7)) | (0x00000080 << ((j % 3) << 3));
   }
   integer b = ((j + 40) >> 5) | 15;
   string buf = "AAA";
   integer i = -5;
   do buf += buf; while((i = -~i));

// llOwnerSay(llList2CSV([i,j]));

   plain = llGetSubString( llDeleteSubString(plain, -4, -1) + 
                           llGetSubString(llIntegerToBase64(T), 0, 5) + 
                           buf, 0, ((b << 4) / 3) - 7) + 
           llGetSubString(llIntegerToBase64((((j & 0xFF) << 20) | ((j & 0xFF00) << 4) | ((j >> 12) & 0xFF0) | ((j >> 28) & 0xF)) >> ((b % 3) << 1)), 0, 5) + 
           "AAAAAAAA";
   integer S = 0;
   list x;
   do
   {
       integer A = H1;
       integer B = H2;
       integer C = H3;
       integer D = H4;
       j = 0;
       x = [];
       do
       {
           T = llBase64ToInteger((buf = llGetSubString(plain, T = (((i + j) << 4) / 3), T+6)) + "A") << (S = (((i + j) % 3) << 1));
           if(S)
               T = T | (llBase64ToInteger("A" + (llDeleteSubString(buf, 0, 1)) + "AA") >> (6 - S));
           x += (T = ((T << 24) | ((T & 0xFF00) << 8) | ((T >> 8) & 0xFF00) | ((T >> 24) & 0xFF)));
           S = A + llList2Integer(k1, j) + T + (D ^ (B & (C ^ D)));
           T = llList2Integer(r1, j & 3);
           A = D;
           D = C;
           C = B;
           B += (S << T) | ((S >> (32 - T)) & ~(0xFFFFFFFF << T));
       }
       while(16 > (j = -~j));
       do
       {
           S = A + llList2Integer(k2, j & 15) + (C ^ (D & (B ^ C))) + llList2Integer(x, (-~(5 * j)) & 15);
           T = llList2Integer(r2, j & 3);
           A = D;
           D = C;
           C = B;
           B += (S << T) | ((S >> (32 - T)) & ~(0xFFFFFFFF << T));
       }
       while(32 > (j = -~j));
       do
       {
           S = A + llList2Integer(k3, j & 15) + (B ^ C ^ D) + llList2Integer(x, (3 * j + 5) & 15);
           T = llList2Integer(r3, j & 3);
           A = D;
           D = C;
           C = B;
           B += (S << T) | ((S >> (32 - T)) & ~(0xFFFFFFFF << T));
       }
       while(48 > (j = -~j));
       do
       {
           S = A + llList2Integer(k4, j & 15) + (C ^ (B | (~D))) + llList2Integer(x, (7 * j) & 15);
           T = llList2Integer(r4, j & 3);
           A = D;
           D = C;
           C = B;
           B += (S << T) | ((S >> (32 - T)) & ~(0xFFFFFFFF << T));
       }
       while(64 > (j = -~j));

// llOwnerSay(llList2CSV(x));

       H1 += A;
       H2 += B;
       H3 += C;
       H4 += D;
   }while(b > (i += 16));
   x = [H4, H3, H2, H1];
   i = -4;
   buf = "";
   do
   {
       T = llList2Integer(x,i);
       j = 32;
       do
           buf = llGetSubString(hexc, b = ((T >> (j - 4)) & 0xF), b) + llGetSubString(hexc, b = ((T >> (j - 8)) & 0xF), b) + buf;
       while ((j -= 8));
   }while ((i = -~i));
   return buf;

}

string Base64_MD5(string plain, integer bit_length) { //$[E20009]

   integer H1 = 1732584193;
   integer H2 = -271733879;
   integer H3 = -1732584194;
   integer H4 = 271733878;
   //OR on the extra bit.
   integer b = (~-(((bit_length + 552) & -512) >> 5));
   integer T = llBase64ToInteger(llGetSubString((TrimRight(llGetSubString(plain = llStringToBase64(plain), -4, -1),"=")) + "AAAAAAAA", 0, 7));
   string buf = "AAA";
   integer i = -5;
   do buf += buf; while((i = -~i));
   if(bit_length)
   {
       i = 0x800000;
       if(T & 0xFF00)
           i = 0x00000080;
       else if(T & 0xFF0000)
           i = 0x00008000;
   }
   else
       T = 0x80000000;//T is corrupt because of https://jira.secondlife.com/browse/SVC-104

// llOwnerSay(llList2CSV([i,j]));

   plain = llGetSubString( llDeleteSubString(plain, -4, -1) + 
                           llGetSubString(llIntegerToBase64(T | i), 0, 5) + 
                           buf, 0, ((b << 4) / 3) - 7) + 
           llGetSubString(llIntegerToBase64((((bit_length & 0xFF) << 20) | ((bit_length & 0xFF00) << 4) | ((bit_length >> 12) & 0xFF0) | ((bit_length >> 28) & 0xF)) >> ((b % 3) << 1)), 0, 5) + 
           "AAAAAAAA";
   integer S = i = 0;
   list x;
   do
   {
       integer A = H1;
       integer B = H2;
       integer C = H3;
       integer D = H4;
       bit_length = 0;
       x = [];
       do
       {
           T = llBase64ToInteger((buf = llGetSubString(plain, T = (((i + bit_length) << 4) / 3), T+6)) + "A") << (S = (((i + bit_length) % 3) << 1));
           if(S)
               T = T | (llBase64ToInteger("A" + (llDeleteSubString(buf, 0, 1)) + "AA") >> (6 - S));
           x += (T = ((T << 24) | ((T & 0xFF00) << 8) | ((T >> 8) & 0xFF00) | ((T >> 24) & 0xFF)));
           S = A + llList2Integer(k1, bit_length) + T + (D ^ (B & (C ^ D)));
           T = llList2Integer(r1, bit_length & 3);
           A = D;
           D = C;
           C = B;
           B += (S << T) | ((S >> (32 - T)) & ~(0xFFFFFFFF << T));
       }
       while(16 > (bit_length = -~bit_length));
       do
       {
           S = A + llList2Integer(k2, bit_length & 15) + (C ^ (D & (B ^ C))) + llList2Integer(x, (-~(5 * bit_length)) & 15);
           T = llList2Integer(r2, bit_length & 3);
           A = D;
           D = C;
           C = B;
           B += (S << T) | ((S >> (32 - T)) & ~(0xFFFFFFFF << T));
       }
       while(32 > (bit_length = -~bit_length));
       do
       {
           S = A + llList2Integer(k3, bit_length & 15) + (B ^ C ^ D) + llList2Integer(x, (3 * bit_length + 5) & 15);
           T = llList2Integer(r3, bit_length & 3);
           A = D;
           D = C;
           C = B;
           B += (S << T) | ((S >> (32 - T)) & ~(0xFFFFFFFF << T));
       }
       while(48 > (bit_length = -~bit_length));
       do
       {
           S = A + llList2Integer(k4, bit_length & 15) + (C ^ (B | (~D))) + llList2Integer(x, (7 * bit_length) & 15);
           T = llList2Integer(r4, bit_length & 3);
           A = D;
           D = C;
           C = B;
           B += (S << T) | ((S >> (32 - T)) & ~(0xFFFFFFFF << T));
       }
       while(64 > (bit_length = -~bit_length));

// llOwnerSay(llList2CSV(x));

       H1 += A;
       H2 += B;
       H3 += C;
       H4 += D;
   }while(b > (i += 16));
   x = [H4, H3, H2, H1];
   i = -4;
   buf = "";
   do
   {
       T = llList2Integer(x,i);
       bit_length = 32;
       do
           buf = llGetSubString(hexc, b = ((T >> (bit_length - 4)) & 0xF), b) + llGetSubString(hexc, b = ((T >> (bit_length - 8)) & 0xF), b) + buf;
       while ((bit_length -= 8));
   }while ((i = -~i));
   return buf;

}

integer go(string in, string answer) {

   llOwnerSay("");
   llResetTime();
   string out = UTF8_MD5(in);
   float t = llGetTime();
   llOwnerSay(llDumpList2String(([out,t,llStringLength(in)]),","));
   if((answer = llToLower(answer)))
   {
       llOwnerSay(answer);
       return answer == out;
   }
   return TRUE;

}

integer secret;

default {

   state_entry()
   {
       llListen(0, "", "", "");
       llListen(1, "", "", "");
       if(go("","D41D8CD98F00B204E9800998ECF8427E"))
           if(go("abc","900150983CD24FB0D6963F7D28E17F72"))
               go("The quick brown fox jumps over the lazy dog","9E107D9D372BB6826BD81D3542A419D6");

// llOwnerSay((string)llGetTime());

   }
   listen(integer a, string b, key c, string d) 
   {
       if(a)
           secret = (integer)d;
       else
       {
           llOwnerSay(UTF8_MD5(d));
           llOwnerSay(UTF8_MD5(d + ":" + (string)secret));
           llOwnerSay(llMD5String(d,secret));
       }
   }

}</lsl>