python 密码学示例——理解哈希(Hash)算法


Posted in Python onSeptember 21, 2020

Hash 是密码学安全性的基石,它引入了单向函数(one-way function)和指纹(fingerprint)的概念。即:

  • 对于任意输入,都可以产生相同的、唯一的输出值
  • 输出值中不包含输入值的任何线索

一、保密性(confidentiality)与完整性(integrity)

简单来说,信息的保密性确保除授权人员以外的任何人都无法读取该消息,信息的完整性则确保除授权人员以外的任何人都无法修改该消息。
很多时候一段加密的消息无法被他人读取和理解(保密性),并不意味着该密文不会在传播过程中被截取和恶意修改(完整性)。

信息摘要(message digest)或指纹(fingerprint)技术即用于验证信息的完整性。

信息摘要需满足的基本条件为:

  • 相同的文档永远会生成相同的摘要(能够作为身份线索)
  • 生成的摘要“感觉”是随机的,即摘要中不包含原始文档的任何信息(无法被破解)

信息摘要也被称作指纹,即可以代表某份文档“身份”的一小段数据,类似于人类的指纹。
每个人都可以通过指纹验证其身份,但该指纹并不包含其身体的所有信息。文档的指纹也是如此,可以很方便快速的通过文档内容计算得出一小段唯一的指纹数据作为其身份证明,但是只有指纹数据就几乎不可能得出原始文档的内容。

对于两份文档,只需要比对其信息摘要(指纹)是否一致,就可以确保其内容是否相同,在传播过程中是否被人恶意修改。同时该指纹信息也不会造成原始文档本内容的泄露。

二、MD5

MD5 是一种比较古老的哈希算法,其名字中的 MD 即代表 message digest。它可以从任意大小的文档计算出一个唯一的 16 字节长度的摘要数据。

PS:鉴于 MD5 较悠久的历史和不够长的摘要长度,不推荐在安全性很敏感的场景中使用该算法。

>>> from hashlib import md5
>>> md5(b'alice').hexdigest()
'6384e2b2184bcbf58eccf10ca7a6563c'
>>> md5(b'bob').hexdigest()
'9f9d51bc70ef21ca5c14f307980a29d8'
>>> md5(b'balice').hexdigest()
'6760742ebf884c998752b4e082b78224'
>>> md5(b'cob').hexdigest()
'386685f06beecb9f35db2e22da429ec9'
>>> md5(b'a').hexdigest()
'0cc175b9c0f1b6a831c399e269772661'
>>> md5(b'aa').hexdigest()
'4124bc0a9335c27f086f24ba207a4912'
>>> md5(b'aa' * 100000).hexdigest()
'561b1994f6baacd6e5eaf4baaa12849f'
>>> md5(b'alice').hexdigest()
'6384e2b2184bcbf58eccf10ca7a6563c'

从输出中可以看出,针对不同的输入内容(即便相似度很高,比如 bob 和 cob),摘要算法生成的输出是发散的,彼此之间没有相似性,像是随机生成的结果。
但是对于任意相同的输入,生成的摘要数据则都是确定的、唯一的。

三、哈希算法的规则

一般我们提到哈希算法,都会关联到密码学、安全性等场景中,实际上我们很早就接触了一种完全“非密码学”的哈希场景。比如小时候跟老师学习判断一个数是奇数还是偶数。。。
从本质上看,哈希函数的目的是将巨大(甚至无穷大)数量的事物映射到一个相对较小的数据集中。比如 MD5,不管输入的文档有多大,最终都会生成一个固定长度(16 字节)的十六进制数字作为指纹。
这就意味着 MD5 的输入集合,实际上是大于其输出集合的。即只要输入文档的集合足够大(很大很大),就有可能出现重复的指纹信息。

这和判断数字奇偶是相通的。不管某个数字有多大多奇特,我们永远可以将它“压缩”成奇数或偶数,用 1 bit 的 1 或 0 表示就可以。但是只说明某个未知数字是奇数(或偶数),我们就无法猜出该数字的准确值。

上面的逻辑验证了哈希函数共有的 3 个特性:

  • consistency(一致性):相同的输入只会生成相同的输出信息
  • compression(压缩):可以将体量很大的输入压缩成一个固定大小的输出
  • lossiness(有损的):只通过检查输出无法反向计算出输入值

但是对于一个满足密码学安全的哈希函数而言,除以上三点以外还需要具有如下属性:

  • Preimage resistance
  • Second-preimage resistance
  • Collision resistance

Preimage Resistance

哈希函数的 preimage 是指能够生成同一个特定指纹的所有输入的合集。即对于某个哈希函数 H 与摘要 k,所有能够生成 k 的输入值 x (满足 H(x) = k)共同组成了 H 与 k 的 preimage。

preimage resistance 的意义即为,在仅仅只是知晓某个摘要的前提下,通过有限的计算无法获取其 preimage 中的任何一个元素。即只通过结果无法知晓输入。
摘要中不包含原始文档的任何信息(lossiness),无法通过逆向运算的方式由摘要反推出原始输入。只能随机地尝试任意输入,以期碰巧得到同样的摘要信息(暴力破解)。

因此前面提到的奇偶函数就不能作为一个安全的哈希函数使用。假设使用奇偶作为哈希函数(奇数输出 1,偶数输出 0),则对于摘要 1,总可以很轻易的在 preimage(此处是全体奇数)中找到任意多个摘要同为 1 的元素。这意味着原始输入可以轻易被修改而不影响指纹数据,则该指纹作为信息完整性的验证条件就失去了意义。

但是对于较安全的哈希算法如 MD5,由 MD5(x) = ca8a0fb205782051bd49f02eae17c9ee 就无法在有限的计算内找到确定的 x 的值。
MD5 生成 16 字节(16 * 8 = 128bit)长度的摘要,其中可以包含 2^128 种不同的数字组合。因此使用暴力破解的话,最多需要尝试 2^128 = 340282366920938463463374607431768211456 次!
假设每秒钟可以尝试一百万条输入,仍需要 10^26 年完成所有验证操作!

Second-Preimage Resistance 与 Collision Resistance

second-primage resistance 是指即便知晓某个原始文档以及由该文档生成的摘要数据,仍很难计算可以出生成同样摘要的另一个不同的文档。
即在已知 MD5(alice) = 384e2b2184bcbf58eccf10ca7a6563c 的情况下,仍无法找出除 alice 以外的另一个输入生成同样的摘要。为了寻求可以替换掉 alice 的另一个值,同时不影响摘要认证,达到混淆的目的,最终仍需使用暴力破解的方式。

collision resistance 是指很难找出任意两个生成相同摘要(相同而非特定)的输入值。
可以参考“生日问题”,即在一个班级中,存在两个生日为同一天的学生的概率远比存在一个生日为特定日期的学生的概率大得多。

collision resistance 的意义在于,无法故意找出两套符合同一指纹的输入以达到混淆的目的。比如 MD5 算法:

>>> from hashlib import md5
>>> md5('bob').hexdigest()
'9f9d51bc70ef21ca5c14f307980a29d8'
>>> md5('cob').hexdigest()
'386685f06beecb9f35db2e22da429ec9'

对于很相似的输入 bob 和 cob,其指纹信息的差异却非常大,没有任何可供预测的规律。这得益于一种称为 avalanche property 的特性:输入的微小变化总可以在输出中产生巨大的无法预测的差异。

由前面提到的生日问题可知,找出两个生成相同指纹的元素远比找出某个可以生成特定指纹的元素要容易的多。以 MD5 算法的暴力破解为例,后者往往需要做 2^128 次尝试,而前者只需要 2^64 次尝试。
现实中 MD5 的 collision resistance 远非想象中那么优异,甚至存在一种非暴力破解的方式 能够在一小时以内攻破 MD5 的 collision resistance。
所以尽量不要使用 MD5 这个已经不再维护超过 10 年、安全漏洞存在 20 年的古老算法。

参考资料

Practical Cryptography in Python: Learning Correct Cryptography by Example

