一、hashlib模块

HASH

Hash,一般翻译做“散列”,也有直接音译为”哈希”的,就是把任意长度的输入(又叫做预映射,pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一的确定输入值。

简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。

HASH主要用于信息安全领域中加密算法,他把一些不同长度的信息转化成杂乱的128位的编码里,叫做HASH值.

Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等。

什么是摘要算法呢?摘要算法又称哈希算法、散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)。

摘要算法就是通过摘要函数f()对任意长度的数据data计算出固定长度的摘要digest,目的是为了发现原始数据是否被人篡改过。

摘要算法之所以能指出数据是否被篡改过,就是因为摘要函数是一个单向函数,计算f(data)很容易,但通过digest反推data却非常困难。而且,对原始数据做一个bit的修改,都会导致计算出的摘要完全不同。

hash值的特点是:

  • 只要传入的内容一样,得到的hash值必然一样:要用明文传输密码文件完整性校验

  • 不能由hash值返解成内容:把密码做成hash值,不应该在网络传输明文密码

  • 只要使用的hash算法不变,无论校验的内容有多大,得到的hash值长度是固定的

MD5(消息摘要算法第五版)

什么是MD5算法

MD5讯息摘要演算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码杂凑函数,可以产生出一个128位的散列值(hash value),用于确保信息传输完整一致。MD5的前身有MD2、MD3和MD4。

MD5功能

输入任意长度的信息,经过处理,输出为128位的信息(数字指纹);不同的输入得到的不同的结果(唯一性);

MD5算法的特点

  1. 压缩性:任意长度的数据,算出的MD5值的长度都是固定的

  2. 容易计算:从原数据计算出MD5值很容易

  3. 抗修改性:对原数据进行任何改动,修改一个字节生成的MD5值区别也会很大

  4. 强抗碰撞:已知原数据和MD5,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。

MD5算法是否可逆?

MD5不可逆的原因是其是一种散列函数,使用的是hash算法,在计算过程中原文的部分信息是丢失了的。

MD5用途

  1. 防止被篡改:

  2. 防止直接看到明文:

  3. 防止抵赖(数字签名):

SHA-1(安全哈希算法)

安全哈希算法(Secure Hash Algorithm)主要适用于数字签名标准(Digital Signature Standard DSS)里面定义的数字签名算法(Digital Signature Algorithm DSA)。对于长度小于2^64位的消息,SHA1会产生一个160位的消息摘要。当接收到消息的时候,这个消息摘要可以用来验证数据的完整性。

SHA是美国国家安全局设计的,由美国国家标准和技术研究院发布的一系列密码散列函数。

科学家们又推出了SHA224, SHA256, SHA384, SHA512,当然位数越长,破解难度越大,但同时生成加密的消息摘要所耗时间也更长。目前最流行的是加密算法是SHA-256 .

通常应用

  1. 密码加密(很常用的一种用法)

    将用户的密码或者账户名密码转为密文进行存储(密文是加了密的的文字,明文是加密之前的文字。),防止用户资料信息被泄露带来各种不安全的情况

  2. 文件校验

在网上下载大尺寸文件的时候常见到网站同时会提供这个文件的MD5的值,它的作用是用户下载后可以在下载文件基础上计算MD5的值,如果和网站提供的MD5是相同的说明文件在下载过程中没有损坏或者说文件没有被恶意网站修改。

3.工作量证明(Proof ofWork)

详见https://www.zhihu.com/question/22369364/answer/23600737

MD5算法例子

import hashlib

m = hashlib.md5() #实例化创建加密对象
m.update(b"nicholas") #传入待加密的字符串,注意要转换为bytes二进制形式,以下两种写法也是可以的
# m.update("nicholas".encode("utf-8"))
# m.update(bytes("nicholas",encoding="utf-8"))

v1 = m.hexdigest()
print(type(v1))
print(v1) #返回产生的十六进制的字符串类型数值
#输出结果532ab4d2bbcc461398d494905db10c95
"""注意这里是十六进制的数,共32个数,由于一位十六进制的数要用4位二进制的数来表示
这里是产生了32*4=128位二进制数,所以我们经常听到MD5是128位的校验,这里的128位是代表128位的二进制数
"""

v2 = m.digest()
print(v2) #返回二进制形式的数值,可以转换为十六进制形式,与hexdigest结果一致
print(type(v2))
import binascii #这里为了方便,直接在这里导入binascii ,将二进制转为十六进制
print(binascii.b2a_hex(v2)) #b'532ab4d2bbcc461398d494905db10c95'

  

输出结果

  <class 'str'>
532ab4d2bbcc461398d494905db10c95
b'S*\xb4\xd2\xbb\xccF\x13\x98\xd4\x94\x90]\xb1\x0c\x95'
<class 'bytes'>
b'532ab4d2bbcc461398d494905db10c95'

  

分析:可以看到digest()和hexdigest()产生的数值其实是一样的,只不过一个是作为二进制数据字符串值(bytes类型),一个是十六进制数据字符串值(字符串类型)。

注意:如果m.update(a)之后再次 m.update(b),那么就相当于m.update(a+b)

例子

  
  import hashlib

m1 = hashlib.md5() #实例化创建加密对象
m1.update(b"nicholas") #传入待加密的字符串
m1.update(b"123")
print(m1.hexdigest()) #12962a329e66f22a0dfbeec2f2498d87

m2 = hashlib.md5()
m2.update(b"nicholas123")
print(m2.hexdigest()) #12962a329e66f22a0dfbeec2f2498d87

  

输出结果

  12962a329e66f22a0dfbeec2f2498d87
12962a329e66f22a0dfbeec2f2498d87

  

分析:可以看到m1传入2次bytes之后产生的结果和m2结果一样的。这种特性表示如果处理同一个大量数据可以分块传入,与一次性传入处理结果是一样的。

SHA算法例子

例子

  
  import hashlib

m1 = hashlib.sha1() #实例化创建加密对象
m1.update(b"nicholas") #传入待加密的字符串
m1.update(b"123")
print(m1.hexdigest())

m2 = hashlib.sha1()
m2.update(b"nicholas123")
print(m2.hexdigest())

  

输出结果

  ef3f18a2b33e1f5366c25161a4869707503225f2
ef3f18a2b33e1f5366c25161a4869707503225f2

  

分析;可以看到,SHA算法的用法和MD5用法类似,也有分批次传入和一次性传入结果一致的特性。

加盐

上述各种算法比明文存储密码确实要安全不少。但在有些场景中,用户通常会将密码设置的尤为简单。这样如果数据库泄露,黑客可以通过简单的密码尝试来完成对加密字串的匹配。即:通过撞库可以反解。为了解决这种方法,我们通常需要对密码做“加盐”处理,即有必要对加密算法中添加自定义key再来做加密。

所谓加盐就是在m = hashlib.md5()这里设置参数,如果没有参数,所以md5遵守一个规则,生成同一个对应关系,如果加了参数,就是在原先加密的基础上再加密一层,这样的话参数只有自己知道,防止被撞库,因为别人永远拿不到这个参数。

例子


 import hashlib

m1 = hashlib.md5() #md5对象,md5不能反解,但是加密是固定的,就是关系是一一对应,所以有缺陷,可以被对撞出来
m1.update(b"nicholas") #传入待加密的字符串
print(m1.hexdigest())
# 输出结果 532ab4d2bbcc461398d494905db10c95
"""这个结果可以别人也可以直接对简单字符串的进行MD5取值生成一个数据库,拿数据库中的MD5值与这个MD5值进行比对,
一致则反向找到了原字符串,因此现在网站注册用户一般会提示密码加上字母、数字、特殊字符多种组合
"""

m2 = hashlib.md5(b"salt") #这里加盐设置的参数自己确定,如果没有参数,所以md5遵守一个规则,
# 生成同一个对应关系,如果加了参数, 就是在原先加密的基础上再加密一层,别人不知道这个对应关系,就加大了撞库破解的难度。
m2.update(b"nicholas")
print(m2.hexdigest())
# 输出结果317bf09f6da0f56f86b896fac6663443

  

tips:sha加盐用法与md5类似。

摘要算法应用场景

(1)大文件md5校验

  
  import hashlib
def file_md5(filename):
md5_value = hashlib.md5()
with open(filename, 'rb') as f:
while True:
data = f.read(2048) # 每次读取2048个字节数据
if not data:
break
md5_value.update(data)# 计算md5值
return md5_value.hexdigest()

file = input("请输入文件完整路径:")
v = file_md5(file)
print(v)

  

输出结果


 32a9d0ad680bcdcb712ec802be9971be

  

(2)网站用户注册登录

  
  import hashlib
import json
import os


def handle_md5(msg):
"对关键信息进行MD5处理"
m = hashlib.md5(bytes("salt",encoding="utf-8")) #加盐
m.update(bytes(msg,encoding="utf-8"))
res = m.hexdigest()
return res


def write_data(filename,data):
with open(filename,"a+",encoding="utf-8") as f:
json.dump(data,f)


def read_data(filename):
with open(filename,"r",encoding="utf-8") as f:
data = json.load(f)
return data

def login():
#用户登录模块
username = input("请输入账户名:").strip()
userpasswd = input("请输入密码:").strip()
username_file = "%s.json"%username
start_file_path = os.path.dirname(os.path.abspath(__file__))
username_file_path = os.path.join(start_file_path,username_file)
if os.path.exists(username_file_path): #判断用户信息文件是否存在
data = read_data(username_file_path)
account = data["name"]
passwd_md5 = data["passwd"]
userpasswd_md5 = handle_md5(userpasswd)
if username == account and userpasswd_md5 == passwd_md5:
print("恭喜%s,登录成功!"%username)
else:
print("账号或者密码错误,请重新登录。")
return "ok"
else:
print("账户不存在,请注册!")
return "no"


def register():
#用户注册模块
username = input("请输入要注册的用户名:").strip()
userpasswd = input("请输入要注册的密码:").strip()
user_filename = "%s.json"%username
user_passwd_md5 = handle_md5(userpasswd)
user_data ={"name":username,"passwd":user_passwd_md5}
write_data(user_filename,user_data)
print("注册成功")


def main():
print("欢迎登录XX")
while True:
res = login()
if res == "no":
register()
elif res == "ok":
print("进入了XX网站")
break


if __name__ == "__main__":
main()

  

