3:hash

3.1:什么是哈希hash

1、什么叫hash:hash是一种算法(3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法),该算法接受传入的内容,经过运算得到一串hash值
2、hash值的特点是:
2.1 只要传入的内容一样,得到的hash值必然一样\=\=\==\=>要用明文传输密码文件完整性校验
2.2 不能由hash值返解成内容=\=\=\=\==\=>把密码做成hash值,不应该在网络传输明文密码
2.3 只要使用的hash算法不变,无论校验的内容有多大,得到的hash值长度是固定的

3.2:hash的用途

用途1:特点2.2用于密码密文传输与验证
用途2:特点2.1、2.3用于文件完整性校验

3.3:如何用hash

注意,传入给hash处理的数据类型必须以bytes类型传入,其他类型会报错

import hashlib

'''有md5、sha等算法,sha比md5复杂些'''
m=hashlib.md5()
'''使用m.update将内容给m处理,指定编码格式输入成bytes类型'''
m.update('hello'.encode('utf-8'))
'''使用m.update将内容给m处理,指定编码格式输入成bytes类型'''
m.update('world'.encode('utf-8'))
'''取出上面全部拼接起来的内容hash后的结果,也就是helloworld哈希后的结果'''
res=m.hexdigest()
print(res)

'''也可以直接在hashlib.md5中添加哈希的内容'''
m1=hashlib.md5('he'.encode('utf-8'))
m1.update('llo'.encode('utf-8'))
m1.update('w'.encode('utf-8'))
m1.update('orld'.encode('utf-8'))
'''取出上面全部拼接起来的内容hash后的结果,也就是helloworld哈希后的结果'''
res=m1.hexdigest()
print(res)

打印
fc5e038d38a57032085441e7fe7010b0
fc5e038d38a57032085441e7fe7010b0
# 相同证明两个数据的内容是一样的。

3.3.1:完整性校验方法1

将内容一次性读到内存当中然后进行校验,这种方法是有风险的,如果文件数据量过大,可能会导致内存溢出

'''一次性读'''
# a.txt文件
202cb962ac59075b964b07152d234b70 # <==123的md5校验值
900150983cd24fb0d6963f7d28e17f72 # <==abc的md5校验值
52e998da4fb9eebbdc21e440ca2f0f67 # <==HeTaoTao.33hao123的md5校验值

# run.py文件
test=1
while test:
res=input('请输入密码[q退出]: ').strip()
m1 = hashlib.md5(res.encode('utf-8'))
with open('a.txt',mode='rb') as f:
if m1.hexdigest() in f.read().decode('utf-8').strip() :
print('密码正确')
elif res == 'q':
break
else:
print('密码错误')

打印:
请输入密码[q退出]: abc
密码正确
请输入密码[q退出]: 123
密码正确
请输入密码[q退出]: q

进程已结束,退出代码

3.3.2:完整性校验方法2

将内容一行一行的读到内存当中然后记性校验,这种方法可以有效避免第一种方法内存溢出的问题,但如果文件非常大就但我没说

'''一行读'''
# a.txt文件
202cb962ac59075b964b07152d234b70 # <==123的md5校验值
900150983cd24fb0d6963f7d28e17f72 # <==abc的md5校验值
52e998da4fb9eebbdc21e440ca2f0f67 # <==HeTaoTao.33hao123的md5校验值

# run.py文件
test=1
while test:
res=input('请输入密码[q退出]: ').strip()
m1 = hashlib.md5(res.encode('utf-8'))
with open('a.txt',mode='rb') as f:
for line in f:
if line.decode('utf-8').strip() == m1.hexdigest():
print('密码正确')
break
elif res == 'q':
test = False
break
else:
print('密码错误')

打印:
请输入密码[q退出]: 123
密码正确
请输入密码[q退出]: abc
密码正确
请输入密码[q退出]: HeTaoTao.33hao123
密码正确
请输入密码[q退出]: 1234
密码错误
请输入密码[q退出]: q

进程已结束,退出代码0

3.3.3:完整性校验方法3

第二种方法如果是密码校验那还好,但用途是用来检验数据完整性的时候可能就撑不住了,因为谁也不知道校验的数据到底会有多大。

可以选择性校验,校验前几个数据就可以了,这样不管文件有多大,校验的数据也就那么大,但也会有一个局限性,篡改者可以躲避你校验的数据,在其他位置进行添加或篡改。

# a.txt文件
哥哥,我的好哥哥
今天你睡了吗?
晚上好?
下午好?
money乃身外之物,理应由我一人承担!!!!!!!

//可以通过此代码获得a.txt文件的md5校验码
with open('a.txt',mode='rb') as f1:
res = f1.read(10)
print(hashlib.md5(res).hexdigest())

打印:
6b6de6d56c49f8aa23ef7e8e88eecbb3 # <==此乃a.txt文件数据前10个bytes的校验码


# run.py文件
m1 = hashlib.md5()
with open('a.txt',mode='rb') as f:
if a_txt_hash == hashlib.md5(f.read(10)).hexdigest():
print('前10Bytes无篡改痕迹')
else:
print('前10Bytes可能被篡改')

打印:
前10Bytes无篡改痕迹 #==> 你敢改a.txt前10Bytes数据吗?你敢碰老子就敢变
前10Bytes可能被篡改 #==> 在a.txt首行哥哥前面加个1,你看,老子变了把!!
前10Bytes无篡改痕迹 #==> 在a.txt末尾添加一万行也不要紧,欸?我加了那么多行你也无动于衷,太伤心了,分手

3.3.4:完整性校验方法4:

最终解决办法,那就是均匀的校验数据,比如文件总大小的四分之一处取5个Bytes、四分之二处取5个Bytes、四分之四处取5个Bytes分别进行校验,如果这都被篡改者碰巧了,那就没招了,自求多福吧。

# a.txt文件
哥哥,我的好哥哥
今天你睡了吗?
晚上好?
下午好?
money乃身外之物,理应由我一人承担!!!!!!!
123

# run.py文件
import hashlib
import os
from functools import wraps

size=os.path.getsize(r'a.txt')
dict_hash={ #<==这是现成的md5校验码,分别是1/4、2/4、4/4Bytes中取到5Bytes的校验码
'a':'3ea3440b77b273550e048f2eae183448',
'b':'bc2a70945c831a070ca0272cd1efeeca',
'c':'d41d8cd98f00b204e9800998ecf8427e'
}

def hash_valiation(h,p,s):
def outter(func):
wraps(func)
def wrapper(*args,**kwargs):
count = 0
with open(p, mode='rb') as f:
'''将游标先移动到总Bytes的四分之一的位置'''
f.seek(int(s * 1 / 4), 0)
if hashlib.md5(f.read(5)).hexdigest() == h['a']:
pass
else:
count = 1
'''将游标先移动到总Bytes的四分之二的位置'''
f.seek(int(s * 2 / 4), 0)
if hashlib.md5(f.read(5)).hexdigest() == h['b']:
pass
else:
count = 1
'''将游标先移动到总Bytes的四分之四的位置'''
f.seek(int(s * 4 / 4), 0)
if hashlib.md5(f.read(5)).hexdigest() == h['c']:
pass
else:
count = 1

if count == 1:
print('可能被篡改')
else:
print('校验正常')
res = func(*args,**kwargs)
return res
return(wrapper)
return outter


@hash_valiation(dict_hash,'a.txt',size)
def index():
pass

index()

#我知道这里应该是可以用循环嵌套解决代码冗余问题,但能力目前有限,先这样。。。。后面俺变强了就给他改咯,如果有大佬能给我改改,那就太感激了+ ~ +

加油