目录
一、数据加密概述
1. 网络数据传输面临的威胁
网络安全涉及很多方面,而网络数据的安全传输通常会面临以下几方面的威胁:
- 数据窃听与机密性: 即怎样保证数据不会因为被截获或窃听而暴露。
- 数据篡改与完整性: 即怎样保证数据不会被恶意篡改。
- 身份冒充与身份验证: 即怎样保证数据交互双方的身份没有被冒充。
2. 相应的解决方案
针对以上几个问题,可以用以下几种数据加密方式来解决(每种数据加密方式又有多种不同的算法实现):
数据加密方式 | 描述 | 主要解决的问题 | 常用算法 |
---|---|---|---|
对称加密 | 指数据加密和解密使用相同的密钥 | 数据的机密性 | DES, AES |
非对称加密 | 也叫公钥加密,指数据加密和解密使用不同的密钥--密钥对儿 | 身份验证 | DSA,RSA |
单向加密 | 指只能加密数据,而不能解密数据 | 数据的完整性 | MD5,SHA系列算法 |
需要说明的是,上面SHA系列算法是根据生成的密文的长度而命名的各种算法名称,如SHA1(160bits)、SHA224、SHA256、SHA384等。我们常听说的MD5算法生成的密文长度为128bits。
关于上面提到的这些内容,大家可以参考《网络数据传输安全及SSH与HTTPS工作原理》这篇博文来了解更多的信息。本文主要讨论的问题是,我们如何使用Python来实现这些数据加密方式。
二、Python中实现数据加密的模块简介
Python中的大部分功能都是通过模块提供的,因此我们主要是通过Python中提供的一些内置的模块或外部模块来实现上面提到的各种加密算法。使用过程也很简单,只需要调用这些模块提供的相应的函数接口即可。
1. Python内置的加密模块演化过程
上面我们已经提到过,单向加密算法有:MD5、SHA系列算法 和 HMAC,而到目前为止Python内置的用于实现数据加密的模块也主要是提供单向加密功能,并且这些模块随着Python版本的迭代也经历了一些调整和整合:
- Python2.5之前的版本所提供的加密模块有:md5、sha和hmac
- Python2.5开始把对md5和sha算法的实现整合到一个新的模块:hashlib;
- Python3.x开始去掉了md5和sha模块,仅剩下hashlib和hmac模块;
- Python3.6增加了一个新的可以产生用于密钥管理的安全随机数的模块:secrets。
md5模块和sha模块为什么会被整合到一个hashlib模块中呢? 因为md5模块提供的是MD5算法的实现,sha模块提供的是SHA1算法的实现,而MD5和SHA1都是hash算法,具体解释看下面的名词解释。
2. 相关名词解释
-
HASH: 一般翻译为“散列”(也有直接音译为“哈希”),就是把任意长度的输入(又叫做预映射,pre-image),通过散列算法,变成固定长度的输出,该输出值就是散列值。这种转换是一种压缩映射,也就是散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一确认输入值。简单来说,hash算法就是一种将任意长度的消息压缩为某一固定长度的消息摘要的函数。
-
MD5: 全称为 Message Digest algorithm 5,即信息摘要算法。该算法可以生成定长的数据指纹,被广泛应用于加密和解密技术,常用于文件和数据的完整性校验。
-
SHA: 全称为 Secure Hash Algorithm,即安全散列算法/安全哈希算法。该算法是数字签名等密码学应用中的重要工具,被广泛应用于电子商务等信息安全领域。根据生成的密文的长度而命名的各种具体的算法有:SHA1(160bits)、SHA224(224bits)、SHA256(256bits)、SHA384(384bits)等。
-
HMAC: 全称为 Hash Message Authentication Code,即散列消息鉴别码。HMAC是基于密钥的哈希算法认证协议,主要是利用哈希算法(如MD5, SHA1),以一个密钥和一个消息作为输入,生成一个消息摘要作为输出,因此其具体的算法名称为HMAC-MD5、HMAC-SHA1等。可见HMAC算法是基于各种哈希算法的,只是它在运算过程中还可以使用一个密钥来增强安全性。
3. 本文要讲解的Python内置模块简介
Python早期的相关模块这里不再介绍了,我们今天主要说明的是以下几个模块:
模块名 | 内置模块 | 描述 |
---|---|---|
hashlib | Y | 主要提供了一些常见的单向加密算法(如MD5,SHA等),每种算法都提供了与其同名的函数实现。 |
hmac | Y | 提供了hmac(散列消息鉴别码)算法的实现,hamc也是单向加密算法,但是它支持设置一个额外的密钥(通常被称为'salt')来提高安全性 |
random | Y | 该模块主要用于一些随机操作,如获取一个随机数,从一个可迭代对象中随机获取指定个数的元素。 |
secrets | Y | 这是Python 3.6中新增的模块,用于获取安全随机数。 |
base64 | Y | 该模块主要用于二进制数据与可打印ASCII字符之间的转换操作,它提供了基于Base16, Base32, 和Base64算法以及实际标准Ascii85和Base85的编码和解码函数。 |
pycrypto | N | 支持单向加密、对称加密和公钥加密以及随机数操作,这是个第三方模块,需要额外安装。 |
说明: random模块严格上来讲并不能被称为数据加密模块,且官方文档中也强调过该模块不应该用于数据加密。但是我们在进行数据加密时,还是会常常用到随机数的操作,所以这里就顺便对这个模块进行下说明。
三、hashlib与hmac模块介绍
hashlib和hmac都是python内置的加密模块,它们都提供实现了单向加密算法的api。
1. hashlib模块
hashlib模块简介:
hashlib模块为不同的安全哈希/安全散列(Secure Hash Algorithm)和 信息摘要算法(Message Digest Algorithm)实现了一个公共的、通用的接口,也可以说是一个统一的入口。因为hashlib模块不仅仅是整合了md5和sha模块的功能,还提供了对更多中算法的函数实现,如:MD5,SHA1,SHA224,SHA256,SHA384和SHA512。
提示: “安全哈希/安全散列” 与 “信息摘要” 这两个术语是可以等价互换的。比较老的算法被称为消息摘要,而现代属于都是安全哈希/安全散列。
hashlib模块包含的函数与属性:
函数名/属性名 | 描述 |
---|---|
hashlib.new(name[, data]) | 这是一个通用的哈希对象构造函数,用于构造指定的哈希算法所对应的哈希对象。其中name参数用于指定哈希算法名称,如'md5', 'sha1',不区分大小写;data是一个可选参数,表示初始数据。 |
hashlib.哈希算法名称() | 这是一个hashlib.new()的替换方式,可以直接通过具体的哈希算法名称对应的函数来获取哈希对象,如 hashlib.md5(),hashlib.sha1()等。 |
hashlib.algorithms_guaranteed | Python 3.2新增的属性,它的值是一个该模块在所有平台都会支持的哈希算法的名称集合:set(['sha1', 'sha224', 'sha384', 'sha256', 'sha512', 'md5']) |
hashlib.algorithms_available | Python 3.2新增的属性,它的值是是一个当前运行的Python解释器中可用的哈希算法的名称集合,algorithms_guaranteed将永远是它的子集。 |
hash对象包含的方法与属性:
函数名/属性名 | 描述 |
---|---|
hash.update(data) | 更新哈希对象所要计算的数据,多次调用为累加效果,如m.update(a); m.update(b)等价于m.update(a+b) |
hash.digest() | 返回传递给update()函数的所有数据的摘要信息--二进制格式的字符串 |
hash.hexdigest() | 返回传递给update()函数的所有数据的摘要信息--十六进制格式的字符串 |
hash.copy() | 返回该哈希对象的一个copy("clone"),这个函数可以用来有效的计算共享一个公共初始子串的数据的摘要信息。 |
hash.digest_size | hash结果的字节大小,即hash.digest()方法返回结果的字符串长度。这个属性的值对于一个哈希对象来说是固定的,md5:16,sha1(20), sha224(28) |
hash.block_size | hash算法内部块的字节大小 |
hash.name | 当前hash对象对应的哈希算法的标准名称--小写形式,可以直接传递给hashlib.new()函数来创建另外一个同类型的哈希对象。 |
hashlib模块使用步骤:
-
1)获取一个哈希算法对应的哈希对象(比如名称为hash): 可以通过
hashlib.new(哈希算法名称, 初始出入信息)
函数,来获取这个哈希对象,如hashlib.new('MD5', 'Hello'),hashlib.new('SHA1', 'Hello')等;也可以通过hashlib.哈希算法名称()
来获取这个哈希对象,如hashlib.md5(), hashlib.sha1()等。 -
2)设置/追加输入信息: 调用已得到哈希对象的
update(输入信息)
方法可以设置或追加输入信息,多次调用该方法,等价于把每次传递的参数凭借后进行作为一个参数垫底给update()方法。也就是说&