hashlib模块
python中的hashlib为我们提供了常见的摘要算法,如MD5、sha1
那么现在问题来了,摘要算法是what?
摘要算法又称哈希算法、散列算法。
它指的是把任意长度的数据data,通过函数f(),转换为一个长度固定的摘要digest(通常用16进制的字符串表示),
目的是为了发现原始的数据是否被人篡改过。
摘要算法之所以可以辨别数据是否被人篡改过,就是因为摘要函数是一个单向函数,
想要计算f(data)很容易,但是通过digest反推data却非常困难。
并且,只要是对原始数据做哪怕一点点改动,都会导致计算出的摘要截然不同。
接下来我们以常见的摘要算法MD5为例,
#计算出一个字符串的MD5值 import hashlib md5 = hashlib.md5() md5.update(b'hello,python') #ps:需要转换成b字节或者encode('utf-8') print(md5.hexdigest())
输出结果:
15ac32041ff74c93c1842b152df7519e
import hashlib md5 = hashlib.md5() md5.update('hello,python'.encode('utf-8')) print(md5.hexdigest())
输出结果:
15ac32041ff74c93c1842b152df7519e
如果数据量很大,可以分块多次调用update(),
一段字符串分成几段摘要和直接进行摘要的结果是相同的
import hashlib md5 = hashlib.md5() md5.update(b'hello,') #原字符串中有逗号的不要忘记了 md5.update(b'python') print(md5.hexdigest())
输出结果:
15ac32041ff74c93c1842b152df7519e
模仿文件校验
import hashlib def check_md5(filename): md5 = hashlib.md5() with open(filename,'rb') as f: while True: content = f.read(2048) #分段读取,以免占用大段内存 if content: md5.update(content) else: break return md5.hexdigest()
file1 = check_md5('md5_test1') #我创建的md5_test1中的数据为11112
file2 = check_md5('md5_test2') #我创建的md5_test2中的数据为11111
print(file1)
print(file2)
输出结果:
afcb7a2f1c158286b48062cd885a9866
b0baee9d279d34fa1dfd71aadb908c3f
md5摘要加密传输进来的密码,并动态加盐提高安全性
import hashlib def md5_digest(salt,pwd): md5 = hashlib.md5(salt.encode('utf-8')) #salt,加盐操作,增加安全性,而且还可以对盐进行切片进一步增加安全性如salt[::-1] md5.update(pwd.encode('utf-8')) return md5.hexdigest() salt = '盐' pwd = '123450' print(md5_digest(salt,pwd))
输出结果:
684d41d1f7512e40a8939fd4fed9518a
经过Salt处理的MD5口令,只要Salt不被黑客知道,即使用户输入简单口令,也很难通过MD5反推明文口令。
但是如果有两个用户都使用了相同的简单口令比如123456,在数据库中,将存储两条相同的MD5值,这说明这两个用户的口令是一样的。有没有办法让使用相同口令的用户存储不同的MD5呢?
如果假定用户无法修改登录名,就可以通过把登录名作为Salt的一部分来计算MD5,从而实现相同口令的用户也存储不同的MD5。
摘要算法在很多地方都有广泛的应用。要注意摘要算法不是加密算法,不能用于加密(因为无法通过摘要反推明文),只能用于防篡改,但是它的单向计算特性决定了可以在不存储明文口令的情况下验证用户口令。
MD5是最常见的摘要算法,速度很快,生成结果是固定的128 bit字节,通常用一个32位的16进制字符串表示。
另一种常见的摘要算法是SHA1,调用SHA1和调用MD5完全一样,就是将前面的md5改成sha1而己。
SHA1的结果是160 bit字节,通常用一个40位的16进制字符串表示。
比SHA1更安全的算法是SHA256和SHA512,不过越安全的算法越慢,而且摘要长度更长。