Python之路(第十九篇)hashlib模块的更多相关文章

  1. Python之路(第二十九篇) 面向对象进阶:内置方法补充、异常处理

    一.__new__方法 __init__()是初始化方法,__new__()方法是构造方法,创建一个新的对象 实例化对象的时候,调用__init__()初始化之前,先调用了__new__()方法 __ ...

  2. Python之路(第十八篇)shutil 模块、zipfile模块、configparser模块

    一.shutil 模块 1.shutil.copyfileobj(fsrc, fdst[, length]) 将文件内容拷贝到另一个文件中,需要打开文件 import shutil shutil.co ...

  3. Python之路(第十六篇)xml模块、datetime模块

    一.xml模块 xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单, xml比较早,早期许多软件都是用xml,至今很多传统公司如金融行业的很多系统的接口还主要 ...

  4. Python之路(第十五篇)sys模块、json模块、pickle模块、shelve模块

    一.sys模块 1.sys.argv 命令行参数List,第一个元素是程序本身路径 2.sys.exit(n) 退出程序,正常退出时exit(0) 3.sys.version . sys.maxint ...

  5. Python之路(第十四篇)os模块

    一.os模块 1.os.getcwd() 获取当前工作目录(当前工作目录默认都是当前文件所在的文件夹) import os print(os.getcwd()) 2.os.chdir(path) 改变 ...

  6. Python学习【第十二篇】模块(2)

    序列化 1.什么是python序列化? 把变量从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling 序列化就是将python的数据类型转换成字符串 反序列化就是将字符串转换成 ...

  7. (十九)hashlib模块

    hashlib模块用于加密相关的操作,3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法 注意:md5和sha25 ...

  8. Python开发【第十九篇】:Python操作MySQL

    本篇对于Python操作MySQL主要使用两种方式: 原生模块 pymsql ORM框架 SQLAchemy pymsql pymsql是Python中操作MySQL的模块,其使用方法和MySQLdb ...

  9. Python之路(第二十八篇) 面向对象进阶:类的装饰器、元类

    一.类的装饰器 类作为一个对象,也可以被装饰. 例子 def wrap(obj): print("装饰器-----") obj.x = 1 obj.y = 3 obj.z = 5 ...

随机推荐

  1. biopython

    转载Part 2  Biopython的重头戏-生物学中序列的处理 Biopyhton的Seq和Python中标准字符串有两大重要的不同之处:首先,他们的处理方法不同.Seq适用于很多不同字符串的用的 ...

  2. ssh架构之hibernate(三)关系映射

    1.单向多对一 1.映射文件配置 2.model: 测试 1.查询测试 执行顺序,先查询多方,在查询一方,一方采用延迟加载 注意:如果不使用一方的数据,就关闭session,报错,同延迟加载中的报错类 ...

  3. 用jQuery实现轮播图效果,js中的排他思想

    ---恢复内容开始--- jQuery实现轮播图不用单独加载. 思路: a. 通过$("#id名");选择需要的一类标签,获得一个伪数组 b.由于是伪数组的原因,而对数组的处理最多 ...

  4. Gamma Correction

    [Gamma Correction] 磁盘上存储的纹理可分为Linear Texture.Gamma Texture. sRGB sampling allows the Unity Editor to ...

  5. IDEA2017-破解方法

    @方法一 第一步:下载jar 包 地址:https://github.com/locationbai/registerIDEA_2017.3.2_jar 第二部:将下载好的jar放在idea安装目录下 ...

  6. 如何向 Windows 7 镜像中添加 USB3.0 驱动

    如何向 Windows 7 镜像中添加 USB3.0 驱动 1. Microsoft 在 Windows 7 的安装光盘并没有集成各个厂商的 USB3.0 驱动,可 以使用下面方法添加 USB3.0 ...

  7. 【linux C】C语言中常用的几个函数的总结【一】

    1.memset函数 定义变量时一定要进行初始化,尤其是数组和结构体这种占用内存大的数据结构.在使用数组的时候经常因为没有初始化而产生“烫烫烫烫烫烫”这样的野值,俗称“乱码”.每种类型的变量都有各自的 ...

  8. 高盛oa

    一道题根本不会,抄答案过了.一道自己写,莫名其妙出现了不会的bug.最后交了暴力解,过了5/7.估计要跪. 总结: 缺点:做过的不熟练.没做过的题不会.一个陌生的小bug也de不出来. 措施:多总结还 ...

  9. Day 07 文件的相关操作

    文件初始: 文件的三要素: path:文件的路径 mode:r w r+ w+ a encoding: 编码方式 # 打开一个文件的方法 f1 = open('e:\echo.txt', encodi ...

  10. MongoDB的增、删、改、查操作(五)

    按照我们关系型数据库的思想,一个服务器要想存放数据,首先要有数据库,表,字段,约束,当然了也少不了主键,外键,索引,关系等: 但是在MongoDB的世界里边,我们不用预先的去创建这些信息从而直接来使用 ...