[专题] 使用 Python 密码模块 hashlib
Python加密模块hashlib的使用
- 一、加密算法介绍
- 二、MD5加密算法
- 三、sha1加密算法
- 四、加密算法应用场景
- 五、小结
一、加密算法介绍
- 什么是加密算法呢?加密算法又称哈希算法、散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)。
- 加密算法就是通过加密算法
f()
对任意长度的数据data计算出固定长度的密文hexdigest
,目的是为了发现原始数据是否被人篡改过。 - 加密算法之所以能指出数据是否被篡改过,就是因为摘要函数是一个单向函数,计算
f(data)
很容易,但通过digest反推data却非常困难。而且,对原始数据做一个bit的修改,都会导致计算出的摘要完全不同。
二、MD5加密算法
以常见的加密算法MD5为例,计算一个字符串的MD5值:
import hashlib
md5 = hashlib.md5()
# update函数的加密文本:英文必须是ASCII的二进制格式
md5.update(b'how are you?I fine, and you?')
print(md5.hexdigest())
输出结果:c61e87d5b1883b97428e02df773ba377
md5 = hashlib.md5()
# update函数如果不是ASCII格式,则必须对文字进行编码,否则会报错
md5.update("天王盖地虎".encode('utf-8'))
print(md5.hexdigest())
输出结果:151df4d2ddbdd1ad6a64c2c18b294828
统一上述的写法,将待加密的汉字或者英文content都可以直接先按照utf-8格式编码。即:
import hashlib
md5 = hashlib.md5()
content= input('请输入待加密的文本内容:')
md5.update(content.encode('utf-8'))
print(md5.hexdigest())
如果数据量很大,可以分块多次调用update()
,最后计算的结果是一样的:
import hashlib
md5 = hashlib.md5()
md5.update(b'how are you?')
md5.update(b'I fine, and you?')
print(md5.hexdigest())
输出的结果也是c61e87d5b1883b97428e02df773ba377
可以看到和上面的加密结果一模一样。一般稍微改动一个字母或者字符,该算法计算出来的结果完全不同。MD5是最常见的摘要算法,速度很快,生成结果是固定的128 bit字节,通常用一个32位的16进制字符串表示。
三、sha1加密算法
除了MD5摘要算法外,比较常用的摘要算法还有SHA1,调用SHA1和调用MD5完全类似:
import hashlib
sha1 = hashlib.sha1()
sha1.update(b'how are you?')
sha1.update(b'I fine, and you?')
print(sha1.hexdigest())
输出结果:3782065e98449054afc40c8dc23de53778703982
SHA1的结果是160 bit字节,通常用一个40位的16进制字符串表示。
有没有可能两个不同的数据通过某个加密算法得到了相同的密文?完全有可能,因为任何摘要算法都是把无限多的数据集合映射到一个有限的集合中。这种情况称为碰撞。
四、加密算法应用场景
任何允许用户登录的网站都会存储用户登录的用户名和密码。如何存储用户名和密码呢?方法是存到数据库表中:
username | password |
---|---|
Chimu | 123456 |
TrainingL | abc123 |
Daimao | abcdef |
如果以明文保存用户密码,如果数据库泄露,所有用户的密码就落入黑客的手里。此外,网站运维人员是可以访问数据库的,也就是能获取到所有用户的密码。这样对用户信息或者数据而言是极不安全的,我们往往希望的是,只有用户自己知道自己的密码。
import hashlib
md5 = hashlib.md5()
password = input("待加密的明文密码:")
md5.update(password.encode('utf-8'))
print(md5.hexdigest())
正确的保存密码的方式是不存储用户的明文密码,而是存储用户密码的密文,比如MD5:
username | password |
---|---|
Chimu | e10adc3949ba59abbe56e057f20f883e |
TrainingL | e99a18c428cb38d5f260853678922e03 |
Daimao | e80b5017098950fc58aad83c8c14978e |
- 当用户登录时,首先计算用户输入的明文密码的MD5,然后和数据库存储的MD5对比,如果一致,说明密码输入正确,如果不一致,密码肯定错误。
- 存储MD5的好处是即使运维人员能访问数据库,也无法获知用户的明文口令。
设计一个验证用户登录的函数,根据用户输入的口令是否正确,返回True或False:
import hashlib
# 存储用户信息的数据表:db.user
db = {
'Chimu':'e10adc3949ba59abbe56e057f20f883e',
'TrainingL':'e99a18c428cb38d5f260853678922e03',
'Daimao':'e80b5017098950fc58aad83c8c14978e'
}
def login(username,password):
md5 = hashlib.md5()
md5.update(password.encode('utf-8'))
if username in db.keys():
if md5.hexdigest() == db[username]:
print("欢迎登陆!")
else:
print('密码错误,请重试!')
else:
print("用户不存在,先注册!")
username = input("请输入用户名:")
password = input("请输入密码:")
login(username,password)
运行效果截图:
由于常用口令的MD5值很容易被计算出来,所以,要确保存储的用户口令不是那些已经被计算出来的常用口令的MD5,这一方法通过对原始口令加一个复杂字符串来实现,俗称“加盐”:
经过Salt处理的MD5口令,只要Salt不被黑客知道,即使用户输入简单口令,也很难通过MD5反推明文口令。
将上述的加密验证需求改进之后如下:
import hashlib,random
def get_md5(s):
return hashlib.md5(s.encode('utf-8')).hexdigest()
class User(object):
def __init__(self,username,password):
self.username = username
self.salt = ''.join([chr(random.randint(48,122)) for i in range(20)])
self.password = get_md5(password + self.salt)
db = {
'chimu': User('michael', '123456'),
'trainingl': User('bob', 'abc123'),
'daimai': User('alice', 'abcdef')
}
def login(username,password):
user = db[username]
pwd = get_md5(password + user.salt)
return user.password == pwd
print(login('bob',"abc999"))
五、小结
摘要算法在很多地方都有广泛的应用。要注意摘要算法不是加密算法,不能用于加密(因为无法通过摘要反推明文),只能用于防篡改,但是它的单向计算特性决定了可以在不存储明文口令的情况下验证用户口令。
参考廖雪峰老师的Python教程
上一篇: Python 学习] 基础 - 常用模块 - hashlib 模块:常用哈希算法,如 MD5、SHA1、SHA256 等。计算
下一篇: python hashlib 库(MD5、sha1、sha256、sha512、pbkdf2_hmac)的用法和 pbkdf2 原理
推荐阅读
-
python 使用多处理模块来实现对回调函数的异步调用。
-
在 Python 中使用请求模块
-
Python3 点击模块使用说明
-
python 的资源使用和控制资源模块
-
python 使用 sched 模块执行定期和定时任务
-
使用 python 图形模块海龟库绘制樱花、玫瑰和圣诞树的代码示例
-
Python 日志库 Loguru 教程(最方便用户使用的 Python 日志模块)
-
使用日期时间和 Win32com 模块,用 python 获取股票数据并进行广播和右下角弹出警报
-
库存 Python 加密解密模块 hashlib 7 种加密算法 - 前言
-
在 python 中使用 hashlib 模块的示例