哈希和加密
哈希函数
概念
哈希,英文叫做 hash。
哈希函数(hash function)可以把 任意长度的数据(字节串)计算出一个为固定长度的结果数据。
我们习惯把 要计算 的数据称之为 源数据, 计算后的结果数据称之为 哈希值(hash value)或者 摘要(digests)。
有好几种哈希函数,对应不同的算法, 常见有的 MD5, SHA1, SHA224, SHA256, SHA384, SHA512
哈希计算的特点是:
- 
相同的 源数据, 采用 相同的哈希算法, 计算出来的哈希值 一定相同 
- 
不管 源数据 有多大,相同的哈希算法,计算出来的哈希值长度 都是一样长的。 、 
| 算法 | 计算结果长度 | 
|---|---|
| MD5 | 16字节 | 
| SHA1 | 20字节 | 
| SHA224 | 28字节 | 
| SHA256 | 32字节 | 
| SHA384 | 48字节 | 
| SHA512 | 64字节 | 
- 算法不可逆。
也就是说,不能通过 哈希值 反过来计算出 源数据。 所以哈希和我们常说的加密解密不同。
- 不同的源数据 使用同样的哈希算法,可能会产生相同的 哈希值,这被称之为碰撞率(collision rate)
各种哈希算法,计算的结果长度越长,碰撞率越低,通常耗费的计算时长也越长。
即使是 MD5 算法, 碰撞率也 非常小,小到几乎可以忽略不计。大约是 1.47*10的负29次方
  
应用场景
那么哈希函数到底有什么用呢?
下面是典型的两个应用场景
校验拷贝下载文件
大家有过下载大文件吧? 比如下载 一部电影、Windows安装iso文件。
这些文件传输过程中,由于种种原因,可能会出现传输出错的。
有的数据文件,只有传错一点,整个文件都是不可用的。
怎么校验我 下载的文件是不是 毫无差错的呢?
一段一段 的再去和原来的 数据进行比对? 太慢 太麻烦了。
这时候,可以使用哈希算法。
下载的网站上,先提供 源文件的 的 哈希值, 下载完后,在我们的电脑上,把本地下载到的 文件也计算哈希值,如果两者相等,那么就可以认为 下载没有问题。
校验信息有效性
如果你经营一个学校,每年开学时,学生要到 管理部 交学费, 一个交完学费,工作人员给他们的手机上发一条信息  张三,学费已交 
张三带着这个手机信息到 教学部 领书, 教学部工作人员,看到手机上 有 张三,学费已交 就给他发书。
这个流程,有一个问题: 教学部的人 怎么知道 学生已交学费的短信 是不是自己伪造的?
一种解决方法,就是, 管理部和教学部 共享一个密钥,也就是一串字符串,比如 13ty8ffbs2v ,
管理部的人,收到费用,并且给学生发的 短信,除了 张三,学费已交 之外, 用哈希算法,对如下字符串进行哈希计算
这个字符串里面包含了密钥, 如果使用MD5算法,产生这样的哈希值 ccdcb2e80ee2cbf2520844498e4169b0
给学生发的短信不仅有 张三,学费已交 ,还要包括哈希值 ccdcb2e80ee2cbf2520844498e4169b0。
到了 教学部, 发书的老师,也使用 哈希算法,对如下字符串进行哈希计算
如果计算的结果 和学生提供的短信里面的哈希值一致,说明没有捏造信息。
注意,密钥 13ty8ffbs2v 只有 教学部 和管理部的老师知道,学生是不知道的。所以学生没有办法产生 管理部们才能制作出来的 哈希值。
  
Python语言计算哈希值
这个网站 提供了哈希值计算功能,大家可以快速得到一个数据的 哈希值。
那么我们怎么使用Python语言来创建哈希值呢?
使用 Python 内置库 hashlib 即可。
比如,我们要产生 MD5 哈希值,就这样写代码
import hashlib
# 使用 md5 算法
m = hashlib.md5()
# 要计算的源数据必须是字节串格式
# 字符串对象需要encode转化为字节串对象
m.update("张三,学费已交|13ty8ffbs2v".encode())
# 产生哈希值对应的bytes对象
resultBytes = m.digest()  
# 产生哈希值的十六进制表示
resultHex   = m.hexdigest()
print(resultHex)
结果为 ccdcb2e80ee2cbf2520844498e4169b0 ,这就是哈希字节串的十六进制表示。
如果你想使用别的哈希算法,比如, sha256 算法,只需要修改为对应的函数 sha256()即可
如下
其它都不用变。
是不是很简单 :)
关于 hashlib用法的其他细节,可以查看官方文档
加密解密
简介
加解密算法,是对源数据 进行运算产生加密数据,以及反向过程,对加密数据反算出 源数据。
加解密算法 和 hash算法 不同点有:
- 
加解密算法 是可逆的,hash算法是不可逆的。 
- 
hash算法可以对很大的数据产生比较小的哈希值,而加密算法源数据很大,加密后的数据也会很大 
加解密算法 可以分为  对称加密  以及  不对称加密 
对称加密 指  加密和解密 使用相同的  密钥 。
而 不对称加密 指 加密和解密 使用不同的 密钥,通常是一对密钥,称之为公钥(用来加密)和私钥(用来解密)。
比较常见的 对称加密算法有: AES, RC4, DES, 3DES, IDEA 等。
其中安全等级较高的是 AES。 关于加密算法安全性可以参考这篇文章
而最知名的 不对称加密系统 就是 RSA (Rivest–Shamir–Adleman) 。
Python语言加解密
计算哈希值, Python有内置的库。
但是,加解密的库,Python 没有内置的。我们需要安装使用第三方开发的库。
目前口碑比较好的Python加解密库有 cryptography 和 PyNaCl
这里,我们以使用比较广泛的 cryptography 为例(Paramiko就使用该库作为底层加解密计算),展示如何进行加解密。
首先,我们执行命令 pip install cryptography 安装该库。
Note
注意:由于Paramiko就使用该库作为底层加解密计算,如果你已经安装了Paramiko,cryptography库肯定已经安装好了。 就会显示 Requirement already satisfied
下面是一个使用 该库进行 AES 加解密运算的例子
from cryptography.fernet import Fernet
# 产生密钥, 密钥是加密解密必须的
key = Fernet.generate_key()
f = Fernet(key)
src = "白月黑羽网站学习Python真好啊"
# 源信息,必须是字节串对象
# 字符串对象需要encode一下
srcBytes = src.encode()
# 生成加密字节串
token = f.encrypt(srcBytes)
print(token)
# 解密,返回值是字节串对象
sb = f.decrypt(token)
print(sb.decode())