Skip to content

Instantly share code, notes, and snippets.

@Forgo7ten
Created August 13, 2022 07:15
Show Gist options
  • Save Forgo7ten/e0c40452cf8a0e8e4a9691136596a991 to your computer and use it in GitHub Desktop.
Save Forgo7ten/e0c40452cf8a0e8e4a9691136596a991 to your computer and use it in GitHub Desktop.
MD5算法实现
import binascii
import sys
import os.path
SV = [0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf,
0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af,
0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e,
0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, 0x21e1cde6,
0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8,
0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122,
0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, 0xd9d4d039,
0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244, 0x432aff97,
0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d,
0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391]
# 根据ascil编码把字符转成对应的二进制
def binvalue(val, bitsize):
binval = bin(val)[2:] if isinstance(val, int) else bin(ord(val))[2:]
if len(binval) > bitsize:
raise ("binary value larger than the expected size")
while len(binval) < bitsize:
binval = "0" + binval
return binval
def string_to_bit_array(text):
array = list()
for char in text:
binval = binvalue(char, 8)
array.extend([int(x) for x in list(binval)])
return array
# 循环左移
def leftCircularShift(k, bits):
bits = bits % 32
k = k % (2 ** 32)
upper = (k << bits) % (2 ** 32)
result = upper | (k >> (32 - (bits)))
return (result)
# 分块
def blockDivide(block, chunks):
result = []
size = len(block) // chunks
for i in range(0, chunks):
result.append(int.from_bytes(block[i * size:(i + 1) * size], byteorder="little"))
return result
# F函数作用于“比特位”上
# if x then y else z
def F(X, Y, Z):
return ((X & Y) | ((~X) & Z))
# if z then x else y
def G(X, Y, Z):
return ((X & Z) | (Y & (~Z)))
# if X = Y then Z else ~Z
def H(X, Y, Z):
return (X ^ Y ^ Z)
def I(X, Y, Z):
return (Y ^ (X | (~Z)))
# 四个F函数
def FF(a, b, c, d, M, s, t):
result = b + leftCircularShift((a + F(b, c, d) + M + t), s)
return (result)
def GG(a, b, c, d, M, s, t):
result = b + leftCircularShift((a + G(b, c, d) + M + t), s)
return (result)
def HH(a, b, c, d, M, s, t):
result = b + leftCircularShift((a + H(b, c, d) + M + t), s)
return (result)
def II(a, b, c, d, M, s, t):
result = b + leftCircularShift((a + I(b, c, d) + M + t), s)
return (result)
# 数据转换
def fmt8(num):
bighex = "{0:08x}".format(num)
binver = binascii.unhexlify(bighex)
result = "{0:08x}".format(int.from_bytes(binver, byteorder='little'))
return (result)
# 计算比特长度
def bitlen(bitstring):
return len(bitstring) * 8
def md5sum(msg):
# 计算比特长度,如果内容过长,64个比特放不下。就取低64bit。
msgLen = bitlen(msg) % (2 ** 64)
# 先填充一个0x80,其实是先填充一个1,后面跟对应个数的0,因为一个明文的编码至少需要8比特,所以直接填充 0b10000000即0x80
msg = msg + b'\x80' # 0x80 = 1000 0000
# 似乎各种编码,即使是一个字母,都至少得1个字节,即8bit才能表示,所以不会出现原文55bit,pad1就满足的情况?可是不对呀,要是二进制文件呢?
# 填充0到满足要求为止。
zeroPad = (448 - (msgLen + 8) % 512) % 512
zeroPad //= 8
msg = msg + b'\x00' * zeroPad + msgLen.to_bytes(8, byteorder='little')
# 计算循环轮数,512个为一轮
msgLen = bitlen(msg)
iterations = msgLen // 512
# 初始化变量
# 算法魔改的第一个点,也是最明显的点
A = 0x67452301
B = 0xefcdab89
C = 0x98badcfe
D = 0x10325476
# MD5的主体就是对abcd进行n次的迭代,所以得有个初始值,可以随便选,也可以用默认的魔数,这个改起来毫无风险,所以大家爱魔改它,甚至改这个都不算魔改。
# main loop
for i in range(0, iterations):
a = A
b = B
c = C
d = D
block = msg[i * 64:(i + 1) * 64]
# 明文的处理,顺便调整了一下端序
M = blockDivide(block, 16)
# Rounds
a = FF(a, b, c, d, M[0], 7, SV[0])
d = FF(d, a, b, c, M[1], 12, SV[1])
c = FF(c, d, a, b, M[2], 17, SV[2])
b = FF(b, c, d, a, M[3], 22, SV[3])
a = FF(a, b, c, d, M[4], 7, SV[4])
d = FF(d, a, b, c, M[5], 12, SV[5])
c = FF(c, d, a, b, M[6], 17, SV[6])
b = FF(b, c, d, a, M[7], 22, SV[7])
a = FF(a, b, c, d, M[8], 7, SV[8])
d = FF(d, a, b, c, M[9], 12, SV[9])
c = FF(c, d, a, b, M[10], 17, SV[10])
b = FF(b, c, d, a, M[11], 22, SV[11])
a = FF(a, b, c, d, M[12], 7, SV[12])
d = FF(d, a, b, c, M[13], 12, SV[13])
c = FF(c, d, a, b, M[14], 17, SV[14])
b = FF(b, c, d, a, M[15], 22, SV[15])
a = GG(a, b, c, d, M[1], 5, SV[16])
d = GG(d, a, b, c, M[6], 9, SV[17])
c = GG(c, d, a, b, M[11], 14, SV[18])
b = GG(b, c, d, a, M[0], 20, SV[19])
a = GG(a, b, c, d, M[5], 5, SV[20])
d = GG(d, a, b, c, M[10], 9, SV[21])
c = GG(c, d, a, b, M[15], 14, SV[22])
b = GG(b, c, d, a, M[4], 20, SV[23])
a = GG(a, b, c, d, M[9], 5, SV[24])
d = GG(d, a, b, c, M[14], 9, SV[25])
c = GG(c, d, a, b, M[3], 14, SV[26])
b = GG(b, c, d, a, M[8], 20, SV[27])
a = GG(a, b, c, d, M[13], 5, SV[28])
d = GG(d, a, b, c, M[2], 9, SV[29])
c = GG(c, d, a, b, M[7], 14, SV[30])
b = GG(b, c, d, a, M[12], 20, SV[31])
a = HH(a, b, c, d, M[5], 4, SV[32])
d = HH(d, a, b, c, M[8], 11, SV[33])
c = HH(c, d, a, b, M[11], 16, SV[34])
b = HH(b, c, d, a, M[14], 23, SV[35])
a = HH(a, b, c, d, M[1], 4, SV[36])
d = HH(d, a, b, c, M[4], 11, SV[37])
c = HH(c, d, a, b, M[7], 16, SV[38])
b = HH(b, c, d, a, M[10], 23, SV[39])
a = HH(a, b, c, d, M[13], 4, SV[40])
d = HH(d, a, b, c, M[0], 11, SV[41])
c = HH(c, d, a, b, M[3], 16, SV[42])
b = HH(b, c, d, a, M[6], 23, SV[43])
a = HH(a, b, c, d, M[9], 4, SV[44])
d = HH(d, a, b, c, M[12], 11, SV[45])
c = HH(c, d, a, b, M[15], 16, SV[46])
b = HH(b, c, d, a, M[2], 23, SV[47])
a = II(a, b, c, d, M[0], 6, SV[48])
d = II(d, a, b, c, M[7], 10, SV[49])
c = II(c, d, a, b, M[14], 15, SV[50])
b = II(b, c, d, a, M[5], 21, SV[51])
a = II(a, b, c, d, M[12], 6, SV[52])
d = II(d, a, b, c, M[3], 10, SV[53])
c = II(c, d, a, b, M[10], 15, SV[54])
b = II(b, c, d, a, M[1], 21, SV[55])
a = II(a, b, c, d, M[8], 6, SV[56])
d = II(d, a, b, c, M[15], 10, SV[57])
c = II(c, d, a, b, M[6], 15, SV[58])
b = II(b, c, d, a, M[13], 21, SV[59])
a = II(a, b, c, d, M[4], 6, SV[60])
d = II(d, a, b, c, M[11], 10, SV[61])
c = II(c, d, a, b, M[2], 15, SV[62])
b = II(b, c, d, a, M[9], 21, SV[63])
A = (A + a) % (2 ** 32)
B = (B + b) % (2 ** 32)
C = (C + c) % (2 ** 32)
D = (D + d) % (2 ** 32)
result = fmt8(A) + fmt8(B) + fmt8(C) + fmt8(D)
return result
if __name__ == "__main__":
data = str("123456").encode("UTF-8")
print("plainText: ", data)
print("result: ", md5sum(data))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment