Quick Links: Download Gideros Studio | Gideros Documentation | Gideros Development Center | Gideros community chat | DONATE
MD5 using Gideros BitOp plugin — Gideros Forum

MD5 using Gideros BitOp plugin

ianchiaianchia Member
edited June 2012 in Code snippets
I needed a MD5 hash in a hurry and found a MD5 implementation in the BitOp demos. Just a quick&dirty wrapper into a Gideros class leveraging the Gideros BitOp plugin. I prefer SHA-1 but MD5 was perfectly acceptable in this particular use-case.
--usage:
crypto = Crypto.new();
local a = os.timer();
print (crypto:md5("The quick brown fox"));
local b = os.timer();
print ("on an iPad2, time taken for MD5 hash: ",b-a);
-- 
-- a2004f37730b9445670a738fa0fc9ee5
-- on an iPad2, time taken for MD5 hash: 	0.00027698278427124
 
-- you can compare the result to various online MD5 generators.
-- eg. <a href="http://www.miraclesalad.com/webtools/md5.php" rel="nofollow">http://www.miraclesalad.com/webtools/md5.php</a>
-- <a href="http://7thspace.com/webmaster_tools/online_md5_encoder.html" rel="nofollow">http://7thspace.com/webmaster_tools/online_md5_encoder.html</a>
 
-- the unit tests supplied with the md5 BitOp demo also passed with no issues:
assert(md5('') == 'd41d8cd98f00b204e9800998ecf8427e')
assert(md5('a') == '0cc175b9c0f1b6a831c399e269772661')
assert(md5('abc') == '900150983cd24fb0d6963f7d28e17f72')
assert(md5('message digest') == 'f96b697d7cb7938d525a2f31aaf161d0')
assert(md5('abcdefghijklmnopqrstuvwxyz') == 'c3fcd3d76192e4007dfb496cca67e13b')
assert(md5('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') ==
       'd174ab98d277d9f5a5611c2c9f419d9f')
assert(md5('12345678901234567890123456789012345678901234567890123456789012345678901234567890') ==
       '57edf4a22be3c955ac49da2e2107b67a')
 
--/////////////////////////////////////////////////////////////////////////////////////
 
-- Crypto.lua (also attached)
 
-- pretty much a cut & paste from the bitop supplied demos from <a href="http://bitop.luajit.org/download.html" rel="nofollow">http://bitop.luajit.org/download.html</a>
-- wrapped into a Gideros class
Crypto = Core.class()
 
function Crypto:init()
 
end
 
