Difference between revisions of "SHA-1"

From Second Life Wiki
Jump to navigation Jump to search
m (of course they list it in the wikipedia article. I think I choose that alternative version because it involved the least number of operators. Go me, trying to save one byte!)
(It failed because our hex function puts out upper case hex, not lower case hex.)
Line 11: Line 11:
<lsl>//////////////////////////////////////////////////////////////////////////////////////
<lsl>//////////////////////////////////////////////////////////////////////////////////////
//
//
// UTF-8 SHA-1 SHA-160
// UTF-8 SHA-1 160
// Version 1.2
// Version 1.3
// ESL Compiled: "Dec 13 2010", "01:29:03"
// ESL Compiled: "Nov 25 2013", "23:44:24"
// Copyright (C) 2010 Strife Onizuka
// Copyright (C) 2013 Strife Onizuka
// Based on Pseudo-code from http://en.wikipedia.org/wiki/SHA-1
// Based on Pseudo-code from http://en.wikipedia.org/wiki/SHA1
// https://wiki.secondlife.com/wiki/SHA-1
// https://wiki.secondlife.com/wiki/SHA1
//
//
// This library is free software; you can redistribute it and/or
// This library is free software; you can redistribute it and/or
Line 36: Line 36:


//===================================================//
//===================================================//
//                 Combined Library                 //
//               Combined Library v1.0              //
//            "Dec 13 2010", "01:29:03"            //
//            "Nov 25 2013", "23:44:24"            //
//  Copyright (C) 2004-2008, Strife Onizuka (cc-by)  //
//  Copyright (C) 2004-2012, Strife Onizuka (cc-by)  //
//    http://creativecommons.org/licenses/by/3.0/    //
//    http://creativecommons.org/licenses/by/3.0/    //
//===================================================//
//===================================================//
//{
//{
string TrimRight(string src, string chrs)//LSLEditor Safe, LSO Safe
{
    integer i = llStringLength(src);
    integer j = i;
    do ; while(~llSubStringIndex(chrs, llGetSubString(src, i = ~-(j = i), i)) && j);
    return llDeleteSubString(src, j, 0x7FFFFFF0);
}


string hexc="0123456789ABCDEF";
string hexc="0123456789ABCDEF";
Line 55: Line 47:
//} Combined Library
//} Combined Library


string Base64_SHA1(string plain, integer bit_length) { //$[E20009]
string Base64_SHA1(string plain, integer bit_length) {  
     integer H1 = 0x67452301;
     integer H1 = 0x67452301;
     integer H2 = 0xefcdab89;
     integer H2 = 0xefcdab89;
Line 62: Line 54:
     integer H5 = 0xc3d2e1f0;
     integer H5 = 0xc3d2e1f0;


    //OR on the extra bit.
     integer b = ((bit_length + 40) >> 5) | 15;//this works because we want the value to be one less than the next appropriate multiple of 16.
     integer b = ((bit_length + 40) >> 5) | 15;
    integer T = llBase64ToInteger((TrimRight(llGetSubString(plain, -4, -1),"=")) + "AAAA");
     string buf = "AAA";
     string buf = "AAA";
     integer i = -5;
     integer i = -5;
     do buf += buf; while((i = -~i));
     do buf += buf; while((i = -~i));
     if(bit_length)
    integer S = (6 * llSubStringIndex((plain)+"=", "="));
    {
    integer T = 0x80000000;
        i = 0x800000;
     if(bit_length) {
        if(!(bit_length % 24))
        if(S < bit_length) {
             i = 0x00000080;
            plain = llDeleteSubString(plain, S, 0x7FFFFFF0);
         else if((bit_length % 24) == 16)
            i = ((bit_length + 23) / 24) * 24;
            i = 0x00008000;
            do
                plain += buf;
             while((S += 576) < i);
         }
        T = 23 - ((~-(bit_length)) % 24);
        T = (llBase64ToInteger(llGetSubString((llGetSubString(plain = llGetSubString(plain, 0, (bit_length / 6) | 3), -4, (~-(S / 6)))) + "AAAAA", 0, 5)) & (0xFFFFFF00 << T)) | (0x00000080 << T);
     }
     }
     else
     //llOwnerSay(llList2CSV([b,j, llStringLength(buf), llIntegerToBase64(j << (6 - ((b % 3) << 1)))]));
        T = 0x80000000;//T is corrupt because of https://jira.secondlife.com/browse/SVC-104
     plain = llInsertString( llDeleteSubString(plain, -4, -1) +  
//    llOwnerSay(llList2CSV([i,bit_length]));
                             llGetSubString(llIntegerToBase64(T), 0, 5) + buf, (-~((b << 4) / 3)),
     plain = llGetSubString( llDeleteSubString(plain, -4, -1) +  
                            llGetSubString(llIntegerToBase64(bit_length << (6 - ((b % 3) << 1))), 0, 5));
                             llGetSubString(llIntegerToBase64(T | i), 0, 5) +  
    //llOwnerSay(llList2CSV([llStringLength(plain), Base64ToHex(plain), T]));
                            buf, 0, (b << 4) / 3) +
            llIntegerToBase64(bit_length << (6 - ((b % 3) << 1)));
     list x;
     list x;
     integer S = i = 0;
     i = 0;
     do
     do
     {
     {
Line 93: Line 86:
         integer E = H5;
         integer E = H5;
         x = (list)(bit_length = 0);//the zero gets flushed off the stack by the later loops
         x = (list)(bit_length = 0);//the zero gets flushed off the stack by the later loops
         do
         do {
        {
             T = llBase64ToInteger(buf = llGetSubString(plain, T = ((i + bit_length) << 4) / 3, T+6)) << (S = ((i + bit_length) % 3) << 1);
             T = llBase64ToInteger(buf = llGetSubString(plain, T = ((i + bit_length) << 4) / 3, T+6)) << (S = ((i + bit_length) % 3) << 1);
             if(S)
             if(S)
                 T = T | (llBase64ToInteger("A" + (llDeleteSubString(buf, 0, 1))) >> (6 - S));
                 T = T | (llBase64ToInteger("A" + (llDeleteSubString(buf, 0, 1))) >> (6 - S));
//            llOwnerSay("W["+(string)bit_length+"]="+hex(T));
//            llOwnerSay("W["+(string)j+"]="+hex(T));
             x += T;
             x += T;
             T += ((A << 5) | ((A >> 27) & 0x1F)) + (D ^ (B & (C ^ D))) + E + 0x5a827999;
             T += ((A << 5) | ((A >> 27) & 0x1F)) + (D ^ (B & (C ^ D))) + E + 0x5a827999;
Line 106: Line 98:
             B = A;
             B = A;
             A = T;
             A = T;
         }while(16 > (bit_length = -~bit_length));
         } while(16 > (bit_length = -~bit_length));
// llOwnerSay(llList2CSV(hexm(x)));
// llOwnerSay(llList2CSV(hexm(x)));
         do
         do {
        {
             S = llList2Integer(x,  -3) ^ llList2Integer(x,  -8) ^ llList2Integer(x, -14) ^ llList2Integer(x, -16);
             S = llList2Integer(x,  -3) ^ llList2Integer(x,  -8) ^ llList2Integer(x, -14) ^ llList2Integer(x, -16);
             x = llList2List(x + (T = ((S << 1) | !!(S & 0x80000000))), -16, -1);
             x = llList2List(x + (T = ((S << 1) | !!(S & 0x80000000))), -16, -1);
//            llOwnerSay("W["+(string)bit_length+"]="+hex(T));
//            llOwnerSay("W["+(string)j+"]="+hex(T));
             T += ((A << 5) | ((A >> 27) & 0x1F)) + (D ^ (B & (C ^ D))) + E + 0x5a827999;
             T += ((A << 5) | ((A >> 27) & 0x1F)) + (D ^ (B & (C ^ D))) + E + 0x5a827999;
             E = D;
             E = D;
Line 119: Line 110:
             B = A;
             B = A;
             A = T;
             A = T;
         }while(20 > (bit_length = -~bit_length));
         } while(20 > (bit_length = -~bit_length));
         do
         do {
        {
             S = llList2Integer(x,  -3) ^ llList2Integer(x,  -8) ^ llList2Integer(x, -14) ^ llList2Integer(x, -16);
             S = llList2Integer(x,  -3) ^ llList2Integer(x,  -8) ^ llList2Integer(x, -14) ^ llList2Integer(x, -16);
             x = llList2List(x + (T = ((S << 1) | !!(S & 0x80000000))), -16, -1);
             x = llList2List(x + (T = ((S << 1) | !!(S & 0x80000000))), -16, -1);
//            llOwnerSay("W["+(string)bit_length+"]="+hex(T));
//            llOwnerSay("W["+(string)j+"]="+hex(T));
             T += ((A << 5) | ((A >> 27) & 0x1F)) + (B ^ C ^ D) + E + 0x6ed9eba1;
             T += ((A << 5) | ((A >> 27) & 0x1F)) + (B ^ C ^ D) + E + 0x6ed9eba1;
             E = D;
             E = D;
Line 131: Line 121:
             B = A;
             B = A;
             A = T;
             A = T;
         }while(40 > (bit_length = -~bit_length));
         } while(40 > (bit_length = -~bit_length));
         do
         do {
        {
             S = llList2Integer(x,  -3) ^ llList2Integer(x,  -8) ^ llList2Integer(x, -14) ^ llList2Integer(x, -16);
             S = llList2Integer(x,  -3) ^ llList2Integer(x,  -8) ^ llList2Integer(x, -14) ^ llList2Integer(x, -16);
             x = llList2List(x + (T = ((S << 1) | !!(S & 0x80000000))), -16, -1);
             x = llList2List(x + (T = ((S << 1) | !!(S & 0x80000000))), -16, -1);
//            llOwnerSay("W["+(string)bit_length+"]="+hex(T));
//            llOwnerSay("W["+(string)j+"]="+hex(T));
             T += ((A << 5) | ((A >> 27) & 0x1F)) + ((B & C) | (B & D) | (C & D)) + E + 0x8f1bbcdc;
             T += ((A << 5) | ((A >> 27) & 0x1F)) + ((B & C) | (B & D) | (C & D)) + E + 0x8f1bbcdc;
             E = D;
             E = D;
Line 143: Line 132:
             B = A;
             B = A;
             A = T;
             A = T;
         }while(60 > (bit_length = -~bit_length));
         } while(60 > (bit_length = -~bit_length));
         do
         do {
        {
             S = llList2Integer(x,  -3) ^ llList2Integer(x,  -8) ^ llList2Integer(x, -14) ^ llList2Integer(x, -16);
             S = llList2Integer(x,  -3) ^ llList2Integer(x,  -8) ^ llList2Integer(x, -14) ^ llList2Integer(x, -16);
             x = llList2List(x + (T = ((S << 1) | !!(S & 0x80000000))), -16, -1);
             x = llList2List(x + (T = ((S << 1) | !!(S & 0x80000000))), -16, -1);
//            llOwnerSay("W["+(string)bit_length+"]="+hex(T));
//            llOwnerSay("W["+(string)j+"]="+hex(T));
             T += ((A << 5) | ((A >> 27) & 0x1F)) + (B ^ C ^ D) + E + 0xca62c1d6;
             T += ((A << 5) | ((A >> 27) & 0x1F)) + (B ^ C ^ D) + E + 0xca62c1d6;
             E = D;
             E = D;
Line 155: Line 143:
             B = A;
             B = A;
             A = T;
             A = T;
         }while(80 > (bit_length = -~bit_length));
         } while(80 > (bit_length = -~bit_length));
         H1 += A;
         H1 += A;
         H2 += B;
         H2 += B;
Line 161: Line 149:
         H4 += D;
         H4 += D;
         H5 += E;
         H5 += E;
     }while(b > (i += 16));
     } while(b > (i += 16));
     x = [H1, H2, H3, H4, H5];
     x = [H1, H2, H3, H4, H5];
     i = -5;
     i = -5;
     buf = "";
     buf = "";
     do
     do {
    {
         T = llList2Integer(x,i);
         T = llList2Integer(x,i);
         bit_length = 32;
         bit_length = 32;
         do
         do {
             buf += llGetSubString(hexc, b = ((T >> (bit_length -= 4)) & 0xF), b);
             buf += llGetSubString(hexc, b = ((T >> (bit_length -= 4)) & 0xF), b);
         while (bit_length);
         } while (bit_length);
     }while ((i = -~i));
     } while ((i = -~i));
     return buf;
     return buf;
}
}
Line 183: Line 170:
     integer H5 = 0xc3d2e1f0;
     integer H5 = 0xc3d2e1f0;


     //OR on the extra bit.
     //ORing on the extra bit. Since we are working in base64 the byte bounderies aren't where we want them.
     integer j = llStringLength(plain = llStringToBase64(plain));
    //So we get the last byte group and append our extra bit onto it. It contains either 1, 2, or 3 bytes.
     integer j = llSubStringIndex((plain = llStringToBase64(plain))+"=", "=");
     integer T = 0x80000000;
     integer T = 0x80000000;
     if (j) {
     if(j) {
        do ; while (llGetSubString(plain, (j = ~-j), j) == "=");
         j = (6 * (T = j)) & -8;//length in bits
         j = (-6 * ~j) & -8;
         T = llBase64ToInteger(llGetSubString((llGetSubString(plain, -4, (~-(T)))) + "AAAA", 0, 5)) | (0x00000080 << ((j % 3) << 3));
         T = llBase64ToInteger((llGetSubString(plain, -4, j / 6)) + "AAAAAA") | (0x00000080 << ((j % 3) << 3));
     }
     }
     integer b = ((j + 40) >> 5) | 15;
     integer b = ((j + 40) >> 5) | 15;//this works because we want the value to be one less than the next appropriate multiple of 16.
     string buf = "AAA";
     string buf = "AAA";
     integer i = -5;
     integer i = -5;
     do buf += buf; while((i = -~i));
     do buf += buf; while((i = -~i));//We need 85, 96 is close enough
