User:Pedro Oval/Base64 HMAC SHA-1

From Second Life Wiki
< User:Pedro Oval
Revision as of 18:36, 6 March 2011 by Pedro Oval (talk | contribs) (First version - no test vectors yet)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

<lsl> string HexToBase64Unpadded(string a) {

   integer i = 0;
   integer len = llStringLength(a += "0000") - 4;
   string res = "";
   while (i < len)
   {
       res += llGetSubString(llIntegerToBase64(4*(integer)("0x" + llGetSubString(a, i, i+5))), 1, 4);
       i += 6;
   }
   return llGetSubString(res, 0, len*2/3);

}

string RemovePadding(string b64) // specialized - it won't work if the string consists of all "=" {

   integer i;
   do ; while(llGetSubString(b64, i = ~-i, i) == "=");
   return llGetSubString(b64, 0, i);

}

list Base64SHA1Compress(string b64, integer H1, integer H2, integer H3, integer H4, integer H5, integer i) {

   integer A = H1;
   integer B = H2;
   integer C = H3;
   integer D = H4;
   integer E = H5;
   integer round;
   integer S = 0;
   integer T;
   list x = [];
   string buf;
   do
   {
       T = llBase64ToInteger(buf = llGetSubString(b64, T = ((i + round) << 4) / 3, T+6)) << (S = ((i + round) % 3) << 1);
       if(S)
           T = T | (llBase64ToInteger("A" + (llDeleteSubString(buf, 0, 1))) >> (6 - S));

// llOwnerSay("W["+(string)round+"]="+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 > (round = -~round));

// 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)round+"]="+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 > (round = -~round));
   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)round+"]="+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 > (round = -~round));
   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)round+"]="+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 > (round = -~round));
   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)round+"]="+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 > (round = -~round));
   return [H1+A, H2+B, H3+C, H4+D, H5+E];

}

string Base64SHA1forHMAC(string b64, integer bit_length, integer extra_bit_length, integer H1, integer H2, integer H3, integer H4, integer H5) {

   //OR on the extra bit.
   integer b = ((bit_length + 40) >> 5) | 15;
   integer T = llBase64ToInteger(RemovePadding(llGetSubString(b64, -4, -1)) + "AAAA");
   string buf = "AAA";
   integer i = -5;
   do buf += buf; while((i = -~i));
   if(bit_length)
   {
       i = 0x800000;
       if(!(bit_length % 24))
           i = 0x80;
       else if((bit_length % 24) == 16)
           i = 0x8000;
   }
   else
       T = 0x80000000;//T is corrupt because of https://jira.secondlife.com/browse/SVC-104
   bit_length += extra_bit_length;

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

   b64 = llGetSubString( llDeleteSubString(b64, -4, -1) + 
                         llGetSubString(llIntegerToBase64(T | i), 0, 5) + 
                         buf, 0, (b << 4) / 3) + 
         llIntegerToBase64(bit_length << (6 - ((b % 3) << 1)));
   list x;
   i = 0;
   do
   {
       x = Base64SHA1Compress(b64, H1, H2, H3, H4, H5, i);
       H1 = llList2Integer(x, 0);
       H2 = llList2Integer(x, 1);
       H3 = llList2Integer(x, 2);
       H4 = llList2Integer(x, 3);
       H5 = llList2Integer(x, 4);
   }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;

}


// The Real Thing string Base64_HMAC_SHA1(string B64Key, string B64Data) { // integer H1 = 0x67452301; // integer H2 = 0xefcdab89; // integer H3 = 0x98badcfe; // integer H4 = 0x10325476; // integer H5 = 0xc3d2e1f0;

   integer bit_length = llSubStringIndex(B64Key, "=");
   if (!~bit_length)
   {
       bit_length = llStringLength(B64Key);
   }
   if (bit_length > 86)
   {
       // Use a hash of the key instead as a key
       B64Key = HexToBase64Unpadded(Base64SHA1forHMAC(B64Key, (bit_length*6)&-8, 0, 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0));
       bit_length = 27;
   }
   B64Key = llGetSubString(B64Key, 0, bit_length-1);
   string buf = "AAA";
   integer i = -5;
   do buf += buf; while((i = -~i));
   B64Key = llXorBase64StringsCorrect(llGetSubString(B64Key + buf, 0, 85) + "==", "NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2Ng==");
   list x = Base64SHA1Compress(B64Key, 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0, 0);
   bit_length = (6 * !(B64Data=="") * (llStringLength(B64Data)-4+llStringLength(RemovePadding(llGetSubString(B64Data,-4,-1))))) & -8;
   B64Data = HexToBase64Unpadded(Base64SHA1forHMAC(B64Data, bit_length, 512, llList2Integer(x, 0), llList2Integer(x, 1), llList2Integer(x, 2), llList2Integer(x, 3), llList2Integer(x, 4))) + "=";
   // Xor with Base64(chr(0x36 xor 0x5C) * 64)
   B64Key = llXorBase64StringsCorrect(B64Key, "ampqampqampqampqampqampqampqampqampqampqampqampqampqampqampqampqampqampqampqampqampqag==");
   x = Base64SHA1Compress(B64Key, 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0, 0);
   bit_length = 160;
   return Base64SHA1forHMAC(B64Data, bit_length, 512, llList2Integer(x, 0), llList2Integer(x, 1), llList2Integer(x, 2), llList2Integer(x, 3), llList2Integer(x, 4));

} </lsl>