-- md5()
-- usage:
-- crypto = Crypto.new();
-- print (crypto:md5("The quick brown fox"));
--
function Crypto:md5(input_string)
 
	local bit = require("bit")
	local tobit, tohex, bnot = bit.tobit or bit.cast, bit.tohex, bit.bnot
	local bor, band, bxor = bit.bor, bit.band, bit.bxor
	local lshift, rshift, rol, bswap = bit.lshift, bit.rshift, bit.rol, bit.bswap
	local byte, char, sub, rep = string.byte, string.char, string.sub, string.rep
 
	if not rol then -- Replacement function if rotates are missing.
	  local bor, shl, shr = bit.bor, bit.lshift, bit.rshift
	  function rol(a, b) return bor(shl(a, b), shr(a, 32-b)) end
	end
 
	if not bswap then -- Replacement function if bswap is missing.
	  local bor, band, shl, shr = bit.bor, bit.band, bit.lshift, bit.rshift
	  function bswap(a)
		 return bor(shr(a, 24), band(shr(a, 8), 0xff00),
				 shl(band(a, 0xff00), 8), shl(a, 24));
	  end
	end
 
	if not tohex then -- (Unreliable) replacement function if tohex is missing.
	  function tohex(a)
		 return string.sub(string.format("%08x", a), -8)
	  end
	end
 
	local function tr_f(a, b, c, d, x, s)
	  return rol(bxor(d, band(b, bxor(c, d))) + a + x, s) + b
	end
 
	local function tr_g(a, b, c, d, x, s)
	  return rol(bxor(c, band(d, bxor(b, c))) + a + x, s) + b
	end
 
	local function tr_h(a, b, c, d, x, s)
	  return rol(bxor(b, c, d) + a + x, s) + b
	end
 
	local function tr_i(a, b, c, d, x, s)
	  return rol(bxor(c, bor(b, bnot(d))) + a + x, s) + b
	end
 
	local function transform(x, a1, b1, c1, d1)
	  local a, b, c, d = a1, b1, c1, d1
 
	  a = tr_f(a, b, c, d, x[ 1] + 0xd76aa478,  7)
	  d = tr_f(d, a, b, c, x[ 2] + 0xe8c7b756, 12)
	  c = tr_f(c, d, a, b, x[ 3] + 0x242070db, 17)
	  b = tr_f(b, c, d, a, x[ 4] + 0xc1bdceee, 22)
	  a = tr_f(a, b, c, d, x[ 5] + 0xf57c0faf,  7)
	  d = tr_f(d, a, b, c, x[ 6] + 0x4787c62a, 12)
	  c = tr_f(c, d, a, b, x[ 7] + 0xa8304613, 17)
	  b = tr_f(b, c, d, a, x[ 8] + 0xfd469501, 22)
	  a = tr_f(a, b, c, d, x[ 9] + 0x698098d8,  7)
	  d = tr_f(d, a, b, c, x[10] + 0x8b44f7af, 12)
	  c = tr_f(c, d, a, b, x[11] + 0xffff5bb1, 17)
	  b = tr_f(b, c, d, a, x[12] + 0x895cd7be, 22)
	  a = tr_f(a, b, c, d, x[13] + 0x6b901122,  7)
	  d = tr_f(d, a, b, c, x[14] + 0xfd987193, 12)
	  c = tr_f(c, d, a, b, x[15] + 0xa679438e, 17)
	  b = tr_f(b, c, d, a, x[16] + 0x49b40821, 22)
 
	  a = tr_g(a, b, c, d, x[ 2] + 0xf61e2562,  5)
	  d = tr_g(d, a, b, c, x[ 7] + 0xc040b340,  9)
	  c = tr_g(c, d, a, b, x[12] + 0x265e5a51, 14)
	  b = tr_g(b, c, d, a, x[ 1] + 0xe9b6c7aa, 20)
	  a = tr_g(a, b, c, d, x[ 6] + 0xd62f105d,  5)
	  d = tr_g(d, a, b, c, x[11] + 0x02441453,  9)
	  c = tr_g(c, d, a, b, x[16] + 0xd8a1e681, 14)
	  b = tr_g(b, c, d, a, x[ 5] + 0xe7d3fbc8, 20)
	  a = tr_g(a, b, c, d, x[10] + 0x21e1cde6,  5)
	  d = tr_g(d, a, b, c, x[15] + 0xc33707d6,  9)
	  c = tr_g(c, d, a, b, x[ 4] + 0xf4d50d87, 14)
	  b = tr_g(b, c, d, a, x[ 9] + 0x455a14ed, 20)
	  a = tr_g(a, b, c, d, x[14] + 0xa9e3e905,  5)
	  d = tr_g(d, a, b, c, x[ 3] + 0xfcefa3f8,  9)
	  c = tr_g(c, d, a, b, x[ 8] + 0x676f02d9, 14)
	  b = tr_g(b, c, d, a, x[13] + 0x8d2a4c8a, 20)
 
	  a = tr_h(a, b, c, d, x[ 6] + 0xfffa3942,  4)
	  d = tr_h(d, a, b, c, x[ 9] + 0x8771f681, 11)
	  c = tr_h(c, d, a, b, x[12] + 0x6d9d6122, 16)
	  b = tr_h(b, c, d, a, x[15] + 0xfde5380c, 23)
	  a = tr_h(a, b, c, d, x[ 2] + 0xa4beea44,  4)
	  d = tr_h(d, a, b, c, x[ 5] + 0x4bdecfa9, 11)
	  c = tr_h(c, d, a, b, x[ 8] + 0xf6bb4b60, 16)
	  b = tr_h(b, c, d, a, x[11] + 0xbebfbc70, 23)
	  a = tr_h(a, b, c, d, x[14] + 0x289b7ec6,  4)
	  d = tr_h(d, a, b, c, x[ 1] + 0xeaa127fa, 11)
	  c = tr_h(c, d, a, b, x[ 4] + 0xd4ef3085, 16)
	  b = tr_h(b, c, d, a, x[ 7] + 0x04881d05, 23)
	  a = tr_h(a, b, c, d, x[10] + 0xd9d4d039,  4)
	  d = tr_h(d, a, b, c, x[13] + 0xe6db99e5, 11)
	  c = tr_h(c, d, a, b, x[16] + 0x1fa27cf8, 16)
	  b = tr_h(b, c, d, a, x[ 3] + 0xc4ac5665, 23)
 
	  a = tr_i(a, b, c, d, x[ 1] + 0xf4292244,  6)
	  d = tr_i(d, a, b, c, x[ 8] + 0x432aff97, 10)
	  c = tr_i(c, d, a, b, x[15] + 0xab9423a7, 15)
	  b = tr_i(b, c, d, a, x[ 6] + 0xfc93a039, 21)
	  a = tr_i(a, b, c, d, x[13] + 0x655b59c3,  6)
	  d = tr_i(d, a, b, c, x[ 4] + 0x8f0ccc92, 10)
	  c = tr_i(c, d, a, b, x[11] + 0xffeff47d, 15)
	  b = tr_i(b, c, d, a, x[ 2] + 0x85845dd1, 21)
	  a = tr_i(a, b, c, d, x[ 9] + 0x6fa87e4f,  6)
	  d = tr_i(d, a, b, c, x[16] + 0xfe2ce6e0, 10)
	  c = tr_i(c, d, a, b, x[ 7] + 0xa3014314, 15)
	  b = tr_i(b, c, d, a, x[14] + 0x4e0811a1, 21)
	  a = tr_i(a, b, c, d, x[ 5] + 0xf7537e82,  6)
	  d = tr_i(d, a, b, c, x[12] + 0xbd3af235, 10)
	  c = tr_i(c, d, a, b, x[ 3] + 0x2ad7d2bb, 15)
	  b = tr_i(b, c, d, a, x[10] + 0xeb86d391, 21)
 
	  return tobit(a+a1), tobit(b+b1), tobit(c+c1), tobit(d+d1)
	end
 
	-- Note: this is copying the original string and NOT particularly fast.
	-- A library for struct unpacking would make this task much easier.
	local function md5(msg)
	  local len = #msg
	  msg = msg.."\128"..rep("\0", 63 - band(len + 8, 63))
			..char(band(lshift(len, 3), 255), band(rshift(len, 5), 255),
			  band(rshift(len, 13), 255), band(rshift(len, 21), 255))
			.."\0\0\0\0"
	  local a, b, c, d = 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476
	  local x, k = {}, 1
	  for i=1,#msg,4 do
		 local m0, m1, m2, m3 = byte(msg, i, i+3)
		 x[k] = bor(m0, lshift(m1, 8), lshift(m2, 16), lshift(m3, 24))
		 if k == 16 then
			a, b, c, d = transform(x, a, b, c, d)
			k = 1
		 else
			k = k + 1
		 end
	  end
	  return tohex(bswap(a))..tohex(bswap(b))..tohex(bswap(c))..tohex(bswap(d))
	end
 
  	return md5(input_string);
 
