Skip to content

Commit 2ef10bc

Browse files
committed
Added additional comments to MD5SUM.LUA
1 parent 18952fb commit 2ef10bc

File tree

1 file changed

+72
-13
lines changed

1 file changed

+72
-13
lines changed

xtra/MD5SUM.LUA

Lines changed: 72 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
#!/usr/bin/env lua
22

3+
--[[ Implicit global variables:
4+
SINE = MD5 sine constants table precomputed values based on sine function
5+
]]
6+
37
---Get file hash
48
---@param file file The file to read
59
---@return string MD5 checksum
610
function md5_file(file)
7-
local MAX = 0xFFFFFFFF -- Maximum value of number (32-bits)
11+
12+
-- MAX = Maximum value of number (32-bits)
13+
local MAX = 0xFFFFFFFF
814

915
---MD5 transformation function
1016
---@param ch string A 64-byte chunk of the message
@@ -14,10 +20,11 @@ function md5_file(file)
1420
---@param D number Fourth word of the current hash state
1521
---@return number, number, number, number Updated hash state (A, B, C, D)
1622
local function T(ch, A, B, C, D)
17-
-- F = Conditional function (if x then y else z)
18-
-- G = Multiplexer function (if z then x else y)
19-
-- H = Parity function (XOR of all inputs)
20-
-- I = Nonlinear mixing function
23+
24+
-- F = Conditional function (if x then y else z)
25+
-- G = Multiplexer function (if z then x else y)
26+
-- H = Parity function (XOR of all inputs)
27+
-- I = Nonlinear mixing function
2128
-- LS = Left bit rotation
2229
local F, G, H, I, LS = function(x, y, z)
2330
return (x & y) | (~x & z)
@@ -30,14 +37,30 @@ function md5_file(file)
3037
end, function(x, n)
3138
return ((x << n) | (x >> (32 - n))) & MAX
3239
end
40+
41+
-- wo = Word array for holding the 16 32-bit words from the current message chunk
42+
-- sh = shift amounts matrix
43+
-- a,b,c,d = Working copies of the hash state variables A,B,C,D
3344
local wo, sh, a, b, c, d = {}, { { 7, 12, 17, 22 }, { 5, 9, 14, 20 }, { 4, 11, 16, 23 }, { 6, 10, 15, 21 } }, A, B, C, D
34-
for i = 0, 15 do
45+
46+
for i = 0, 15 do -- Convert into 16 32-bit little-endian words
47+
48+
-- o = Byte offset within the chunk
3549
local o = i * 4 + 1
3650
wo[i + 1] = string.byte(ch, o) | (string.byte(ch, o + 1) << 8) | (string.byte(ch, o + 2) << 16) | (string.byte(ch, o + 3) << 24)
3751
end
52+
3853
for i = 1, 64 do
39-
local r, f, g, t = math.floor((i - 1) / 16) + 1
40-
local s = sh[r][(i - 1) % 4 + 1]
54+
55+
-- r = Round number (1 to 4)
56+
-- f = Result of round function
57+
-- g = Index into message word array
58+
-- t = Temporary variable for state transformation
59+
-- s = Shift amount for current step
60+
local r, f, g, t, s = math.floor((i - 1) / 16) + 1
61+
62+
s = sh[r][(i - 1) % 4 + 1]
63+
4164
if r == 1 then
4265
f = F(b, c, d)
4366
g = (i - 1) % 16
@@ -51,13 +74,16 @@ function md5_file(file)
5174
f = I(b, c, d)
5275
g = (7 * (i - 1)) % 16
5376
end
77+
78+
-- Transform the state variables (a,b,c,d) according to MD5 algorithm
5479
t = d
5580
d = c
5681
c = b
5782
b = (b + LS((a + f + wo[g + 1] + SINE[i]) & MAX, s)) & MAX
5883
a = t
5984
end
6085

86+
-- Add the transformed chunk values to the hash state (modulo 2^32)
6187
A = (A + a) & MAX
6288
B = (B + b) & MAX
6389
C = (C + c) & MAX
@@ -69,42 +95,68 @@ function md5_file(file)
6995
---@param msgLen number The length of the message in bytes
7096
---@return string The padding string to append to the message
7197
local function P(msgLen)
98+
99+
-- ml = Message length in bits
100+
-- p = padding string
101+
-- pl = padding length
72102
local ml, p, pl = msgLen * 8, "\128", (56 - (msgLen % 64))
103+
73104
if pl <= 0 then
74105
pl = pl + 64
75106
end
107+
76108
p = p .. string.rep("\0", pl - 1)
109+
110+
-- Append the 64-bit message length as little-endian bytes
77111
for i = 0, 7 do
78112
p = p .. string.char((ml >> (8 * i)) & 0xFF)
79113
end
114+
80115
return p
81116
end
82117

118+
-- A,B,C,D = The four words that form the 128-bit MD5 state/digest
119+
-- l = total length of processed data
83120
local A, B, C, D, l = 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0
84-
while 1 do
121+
122+
while 1 do -- Process the input file in 64-byte chunks
123+
124+
-- c = Chunk of data
85125
local c = file:read(64)
86-
if not c then
126+
127+
if not c then -- End of file
87128
break
88129
end
130+
89131
l = l + #c
90-
if #c < 64 then
132+
133+
if #c < 64 then -- Pad the chunk if not 64 bytes long
91134
c = c .. P(l)
92135
end
136+
137+
-- Process this chunk through the MD5 transformation
93138
A, B, C, D = T(c, A, B, C, D)
139+
94140
if #c > 64 then
95141
break
96142
end
97143
end
144+
145+
--- Convert a 32-bit word to an 8-character hexadecimal string (little-endian)
146+
---@param x number The 32-bit word to convert
147+
---@return string The hexadecimal representation (8 characters)
98148
local function hex(x)
99149
return string.format("%02x%02x%02x%02x", x & 0xFF, (x >> 8) & 0xFF, (x >> 16) & 0xFF, (x >> 24) & 0xFF)
100150
end
151+
152+
-- Concatenate the four state words as hexadecimal to form the final 32-character MD5 digest
101153
return hex(A) .. hex(B) .. hex(C) .. hex(D)
102154
end
103155

104-
---Initialize the MD5 sine constants table
156+
---Initialize the MD5 sine constants table with precomputed values used in each step of the MD5 algorithm
105157
local function init()
106158
SINE = {}
107-
for i = 1, 64 do
159+
for i = 1, 64 do -- Formula from RFC 1321 truncated to 32 bits
108160
SINE[i] = math.floor(2 ^ 32 * math.abs(math.sin(i)))
109161
end
110162
end
@@ -120,9 +172,16 @@ if #arg < 1 then
120172
else
121173
init()
122174
for i = 1, #arg do
175+
176+
-- f = open file handle
177+
-- e = error string if file failed to open
123178
local f, e = io.open(arg[i], "rb") --#squish keep-eol
179+
124180
if f then
181+
182+
-- sum = MD5 string of file
125183
local sum = md5_file(f)
184+
126185
f:close()
127186
if sum then
128187
print(sum .. " " .. arg[i])

0 commit comments

Comments
 (0)