Created
August 13, 2022 07:15
-
-
Save Forgo7ten/e0c40452cf8a0e8e4a9691136596a991 to your computer and use it in GitHub Desktop.
MD5算法实现
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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