python标准库:hashlib模块

hashlib


Hash的定义

Hash,译做“散列”,也有直接音译为“哈希”的。把任意长度的输入,通过某种hash算法,变换成固定长度的输出,该输出就是散列值,也称摘要值。该算法就是哈希函数,也称摘要函数。

通过摘要函数对任意长度的数据计算出固定长度的摘要digest,目的是为了提供一个验证文件未被篡改的方法。摘要函数是一个单向函数,计算digest很容易,但通过digest反推原始数据却非常困难。而且,最关键的是,对原始数据做一个比特位的修改,都会导致计算出的摘要完全不同

所以hash通常情况下可以用来进行加密处理,比如说,当你注册一个账号密码如果不经过hash的处理那么如果数据库密码一旦被泄露就会导致所有人的密码被泄露,所以用户数据库中密码的存储应该为hash的值,当用户登录时,首先计算用户输入的明文口令的摘要值,然后和数据库存储的摘要值进行对比。如果两者一致,说明口令输入正确,如果不一致,口令肯定错误。这样,不但数据库不用储存明文密码,即使能访问数据库的管理员“叛变”了,盗走了整个数据库,也无法获知用户的明文口令。

但是即使如此也并不是完全安全的,懂技术的人会通过计算些简单的口令的摘要值比如‘123456’,‘abcdef’等,从而获得一个反推表。只需要对比数据库的密码摘要,就可以获得使用常用口令的用户账号。

所以为了避免这种情况的发生,我们通常会采用加盐的办法。

加盐:额外给原始数据添加一点自定义的数据,使得生成的消息摘要不同于普通方式计算的摘要。

s='hello'+'salt'
hash.update(s.encode())

比如我给密码字符串“password”加上字符串“salt”,这里的“salt”字符串就是所谓的盐,其摘要值必然不等于正常摘要“password”字符串的值。当然这个“salt”具体是什么,完全可以自定义,而且不能告诉他人!当然真正的加盐可比“salt”要复杂的多。经过加盐处理的密码口令,只要“salt”不被黑客知道,即使用户使用的是简单口令,也很难通过摘要对比的方式反推明文口令。问题又来了!那如果两个用户的密码正好一样,即使加了盐,生成的消息摘要也是一样的,也有被破解的风险,怎么办?

我们一般认为用户名是不能重复的,就像QQ号码是独一无二的一样。将用户名作为盐的一部分,就不会出现一样的密码消息摘要了。

hashlib模块

Python内置的hashlib模块为我们提供了多种安全方便的摘要方法,当前,在大部分操作系统下,hashlib模块支持md5(),sha1()sha224()sha256()sha384()sha512()blake2b()blake2s()sha3_224()sha3_256()sha3_384()sha3_512()shake_128()shake_256()等多种hash构造方法。这些构造方法在使用上通用,返回带有同样接口的hash对象,对算法的选择,差别只在于构造方法的选择。例如sha1()能创建一个SHA-1对象,sha256()能创建一个SHA-256对象。然后就可以使用通用的update()方法将bytes类型的数据添加到对象里,最后通过digest()或者hexdigest()方法获得当前的摘要。

import hashlib

hash = hashlib.md5()    #生成md5对象
#hash = hashlib.md5('hello'.encode('utf-8'))
hash.update('hello'.encode())
#获取结果
print(hash.hexdigest())         #返回摘要,获得16进制数据字符串值 (str类型)
print(hash.digest())             #获得二进制数据字符串值
5d41402abc4b2a76b9719d911017c592
b']A@*xbcK*vxb9qx9dx91x10x17xc5x92'

1. hashlib模块的两个常量属性:

hashlib.algorithms_guaranteed

所有平台中,模块支持的hash算法列表

hashlib.algorithms_available

当前Python解释器环境中,模块支持的hash算法列表

print(hashlib.algorithms_available)

>>>{'SHA256', 'dsaEncryption', 'whirlpool', 'SHA384', 'MD5', 'MD4', 'md5', 'ripemd160', 'sha512', 'DSA', 'SHA224', 'dsaWithSHA', 'SHA', 'sha224', 'DSA-SHA', 'sha', 'SHA1', 'ecdsa-with-SHA1', 'SHA512', 'sha384', 'sha256', 'RIPEMD160', 'md4', 'sha1'}
print(hashlib.algorithms_guaranteed)

>>>{'sha384', 'md5', 'sha512', 'sha256', 'sha224', 'sha1'}

2. hash对象的两个常量属性

hash.digest_size

hash结果的长度

hash.block_size

hash内部块的大小

3. hash对象的属性

hash.name

hash算法名称字符串

import hashlib

hash = hashlib.md5()    #生成md5对象
#hash = hashlib.md5('hello'.encode('utf-8'))
hash.update('hello'.encode())
#获取结果
print(hash.hexdigest())         #返回摘要,获得16进制数据字符串值 (str类型)
print(hash.digest())             #获得二进制数据字符串值
print(hash.digest_size)         #长度
print(hash.block_size)          #内部块的长度
print(hash.name)                #名字

4. hash对象的方法

hash.update(arg)

更新hash对象。连续的调用该方法相当于连续的追加更新。例如m.update(a); m.update(b)相当于m.update(a+b)。注意,当数据规模较大的时候,Python的GIL在此时会解锁,用于提高计算速度。

一定要理解update()的作用,由于消息摘要是只针对当前状态产生的,所以每一次update后,再次计算hexdigest()的值都会不一样。

hash.digest()

返回bytes格式的消息摘要

hash.hexdigest()

与digest方法类似,不过返回的是两倍长度的字符串对象,所有的字符都是十六进制的数字。通常用于邮件传输或非二进制环境中。通常我们比较摘要时,比较的就是这个值!

hash.copy()

返回一个hash对象的拷贝

原文地址:https://www.cnblogs.com/austinjoe/p/9650065.html