Pure Lua implementation of md5

前端 未结 4 559
无人共我
无人共我 2021-01-12 06:23

Is there a pure lua implementation of the md5 hashing algorithm? One that doesn\'t rely on any c or external libraries? There\'s javascript implementations that don\'t rely

相关标签:
4条回答
  • 2021-01-12 06:38

    I combined the mentioned lua MD5 library that required bitlib and added in LuaBit to make it a pure lua implementation.

    As an additional benefit it's structured in such a way that it will work inside of the redis lua scripting environment.

    Please note that it is extremely slow compared to other non pure lua based implementations.

    --[[---------------
    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 (abrash_han@hotmail.com)
    --]]---------------
    
    --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 jcw@equi4.com
    
    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
    

    It is available in this gist.

    0 讨论(0)
  • 2021-01-12 06:42

    There's an old one here but it requires bitlib.

    0 讨论(0)
  • 2021-01-12 06:45

    I've refined @Adam Baldwin's solution and made a library that calculates md5 sums in pure Lua, with no external dependencies and no C:

    https://github.com/kikito/md5.lua

    Summary of changes:

    • Implemented two functions on the interface, md5.sum and md5.sumhex, that work exactly like their counterparts in the Kepler library, but are implemented in Lua alone.
    • Added a small test suite with using busted.
    • Removed some unused functions
    • Avoided re-creation of anonymous functions when it was not needed
    • Simplified the creation of the constants, and made them private
    • Spacing and naming changes.

    For now I don't need md5.crypt and md5.decrypt, so I have not implemented those. But I will accept pull requests :)

    0 讨论(0)
  • 2021-01-12 06:47

    http://equi4.com/md5/md5calc.lua but that still requires a lib.

    0 讨论(0)
提交回复
热议问题