Python中的hashlib库的md5摘要是不可反解的,非常安全;摘要是单项不可逆的;加密是可以解密的,是双向的;haxdigest中hax代表16进制,digest代表摘要。
密码加密的几种方式:
1.明文转码加密:BASE64, 7BIT等,这种方式只是个障眼法,不是真正的加密。
2.对称算法加密:DES, RSA等。
3.签名算法加密:也可以理解为单向哈希加密,比如MD5, SHA1等。加密算法固定,容易被暴力破解。如果密码相同,得到的哈希值是一样的。
4.加盐哈希加密:加密时混入一段“随机”字符串(盐值)再进行哈希加密。即使密码相同,如果盐值不同,那么哈希值也是不一样的。现在网站开发中主要是运用这种加密方法。
目录
加密逻辑
1.hash
Hash,一般翻译为散列、杂凑,或音译为哈希,是把任意长度的输入(又叫做预映射pre- image)通过散列算法变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射。也就是,散列值的空间通常远小于输入的空间。不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值。
简单来说就是将任意长度的消息压缩到某一固定长度的消息摘要的函数。
hash主要用于信息安全领域中,把不同长度的信息转化为杂乱的128位编码,叫做hash值。
2.MD5
MD5是一种非常常见的摘要(hash)逻辑,其特点就是小巧,速度快,极难被破解。曾被山东大学王小云女士破解,MD5依然是国内非常多互联网公司选择的密码摘要算法。
MD5 Message Digest Algorithm 广泛使用的密码杂凑函数,可以产生128位的hash value(数字指纹finger print)
三个特点
(1)不可逆,所以摘要算法就不是一个加密逻辑;
(2)相同的内容计算出来的摘要大概率是一样的;
(3)不同的内容(哪怕只是极其细微的区别)计算出来的结果差别非常大。
在数学上,摘要计算逻辑就是hash,hash(数据data) => 数字。
三种用途
1.防止被篡改
一致性检测
发送文件,软件下载,svn
2.防止看到明文
网站数据库存储用户的密码都用MD5值,如果以明文保存用户口令,如果数据库泄漏,所有用户的口令就会落入黑客的手里。此外,网站运维人员是可以访问数据库的,也就是能获取到所有用户的口令。正确的保存口令的方式是不存储用户的明文口令,而是存储用户口令的摘要,比如MD5,存储MD5的好处是即使运维人员能访问数据库,也无法获知用户的明文口令。
3.防止抵赖
数字签名
哈希函数-MD5算法_tomorrow00hello的博客-CSDN博客_哈希算法md5
3.加密练习
练习1
注意代码注释
#md5加密是不可反解的
from hashlib import md5
#实例化对象
obj = md5() #先创建一个md5的对象
#写入要加密的字节:iot
#对谁加密就把谁写在前面,python3中必须是字节,所以必须用encode()
obj.update("iot".encode("utf-8"))
#获取密文
secret = obj.hexdigest()
print(secret) #output = 97c209ca505f2958db30a42135afab5c
可以添加多个被加密的内容
练习2
from hashlib import md5
s1 = "iot is fun."
s2 = "socket is fun!"
val = md5()
val.update(s1.encode('utf-8'))
val.update(s2.encode('utf-8'))
val.hexdigest()
md5((s1+s2).encode('utf-8')).hexdigest()
#ouput = 'e3ee4aca992bae6e8d8710f020552971'
如果数据量很大,可以分块多次调用update(),最后计算的结果是一样的。
我们把密文丢到网页里,发现有些网站可以直接解密,但其实不然,这里并不是直接解密MD5,而是“撞库”。黑客可以事先计算出这些常用口令的MD5值,得到一个反推表,就是网站里存储的大量的MD5值。而在需要进行查询的时候,只需要一条select语句就可以查询到了,这就是传说中的“撞库”。
4.如何避免“撞库”
加盐
MD5在进行计算的时候可以加盐,加盐之后,就很难撞库了。
通过哈希算法,我们可以验证一段数据是否有效,方法就是对比该数据的哈希值,例如,判断用户口令是否正确,我们用保存在数据库中的password_md5对比计算md5(password)的结果,结果一致,用户输入的口令是正确的。
为了防止黑客通过彩虹表根据哈希值反推原始口令,在计算哈希的时候,不能仅针对原始输入计算,需要增加一个salt来使得相同的输入也能得到不同的哈希,这样大大增加了黑客破解的难度。
如果salt是我们自己随机生成的,通常我们计算MD5时采用md5(message + salt)。但实际上,把salt看做一个“口令”。加salt的哈希就是:计算一段message的哈希时,根据不同口令计算出不同的哈希。要验证哈希值,必须同时提供正确的口令。
代码实现
import hashlib
obj=hashlib.md5(b'12334') #实例化md5的时候可以给传个参数,这叫加盐
obj.update("admin".encode("utf-8")) #是在加密的时候传入一块字节
secret=obj.hexdigest()
print(secret)
#output = d12852f3460a3fc6ed5accfe3ac9ac38
from hashlib import md5
salt = "I am salt.add me in"
obj = md5(salt.encode("utf-8"))
obj.update("iot".encode("utf-8"))
bs = obj.hexdigest()
print(bs)
output = 6667b4ef3ceda4d384a83a9e0796da34
from hashlib import md5
salt = "I am salt. add me in"
obj = md5(salt.encode("utf-8"))
obj.update("iot".encode("utf-8"))
bs = obj.hexdigest()
print(bs)
#output = 0f8bb42d52a9f4cac1fb2f219d6741a9
扩展应用
import hashlib
SALT = b'2erer3asdfwerxdf34sdfsdfs90'
def md5(pwd):
# 实例化对象
obj = hashlib.md5(SALT)
# 写入要加密的字节
obj.update(pwd.encode('utf-8'))
# 获取密文
return obj.hexdigest()
user = input("请输入用户名:")
pwd = input("请输入密码:")
if user == 'bai' and md5(pwd) == 'c5395258d82599e5f1bec3be1e4dea4a':
print('登录成功')
else:
print('登录失败')
比SHA1更安全的算法是SHA256和SHA512,不过越安全的算法不仅越慢,而且摘要长度更长。
扩展:SHA256
代码实现
from hashlib import sha1,sha256,sha384,sha512
sha = sha256(b'salt')
sha.update(b'iot')
print(sha.hexdigest())
不论是SHA1,SHA256,MD5都属于摘要算法,都是在计算hash值, 只是散列的程度不同,这种算法有一个特征:他们是散列,不是加密,而且由于hash算法是不可逆的,所以不存在解密的逻辑。
三种盐的实例:
>>> [chr(random.randint(48,122)) for i in range(32)]
['V', 'z', 'y', 'k', '@', 'Q', 'f', 'T', 'd', 'x', 'Y', 'w', 'o', '5', 'T', 'd', '0', 'f', '6', 'Q', '5', 'q', 'b', '1', 'R', 'Q', 'j', 'q', '_', '8', 'l', 'E']
>>> ''.join[chr(random.randint(48,122)) for i in range(32)]
File "<stdin>", line 1
''.join[chr(random.randint(48,122)) for i in range(32)]
^^^
SyntaxError: invalid syntax
>>> join[chr(random.randint(48,122)) for i in range(32)]
File "<stdin>", line 1
join[chr(random.randint(48,122)) for i in range(32)]
^^^
SyntaxError: invalid syntax
>>> ".join[chr(random.randint(48,122)) for i in range(32)]
File "<stdin>", line 1
".join[chr(random.randint(48,122)) for i in range(32)]
^
SyntaxError: unterminated string literal (detected at line 1)
>>> ".join([chr(random.randint(48,122)) for i in range(32)])
File "<stdin>", line 1
".join([chr(random.randint(48,122)) for i in range(32)])
^
SyntaxError: unterminated string literal (detected at line 1)
>>> join([chr(random.randint(48,122)) for i in range(32)])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'join' is not defined
>>> salt = ".join([chr(random.randint(48,122)) for i in range(32)])
File "<stdin>", line 1
salt = ".join([chr(random.randint(48,122)) for i in range(32)])
^
SyntaxError: unterminated string literal (detected at line 1)
学习参考:
sha256加密_python中使用加盐哈希函数加密密码_weixin_39600616的博客-CSDN博客