Python 之网络编程之socket(3)hashlib模块

时间:2022-04-13 23:55:55

 

 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'\xb7wQ\xe4\r5\x15\xca\xc3\x7fUY\xc3\xcb\x84<\x10\x7f\xb1\x8b\xac_\x04\xf2\x8b\x948C\x1e\xa6\x1a\x10'

fa9e0bceb2effd7adbcdb76b414ccf95

32

#第二次运行:

eade56028e252b77f7a0b8792e58b9cc

32

b'\xf6\x08\xf5\x8d8+4\xec\xad[\xc0#T^\xed\xb2{V\xa4\xe9\xb5\xb7\xe5>\xecn\xf6\xd4\xe3\xe3\xb6\x87'

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("昨天晚上\n下雨了".encode())
res = hs.hexdigest()
print(res) # 894c4dd4b1f57472322db524e7b6a47f

# 可以连续update 到hs对象进行字节流的拼接
hs = hashlib.md5()
hs.update("昨天晚上\n".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.hashlibhmac加密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.hashlibmd5加密socket应用二(验证登录)

首先需要创建一个用户信息包括用户名和加密后的密码:

解密的方式是已用户名为盐值,用密码+用户名进行md5加密

userinfo.txt内存入这三个信息密码加密后存入文本:

 zhangsan 111
 li  222
 wangwu 333

解密的内容如图方式:

Python 之网络编程之socket(3)hashlib模块

服务端代码为:

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()

#运行结果是,在客户端让其输入用户密码:

#如果用户或密码错误会返回登录失败:

Python 之网络编程之socket(3)hashlib模块

#如果用正确的用户密码输入返回成功:

Python 之网络编程之socket(3)hashlib模块