hashlib模块
#hashlib 这个模块是一堆加密算法的集合体,哈希算法的加密方式不止一种
httpswww.cmd5.com md5解密
# 应用场景在需要效验功能时使用
用户密码的 = 加密,解密
相关效验的 = 加密,解密
#哈希算法也叫摘要算法,相同的数据始终得到相同的输出,不同的数据得到不同的输出。
#(1)哈希将不可变的任意长度的数据,变成具有固定长度的唯一值
(2) 字典的键值对映射关系是通过哈希计算的,哈希存储的数据是散列(无序)
1. hashlib基本用法
#例:
import hashlib ##基本用法使用md5加密 # (1)创建一个md5算法的对象 hs = hashlib.md5() # (2)把想要加密的字符串通过update更新到hs这个对象 # 参数是二进制字节流 hs.update("hsz".encode("utf-8")) # (3)返回32位16进制的字符串 res = hs.hexdigest() print(res) print(len(res),"位") # (4)加盐 (加key只有你自己知道的明文) 目的: 增加密码的复杂度 hs = hashlib.md5("hsz".encode("utf-8")) hs.update("123".encode("utf-8")) res = hs.hexdigest() print(res) #(5)动态加盐 import random res = str(random.randrange(10000,100000)) hs = hashlib.md5(res.encode()) hs.update("aabbccdd".encode()) res = hs.hexdigest() print(res)
得到的结果为:(因为最后一个是动态加盐,加入的是随机值,所有最后一个值一直在变化)
071a5dcfd09db850f1ff95131acc5f2c
32 位
72646ae443c21a820b2013262ea43f86
27b72799df64dc1ceca1544ebdd82876
# mod5 加密效率快 ,通用的加密方法,安全性稍差 位数是32位
# sha 加密效率慢 ,算法相对来精密,安全性稍高
##基本用法使用sha系列密方法
#例:
import hashlib hs = hashlib.sha1() hs.update("hahaha_123".encode()) res = hs.hexdigest() # 返回的加密的字符串长度是40位 print(res) print(len(res),"位") # 加密 hs = hashlib.sha1("qwe".encode()) hs.update("xx_qq123".encode()) res = hs.hexdigest() print(res) # sha512 hs = hashlib.sha512() hs.update("123456".encode()) res = hs.hexdigest() #返回的字符串长度是128位 print(res) print(len(res),"位")
输出结果为:
f1817bcbd94c1b26f5e25ed375b92de337cfe38d
40 位
a2affd3f2502b5de251e6e7704a9d5d641e5338a
ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413
128 位
##基本用法使用hmac 加密
#hmac 加密的算法更加不容易破解
#例:
import hashlib import hmac import os key = b"123" msg = b"456" # hmac里面的new方法相当于hashlib 创建对象和update 粘合在一起操作 hm = hmac.new(key,msg) res = hm.hexdigest() print(res) print(len(res),"位") # 随机返回长度为32位的二进制字节流(加盐) key = os.urandom(32) print(key) hs = hmac.new(key,msg) res = hs.hexdigest() print(res) print(len(res),"位")
由于后面两个加密时加盐,所有后面两个输出会一直在变化,这样安全性更强:
#第一次运行:
eade56028e252b77f7a0b8792e58b9cc
32 位
b'xb7wQxe4 5x15xcaxc3x7fUYxc3xcbx84<x10x7fxb1x8bxac_x04xf2x8bx948Cx1exa6x1ax10'
fa9e0bceb2effd7adbcdb76b414ccf95
32 位
#第二次运行:
eade56028e252b77f7a0b8792e58b9cc
32 位
b'xf6x08xf5x8d8+4xecxad[xc0#T^xedxb2{Vxa4xe9xb5xb7xe5>xecnxf6xd4xe3xe3xb6x87'
fe78046eae3682d73ac9cfd838c4800c
32 位
2.文件效验
首先需要创建两个文件:ceshi1.txt ceshi2.txt,然后都输入aaaaa,两个文件内容相同:
#例:
import hashlib # (1) 针对小文件的内容效验 def check_md5(file): with open(file, mode="rb") as fp: hs = hashlib.md5() hs.update(fp.read()) return hs.hexdigest() print(check_md5("ceshi1.txt")) print(check_md5("ceshi2.txt"))
输出结果为:
594f803b380a41396ed63dca39503542
594f803b380a41396ed63dca39503542
如果文件过大,是一次性读取不了的,所有(1)的方法只适合小文件的内容效验
#例:
import hashlib # (2) 针对于大文件的内容效验 hs = hashlib.md5() hs.update("昨天晚上 下雨了".encode()) res = hs.hexdigest() print(res) # 894c4dd4b1f57472322db524e7b6a47f # 可以连续update 到hs对象进行字节流的拼接 hs = hashlib.md5() hs.update("昨天晚上 ".encode()) hs.update("下雨了".encode()) res = hs.hexdigest() print(res)
输出结果为:
894c4dd4b1f57472322db524e7b6a47f
894c4dd4b1f57472322db524e7b6a47f
#例:
import hashlib # 方法一 def check_md5_01(file): hs = hashlib.md5() with open(file,mode="rb") as fp: while True: content = fp.read(1) if content: hs.update(content) else: break return hs.hexdigest() print(check_md5_01("ceshi1.txt")) print(check_md5_01("ceshi2.txt")) print("========================") # 方法二 import os def check_md5_02(file): hs = hashlib.md5() file_size = os.path.getsize(file) with open(file,mode="rb") as fp: while file_size: # read(1) 最多最多读一个,如果文件空了就不读了 content = fp.read(1) hs.update(content) file_size -= len(content) return hs.hexdigest() print(check_md5_02("ceshi1.txt")) print(check_md5_02("ceshi2.txt"))
输出结果为:
594f803b380a41396ed63dca39503542
594f803b380a41396ed63dca39503542
========================
594f803b380a41396ed63dca39503542
594f803b380a41396ed63dca39503542
3.hashlib之hmac加密socket应用一(效验秘钥)
模拟客户端连接服务端需要秘钥的情况的过程
服务端代码:
import socket import hmac import os def auth(conn, secret_key): # 随机获取二进制的字节流 msg = os.urandom(32) #print(msg) conn.send(msg) hm = hmac.new(secret_key, msg) res_serve = hm.hexdigest() # 接收客户端发给我的字符串 res_client = conn.recv(1024).decode("utf-8") if res_serve == res_client: print("合法的链接") return True else: print("不合法的链接") return False sk = socket.socket() sk.bind(("127.0.0.1", 9009)) sk.listen() conn,addr = sk.accept() secret_key = b"hszhahaha" if auth(conn,secret_key): # 如果返回真,可以接收客户发过来的各种请求 print(conn.recv(1024).decode("utf-8")) # 收发数据逻辑. # ... # 四次挥手 conn.close() # 退还端口 sk.close()
客户端代码:
import socket import hmac def auth(sk, key): # 接收服务器发过来的随机二进制字节流 msg = sk.recv(32) # print(msg) hm = hmac.new(key, msg) res = hm.hexdigest() # 把加密后的字符串发送给服务器 sk.send(res.encode()) sk = socket.socket() key = b"hszhahaha" sk.connect(("127.0.0.1", 9009)) auth(sk,key) sk.send(b"download") sk.close()
3.hashlib之md5加密socket应用二(验证登录)
首先需要创建一个用户信息包括用户名和加密后的密码:
解密的方式是已用户名为盐值,用密码+用户名进行md5加密
在userinfo.txt内存入这三个信息密码加密后存入文本:
zhangsan 111
li 222
wangwu 333
解密的内容如图方式:
服务端代码为:
import socket import json # zhangsan 111 # li 222 # wangwu 333 sk = socket.socket() sk.connect(("127.0.0.1", 9005)) # 收发数据的逻辑 usr = input("请输入用户名:") pwd = input("请输入您的密码:") dic = {"username":usr,"password":pwd,"operate":"login"} # 把字典系列化成字符串 json_dic = json.dumps(dic) #把字符串变成字节流 bytes_msg = json_dic.encode("utf-8") sk.send(bytes_msg) # 接收服务器的返回值 res_msg = sk.recv(1024).decode() # 反序列化成字典 dic_code = json.loads(res_msg) if dic_code['code']: print("恭喜你,登录成功") else: print("抱歉,登录失败")
客户端代码为:
import socket import json import hashlib def get_md5_code(usr, pwd): hs = hashlib.md5(usr.encode()) hs.update(pwd.encode()) return hs.hexdigest() sk = socket.socket() sk.bind(("127.0.0.1", 9005)) sk.listen() conn,addr = sk.accept() # 把接收的字节流变成字符串 msg = conn.recv(1024).decode() # 反序列化字典 dic = json.loads(msg) # 默认编辑用户不存在 sign = False with open("userinfo.txt",mode="r",encoding="utf-8") as fp: for line in fp: usr,pwd = line.strip().split(":") if usr == dic['username'] and pwd == get_md5_code(dic['username'],dic['password']): res = {"code":1} res_msg = json.dumps(res).encode() conn.send(res_msg) # 该用户找到了,存在 sign = True break if sign == False: res = {"code":0} res_msg = json.dumps(res).encode() conn.send(res_msg) conn.close() sk.close()
#运行结果是,在客户端让其输入用户密码:
#如果用户或密码错误会返回登录失败:
#如果用正确的用户密码输入返回成功: