Difference between revisions of "User:Pedro Oval/Base64 HMAC SHA-1"
Jump to navigation
Jump to search
Pedro Oval (talk | contribs) m (moved User:Pedro Oval/Base64 HMAC SHA1 to User:Pedro Oval/Base64 HMAC SHA-1: Fix spelling) |
Pedro Oval (talk | contribs) m (<lsl> to <source>) |
||
(2 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
< | TODO: Add some text here, add padding test vectors | ||
<source lang="lsl2"> | |||
string HexToBase64Unpadded(string a) | string HexToBase64Unpadded(string a) | ||
{ | { | ||
Line 144: | Line 146: | ||
bit_length = 32; | bit_length = 32; | ||
do | do | ||
buf += llGetSubString( | buf += llGetSubString("0123456789abcdef", b = ((T >> (bit_length -= 4)) & 0xF), b); | ||
while (bit_length); | while (bit_length); | ||
}while ((i = -~i)); | }while ((i = -~i)); | ||
Line 186: | Line 188: | ||
return Base64SHA1forHMAC(B64Data, bit_length, 512, llList2Integer(x, 0), llList2Integer(x, 1), llList2Integer(x, 2), llList2Integer(x, 3), llList2Integer(x, 4)); | return Base64SHA1forHMAC(B64Data, bit_length, 512, llList2Integer(x, 0), llList2Integer(x, 1), llList2Integer(x, 2), llList2Integer(x, 3), llList2Integer(x, 4)); | ||
} | } | ||
</ | |||
test_vector_SHA1(string B64Key, string B64Data, string HexHash) | |||
{ | |||
llResetTime(); | |||
string hmac = Base64_HMAC_SHA1(B64Key, B64Data); | |||
if (hmac != HexHash) | |||
{ | |||
llOwnerSay("HMAC-SHA1 test failed.\nComputed: " + hmac + "\nExpected : " + HexHash); | |||
} | |||
else | |||
{ | |||
llOwnerSay("HMAC-SHA1 test passed in " + (string)llGetTime() + " seconds."); | |||
} | |||
} | |||
default | |||
{ | |||
state_entry() | |||
{ | |||
// RFC 2202 test vectors: | |||
test_vector_SHA1(HexToBase64Unpadded("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") + "=", | |||
llStringToBase64("Hi There"), | |||
"b617318655057264e28bc0b6fb378c8ef146be00"); | |||
test_vector_SHA1(llStringToBase64("Jefe"), | |||
llStringToBase64("what do ya want for nothing?"), | |||
"effcdf6ae5eb2fa2d27416d5f184df9c259a7c79"); | |||
test_vector_SHA1("qqqqqqqqqqqqqqqqqqqqqqqqqqo=", | |||
"3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d0=", | |||
"125d7342b9ac11cd91a39af48aa17b4f63f175d3"); | |||
test_vector_SHA1(HexToBase64Unpadded("0102030405060708090a0b0c0d0e0f10111213141516171819")+"==", | |||
HexToBase64Unpadded("cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd")+"=", | |||
"4c9007f4026250c6bc8414f9bf50c86c2d7235da"); | |||
test_vector_SHA1(HexToBase64Unpadded("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c") + "=", | |||
llStringToBase64("Test With Truncation"), | |||
"4c1a03424b55e07fe7f27be1d58bb9324a9a5a04"); | |||
string buf = "aaaaa"; | |||
buf += buf; | |||
buf += buf; | |||
buf += buf; | |||
buf += buf; | |||
buf += buf; | |||
test_vector_SHA1(HexToBase64Unpadded(buf) + "=", | |||
llStringToBase64("Test Using Larger Than Block-Size Key - Hash Key First"), | |||
"aa4ae5e15272d00e95705637ce8a3b55ed402112"); | |||
test_vector_SHA1(HexToBase64Unpadded(buf) + "=", | |||
llStringToBase64("Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"), | |||
"e8e99d0f45237d786d6bbaa7965c7808bbff1a91"); | |||
// Test vector added by the author | |||
test_vector_SHA1("", "", "fbdb1d1b18aa6c08324b7d64b71fb76370690e1d"); | |||
// Test vectors added by the author for zero-terminated data strings at different padding positions | |||
// (generated with an independent program written in PHP): | |||
test_vector_SHA1("blah", "", "cf63ad15d4e1d7cdc33cb0084e362afe60d047b1"); // "" | |||
test_vector_SHA1("blah", "AA==", "36cda2fc2a348a0b3645a9c135a12118e6f4dcca"); // "\0" | |||
test_vector_SHA1("blah", "AAA=", "7b6527796c885a794f695541b4ec1a5af28dec3e"); // "\0\0" | |||
test_vector_SHA1("blah", "AAAA", "d79915ec627764b7092ec66036fcaf94e4d94091"); // "\0\0\0" | |||
test_vector_SHA1("blah", "MQA=", "9fa63e8684813ca6f601e7e082fd989c72295019"); // "1\0" | |||
test_vector_SHA1("blah", "MQAA", "0d1ad14b1c4da14d5fca5b2e3486a7df2ef5fa12"); // "1\0\0" | |||
test_vector_SHA1("blah", "MQAAAA==", "29ba52e7d932fdb2854cf52f75dea30aa0773025"); // "1\0\0\0" | |||
test_vector_SHA1("blah", "MTIA", "ee65d68cdba172a95b7cc1640573bfa4f10fcf9d"); // "12\0" | |||
test_vector_SHA1("blah", "MTIAAA==", "4908fdece951bc779690565b54960a5e93119d56"); // "12\0\0" | |||
test_vector_SHA1("blah", "MTIAAAA=", "3213b2e563af1d5c04159bfcee0ee81124aaefb7"); // "12\0\0\0" | |||
test_vector_SHA1("blah", "MTIzAA==", "f3967f44b64b8a32b3d0c9cfe514e580aca6869d"); // "123\0" | |||
test_vector_SHA1("blah", "MTIzAAA=", "e509dfb925f1bd533216ba1f44d3ba1a998d078c"); // "123\0\0" | |||
test_vector_SHA1("blah", "MTIzAAAA", "06476a68a5c2c6cfc5c595b83dcc672e910a3e3e"); // "123\0\0\0" | |||
llOwnerSay("End of tests."); | |||
} | |||
} | |||
</source> |
Latest revision as of 20:29, 23 January 2015
TODO: Add some text here, add padding test vectors
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("0123456789abcdef", 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));
}
test_vector_SHA1(string B64Key, string B64Data, string HexHash)
{
llResetTime();
string hmac = Base64_HMAC_SHA1(B64Key, B64Data);
if (hmac != HexHash)
{
llOwnerSay("HMAC-SHA1 test failed.\nComputed: " + hmac + "\nExpected : " + HexHash);
}
else
{
llOwnerSay("HMAC-SHA1 test passed in " + (string)llGetTime() + " seconds.");
}
}
default
{
state_entry()
{
// RFC 2202 test vectors:
test_vector_SHA1(HexToBase64Unpadded("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") + "=",
llStringToBase64("Hi There"),
"b617318655057264e28bc0b6fb378c8ef146be00");
test_vector_SHA1(llStringToBase64("Jefe"),
llStringToBase64("what do ya want for nothing?"),
"effcdf6ae5eb2fa2d27416d5f184df9c259a7c79");
test_vector_SHA1("qqqqqqqqqqqqqqqqqqqqqqqqqqo=",
"3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d0=",
"125d7342b9ac11cd91a39af48aa17b4f63f175d3");
test_vector_SHA1(HexToBase64Unpadded("0102030405060708090a0b0c0d0e0f10111213141516171819")+"==",
HexToBase64Unpadded("cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd")+"=",
"4c9007f4026250c6bc8414f9bf50c86c2d7235da");
test_vector_SHA1(HexToBase64Unpadded("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c") + "=",
llStringToBase64("Test With Truncation"),
"4c1a03424b55e07fe7f27be1d58bb9324a9a5a04");
string buf = "aaaaa";
buf += buf;
buf += buf;
buf += buf;
buf += buf;
buf += buf;
test_vector_SHA1(HexToBase64Unpadded(buf) + "=",
llStringToBase64("Test Using Larger Than Block-Size Key - Hash Key First"),
"aa4ae5e15272d00e95705637ce8a3b55ed402112");
test_vector_SHA1(HexToBase64Unpadded(buf) + "=",
llStringToBase64("Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"),
"e8e99d0f45237d786d6bbaa7965c7808bbff1a91");
// Test vector added by the author
test_vector_SHA1("", "", "fbdb1d1b18aa6c08324b7d64b71fb76370690e1d");
// Test vectors added by the author for zero-terminated data strings at different padding positions
// (generated with an independent program written in PHP):
test_vector_SHA1("blah", "", "cf63ad15d4e1d7cdc33cb0084e362afe60d047b1"); // ""
test_vector_SHA1("blah", "AA==", "36cda2fc2a348a0b3645a9c135a12118e6f4dcca"); // "\0"
test_vector_SHA1("blah", "AAA=", "7b6527796c885a794f695541b4ec1a5af28dec3e"); // "\0\0"
test_vector_SHA1("blah", "AAAA", "d79915ec627764b7092ec66036fcaf94e4d94091"); // "\0\0\0"
test_vector_SHA1("blah", "MQA=", "9fa63e8684813ca6f601e7e082fd989c72295019"); // "1\0"
test_vector_SHA1("blah", "MQAA", "0d1ad14b1c4da14d5fca5b2e3486a7df2ef5fa12"); // "1\0\0"
test_vector_SHA1("blah", "MQAAAA==", "29ba52e7d932fdb2854cf52f75dea30aa0773025"); // "1\0\0\0"
test_vector_SHA1("blah", "MTIA", "ee65d68cdba172a95b7cc1640573bfa4f10fcf9d"); // "12\0"
test_vector_SHA1("blah", "MTIAAA==", "4908fdece951bc779690565b54960a5e93119d56"); // "12\0\0"
test_vector_SHA1("blah", "MTIAAAA=", "3213b2e563af1d5c04159bfcee0ee81124aaefb7"); // "12\0\0\0"
test_vector_SHA1("blah", "MTIzAA==", "f3967f44b64b8a32b3d0c9cfe514e580aca6869d"); // "123\0"
test_vector_SHA1("blah", "MTIzAAA=", "e509dfb925f1bd533216ba1f44d3ba1a998d078c"); // "123\0\0"
test_vector_SHA1("blah", "MTIzAAAA", "06476a68a5c2c6cfc5c595b83dcc672e910a3e3e"); // "123\0\0\0"
llOwnerSay("End of tests.");
}
}