以上就是python密码学示例——理解哈希(Hash)算法的详细内容,更多关于python 哈希(Hash)算法的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
在Lighttpd服务器中运行Django应用的方法
Jul 22 Python
Python基础语法(Python基础知识点)
Feb 28 Python
详解python3实现的web端json通信协议
Dec 29 Python
解决python3 urllib中urlopen报错的问题
Mar 25 Python
Python 反转字符串(reverse)的方法小结
Feb 20 Python
python中yaml配置文件模块的使用详解
Apr 27 Python
Java文件与类动手动脑实例详解
Nov 10 Python
浅谈tensorflow中Dataset图片的批量读取及维度的操作详解
Jan 20 Python
已安装tensorflow-gpu,但keras无法使用GPU加速的解决
Feb 07 Python
Django基于客户端下载文件实现方法
Apr 21 Python
如何以Winsows Service方式运行JupyterLab
Aug 30 Python
Pycharm编辑器功能之代码折叠效果的实现代码
Oct 15 Python
python中的垃圾回收(GC)机制
Sep 21 #Python
如何在Python3中使用telnetlib模块连接网络设备
Sep 21 #Python
总结Pyinstaller的坑及终极解决方法(小结)
Sep 21 #Python
python生成xml时规定dtd实例方法
Sep 21 #Python
Python中的特殊方法以及应用详解
Sep 20 #Python
matplotlib 三维图表绘制方法简介
Sep 20 #Python
Python三维绘图之Matplotlib库的使用方法
Sep 20 #Python
You might like
php 获取select下拉列表框的值
2010/05/08 PHP
PHP时间戳与日期之间转换的实例介绍
2013/04/19 PHP
PHP输出缓存ob系列函数详解
2014/03/11 PHP
PHP根据两点间的经纬度计算距离
2014/10/31 PHP
CodeIgniter记录错误日志的方法全面总结
2016/05/17 PHP
yii2安装详细流程
2018/05/23 PHP
让GoogleCode的SVN下的HTML文件在FireFox下正常显示.
2009/05/25 Javascript
Js从头学起(基本数据类型和引用类型的参数传递详细分析)
2012/02/16 Javascript
javaScript(JS)替换节点实现思路介绍
2013/04/17 Javascript
jquery实现兼容IE8的异步上传文件
2015/06/15 Javascript
javascript正则表达式模糊匹配IP地址功能示例
2017/01/06 Javascript
详解Javascript百度地图接口开发文档中的类和方法
2017/02/07 Javascript
什么是Vue.js框架 为什么选择它?
2017/10/17 Javascript
js设置随机切换背景图片的简单实例
2017/11/12 Javascript
浅谈小程序 setData学问多
2019/02/20 Javascript
浅谈Javascript中的对象和继承
2019/04/19 Javascript
vue+eslint+vscode配置教程
2019/08/09 Javascript
layui 上传插件 带预览 非自动上传功能的实例(非常实用)
2019/09/23 Javascript
[42:20]Secret vs Liquid 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/17 DOTA
python友情链接检查方法
2015/07/08 Python
Python3中的列表,元组,字典,字符串相关知识小结
2017/11/10 Python
在Python中pandas.DataFrame重置索引名称的实例
2018/11/06 Python
Pandas操作CSV文件的读写实现方法
2019/11/13 Python
python selenium 执行完毕关闭chromedriver进程示例
2019/11/15 Python
关于ZeroMQ 三种模式python3实现方式
2019/12/23 Python
Python改变对象的字符串显示的方法
2020/08/01 Python
BIFFI美国站:意大利BIFFI BOUTIQUES豪华多品牌时装零售公司
2020/02/11 全球购物
面向对象编程是如何提高软件开发水平的
2014/05/06 面试题
社区学习雷锋活动总结
2014/04/25 职场文书
小组口号大全
2014/06/09 职场文书
2015年结对帮扶工作总结
2015/05/04 职场文书
关于环保的宣传稿
2015/07/23 职场文书
小学一年级班主任工作经验交流材料
2015/11/02 职场文书
js实现上传图片到服务器
2021/04/11 Javascript
如何开发一个渐进式Web应用程序PWA
2021/05/10 Javascript
简述Java中throw-throws异常抛出
2021/08/07 Java/Android