MD5 algo in Python

I just came across the solution for an MD5 python implementation. There is ofcourse an easier way to do that…hashlib.md5(). you can read more about it here in the python documentation:

https://docs.python.org/3.1/library/hashlib.html

############CODE starts here######################################

# March 26, 2013
# Greenlaw and Snyder
# This is an implementation of the MD5 hashing algorithm.
# It is adopted from a C implementation found at
# http://en.wikipedia.org/wiki/MD5

import binascii

#The per-round shift amounts
S = (7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21)

#for simplicity, I just do a for loop. to increase performance, constants are better.

#Use binary integer part of the sines of integers (Radians) as constants:
for i from 0 to 63
K[i] := floor(abs(sin(i + 1)) × (2 pow 32))
end for

#Leftrotate function
def leftRotate(x, c):
#If x has more than 32 bits, this selects just the last 32 bits
x &= 0xFFFFFFFF
return ((x<<c)|(x>>(32-c)) & 0xFFFFFFFF)

#MD5 function itself
def MD5(input):

#input.encode() converts the string to the byte level.  Message will be
#prefaced by a b.
message = (input.encode())

#This gives the number of bytes in the string.
length = len(message)

#Append padded bits
newLength = length + 1

#Here we are counting bytes
while(newLength%64 != 56):
newLength += 1
paddingLength = newLength – length
#The first byte is two hex numbers 8 and 0.  This gives us the bit string
#1000000 and this is the first part of the padding.
padding = b’\x80′ + bytes(paddingLength – 1)
message += padding

#Append a 64-bit representation of the length of the original message in bits
message += (length*8).to_bytes(8, byteorder=’little’)

#Initialize variables
A = 0x67452301
B = 0xefcdab89
C = 0x98badcfe
D = 0x10325476

#Process the message with 512-bit chucks
chunk_offset = 0
for chunk_offset in range(0, len(message), 64):

#Initialize buffer
RA = A
RB = B
RC = C
RD = D

chunk = message[chunk_offset:chunk_offset+64]
for i in range(64):
if i in range(16):
F = (RB&RC)|((~RB)&RD)
g = i
elif i in range(16, 32):
F = (RD&RB)|((~RD)&RC)
g = ((5*i)+1)%16
elif i in range(32, 48):
F = RB^RC^RD
g = ((3*i)+5)%16
elif i in range(48, 64):
F = RC^(RB|(~RD))
g = (7*i)%16
temp = RD
RD = RC
RC = RB
#Convert the revelant part of the message from bytes to an int
M = int.from_bytes(chunk[4*g:4*g+4], byteorder=’little’)
#And with the 32-bit string of 1s to elminate any carry bits
RB = RB + leftRotate(RA + F + K[i] + M, S[i]) & 0xFFFFFFFF
RA = temp

#Add the hash of the current chunk to the result so far
A += RA
B += RB
C += RC
D += RD

#And with the 32-bit string of 1s to elminate any carry bits
A &= 0xFFFFFFFF
B &= 0xFFFFFFFF
C &= 0xFFFFFFFF
D &= 0xFFFFFFFF

#Return output
ret = “”
for i in [A, B, C, D]:
ret += binascii.hexlify(i.to_bytes(4, byteorder=’little’)).decode()
return ret

string = input(‘Please enter string: ‘)
print(“MD5:”, MD5(string))

Leave a Reply

Your email address will not be published. Required fields are marked *