Created
September 5, 2012 23:46
-
-
Save evilpacket/3647908 to your computer and use it in GitHub Desktop.
Pure lua MD5 Implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[--------------- | |
LuaBit v0.4 | |
------------------- | |
a bitwise operation lib for lua. | |
http://luaforge.net/projects/bit/ | |
How to use: | |
------------------- | |
bit.bnot(n) -- bitwise not (~n) | |
bit.band(m, n) -- bitwise and (m & n) | |
bit.bor(m, n) -- bitwise or (m | n) | |
bit.bxor(m, n) -- bitwise xor (m ^ n) | |
bit.brshift(n, bits) -- right shift (n >> bits) | |
bit.blshift(n, bits) -- left shift (n << bits) | |
bit.blogic_rshift(n, bits) -- logic right shift(zero fill >>>) | |
Please note that bit.brshift and bit.blshift only support number within | |
32 bits. | |
2 utility functions are provided too: | |
bit.tobits(n) -- convert n into a bit table(which is a 1/0 sequence) | |
-- high bits first | |
bit.tonumb(bit_tbl) -- convert a bit table into a number | |
------------------- | |
Under the MIT license. | |
copyright(c) 2006~2007 hanzhao ([email protected]) | |
--]]--------------- | |
--do | |
------------------------ | |
-- bit lib implementions | |
local function check_int(n) | |
-- checking not float | |
if(n - math.floor(n) > 0) then | |
error("trying to use bitwise operation on non-integer!") | |
end | |
end | |
local function tbl_to_number(tbl) | |
local n = #tbl | |
local rslt = 0 | |
local power = 1 | |
for i = 1, n do | |
rslt = rslt + tbl[i]*power | |
power = power*2 | |
end | |
return rslt | |
end | |
local function expand(tbl_m, tbl_n) | |
local big = {} | |
local small = {} | |
if(#tbl_m > #tbl_n) then | |
big = tbl_m | |
small = tbl_n | |
else | |
big = tbl_n | |
small = tbl_m | |
end | |
-- expand small | |
for i = #small + 1, #big do | |
small[i] = 0 | |
end | |
end | |
local to_bits = function () end | |
local function bit_not(n) | |
local tbl = to_bits(n) | |
local size = math.max(#tbl, 32) | |
for i = 1, size do | |
if(tbl[i] == 1) then | |
tbl[i] = 0 | |
else | |
tbl[i] = 1 | |
end | |
end | |
return tbl_to_number(tbl) | |
end | |
to_bits = function (n) | |
check_int(n) | |
if(n < 0) then | |
-- negative | |
return to_bits(bit_not(math.abs(n)) + 1) | |
end | |
-- to bits table | |
local tbl = {} | |
local cnt = 1 | |
while (n > 0) do | |
local last = math.mod(n,2) | |
if(last == 1) then | |
tbl[cnt] = 1 | |
else | |
tbl[cnt] = 0 | |
end | |
n = (n-last)/2 | |
cnt = cnt + 1 | |
end | |
return tbl | |
end | |
local function bit_or(m, n) | |
local tbl_m = to_bits(m) | |
local tbl_n = to_bits(n) | |
expand(tbl_m, tbl_n) | |
local tbl = {} | |
local rslt = math.max(#tbl_m, #tbl_n) | |
for i = 1, rslt do | |
if(tbl_m[i]== 0 and tbl_n[i] == 0) then | |
tbl[i] = 0 | |
else | |
tbl[i] = 1 | |
end | |
end | |
return tbl_to_number(tbl) | |
end | |
local function bit_and(m, n) | |
local tbl_m = to_bits(m) | |
local tbl_n = to_bits(n) | |
expand(tbl_m, tbl_n) | |
local tbl = {} | |
local rslt = math.max(#tbl_m, #tbl_n) | |
for i = 1, rslt do | |
if(tbl_m[i]== 0 or tbl_n[i] == 0) then | |
tbl[i] = 0 | |
else | |
tbl[i] = 1 | |
end | |
end | |
return tbl_to_number(tbl) | |
end | |
local function bit_xor(m, n) | |
local tbl_m = to_bits(m) | |
local tbl_n = to_bits(n) | |
expand(tbl_m, tbl_n) | |
local tbl = {} | |
local rslt = math.max(#tbl_m, #tbl_n) | |
for i = 1, rslt do | |
if(tbl_m[i] ~= tbl_n[i]) then | |
tbl[i] = 1 | |
else | |
tbl[i] = 0 | |
end | |
end | |
--table.foreach(tbl, print) | |
return tbl_to_number(tbl) | |
end | |
local function bit_rshift(n, bits) | |
check_int(n) | |
local high_bit = 0 | |
if(n < 0) then | |
-- negative | |
n = bit_not(math.abs(n)) + 1 | |
high_bit = 2147483648 -- 0x80000000 | |
end | |
for i=1, bits do | |
n = n/2 | |
n = bit_or(math.floor(n), high_bit) | |
end | |
return math.floor(n) | |
end | |
-- logic rightshift assures zero filling shift | |
local function bit_logic_rshift(n, bits) | |
check_int(n) | |
if(n < 0) then | |
-- negative | |
n = bit_not(math.abs(n)) + 1 | |
end | |
for i=1, bits do | |
n = n/2 | |
end | |
return math.floor(n) | |
end | |
local function bit_lshift(n, bits) | |
check_int(n) | |
if(n < 0) then | |
-- negative | |
n = bit_not(math.abs(n)) + 1 | |
end | |
for i=1, bits do | |
n = n*2 | |
end | |
return bit_and(n, 4294967295) -- 0xFFFFFFFF | |
end | |
local function bit_xor2(m, n) | |
local rhs = bit_or(bit_not(m), bit_not(n)) | |
local lhs = bit_or(m, n) | |
local rslt = bit_and(lhs, rhs) | |
return rslt | |
end | |
-- An MD5 mplementation in Lua, requires bitlib (hacked to use LuaBit from above, ugh) | |
-- 10/02/2001 [email protected] | |
local md5={ff=tonumber('ffffffff',16),consts={}} | |
string.gsub([[ d76aa478 e8c7b756 242070db c1bdceee | |
f57c0faf 4787c62a a8304613 fd469501 | |
698098d8 8b44f7af ffff5bb1 895cd7be | |
6b901122 fd987193 a679438e 49b40821 | |
f61e2562 c040b340 265e5a51 e9b6c7aa | |
d62f105d 02441453 d8a1e681 e7d3fbc8 | |
21e1cde6 c33707d6 f4d50d87 455a14ed | |
a9e3e905 fcefa3f8 676f02d9 8d2a4c8a | |
fffa3942 8771f681 6d9d6122 fde5380c | |
a4beea44 4bdecfa9 f6bb4b60 bebfbc70 | |
289b7ec6 eaa127fa d4ef3085 04881d05 | |
d9d4d039 e6db99e5 1fa27cf8 c4ac5665 | |
f4292244 432aff97 ab9423a7 fc93a039 | |
655b59c3 8f0ccc92 ffeff47d 85845dd1 | |
6fa87e4f fe2ce6e0 a3014314 4e0811a1 | |
f7537e82 bd3af235 2ad7d2bb eb86d391 | |
67452301 efcdab89 98badcfe 10325476 ]],"(%w+)", function (s) table.insert(md5.consts, tonumber(s,16)) end) | |
--67452301 efcdab89 98badcfe 10325476 ]],"(%w+)", function (s) tinsert(md5.consts,tonumber(s,16)) end) | |
function md5.transform(A,B,C,D,X) | |
local f=function (x,y,z) return bit_or(bit_and(x,y),bit_and(-x-1,z)) end | |
local g=function (x,y,z) return bit_or(bit_and(x,z),bit_and(y,-z-1)) end | |
local h=function (x,y,z) return bit_xor(x,bit_xor(y,z)) end | |
local i=function (x,y,z) return bit_xor(y,bit_or(x,-z-1)) end | |
local z=function (f,a,b,c,d,x,s,ac) | |
a=bit_and(a+f(b,c,d)+x+ac,md5.ff) | |
-- be *very* careful that left shift does not cause rounding! | |
return bit_or(bit_lshift(bit_and(a,bit_rshift(md5.ff,s)),s),bit_rshift(a,32-s))+b | |
end | |
local a,b,c,d=A,B,C,D | |
local t=md5.consts | |
a=z(f,a,b,c,d,X[ 0], 7,t[ 1]) | |
d=z(f,d,a,b,c,X[ 1],12,t[ 2]) | |
c=z(f,c,d,a,b,X[ 2],17,t[ 3]) | |
b=z(f,b,c,d,a,X[ 3],22,t[ 4]) | |
a=z(f,a,b,c,d,X[ 4], 7,t[ 5]) | |
d=z(f,d,a,b,c,X[ 5],12,t[ 6]) | |
c=z(f,c,d,a,b,X[ 6],17,t[ 7]) | |
b=z(f,b,c,d,a,X[ 7],22,t[ 8]) | |
a=z(f,a,b,c,d,X[ 8], 7,t[ 9]) | |
d=z(f,d,a,b,c,X[ 9],12,t[10]) | |
c=z(f,c,d,a,b,X[10],17,t[11]) | |
b=z(f,b,c,d,a,X[11],22,t[12]) | |
a=z(f,a,b,c,d,X[12], 7,t[13]) | |
d=z(f,d,a,b,c,X[13],12,t[14]) | |
c=z(f,c,d,a,b,X[14],17,t[15]) | |
b=z(f,b,c,d,a,X[15],22,t[16]) | |
a=z(g,a,b,c,d,X[ 1], 5,t[17]) | |
d=z(g,d,a,b,c,X[ 6], 9,t[18]) | |
c=z(g,c,d,a,b,X[11],14,t[19]) | |
b=z(g,b,c,d,a,X[ 0],20,t[20]) | |
a=z(g,a,b,c,d,X[ 5], 5,t[21]) | |
d=z(g,d,a,b,c,X[10], 9,t[22]) | |
c=z(g,c,d,a,b,X[15],14,t[23]) | |
b=z(g,b,c,d,a,X[ 4],20,t[24]) | |
a=z(g,a,b,c,d,X[ 9], 5,t[25]) | |
d=z(g,d,a,b,c,X[14], 9,t[26]) | |
c=z(g,c,d,a,b,X[ 3],14,t[27]) | |
b=z(g,b,c,d,a,X[ 8],20,t[28]) | |
a=z(g,a,b,c,d,X[13], 5,t[29]) | |
d=z(g,d,a,b,c,X[ 2], 9,t[30]) | |
c=z(g,c,d,a,b,X[ 7],14,t[31]) | |
b=z(g,b,c,d,a,X[12],20,t[32]) | |
a=z(h,a,b,c,d,X[ 5], 4,t[33]) | |
d=z(h,d,a,b,c,X[ 8],11,t[34]) | |
c=z(h,c,d,a,b,X[11],16,t[35]) | |
b=z(h,b,c,d,a,X[14],23,t[36]) | |
a=z(h,a,b,c,d,X[ 1], 4,t[37]) | |
d=z(h,d,a,b,c,X[ 4],11,t[38]) | |
c=z(h,c,d,a,b,X[ 7],16,t[39]) | |
b=z(h,b,c,d,a,X[10],23,t[40]) | |
a=z(h,a,b,c,d,X[13], 4,t[41]) | |
d=z(h,d,a,b,c,X[ 0],11,t[42]) | |
c=z(h,c,d,a,b,X[ 3],16,t[43]) | |
b=z(h,b,c,d,a,X[ 6],23,t[44]) | |
a=z(h,a,b,c,d,X[ 9], 4,t[45]) | |
d=z(h,d,a,b,c,X[12],11,t[46]) | |
c=z(h,c,d,a,b,X[15],16,t[47]) | |
b=z(h,b,c,d,a,X[ 2],23,t[48]) | |
a=z(i,a,b,c,d,X[ 0], 6,t[49]) | |
d=z(i,d,a,b,c,X[ 7],10,t[50]) | |
c=z(i,c,d,a,b,X[14],15,t[51]) | |
b=z(i,b,c,d,a,X[ 5],21,t[52]) | |
a=z(i,a,b,c,d,X[12], 6,t[53]) | |
d=z(i,d,a,b,c,X[ 3],10,t[54]) | |
c=z(i,c,d,a,b,X[10],15,t[55]) | |
b=z(i,b,c,d,a,X[ 1],21,t[56]) | |
a=z(i,a,b,c,d,X[ 8], 6,t[57]) | |
d=z(i,d,a,b,c,X[15],10,t[58]) | |
c=z(i,c,d,a,b,X[ 6],15,t[59]) | |
b=z(i,b,c,d,a,X[13],21,t[60]) | |
a=z(i,a,b,c,d,X[ 4], 6,t[61]) | |
d=z(i,d,a,b,c,X[11],10,t[62]) | |
c=z(i,c,d,a,b,X[ 2],15,t[63]) | |
b=z(i,b,c,d,a,X[ 9],21,t[64]) | |
return A+a,B+b,C+c,D+d | |
end | |
-- convert little-endian 32-bit int to a 4-char string | |
local function leIstr(i) | |
local f=function (s) return string.char(bit_and(bit_rshift(i,s),255)) end | |
return f(0)..f(8)..f(16)..f(24) | |
end | |
-- convert raw string to big-endian int | |
local function beInt(s) | |
local v=0 | |
for i=1,string.len(s) do v=v*256+string.byte(s,i) end | |
return v | |
end | |
-- convert raw string to little-endian int | |
local function leInt(s) | |
local v=0 | |
for i=string.len(s),1,-1 do v=v*256+string.byte(s,i) end | |
return v | |
end | |
-- cut up a string in little-endian ints of given size | |
local function leStrCuts(s,...) | |
local o,r=1,{} | |
for i=1,#arg do | |
table.insert(r,leInt(string.sub(s,o,o+arg[i]-1))) | |
o=o+arg[i] | |
end | |
return r | |
end | |
function md5.Calc(s) | |
local msgLen=string.len(s) | |
local padLen=56- msgLen % 64 | |
if msgLen % 64 > 56 then padLen=padLen+64 end | |
if padLen==0 then padLen=64 end | |
s=s..string.char(128)..string.rep(string.char(0),padLen-1) | |
s=s..leIstr(8*msgLen)..leIstr(0) | |
assert(string.len(s) % 64 ==0) | |
local t=md5.consts | |
local a,b,c,d=t[65],t[66],t[67],t[68] | |
for i=1,string.len(s),64 do | |
local X=leStrCuts(string.sub(s,i,i+63),4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4) | |
assert(#X==16) | |
X[0]=table.remove(X,1) -- zero based! | |
a,b,c,d=md5.transform(a,b,c,d,X) | |
end | |
local swap=function (w) return beInt(leIstr(w)) end | |
return string.format("%08x%08x%08x%08x",swap(a),swap(b),swap(c),swap(d)) | |
end | |
return md5.Calc("asdf"); -- 912ec803b2ce49e4a541068d495ab570 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi, I was using this md5 implementation in a project I was working and and noticed an issue with calculating especially large strings. Especially long strings (roughly 3000+ characters) were all being encoded as 0000 0000 0000 0000.
It seemed that the issues is that the C implementation of md5 relies on the fact that a,b,c,d are uint32 and that they naturally buffer overflow. Our lua implementation needs to simulate this buffer overflow so I added these lines after the md5 transform:
a = a % (2^32)
b = b % (2^32)
c = c % (2^32)
d = d % (2^32)