hashlib 模块学习
1 hashilib 模块的功能
python 的 hashlib 提供了常见的摘要算法,如 MD5、SHA1 等等。
什么是摘要算法呢?
摘要算法又称哈希算法、散列算法。它通过一个函数,把任意长度的数据转换成一个长度固定的数据串(通常用 16 进制的字符串表示)。
摘要算法就是通过摘要函数对任意长度的data计算出固定长度的摘要digest,目的是为了发现原始数据是否被人篡改过。
摘要算法之所以能指出数据是否被篡改过,就是因为摘要函数是一个单向函数,计算data的摘要digest很容易,但是通过digest反推data却非常困难,而且,对原始数据做一个bit的修改,都会导致据算出的摘要完全不同。
2 如何使用 hashilib 模块
使用 hashilib 模块一般分为 4 步:
(1)在 python 中引用 hashlib 模块。
(2)创建一个 hash 对象,使用 hash 算法命名的构造函数,或者通用构造函数。
(3)使用 hash 对象调用 update() 方法填充对象
(4)调用 digest()或者 hexdigest() 方法来获取摘要(加密结果)
3 实例代码
import hashlib
s = "How to use md5 in python hashlib?"
md5 = hashlib.md5() # 调用一个 md5对象
# 调用md5的update()方法,对参数进行加密,加密必须为bytes类型
md5.update(s.encode("utf-8"))
print(md5.hexdigest()) # 打印加密结果
4 hashlib 的常用代码
4.1 md5 = hashlib.md5()或 md5 = hashlib.new(“md5”)
md5 可以替换为其他的哈希类型。
4.2 md5.update(arg)
将字节对象 arg 填充到 hashlib 对象中,arg 通常为要加密的字符串
4.3 md5.digest()
返回加密结果,它是一个字节对象,长度为 md5.digest_size。
4.4 md5.hexdigest()
返回加密结果,它是一个字符串对象,长度为 md5.digest_size*2,只包含 16 进制数字。
5 hashlib 模块提供的常量属性
5.1 hashlib.algorithms_guaranteed
获取保证在所有平台上此模块支持的 hash 算法名称的集合。
5.2 hashlib.algorithms_available
获取可以运行在 python 解释器中的 hash 算法名称的集合。
6 注意事项
(1)update() 方法需要接收的参数是一个字节对象。
(2)常用的一些算法主要有 sha1, sha224, sha256, sha384, sha512, md5 等算法。
(3)sha1 算法比较早,是不能暴力破解的。
7. 当要加密的数据量很大时,可以分块多次调用 update(),最后计算的结果是一样的
import hashlib # 调用hashlib模块
# s = "How to use md5 in python hashlib?"
# 创建一个md5模块
md5 = hashlib.md5()
# 调用md5的update()方法,对参数进行加密,加密必须为bytes类型
md5.update("How to use md5 in ".encode("utf-8"))
md5.update("python hashlib?".encode("utf-8"))
print(md5.hexdigest()) # 获取摘要内容
8 sha1 摘要算法
sha1 摘要算法是另一种常见的摘要算法,调用 sha1 的方式和 md5 类似
import hashlib
sha1 = hashlib.sha1()
sha1.update("how to use sha1 in ".encode("utf-8"))
sha1.update("python hashlib?".encode("utf-8"))
print(sha1.hexdigest())
9 hashlib 的应用
9.1 密码验证
所有允许用户登录的网站都会将用户登录的用户名和密码存储在数据库中。
如果以明文保存用户口令,如果数据库泄漏,所有用户的口令就落入黑客的手中。此外,网站运维人员是可以访问数据库的,也可以获取到所有用户的口令。正确的把保存口令的方式不是存储用户的明文密码,而是存储用户密码的摘要,比如 md5:
9.2 文件校验
hashlib 的还有一个方面的应用就是文件校验,它可以在文件传输时,验证文件是否被完整接收,这用到的是 hashlib 的“相同字符串的摘要一致”原理。如果摘要一致,说明文件传输完成,否则就是文件在传输过程中丢帧。
10 加盐
考虑到有这个一个情况,就是有些用户喜欢用“123456”、“888888”等一些简单的口令,于是,黑客可以事先计算出这些常见口令的 md5 值,得到一个反推表:
'e10adc3949ba59abbe56e057f20f883e': '123456'
'21218cca77804d2ba1922c33e0151105': '888888'
这样,无需破解,只需要对比数据库的 md5,黑客就获得了使用常用口令的用户帐号。
对于用户来说,当然不要使用过于简单的口令。同时,我们在程序设计上对简单口令加强保护。
由于常用口令的 md5 值很容易被计算出来,所以,要确保存储的用户密码不是那些已经被计算出来的常用口令的 md5。这一方法通过对原始口令加一个复杂字符串来实现,俗成“加盐”:
hashlib.md5("salt".encode("utf-8"))
经过“salt”处理的 md5 口令,只要“salt”不被黑客知道,即使用户输入简单口令,也很难通过 md5 反推明文口令。
但是如果有两个用户都使用了相同的简单密码,比如“123456”,在数据库中,将存储两条相同的 md5 值,这说明两个用户的密码是一样的。
那么,有没有办法让使用相同口令的用户存储不同的 md5 呢?
假定用户无法修改登录名,就可以通过把登录名作为“salt”的一部分来计算 md5,从而实现相同口令的用户也存储相同的 md5。
11 hashlib 模块补充
摘要算法在很多地方都有广泛的应用,要注意摘要算法不是加密算法,不能用于加密(因为无法通过摘要反推明文),只能用于防篡改,但是他的单向计算特性决定了可以在不存储明文密码的情况下验证用户口令。
12 一个简单的验证存储明文口令程序
import hashlib
def md5(arg):
"""这是加密函数,将传进来的函数加密"""
# 加盐
md5_pwd = hashlib.md5(bytes("salt", encoding="utf-8"))
md5_pwd.update(bytes(arg, encoding="utf-8"))
return md5_pwd.hexdigest() # 返回加密的数据
def log(user, pwd): # 登录时候的函数,由于md5不能反解, 因此登录的时候用正解
with open("user.txt", mode="r", encoding="utf-8") as f:
for line in f:
name, password = line.strip().split("|")
# 登录的时候验证用户名以及加密的密码跟之前保存的是否一样
if user == name and password == md5(pwd):
return True
def register(user, pwd): # 注册的时候把用户名和加密的密码写进文件,保存起来
with open("user.txt", mode="a", encoding="utf-8") as f:
msg = user + "|" + md5(pwd) + "\n"
f.write(msg)
i = input("1表示登录,2表示注册\n请选择:").strip()
if i == "2":
user = input("用户名:")
pwd = input("密码:")
register(user, pwd)
elif i == "1":
user = input("用户名:")
pwd = input("密码:")
r = log(user, pwd) # 验证用户名和密码
if r == True:
print("登录成功")
else:
print("登录失败")
else:
print("输入不合法")