end
zip
zip
ut.md5.zip
3K
+1 -1 (+3 / -0 )Share on Facebook

Comments

  • gimgim Member
    edited April 2014
    Nice work! LTN12 version is here.
    function sink.md5()
            -- local variables except function md5(msg) in Crypto:md5(input_string) should be here as original posting.
     
    	local len = 0
    	local msg = ""
    	local a, b, c, d = 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476
    	local x, k = {}, 1
    	local closed
     
    	return function(chunk, err)
    		local index = 1
    		if not chunk then
    			if closed then return nil, "closed" end
    			closed = true
    			msg = msg.."\128"..rep("\0", 63 - band(len + 8, 63))
    				..char(band(lshift(len, 3), 255), band(rshift(len, 5), 255),band(rshift(len, 13), 255), band(rshift(len, 21), 255))
    				.."\0\0\0\0"
    		else
    			len = len + #chunk
    			if #msg < 1 then
    				msg = chunk
    			else
    				if #msg + #chunk < 4 then
    					msg = msg..chunk
    				else
    					index = 5 - #msg
    					msg = msg..sub(chunk, 1, 4 - #msg)
    					local m0, m1, m2, m3 = byte(msg, 1, 4)
    					x[k] = bor(m0, lshift(m1, 8), lshift(m2, 16), lshift(m3, 24))
    					if k == 16 then
    						a, b, c, d = transform(x, a, b, c, d)
    						k = 1
    					else
    						k = k + 1
    					end
    					msg = chunk
    				end
    			end
    		end
    		for i=index,#msg-band(#msg-index+1, 3),4 do
    			local m0, m1, m2, m3 = byte(msg, i, i+3)
    			x[k] = bor(m0, lshift(m1, 8), lshift(m2, 16), lshift(m3, 24))
    			if k == 16 then
    				a, b, c, d = transform(x, a, b, c, d)
    				k = 1
    			else
    				k = k + 1
    			end
    		end
    		msg = sub(msg, #msg-band(#msg-index+1, 3)+1)
    		return tohex(bswap(a))..tohex(bswap(b))..tohex(bswap(c))..tohex(bswap(d))
    	end
    end
    Wrapper function Crypto:md5 would be:
    function Crypto:md5(input_string)
    	local source = ltn12.source.string(input_string)
    	local sink = ltn12.sink.md5()
    	local chunk = source()
    	while chunk do
    		sink(chunk)
    		chunk = source()
    	end
    	return sink(nil, "closed")
    end
Sign In or Register to comment.