MD5全称:message-digest algorithm 5
翻译过来就是:信息 摘要 算法 5
一、特点
1.长度固定:
不管多长的字符串,加密后长度都是一样长
作用:方便平时信息的统计和管理
详解:经过MD5加密生成一个固定长度为128bit的串。因为128位0和1的二进制串表达不友好,因此转化为了16进制,128/4 = 32位的16进制。将32位去掉前8位和后8位得到的是16位。因此会有MD5的32位 和16位加密说法
2.易计算:
字符串和文件加密的过程是容易的.
作用: 开发者很容易理解和做出加密工具
3.细微性
一个文件,不管多大,小到几k,大到几G,你只要改变里面某个字符,那么都会导致MD5值改变.
作用:很多软件和应用在网站提供下载资源,其中包含了对文件的MD5码,用户下载后只需要用工具测一下下载好的文件,通过对比就知道该文件是否有过更改变动.
4.不可逆性
你明明知道密文和加密方式,你却无法反向计算出原密码.
作用:基于这个特点,很多安全的加密方式都是用到.大大提高了数据的安全性
不可逆的原因:摘要是部分内容,因此由MD5的密文和加密方式会得到很多明文,而无法确定明文。
一个原始数据,只对应一个md5值;但是一个md5值,可能对应多个原始数据。
补充:MD5常用于字符串和文件的加密
二、撞库
关于撞库破解:
这是概率极低的破解方法,原理就是:
1.建立一个大型的数据库,把日常的各个语句,通过MD5加密成为密文,不断的积累大量的句子,放在一个庞大的数据库里.
2.比如一个人拿到了别人的密文,想去查询真实的密码,就需要那这个密文去到提供这个数据库的公司网站去查询.
这就是撞库的概念.
三、关于MD5加盐:
比如我的银行密码是"12345"
1.得到的MD5是:827ccb0eea8a706c4c34a16891f84e7b
2.一个人截取到这个密文,那么通过撞库肯定容易撞出12345.
3.我们要做的就是加盐,银行密码还是"12345",然后我把银行密码加上我特定的字符串才计算MD5
import binascii
import sys
import os.pathSV = [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" + binvalreturn binvaldef 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 % 32k = k % (2 ** 32)upper = (k << bits) % (2 ** 32)result = upper | (k >> (32 - (bits)))return (result)# 分块
def blockDivide(block, chunks):result = []size = len(block) // chunksfor 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) * 8def md5sum(msg):# 计算比特长度,如果内容过长,64个比特放不下。就取低64bit。msgLen = bitlen(msg) % (2 ** 64)# 先填充一个0x80,其实是先填充一个1,后面跟对应个数的0,因为一个明文的编码至少需要8比特,所以直接填充 0b10000000即0x80msg = msg + b'\x80' # 0x80 = 1000 0000# 似乎各种编码,即使是一个字母,都至少得1个字节,即8bit才能表示,所以不会出现原文55bit,pad1就满足的情况?可是不对呀,要是二进制文件呢?# 填充0到满足要求为止。zeroPad = (448 - (msgLen + 8) % 512) % 512zeroPad //= 8msg = msg + b'\x00' * zeroPad + msgLen.to_bytes(8, byteorder='little')# 计算循环轮数,512个为一轮msgLen = bitlen(msg)iterations = msgLen // 512# 初始化变量# 算法魔改的第一个点,也是最明显的点A = 0x67452301B = 0xefcdab89C = 0x98badcfeD = 0x10325476# MD5的主体就是对abcd进行n次的迭代,所以得有个初始值,可以随便选,也可以用默认的魔数,这个改起来毫无风险,所以大家爱魔改它,甚至改这个都不算魔改。# main loopfor i in range(0, iterations):a = Ab = Bc = Cd = Dblock = msg[i * 64:(i + 1) * 64]# 明文的处理,顺便调整了一下端序M = blockDivide(block, 16)# Roundsa = 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 resultif __name__ == "__main__":data = str("123456").encode("UTF-8")print("plainText: ", data)print("result: ", md5sum(data))
四、MD5加密调用:
import hashlibstr = "codeooo"#字符串转化bytes
encryptValue = bytes(str, encoding="utf8")
# encryptValue = str.encode(str)#bytes转化字符串
# byteValue = b'codeooo'
# str(byteValue, encoding="utf-8")
# bytes.decode(byteValue)#常规写法
m = hashlib.md5()
m.update(encryptValue)
md5_encrypt = m.hexdigest()# 或者可以这样
md5_encrypt = hashlib.md5(encryptValue).hexdigest()# 也可以使用hash.new()这个一般方法
md5_encrypt = hashlib.new(encryptValue).hexdigest()
HMAC-MD5 特征:
十六进制:
十进制: