文章目录:
- 1 hashlib介绍
- 2 hashlib模块使用
-
- 2.1 查看hashlib中有哪些hash算法
- 2.2 加密字符串
- 2.3 数据比较大,加密可以分块,结果一样
- 2.4 hashlib的高级用法
- 2.5 验证文件的一致性
- 3 hmac加密模块,在hashlib类似
- 4 破解用户密码
1 hashlib介绍
1、Hash,译做“散列”
,也有直接音译“哈希”
的。把输入任意长度
,通过某种hash算法
,变换成输出固定长度
,该输出就是散列值
,也称摘要值
。该算法是哈希函数
,也称摘要函数
。
2、hash函数的主要目的是加密字符串
,比如:我们注册的用户名和密码,都是明文(就是我们自己能看的明白的)需要先通过hash加密,然后生成一串固定长度的字符串(所以我们甚至看不到),并将其存储在数据库中。下次登录时,我们只需要在数据中比较相应的字符串hash即使,即使数据中有值,hash值数据泄露,也不知道我们的用户名和密码,所以hash值得这样的特点:
- 每次生成相同的字符串hash值也一样
- hash值是不可逆转的,也就是说,我们知道hash其对应的明文也不可能反解值!
2 hashlib模块使用
下面使用的hexdigest()
: 生成的哈希值数字签名,hex
表示是十六进制
,digest
表示生成hash的数字签名
2.1 查看hashlib中有哪些hash算法
在hashlib模块中,sha1()、sha224()、sha256()、sha384()、sha512()和blake2b()、blake2s()方法总是存在的。md5安全性不是很高!
1、查看hashlib下支持的hash算法有哪些
hashlib.algorithms_available
:返回hash算法名的集合
注:相同的hash不同的名字(大小写)可能会出现在函数算法中很多次
>>> import hashlib >>> alg_set1 = hashlib.algorithms_available >>> alg_set1 {
'md4', 'sha3_512', 'sha512_224', 'ripemd160', 'sha512', 'md5-sha1', 'sha3_224', 'blake2s', 'md5', 'sha256', 'blake2b', 'mdc2', 'sha384', 'sha1', 'shake_128', 'sha512_256', 'sha3_384', 'sm3', 'sha224', 'shake_256', 'whirlpool', 'sha3_256'} >>> len(alg_set1) 22 >>> alg_set2 = hashlib.algorithms_guaranteed >>> alg_set2 {
'sha3_512', 'sha3_224', 'blake2s', 'md5', 'shake_128', 'sha256', 'sha224', 'sha384', 'sha1', 'shake_256', 'sha512', 'sha3_256', 'blake2b', 'sha3_384'}
>>> len(alg_set2)
14
>>> alg_12 = alg_set1 & alg_set2
>>> alg_12
{
'sha3_512', 'sha3_224', 'blake2s', 'md5', 'sha256', 'sha224', 'sha384', 'sha1', 'shake_256', 'sha512', 'shake_128', 'blake2b', 'sha3_384', 'sha3_256'}
>>> len(alg_12)
14
hashlib.algorithms_guaranteed
:返回hash算法名的集合,返回的集合是hashlib.algorithms_available
返回集合的子集!
2.2 对字符串进行加密
1、对字符串使用md5进行加密
注意需要先对加密的字符串进行编码转换,否则会报错:TypeError: Unicode-objects must be encoded before hashing
,如下,三种转换写法都可以:
- md5.update(‘hello’.encode(‘utf-8’))
- md5.update(b’hello’)
- md5.update(bytes(‘hello’, encoding=‘utf-8’)) # 使用bytes转换为二进制
import hashlib
def str_encryption_md5():
password_str = 'Tom888'
md5 = hashlib.md5()
# md5.update(password_str) # TypeError: Unicode-objects must be encoded before hashing
md5.update(password_str.encode('utf-8')) # 注意转码
# md5.update(bytes(password_str, encoding='utf-8'))
# md5.update(b'Tom888')
print(md5.digest_size) # 16 # 生成hash结果大小,单位字节
print(md5.block_size) # 64 # hash算法的内部快大小,单位字节
res = md5.hexdigest()
# 字符串 Tom888(明文)被加密成一串 32位长的字符串
print('md5加密结果:', res, len(res)) # md5加密结果: 5a2b7072fbe5c1216be444fe30d965e8 32
if __name__ == '__main__':
str_encryption_md5()
2、对字符串使用sha1进行加密
import hashlib
def str_encryption_sha1():
password_str = 'Tom888'
sha1 = hashlib.md5()
sha1.update(password_str.encode('utf-8')) # 注意转码
print(md5.digest_size) # 16 # 生成hash结果大小,单位字节
print(md5.block_size) # 64 # hash算法的内部快大小,单位字节
res = sha1.hexdigest()
# 字符串 Tom888(明文)被加密成一串 32位长的字符串
print('sha1加密结果:', res, len(res)) # sha1加密结果: 5a2b7072fbe5c1216be444fe30d965e8 32
if __name__ == '__main__':
str_encryption_sha1()
3、其他更多加密算法测试
- 可以看出,不同的加密算法,生成的字符串的长度可能不一样!
import hashlib
def str_encryption_all_alg():
password_str = 'Tom888'
all_hash_algorithms = {
'sha3_512': hashlib.sha3_512,
'sha3_224': hashlib.sha3_224,
'blake2s': hashlib.blake2s,
'md5': hashlib.md5,
'shake_128': hashlib.shake_128,
'sha256': hashlib.sha256,
'sha224': hashlib.sha224,
'sha384': hashlib.sha384,
'sha1': hashlib.sha1,
'shake_256': hashlib.shake_256,
'sha512': hashlib.sha512,
'sha3_256': hashlib.sha3_256,
'blake2b': hashlib.blake2b,
'sha3_384': hashlib.sha3_384}
for hash_alg in all_hash_algorithms.keys():
print(f'Start hash algorithm: {hash_alg}')
alg = all_hash_algorithms[hash_alg]()
alg.update(password_str.encode('utf-8'))
try:
res = alg.hexdigest()
print(f'{hash_alg}加密结果:', len(res), res)
except TypeError as e:
pass
''' Start hash algorithm: sha3_512 sha3_512加密结果: 128 0a4ce5b6e85b206d220b1c25059070e171c7635d2357bb7fe7ac65fcb054cecb1f6bbceda7bd70701ef48a24a4c25e5ac45cecb4e169efb24f8d72d302926bbf Start hash algorithm: sha3_224 sha3_224加密结果: 56 9b13e0708c8577ce37bb8fefa714a38a3e0e57286b501ee3db813e71 Start hash algorithm: blake2s blake2s加密结果: 64 e572b36c0f9c61878fb296883a29df73e567df275d33c6f7a7b78b9950a9798b Start hash algorithm: md5 md5加密结果: 32 5a2b7072fbe5c1216be444fe30d965e8 Start hash algorithm: shake_128 Start hash algorithm: sha256 sha256加密结果: 64 04d016992b2c6d1163861542705bf725d951e83afc5360cc3c97510e2ccc070b Start hash algorithm: sha224 sha224加密结果: 56 3be1b04e03d47a39a14955fd6628d3ebc29cc3e638224254607a4458 Start hash algorithm: sha384 sha384加密结果: 96 37940a0bac0de66d5ce44fbde401d5ff6639ab0f24b9a3b80400be5a369df663454b4e2cc224d6e2958bc3d34955b7a5 Start hash algorithm: sha1 sha1加密结果: 40 54f3d519f107922e616a336118a1e8e89ec9d25e Start hash algorithm: shake_256 Start hash algorithm: sha512 sha512加密结果: 128 0806221d502cd98bc9e592668371bcc8a4dc125af262c1aeaf2676bb9ec32776ea8e54cf6a42a76e78b9170d069cb3a5d05e002378a86044a1e9343b644135de Start hash algorithm: sha3_256 sha3_256加密结果: 64 714c04befcc26385f0ad39bad838af74a7d8a2376e46d11a7f9e20b889ce4bba Start hash algorithm: blake2b blake2b加密结果: 128 a0daffc1dd95b7d44bb5883053abcee11ab1f25efe61f098f4fe70ae30330b197ccb1bef0c110cb4ba09637a684f9f1538f24b1483a9213f4c3ac7a2b8886df6 Start hash algorithm: sha3_384 sha3_384加密结果: 96 5aad1c17d3e9b1020436a2070bab048f4857e258034eafebac4fe0ea7647eba62d07dc5c58b9e651284ea47c83cfca0c '''
if __name__ == '__main__':
str_encryption_all_alg()
2.3 对于数据比较大,加密可以分块,结果一样
如果数据量很大,可以分块多次调用update(),最后计算的结果是一样的:
如下,把一个长字符串分开进行hash,最终得到的hash值的结果是一样的!
import hashlib
def str_encryption_sha256():
sha256 = hashlib.sha256()
sha256.update('how to use sha256 in python hashlib?'.encode('utf-8'))
print(sha256.hexdigest()) # de6cdf7a7e6a68182ce0dba30671e7d81df8208866c8160a77dfc61f9ef89706
sha256_2 = hashlib.sha256()
sha256_2.update('how to use sha256 in '.encode('utf-8'))
sha256_2.update('python hashlib?'.encode('utf-8'))
print(sha256_2.hexdigest()) # de6cdf7a7e6a68182ce0dba30671e7d81df8208866c8160a77dfc61f9ef89706
if __name__ == '__main__':
str_encryption_sha256()
2.4 hashlib的高级用法
高级用法,就是为了防止撞库反解。所以,有必要对加密算法中添加自定义key
再来做加密。
- 就是在
hashlib.md5(b'key')
其实就是把自己要加密的字符串和这个key拼接在一起,然后再生成一个加密后的字符串 - 从下面加密的结果可以证实!
def str_encryption_self():
# 普通加埋
md5 = hashlib.md5()
md5.update('alex88888'.encode('utf-8'))
res = md5.hexdigest()
print('普通加密结果:', res) # 普通加密结果: 8c26a75d12ea2a730654679d2061b953
# 高级加密:自己定义一个key参数
md5 = hashlib.md5(b'super_encryption')
md5.update('alex88888'.encode('utf-8'))
res = md5.hexdigest()
print('高级加密结果:', res) # 高级加密结果: 5649795aaa6aaf64deaab659b0a0c63f
md5 = hashlib.md5()
md5.update('super_encryption'.encode('utf-8'))
md5.update('alex88888'.encode('utf-8'))
res = md5.hexdigest()
print('加密结果:', res) # 加密结果: 5649795aaa6aaf64deaab659b0a0c63f
if __name__ == '__main__':
str_encryption_self()
2.5 校验文件的一致性
1、校验文件的一致性(如何保证下载的文件过程中不丢包,保证下载数据的完整性)(参考)
# -----------文件一致校验----------------
'''可以拷贝一个文件放在两个不同的盘中,然后通过判断两个文件的hash值是否相等,判断两个文件是否是同一个文件'''
import hashlib
m = hashlib.md5()
with open(r'G:/logging模块配图.png','rb') as f:
for line in f:
m.update(line)
print(m.hexdigest()) #47a6b079cc33a4f312786b46e61e0305
import hashlib
m = hashlib.md5()
with open(r'H:/logging模块配图.png','rb') as f:
for line in f:
m.update(line)
print(m.hexdigest())
3 hmac模块的加密方式,于hashlib类似
python 还有一个 hmac 模块,它内部对我们创建 key 和 内容 进行进一步的处理然后再加密
import hmac
def str_encryption_hmac():
# key值就是加的salt
h = hmac.new(key='天王盖地虎'.encode('utf8'), digestmod='md5') # new里面的参数key就是salt
h.update('alex88888'.encode('utf-8'))
print(h.hexdigest()) # 3414e379c15069a81b1e8ca0012fc59d
if __name__ == '__main__':
str_encryption_hmac()
4 破解用户密码
我们说即使拿到hash的值,就是一串固定的长度的字符串,我们是不能够反解出其对应的明文的
,但有没有方法能够获取都明文呢,当前有的,那就是撞库
,撞库的原理:
- 先生成很多常用的字符串
- 然后根据hash算法,生成这些字符串对应的hash值
- 构建一个{hash值:字符串,…}的字典(/数据库)
- 然后就可以去库中找是否有对应的hash值,这样就可以取出对应的明文了!
import hashlib
def break_passward(in_hash_value):
passwds=[ #可以通过random实现对passwds中的内容
'alex3714',
'alex1313',
'alex94139413',
'alex123456',
'123456alex',
'a123lex',
]
hash_passwd_dict = {
}
for passwd in passwds:
md5 = hashlib.md5()
md5.update(passwd.encode('utf-8'))
hash_passwd_dict[md5.hexdigest()] = passwd
print(hash_passwd_dict)
''' {'aee949757a2e698417463d47acac93df': 'alex3714', '5dd873761a1ac42d2afbca152ec1e772': 'alex1313', '5e3c46d350ac2780222040b0ed62aa7c': 'alex94139413', '94e4ccf5e2749b0bfe0428603738c0f9': 'alex123456', 'd5a3f30371e61ecfb519acfd5f709630': '123456alex', '601b259d02dac6d75686a0b08a00b755': 'a123lex'} '''
if in_hash_value in hash_passwd_dict.keys():
decode_value = hash_passwd_dict[in_hash_value]
print('撞库成功')
print('哈希值:{} 对应明文是:{}'.format(in_hash_value, decode_value))
else:
print('撞库失败!')
if __name__ == '__main__':
break_passward('601b259d02dac6d75686a0b08a00b755')
# 撞库成功
# 哈希值:601b259d02dac6d75686a0b08a00b755 对应明文是:a123lex
break_passward('601b259d02dac6d75686a0b08a00b777')
# 撞库失败!
参考:https://www.cnblogs.com/alex3714/articles/5161349.html 参考:https://www.liaoxuefeng.com/wiki/1016959663602400/1017686752491744 参考:https://www.cnblogs.com/pycode/p/hashlib.html 参考:https://zhuanlan.zhihu.com/p/52651497 参考:https://docs.python.org/3/library/hashlib.html