# 41. hashlib模块 - 加密算法模块(摘要算法)
# hashlib摘要模块
hashlib模块提供了常用的摘要算法,比如MD5、SHA1等
什么是摘要算法呢?摘要算法又称哈希算法、散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)
摘要算法就是通过摘要函数f()对任意长度的数据data计算出固定长度的摘要digest,目的是为了发现原始数据是否被人篡改过。
摘要算法之所以能指出数据是否被篡改过,就是因为摘要函数是一个单向函数,计算f(data)很容易,但通过digest反推data却非常困难。而且,对原始数据做一个bit的修改,都会导致计算出的摘要完全不同
对于同一个字符串,不管 这个字符串有多少,只要是相同的,无论在任何环境下,多少次执行,无论任何语言中,使用相同算法得到的结果永远都是相同的
**注意:**字符串可以通过算法加密成密文,但是密文不可以逆推成字符串
# hashlib模块的使用
目前先介绍二个算法:MD5、SHA1
# MD5算法
- 32位的算法程序,每个字符都是一个十六进制
- MD5算法效率多,算法相对简单
- 目前大量的人使用MD5算法,也导致MD5的撞库的数据库比较多,比较容易让人破解
- 撞库:就是别人把值跟对应的MD5存在一个数据库里,可以拿一个MD5值去数据进行对比,如果存在,在把数据库中的MD5对应的值拿出来,这就相对的破解了
import hashlib
so = "sakjkh21h3h12jkh3jk1h23jk1"
md5 = hashlib.md5() ## 实例化hashlib中的md5类
md5.update(so.encode("utf-8")) ##想把字符串进行算法,要先转换成bytes类型的数据
print(md5.hexdigest(),type(md5.hexdigest()),len(md5.hexdigest()))
执行结果:
2ec318fb8955b68052e8d3e3188c50ae <class 'str'> 32
## 运算出的密文是字符串类型
## 数量为32
# SHA1算法
- 40位的算法程序,每个字符都是一个十六进制
- SHA1算法效率比较低,算法也相对比较复杂
- 目前使用SHA1算法的人比较少,但是也是有,也是有撞库的存在,只是这种算法的撞库数据库比较少
import hashlib
so = "sakjkh21h3h12jkh3jk1h23jk1"
md5 = hashlib.sha1() ## 实例化hashlib中的sha1类
md5.update(so.encode("utf-8")) ##想把字符串进行算法,要先转换成bytes类型的数据
print(md5.hexdigest(),type(md5.hexdigest()),len(md5.hexdigest()))
执行结果:
eb3e29dfdff231ad1483fb0abbd5545f8dd34c87 <class 'str'> 40
## 运算出的密文是字符串类型
## 数量为40
# 总结
在hashlib模块中使用算法的过程都是一样的,只是在实例化算法的时候选择自己想要的算法,接下的操作过程都是差不多的,
可以考虑上面的MD5跟SHA1的运算过程,会发现基本一致
无论是MD5或SHA1或其他的算法都有可能被撞库给破解了,这里就要运用一个安全机制的加密,被称为加盐
# hashlib模块加盐
加盐是什么:在输入的字符进行加密运算是,加上指定的字符一起运算,得到结果安全级别比较高,加的盐,如果盐有一点变化,那么运算出的值也会进行变化
# 静态加盐
import hashlib
so = "sakjkh21h3h12jkh3jk1h23jk1"
md5 = hashlib.md5("这是我要加的盐".encode('utf-8')) ## 注意:加盐的值也必须是bytes类型的数据
md5.update(so.encode("utf-8"))
print(md5.hexdigest())
md5_1 = hashlib.md5()
md5_1.update(so.encode("utf-8"))
print(md5_1.hexdigest())
执行结果:
8bfe8b2beb15b9059dde5f8ba4266555
2ec318fb8955b68052e8d3e3188c50ae
在这里不推荐使用静态加盐,为什么呢,因为如果自己的网站使用静态加盐,那黑客通过某种手段,获取到自己的数据库用户信息,那么黑客就可以通过恶意注册用户,进行注册大量的用户,每个用户的密码都不一样, 注册完,拿到自己注册的用户密码的MD5码,在对拿的数据库用户信息进行匹配,匹上,就可以逆推出网站用户密码,这就是静态加盐的不完善之处
# 动态加盐
通过上次的静态加盐,我也很详细的说明了静态加盐的不足之处
那么动态加盐是怎么个动态法
- 比如自己的网站用户注册,用户名正常来说,是不允许相同的
- 那这样子,就可以使用,用户自身的用户名来对用户的密码进行动态加盐
- 也可以通过其他方式,上面这种方式是比较常用的动态加盐方式
import hashlib
so = "sakjkh21h3h12jkh3jk1h23jk1"
passwd = "江凡"
md5 = hashlib.md5(passwd.encode('utf-8')) ## 注意:加盐的值也必须是bytes类型的数据
md5.update(so.encode("utf-8"))
print(md5.hexdigest())
执行结果:
c25d388a53465fe044c55e3f84468e2a
# 模拟用户登录练习题
要求
- 模拟用户登录
- 密码需要使用MD5加密
- 密码的加盐方式,使用动态用户名加盐
import hashlib
user = input("请输入用户名:")
passwd = input("请输入密码:")
md5 = hashlib.md5(user.encode("utf-8"))
md5.update(passwd.encode("utf-8"))
passwd = md5.hexdigest()
if user == "江凡" and passwd == "78326743f649109417bf9b702f4de79e":
print("登录成功")
else:
print("账号或密码错误")
执行结果:
登录成功
# 文件的一致性校验
创建二个文件,内容一致
## so1 文件
666
666
666
## so2 文件
666
666
666
进行对这so1跟so2二个文件的校验
import hashlib
md5_so1 = hashlib.md5()
with open("so1","rb") as f:
md5_so1.update(f.read())
md5_so1 = md5_so1.hexdigest()
md5_so2 = hashlib.md5()
with open("so2","rb") as f:
md5_so2.update(f.read())
md5_so2 = md5_so2.hexdigest()
if md5_so1 == md5_so2:
print("文件一致")
else:
print("文件不一致")
print(md5_so1)
print(md5_so2)
执行结果:
文件一致
6183c52d316047c44682121a70853948
6183c52d316047c44682121a70853948