//   llOwnerSay(llList2CSV([i,j]));
    //llOwnerSay(llList2CSV([b,j, llStringLength(buf), llIntegerToBase64(j << (6 - ((b % 3) << 1)))]));
     plain = llGetSubString( llDeleteSubString(plain, -4, -1) +  
     plain = llInsertString( llDeleteSubString(plain, -4, -1) +  
                             llGetSubString(llIntegerToBase64(T), 0, 5) +  
                             llGetSubString(llIntegerToBase64(T), 0, 5) + buf, (b << 4) / 3,
                            buf, 0, (b << 4) / 3) +
                            llGetSubString(llIntegerToBase64(j >> ((b % 3) << 1)), 0, 5));
            llIntegerToBase64(j << (6 - ((b % 3) << 1)));
    //llOwnerSay(llList2CSV([llStringLength(plain), Base64ToHex(plain)]));
     list x;
     list x;
     integer S = 0;
     integer S = 0;
Line 294: Line 281:




integer go(string in, string answer)
integer go(string in, string answer) {
{
     llOwnerSay("");
     llOwnerSay("");
    string b = llStringToBase64(in);
    integer len = (6 * llSubStringIndex((b)+"=", "=")) & -8;
     llResetTime();
     llResetTime();
     string out = UTF8_SHA1(in);
     string outu = UTF8_SHA1(in);
     float t = llGetTime();
     float tu = llGetTime();
     llOwnerSay(llDumpList2String(([out,t,llStringLength(in)]),","));
     llOwnerSay(llList2CSV(([outu, tu, len])));
     if(answer)
    llResetTime();
    {
    string outb = Base64_SHA1(b, len);
         llOwnerSay(answer);
    float tb = llGetTime();
         return answer == out;
    llOwnerSay(llList2CSV(([outb, tb, len])));
     if(answer) {
         llOwnerSay(llList2CSV(([answer, (answer == outu),(answer == outb)])));
         return (answer == outb) && (answer == outu);
     }
     }
     return TRUE;
     return TRUE;
Line 313: Line 304:
     state_entry()
     state_entry()
     {
     {
         if (Base64_SHA1("AAAA", 24) != "29e2dcfbb16f63bb0254df7585a15bb6fb5e927d")
         if(Base64_SHA1("AAAA", 24) != "29E2DCFBB16F63BB0254DF7585A15BB6FB5E927D")
             llOwnerSay("Failed Base64_SHA1(\"AAAA\", 24)");
             llOwnerSay("Failed Base64_SHA1(\"AAAA\", 24)");
         if(go("", "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709"))
         if(go("", "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709"))
            if(go("abc", "A9993E364706816ABA3E25717850C26C9CD0D89D"))
        if(go("abc", "A9993E364706816ABA3E25717850C26C9CD0D89D"))
                if(go("The quick brown fox jumps over the lazy dog", "2FD4E1C67A2D28FCED849EE1BB76E7391B93EB12"))
        if(go("The quick brown fox jumps over the lazy dog", "2FD4E1C67A2D28FCED849EE1BB76E7391B93EB12"))
                    if(go("Étude¿º", llSHA1String("Étude¿º")))
            llOwnerSay("All Tests Passed!");
                        go("DA39A3EE5E6B4B0D3255BFEF95601890AFD80709DA39A3EE5E6B4B0D3255BFEF95601890AFD80709DA39A3EE5E6B4B0D3255BFEF95601890AFD80709DA39A3EE5E6B4B0D3255BFEF95601890AFD80709DA39A3EE5E6B4B0D3255BFEF95601890AFD80709DA39A3EE5E6B4B0D3255BFEF95601890AFD80709DA39A3EE5E6B4B0D3255BFEF95601890AFD80709DA39A3EE5E6B4B0D3255BFEF95601890AFD80709DA39A3EE5E6B4B0D3255BFEF95601890AFD80709DA39A3EE5E6B4B0D3255BFEF95601890AFD80709DA39A3EE5E6B4B0D3255BFEF95601890AFD80709DA39A3EE5E6B4B0D3255BFEF95601890AFD80709DA39A3EE5E6B4B0D3255BFEF95601890AFD80709DA39A3EE5E6B4B0D3255BFEF95601890AFD80709DA39A3EE5E6B4B0D3255BFEF95601890AFD80709DA39A3EE5E6B4B0D3255BFEF95601890AFD80709DA39A3EE5E6B4B0D3255BFEF95601890AFD80709DA39A3EE5E6B4B0D3255BFEF95601890AFD80709DA39A3EE5E6B4B0D3255BFEF95601890AFD80709DA39A3EE5E6B4B0D3255BFEF95601890AFD80709DA39A3EE5E6B4B0D3255BFEF95601890AFD80709DA39A3EE5E6B4B0D3255BFEF95601890AFD80709DA39A3EE5E6B4B0D3255BFEF95601890AFD80709DA39A3EE5E6B4B0D3255BFEF95601890AFD80709DA39A3EE5E6B4B0D3255BFEF95601890AFD80709DA39A3EE5E6B4B0D3255BFEF", "");
//        llOwnerSay((string)llGetTime());
//        llOwnerSay((string)llGetTime());
     }
     }

Revision as of 22:08, 25 November 2013

 NEW  LSL now includes the function llSHA1String, which removes the need for the UTF8_SHA1 variant from this library.

Preforms a SHA-1 Hash on the text. Similar to and MD5 hash, although (slightly) more secure. Two versions of the function are provided, one for UTF-8 Strings (all strings in LSL are UTF-8) and the other is for Base64 Strings (you need to tell it how many bits long the data is).

There is also an SHA-2 implementations (224 & 256).

View "Wikipedia logo"SHA-1 for more information.

<lsl>////////////////////////////////////////////////////////////////////////////////////// // // UTF-8 SHA-1 160 // Version 1.3 // ESL Compiled: "Nov 25 2013", "23:44:24" // Copyright (C) 2013 Strife Onizuka // Based on Pseudo-code from http://en.wikipedia.org/wiki/SHA1 // https://wiki.secondlife.com/wiki/SHA1 // // 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 // // "Nov 25 2013", "23:44:24" // // Copyright (C) 2004-2012, Strife Onizuka (cc-by) // // http://creativecommons.org/licenses/by/3.0/ // //===================================================// //{

string hexc="0123456789ABCDEF";

//} Combined Library

string Base64_SHA1(string plain, integer bit_length) {

   integer H1 = 0x67452301;
   integer H2 = 0xefcdab89;
   integer H3 = 0x98badcfe;
   integer H4 = 0x10325476;
   integer H5 = 0xc3d2e1f0;
   integer b = ((bit_length + 40) >> 5) | 15;//this works because we want the value to be one less than the next appropriate multiple of 16.
   string buf = "AAA";
   integer i = -5;
   do buf += buf; while((i = -~i));
   integer S = (6 * llSubStringIndex((plain)+"=", "="));
   integer T = 0x80000000;
   if(bit_length) {
       if(S < bit_length) {
           plain = llDeleteSubString(plain, S, 0x7FFFFFF0);
           i = ((bit_length + 23) / 24) * 24;
           do 
               plain += buf;
           while((S += 576) < i);
       }
       T = 23 - ((~-(bit_length)) % 24);
       T = (llBase64ToInteger(llGetSubString((llGetSubString(plain = llGetSubString(plain, 0, (bit_length / 6) | 3), -4, (~-(S / 6)))) + "AAAAA", 0, 5)) & (0xFFFFFF00 << T)) | (0x00000080 << T);
   }
   //llOwnerSay(llList2CSV([b,j, llStringLength(buf), llIntegerToBase64(j << (6 - ((b % 3) << 1)))]));
   plain = llInsertString( llDeleteSubString(plain, -4, -1) + 
                           llGetSubString(llIntegerToBase64(T), 0, 5) + buf, (-~((b << 4) / 3)), 
                           llGetSubString(llIntegerToBase64(bit_length << (6 - ((b % 3) << 1))), 0, 5));
   //llOwnerSay(llList2CSV([llStringLength(plain), Base64ToHex(plain), T]));
   list x;
   i = 0;
   do
   {
       integer A = H1;
       integer B = H2;
       integer C = H3;
       integer D = H4;
       integer E = H5;
       x = (list)(bit_length = 0);//the zero gets flushed off the stack by the later loops
       do {
           T = llBase64ToInteger(buf = llGetSubString(plain, T = ((i + bit_length) << 4) / 3, T+6)) << (S = ((i + bit_length) % 3) << 1);
           if(S)
               T = T | (llBase64ToInteger("A" + (llDeleteSubString(buf, 0, 1))) >> (6 - S));

// llOwnerSay("W["+(string)j+"]="+hex(T));

           x += T;
           T += ((A << 5) | ((A >> 27) & 0x1F)) + (D ^ (B & (C ^ D))) + E + 0x5a827999;
           E = D;
           D = C;
           C = ((B << 30) | ((B >> 2) & 0x3FFFFFFF));
           B = A;
           A = T;
       } while(16 > (bit_length = -~bit_length));

// llOwnerSay(llList2CSV(hexm(x)));

       do {
           S = llList2Integer(x,  -3) ^ llList2Integer(x,  -8) ^ llList2Integer(x, -14) ^ llList2Integer(x, -16);
           x = llList2List(x + (T = ((S << 1) | !!(S & 0x80000000))), -16, -1);

// llOwnerSay("W["+(string)j+"]="+hex(T));

           T += ((A << 5) | ((A >> 27) & 0x1F)) + (D ^ (B & (C ^ D))) + E + 0x5a827999;
           E = D;
           D = C;
           C = ((B << 30) | ((B >> 2) & 0x3FFFFFFF));
           B = A;
           A = T;
       } while(20 > (bit_length = -~bit_length));
       do {
           S = llList2Integer(x,  -3) ^ llList2Integer(x,  -8) ^ llList2Integer(x, -14) ^ llList2Integer(x, -16);
           x = llList2List(x + (T = ((S << 1) | !!(S & 0x80000000))), -16, -1);

// llOwnerSay("W["+(string)j+"]="+hex(T));

           T += ((A << 5) | ((A >> 27) & 0x1F)) + (B ^ C ^ D) + E + 0x6ed9eba1;
           E = D;
           D = C;
           C = ((B << 30) | ((B >> 2) & 0x3FFFFFFF));
           B = A;
           A = T;
       } while(40 > (bit_length = -~bit_length));
       do {
           S = llList2Integer(x,  -3) ^ llList2Integer(x,  -8) ^ llList2Integer(x, -14) ^ llList2Integer(x, -16);
           x = llList2List(x + (T = ((S << 1) | !!(S & 0x80000000))), -16, -1);

// llOwnerSay("W["+(string)j+"]="+hex(T));

           T += ((A << 5) | ((A >> 27) & 0x1F)) + ((B & C) | (B & D) | (C & D)) + E + 0x8f1bbcdc;
           E = D;
           D = C;
           C = ((B << 30) | ((B >> 2) & 0x3FFFFFFF));
           B = A;
           A = T;
       } while(60 > (bit_length = -~bit_length));
       do {
           S = llList2Integer(x,  -3) ^ llList2Integer(x,  -8) ^ llList2Integer(x, -14) ^ llList2Integer(x, -16);
           x = llList2List(x + (T = ((S << 1) | !!(S & 0x80000000))), -16, -1);

// llOwnerSay("W["+(string)j+"]="+hex(T));

           T += ((A << 5) | ((A >> 27) & 0x1F)) + (B ^ C ^ D) + E + 0xca62c1d6;
           E = D;
           D = C;
           C = ((B << 30) | ((B >> 2) & 0x3FFFFFFF));
           B = A;
           A = T;
       } while(80 > (bit_length = -~bit_length));
       H1 += A;
       H2 += B;
       H3 += C;
       H4 += D;
       H5 += E;
   } while(b > (i += 16));
   x = [H1, H2, H3, H4, H5];
   i = -5;
   buf = "";
   do {
       T = llList2Integer(x,i);
       bit_length = 32;
       do {
           buf += llGetSubString(hexc, b = ((T >> (bit_length -= 4)) & 0xF), b);
       } while (bit_length);
   } while ((i = -~i));
   return buf;

}

string UTF8_SHA1(string plain) {

   integer H1 = 0x67452301;
   integer H2 = 0xefcdab89;
   integer H3 = 0x98badcfe;
   integer H4 = 0x10325476;
   integer H5 = 0xc3d2e1f0;
   //ORing on the extra bit. Since we are working in base64 the byte bounderies aren't where we want them.
   //So we get the last byte group and append our extra bit onto it. It contains either 1, 2, or 3 bytes.
   integer j = llSubStringIndex((plain = llStringToBase64(plain))+"=", "=");
   integer T = 0x80000000;
   if(j) {
       j = (6 * (T = j)) & -8;//length in bits
       T = llBase64ToInteger(llGetSubString((llGetSubString(plain, -4, (~-(T)))) + "AAAA", 0, 5)) | (0x00000080 << ((j % 3) << 3));
   }
   integer b = ((j + 40) >> 5) | 15;//this works because we want the value to be one less than the next appropriate multiple of 16.
   string buf = "AAA";
   integer i = -5;
   do buf += buf; while((i = -~i));//We need 85, 96 is close enough
   //llOwnerSay(llList2CSV([b,j, llStringLength(buf), llIntegerToBase64(j << (6 - ((b % 3) << 1)))]));
   plain = llInsertString( llDeleteSubString(plain, -4, -1) + 
                           llGetSubString(llIntegerToBase64(T), 0, 5) + buf, (b << 4) / 3, 
                           llGetSubString(llIntegerToBase64(j >> ((b % 3) << 1)), 0, 5));
   //llOwnerSay(llList2CSV([llStringLength(plain), Base64ToHex(plain)]));
   list x;
   integer S = 0;
   do
   {
       integer A = H1;
       integer B = H2;
       integer C = H3;
       integer D = H4;
       integer E = H5;
       x = (list)(j = 0);//the zero gets flushed off the stack by the later loops
       do
       {
           T = llBase64ToInteger(buf = llGetSubString(plain, T = ((i + j) << 4) / 3, T+6)) << (S = ((i + j) % 3) << 1);
           if(S)
               T = T | (llBase64ToInteger("A" + (llDeleteSubString(buf, 0, 1))) >> (6 - S));

// llOwnerSay("W["+(string)j+"]="+hex(T));

           x += T;
           T += ((A << 5) | ((A >> 27) & 0x1F)) + (D ^ (B & (C ^ D))) + E + 0x5a827999;
           E = D;
           D = C;
           C = ((B << 30) | ((B >> 2) & 0x3FFFFFFF));
           B = A;
           A = T;
       }while(16 > (j = -~j));

// llOwnerSay(llList2CSV(hexm(x)));

       do
       {
           S = llList2Integer(x,  -3) ^ llList2Integer(x,  -8) ^ llList2Integer(x, -14) ^ llList2Integer(x, -16);
           x = llList2List(x + (T = ((S << 1) | !!(S & 0x80000000))), -16, -1);

// llOwnerSay("W["+(string)j+"]="+hex(T));

           T += ((A << 5) | ((A >> 27) & 0x1F)) + (D ^ (B & (C ^ D))) + E + 0x5a827999;
           E = D;
           D = C;
           C = ((B << 30) | ((B >> 2) & 0x3FFFFFFF));
           B = A;
           A = T;
       }while(20 > (j = -~j));
       do
       {
           S = llList2Integer(x,  -3) ^ llList2Integer(x,  -8) ^ llList2Integer(x, -14) ^ llList2Integer(x, -16);
           x = llList2List(x + (T = ((S << 1) | !!(S & 0x80000000))), -16, -1);

// llOwnerSay("W["+(string)j+"]="+hex(T));

           T += ((A << 5) | ((A >> 27) & 0x1F)) + (B ^ C ^ D) + E + 0x6ed9eba1;
           E = D;
           D = C;
           C = ((B << 30) | ((B >> 2) & 0x3FFFFFFF));
           B = A;
           A = T;
       }while(40 > (j = -~j));
       do
       {
           S = llList2Integer(x,  -3) ^ llList2Integer(x,  -8) ^ llList2Integer(x, -14) ^ llList2Integer(x, -16);
           x = llList2List(x + (T = ((S << 1) | !!(S & 0x80000000))), -16, -1);

// llOwnerSay("W["+(string)j+"]="+hex(T));

           T += ((A << 5) | ((A >> 27) & 0x1F)) + ((B & C) | (B & D) | (C & D)) + E + 0x8f1bbcdc;
           E = D;
           D = C;
           C = ((B << 30) | ((B >> 2) & 0x3FFFFFFF));
           B = A;
           A = T;
       }while(60 > (j = -~j));
       do
       {
           S = llList2Integer(x,  -3) ^ llList2Integer(x,  -8) ^ llList2Integer(x, -14) ^ llList2Integer(x, -16);
           x = llList2List(x + (T = ((S << 1) | !!(S & 0x80000000))), -16, -1);

// llOwnerSay("W["+(string)j+"]="+hex(T));

           T += ((A << 5) | ((A >> 27) & 0x1F)) + (B ^ C ^ D) + E + 0xca62c1d6;
           E = D;
           D = C;
           C = ((B << 30) | ((B >> 2) & 0x3FFFFFFF));
           B = A;
           A = T;
       }while(80 > (j = -~j));
       H1 += A;
       H2 += B;
       H3 += C;
       H4 += D;
       H5 += E;
   }while(b > (i += 16));
   x = [H1, H2, H3, H4, H5];
   i = -5;
   buf = "";
   do
   {
       T = llList2Integer(x,i);
       j = 32;
       do
           buf += llGetSubString(hexc, b = ((T >> (j -= 4)) & 0xF), b);
       while (j);
   }while ((i = -~i));
   return buf;

}


integer go(string in, string answer) {

   llOwnerSay("");
   string b = llStringToBase64(in);
   integer len = (6 * llSubStringIndex((b)+"=", "=")) & -8;
   llResetTime();
   string outu = UTF8_SHA1(in);
   float tu = llGetTime();
   llOwnerSay(llList2CSV(([outu, tu, len])));
   llResetTime();
   string outb = Base64_SHA1(b, len);
   float tb = llGetTime();
   llOwnerSay(llList2CSV(([outb, tb, len])));
   if(answer) {
       llOwnerSay(llList2CSV(([answer, (answer == outu),(answer == outb)])));
       return (answer == outb) && (answer == outu);
   }
   return TRUE;

}

default {

   state_entry()
   {
       if(Base64_SHA1("AAAA", 24) != "29E2DCFBB16F63BB0254DF7585A15BB6FB5E927D")
           llOwnerSay("Failed Base64_SHA1(\"AAAA\", 24)");
       if(go("", "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709"))
       if(go("abc", "A9993E364706816ABA3E25717850C26C9CD0D89D"))
       if(go("The quick brown fox jumps over the lazy dog", "2FD4E1C67A2D28FCED849EE1BB76E7391B93EB12"))
           llOwnerSay("All Tests Passed!");

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

   }

}</lsl>