摘要算法
1. 摘要算法又称为哈希算法、散列算法,是通过函数将任意长度的数据转化成固定长度的数据串(通常用16进制的字符串表示)。
2. 摘要算法将通过摘要函数f()将数据转化成固定长度的摘要(digest),目的是判断原始数据是否被别人修改过
3. 能够判断的原因是摘要函数是单向函数,计算data很容易,通过digest反推data很难,而且对原始数据做一个bit的修改都会导致计算出的摘要完全不同
常见的摘要算法有MD5,SHA1等
1 import hashlib 2 s1 = "life is short, carpe diem!" 3 ret = hashlib.md5() 4 ret.update(s1.encode("utf-8")) 5 print(ret.hexdigest()) # 7eda5bd766debaf18e333c949f250580
输入数据量大,可以分块多次调用update()
ret = hashlib.md5() with open("test", encoding="utf-8", mode="r") as f1: for line in f1: ret.update(line.encode("utf-8")) print(ret.hexdigest()) # 271d9daa363f2ab8a48c0d0ecd339dd3
MD5是常见的摘要算法,生成速度快,生成结果是一个128bit的数字,通常用32个16进制位表示。SHA1与MD5的用法类似
s1 = "life is short, seize the day!" ret = hashlib.sha1() ret.update(s1.encode("utf-8")) print(ret.hexdigest()) # bd60da31ae2b9f407d019ff61bdbc237925ab664
SHA1的生成结果是160bit,用40个16进制表示,比SHA1更安全的算法是SHA256, SHA512,它们生成的结果更长,速度也更慢
摘要算法应用
1. 保存用户名和口令
如果以明文存储密码的话,那么数据库泄露,所有的用户口令就会落到黑客手中,此外,运维人员也是可以访问数据库的,也能获取到用户的口令,所以正确的方式应该是存储密文。
简化版
password = "123456" ret = hashlib.md5() ret.update(password.encode("utf-8")) print(ret.hexdigest()) # e10adc3949ba59abbe56e057f20f883e
上述口令比较简单,因此可以把常用的口令如123,888等对应的MD5值计算出来,得到反推表,然后通过反推表去破解密码(撞库),怎么防止呢?加盐!原始口令加一个复杂的字符串来MD5,这个复杂的字符串就称为"盐"
加盐版
password = "123456" ret = hashlib.md5("hello".encode("utf-8")) # "hello"就是盐 ret.update(password.encode("utf-8")) print(ret.hexdigest()) # eeb9bad681184779aa6570e402d6ef6c
经过加盐的口令,只要不是盐被黑客知道,就很难破解。但是如果两个用户的口令相同,那么它们的MD5也会是相同的,有没有一种方法使不同的用户生成不同的MD5呢,?有的,我们可以把用户名设置成盐,不同的用户名作为盐,这就是动态加盐
动态加盐版
name = input(">>>") password = input(">>>") ret = hashlib.md5(name[::2].encode("utf-8")) ret.update(password.encode("utf-8")) print(ret.hexdigest())
输入不同的用户名(密码相同)
>>>Robin >>>123456 0acbae48d9e086089d52d54392365a04 >>>Rose >>>123456 825f3023698149b539a17a0f74753eeb # MD5不同
2. 文件校验
文件在传输过程中可能发生损坏,因此需要进行文件校验。我们先创建两个相同的文件test1和test2。文件内容:
临江仙 夜饮东坡醒复醉 归来仿佛三更 家童鼻息已雷鸣 敲门都不应 倚仗听江声 长恨此生非我有 何时忘却营营 夜阑风静縠纹平 小舟从此逝 江海寄余生
1 def file_veri(file): 2 with open(file, encoding="utf-8", mode="r") as f: 3 while True: 4 content = f.read(1024) 5 if not content: 6 break 7 ret = hashlib.md5() 8 ret.update(content.encode("utf-8")) 9 return ret.hexdigest() 10 11 12 print(file_veri("test1")) # 4b852fe14346408bdc7c1ab6603b03fe 13 print(file_veri("test2")) # 4b852fe14346408bdc7c1ab6603b03fe
注意摘要算法不是加密算法,不能用于加密,因为无法通过摘要反推明文,只能用于防篡改,但是它的单向计算特性决定了可以在不存储明文口令的情况下验证用户口令。