Python中hash加密

目录

简介

概念

散列算法(Hash Algorithm),又称哈希算法,杂凑算法,是一种从任意文件中创造小的数字「指纹」的方法。与指纹一样,散列算法就是一种以较短的信息来保证文件唯一性的标志,这种标志与文件的每一个字节都相关,而且难以找到逆向规律。因此,当原有文件发生改变时,其标志值也会发生改变,从而告诉文件使用者当前的文件已经不是你所需求的文件

Hash简单点讲就是把任意一段数据经过某种算法生成一段唯一的固定长度的数据

也可以把哈希值当做是文件指纹,因为它是文件唯一性的标志,与每一个字节都有关,当文件发生改变是,指纹值也会改变

  1. 如果把hash算法比喻为一座工厂

  2. 那传给hash算法的内容就是原材料

  3. 生成的hash值就是生产出的产品

特点

  • 正向快速:给定明文和 Hash 算法,在有限时间和有限资源内能计算得到 Hash 值
    • 只要传入的内容一样,得到的hash值必然一样
  • 逆向困难:给定 Hash 值,在有限时间内很难逆推出明文
  • 输入敏感:原始输入信息发生任何变化,新的 Hash 值都应该出现很大变化
  • 冲突避免:很难找到两段内容不同的明文,使得它们的 Hash 值一致
  • 长度固定:只要我们使用是hash算法固定,无论传入的内容有多大,得到的hash值的长度是固定
  • 信息摘要:hash只是信息的摘要,信息指纹,是用来做数据识别的

hash有哪些

常见 Hash 算法有 MD5 和 SHA 系列,目前 MD5 和 SHA1 已经被破解,一般推荐至少使用 SHA2-256 算法

哈希算法 输出长度(bit) 输出长度(字节)
MD5 128 bit 16 bytes
RipeMD160 160 bits 20 bytes
SHA-1 160 bits 20 bytes
SHA-256 256 bits 32 bytes
SHA-512 512 bits 64 bytes

算法碰撞

稍微想一下就可以发现,既然输入数据长度不固定,而输出的哈希值却是固定长度的,这意味着哈希值是一个有限集合,而输入数据则可以是无穷多个,那么建立一对一关系明显是不现实的。所以“碰撞”是必然会发生的,所以一个成熟的哈希算法会有较好的抗冲突性,同时在实现哈希表的结构时也要考虑到哈希冲突的问题

  • 比如“666”经过 Hash 后是“fae0b27c451c728867a567e8c1bb4e53”,相同 Hash 算法得到的值是一样的。比如 WiFi 密码如果是 8 位纯数字的话,顶多就是 99999999 种可能性,破解这个密码需要做的就是提前生成好 0 到 1 亿数字的 Hash 值,然后做 1 亿次布尔运算(就是 Bool 值判断,0 或者 1),而现在普通 I5 四核 CPU 每秒能到达 200 亿次浮点数计算,做 1 亿次布尔运算也就是秒级别的时间就破解了

  • 8位大小写字母、数字、特殊符号组成的密码,若按照MD5加密,则hash值大概10000千亿,i9算力每秒1千亿。也需要至少24h。这只是极端情况下,如果加上加密算法不确定(比如3),请求时间(比如3),查询时间(比如3),这就已经需要半年左右,倘若再加上错误等待时间(比如输入5次错误等待24小时),那就已经需要50年。。。
    当然,如果有三万台电脑同时破解,也还是一天 -_-|||。
    不过道高一尺,魔高一丈。谁又会傻乎乎的一个站着打一个等着挨。都是相对的

所以密码尽量不要用纯数字,因为根本没有任何安全性

加盐防碰撞

对数字内容进行 Hash 运算,获取唯一的摘要值来指代原始完整的数字内容,利用 Hash 函数的抗碰撞性来确保内容未被篡改

常用于用户名和密码来确保用户信息安全,为了防止攻击会采用加盐的方法,就是原来的明文加上一个随机数之后的 Hash 值,Hash 值和盐会保存在两个地方,只要不是同时泄漏就很难被破解

加密

如果在Python中需要对用户输入的密码或者其他内容进行加密,首选的方法是生成hash值

在Python中可以利用二个模块来进行:

  • crypt
  • hashlib

hashlib

主要方法

使用:hashlib.md5()

名称 描述
md5(…) 利用md5算法加密
sha1(…) 利用sha1算法加密
sha224(…) 利用sha224算法加密
sha256(…) 利用sha256算法加密
sha384(…) 利用sha384算法加密
sha512(…) 利用sha512算法加密

特有方法

如果你利用hashlib生成了一个Hash对象,那么这个Hash对象会包含如下方法

名称 描述
update(arg) 可以重复利用指定了特殊加密算法的Hash对象,对arg进行加密
digest(…) 以字符形式返回加密内容
hexdigest(…) 以16进制形式返回加密内容
copy(…) 为了达到重复利用Hash对象的目的,而克隆Hash对象

使用方法

  1. 直接使用hashlib方法

    import hashlib
    
    hashlib.sha224("Nobody inspects the spammish repetition".encode("utf-8"))  # 加密
    hashlib.sha224("Nobody inspects the spammish repetition".encode("utf-8")).hexdigest()  # 返回加密内容
    
  2. 直接使用Hash对象中的方法

    import hashlib
    
    # 造出工厂
    m = hashlib.md5()
    # 放入原料
    m.update("Nobody inspects".encode('utf-8'))
    # 产出hash值
    m.digest()
    
    m.update("the spammish repetition".encode("utf-8"))
    m.digest()
    m.hexdigest()
    

加盐

import hashlib

# 造出工厂
m = hashlib.md5("this is salt".encode("utf-8"))
# 放入原料
m.update("Nobody inspects".encode('utf-8'))
# 产出hash值
m.digest()

m.update("the spammish repetition".encode("utf-8"))
m.digest()
m.hexdigest()

crypt

主要方法

名称 类型 描述
crypt(…) 方法 对指定内容进行hash加密
mksalt(…) 方法 根据加密算法生成salt
methods list 返回可用加密算法的列表
MOTHOD_CRYPT 常量 加密算法
METHOD_MD5 常量 md5加密算法
METHOD_SHA256 常量 sha256加密算法
METHOD_SHA512 常量 sha512加密算法

使用说明

使用crypt.crypt(…)进行hash加密的时候,需要提供二个参数:

  • 加密内容
  • salt
import crypt

salt = crypt.mksalt(crypt.METHOD_SHA512)
hash = crypt.crypt("helloworld",salt)

应用

密码加密

m=hashlib.md5()

m.update('key'.encode('utf-8'))      #添加个其他元素,提升密码复杂度,不是加盐
m.update(password.encode('utf-8'))
print(m.hexdigest()) 

应用一致性校验

m = hashlib.md5()
with open(r'E:\01.mp4','rb') as f:
    for line in f:  
        m.update(line)
        
print(m.hexdigest)
上一篇:HashMap简介及部分源码分析


下一篇:面试官:HashMap实现原理是什么?HashMap是线程安全的吗?