哈希与加密解密
一、哈希函数
1、概念
哈希,英文叫做hash
哈希函数(hash function)可以把任意长度的数据(字符串)计算出一个固定长度的结果数据。
我们习惯把要计算的数据称之为源数据,计算后的数据结果称之为哈希值(hash value)
有好几种常用哈希函数,对应不同的算法,常见的有MD5,SHA1,SHA224,SHA384,SHA512
2、特点
- 相同的源数据,采用相同的哈希算法,计算出来的哈希值一定相同
- 不管源数据有多大,相同的哈希算法,计算出来的哈希值长度都是一样长的
算法 | 哈希值长度 |
---|---|
MD5 | 16字节 |
SHA1 | 20字节 |
SHA224 | 28字节 |
SHA256 | 32字节 |
SHA384 | 48字节 |
SHA512 | 64字节 |
-
算法不可逆
也就是说,不能通过哈希值反过来计算出源数据。所以哈希和我们常说的加密解密不同
-
不同的源数据 使用同样的哈希算法,可能会产生相同的 哈希值,这被称之为碰撞率(collision rate)
各种哈希算法,计算的结果长度越长,碰撞率越低,通常耗费的计算时长也越长。
即使是 MD5 算法, 碰撞率也 非常小,小到几乎可以忽略不计。大约是 1.47*10的负29次方
3、应用场景
那哈希函数到底有什么用呢?
-
校验下载文件
相信大家都在网上下载过数据量较大的文件,比如高达几十G的游戏,电影,Gho镜像文件等等。
这些文件,在传输过程中,是有可能出错的;而一旦出错,整个文件就不可用。怎么快速的校验我下载的文件是不是对的呢?这时候,就可以使用哈希算法
在下载的网站上,会提供源文件的哈希值,下载完后,在我们的电脑上,把哈希值计算出来,进行比对,如果两者相等,那么久可以认为下载没有问题。
-
校验信息的有效性
如果你经营一个学校,每年开学时,学生要到 管理部 交学费, 一个交完学费,工作人员给他们的手机上发一条信息
张三,学费已交
张三带着这个手机信息到 教学部 领书, 教学部工作人员,看到手机上 有
张三,学费已交
就给他发书。这个流程,有一个问题: 教学部的人 怎么知道 学生已交学费的短信 是不是自己伪造的?
一种解决方法,就是, 管理部和教学部 共享一个密钥,也就是一串字符串,比如
13ty8ffbs2v
,管理部的人,收到费用,并且给学生发的 短信,除了
张三,学费已交
之外, 用哈希算法,对如下字符串进行哈希计算张三,学费已交|13ty8ffbs2v
这个字符串里面包含了密钥, 如果使用MD5算法,产生这样的哈希值
ccdcb2e80ee2cbf2520844498e4169b0
给学生发的短信不仅有
张三,学费已交
,还要包括哈希值ccdcb2e80ee2cbf2520844498e4169b0
。到了 教学部, 发书的老师,也使用 哈希算法,对如下字符串进行哈希计算
张三,学费已交|13ty8ffbs2v
如果计算的结果 和学生提供的短信里面的哈希值一致,说明没有捏造信息。
注意,密钥 13ty8ffbs2v 只有 教学部 和管理部的老师知道,学生是不知道的。所以学生没有办法产生 管理部们才能制作出来的 哈希值。
二、Python计算哈希值
1、hashlib
那么我们怎么使用python来创建哈希值呢?
使用Python内置库hashlib即可
import hashlib
# 使用 md5 算法
m = hashlib.md5()
# 要计算的源数据必须是字节串格式
# 字符串对象需要encode转化为字节串对象
m.update("张三,学费已交|13ty8ffbs2v".encode())
# 产生哈希值对应的bytes对象
resultBytes = m.digest()
# 产生哈希值的十六进制表示
resultHex = m.hexdigest()
print(resultHex)
结果为 ccdcb2e80ee2cbf2520844498e4169b0
,这就是哈希字节串的十六进制表示。
如果你想用别的哈希算法,比如,sha256算法,只需要修改对应的函数sha256()即可
如下
import hashlib
m = hashlib.sha256()
2、盐(salt)
在上一节,我们已经使用了md5算法对一串字符串进行哈希值的运算。但现在有个问题,不考虑哈希碰撞的情况,我们可以理解为每一串字符串都有唯一对应的哈希值。那么就会产生下面的情况:
比如我的密码是qwe123456
,对其进行md5加密后的哈希值是2569d419bfea999ff13fd1f7f4498b89
而在经过穷举的方法,可以将大多数简单的明文密文直接查询出来,如www.cmd5.com
这样,我们可以采用一种加盐的方法,进一步加强我们的算法,如下
import hashlib
# md5()里的参数"125hash241"就是我们所加的盐
m = hashlib.md5(b'125hash241')
m.update('qwe123456'.encode())
resultBytes = m.digest() # 摘要
resultHex = m.hexdigest()
print(resultHex) # 十六进制哈希值:ebb1f8065437f033661b6613033da7f4
这样,就很难再被穷举破解了。使用这种方法,盐一定不能被泄露出去~~
三、加密与解密
加解密算法,是对源数据进行运算产生加密数据,以及反向过程,对加密数据反算出源数据。
加解密算法和hash算法不同点有:
- 加解密算法是可逆的,hash算法是不可逆的
- hash算法可以对很大的数据产生比较小的哈希值,而加密算法源数据很大,加密后的数据也会很大
加解密算法可以分为对称加密
和非对称加密
1、对称加密
常见的对称加密算法有:AES,RC4,DES,3DES,IDEA等。
其中安全等级较高的是AES
cryptography
是python的一个加密库
from cryptography.fernet import Fernet
# 产生密钥, 密钥是加密解密必须的
key = Fernet.generate_key()
f = Fernet(key)
src = "明天晚上6点组织进攻"
# 源信息,必须是字节串对象
# 字符串对象需要encode一下
srcBytes = src.encode()
# 生成加密字节串
token = f.encrypt(srcBytes)
print(token)
# 解密,返回值是字节串对象
sb = f.decrypt(token)
print(sb.decode())
2、非对称加密
最知名的非对称加密系统就是RSA(Rivest–Shamir–Adleman)
早期的加密方法(1976年前),所有加密方法都是对称加密,这种加密模式有一个最大弱点,甲方和乙方都必须知道具体的加密规则,否则无法解密。
1977年,三位数学家Rivest、Shamir 和 Adleman 设计了一种算法,可以实现非对称加密。这种算法用他们三个人的名字命名,叫做RSA算法。从那时直到现在,RSA算法一直是最广为使用的"非对称加密算法"。毫不夸张地说,只要有计算机网络的地方,就有RSA算法。
这种算法非常可靠,密钥越长,它就越难破解。根据已经披露的文献,目前被破解的最长RSA密钥是768个二进制位。也就是说,长度超过768位的密钥,还无法破解(至少没人公开宣布)。因此可以认为,1024位的RSA密钥基本安全,2048位的密钥极其安全。
步骤 | 说明 | 描述 | 备注 |
---|---|---|---|
1 | 找出质数 | P、Q | - |
2 | 计算公共模数 | N = P * Q | - |
3 | 欧拉函数 | φ(N) = (P-1)(Q-1) | - |
4 | 计算公钥E | 1 < E < φ(N) | E的取值必须是整数 E 和 φ(N) 必须是互质数 |
5 | 计算私钥D | E * D % φ(N) = 1 | - |
6 | 加密 | C = M E mod N | C:密文 M:明文 |
7 | 解密 | M =C D mod N | C:密文 M:明文 |
具体的算法原理推荐两篇文章: