笔记——》彩虹表的算法原理

背景

最近在做一个md5撞库比对的功能,本来想用穷举法暴力撞库的,但遭遇瓶颈。情况是这样的:

数据库表中有3个字段,id,mobile,md5_mobile。要存40亿数据算了下 大概需要接近1TB的数据库容量,以及 30天的入库时间。时间和空间都不允许,怎么办。看了下网上说的彩虹表算法来破解md5,了解下来有了一点自己的理解。

预计算的哈希链

了解彩虹表前先了解 一个概念:预计算的哈希链

预计算的哈希链 涉及以下这几个定义

  • H函数:hash函数:用于将明文转为密文(加密函数)
  • R函数:自定义逆hash函数:用于将密文转为明文

R函数

R函数可以是一个自定义的伪逆hash函数。什么意思?

假设明文是:bixie,密文是 hicxvhiniojjghg

就是R函数是一个我们自定义的函数,用于将密文转为明文,比如将 hicxvhiniojjghg这个密文转为一个明文 hic。

哈希链

在此处我把R函数自定义为 截取字符串前3位(类似substring函数)

此时我们通过一个 明文 bixie 经过【三轮】 H函数 和 R函数 得到了一个值 vbj

timeline 初始值 : bixie H1函数 : hicxvhiniojjghg R1函数 : hic H2函数 : loiasdhuibqwebx R2函数 : loi H3函数 : vbjyuqwwejomihbn R3函数 : vbj

上图就是一个hash链,经过3轮(同时把3轮中的这个3定义为K) H、R 函数的计算,在hash链的末尾可以看到,我们得到了一个vbj的值。

我们把这个链的首尾值(bixie、vbj)先存到表中,并记下这个 轮数 K=3。

预计算

情况1:末位匹配

假设我们现在需要破解一个密文:vbjyuqwwejomihbn

我们先在程序中用R函数得出一个结果:vbj,然后去表中根据尾值查询,刚好能查到 bixie->vbj 这个键值对,说明密文大概率处于 bixie->vbj 这条链上。

那我们从bixie这个字符开始重新生成 hash链,可以在 RK 这个位置查到密文,Rk-1这个位置查到明文,破解成功,明文是 loi。

情况2:末位不匹配

假设我们现在需要破解一个密文:loiasdhuibqwebx

我们先在程序中用R函数得出一个结果:loi,然后去表中根据尾值查询,此时是查不到数据的。

但结合上面的hash链,在上帝视角,我们可以看到 loi确实是处于 bixie->vbj 这条链上的,并且是在R2的位置。

但当局者迷,程序本身是不知道这个信息的,那我们需要帮助它,让它从loi转为vbj,然后再去表中根据尾值查询。

此时我们对loi 再进行一轮 H函数和R函数的运算,就得到了 vbj,这个时候就能在表中找到这个bixie这个初始参数了,找到之后根据首位值重新生成 hash链 可以在R1的位置找到明文了。

------------------------------------------------------分割线---------------------------------------------------------

假设我们现在需要破解一个密文:hicxvhiniojjghg(此时密文处于H1的位置)

我们先在程序中用R函数得出一个结果:hic,然后去表中根据尾值查询,此时是查不到数据的。

此时我们对hic进行一轮 H函数和R函数的运算,就得到了 loi,但loi还是不能匹配,那么就再对loi 进行一次 H、R函数,即 对对hic进行两轮 H函数和R函数的运算,就得到了 vbj

然后重复上面的生成操作,就能找到明文是初始值 bixie。

分析1:R函数的次数

在上面的两种情况中,可以看到密文都破解成功了,但是情况2中有一个点是要引起注意的,即如果末位不匹配,到底需要计算多少轮呢,总不能一直循环下去吧。

结合上面的例子,其实很容易发现,我们的 hash链 bixie->vbj是经历了3轮H、R函数的运算 的。那么即使密文处于第一个位置,即 H1,那么它最多也只需要 3轮计算就能得出 尾值 vbj。

如果计算超过3轮计算的值依旧匹配不上这条hash链的尾值,说明明文就不在这条链上,那么就该放弃这条链去匹配其他的hash链了,此时做超过3轮的计算已经没有意义了。

所以说 密文进行 H、 R函数最多就是三轮,即上文记下的 K=3(K=3)。换言之,链长为K,最多进行K次H、R函数计算,就可以匹配到尾值从而找到链进行比对。

进行的K次H、R函数计算的过程,就是我理解的预计算的概念(预先计算好尾值,再去匹配)

分析2:时空的平衡

在很多有关彩虹表的说明中,都说 与彩虹表算法是时空平衡的算法, 与之对应的两个极端是穷举法字典法

此时我们有一个密文 AAA,想要通过撞库得到一个明文

  1. 穷举法:先生成n个明文,遍历所有明文,每一次遍历得到一个密文,将密文与AAA进行对比,一致则把明文返回出来。此法需要耗费极长的时间,才能获取到明文,
  2. 字典法:将穷举法遍历的所有明文和与之对应的密文全都存到表中。这样查询的 时候就不需要再穷举了,可以根据密文快速检索出明文。此法需要占用极大的存储空间,才能将所有的明文和密文都存下来

预计算的哈希链:在上文中我们提到,链长为K,最多进行K次R函数,就可以匹配到尾值,那如果K=1呢,K=1的时候,初始值就只进行了一次 H、R运算。首值与尾值 是一对一的,那么数据库中需要存的链 就跟字典法要存的链一样多了

那么就可以得到一个结论:

  1. 当链长越长,所需要计算 R函数的次数就越多,耗时越长,数据库中存的链越少,所占存储就越少
  2. 当链长越短,所需要计算 R函数的次数就越少,耗时越少,数据库中存的链越多,所占存储就越多
  3. 一条链有K个H函数的结果,那么这条链上 能破解的密文个数等于K

只要找到一个合适的链长 K 值,那么时间和空间的 占用就可以达到一个折中平衡,时空互补的状态。

预计算的哈希链的缺点

上面的算法我称之为 哈希链的预计算 算法,此算法有不足。

就是 H函数每次生成的值是加密后的,但是R函数是我自定义的逆加密函数,用来生成跟明文同格式的字符。

这就产生了一个问题,当一个链足够长的时候,R函数有极大概率生成 重复的值,甚至生成初始值。如下

第一条链

timeline 初始值 : aaa H1函数 : bbb111 R1函数 : bbb H2函数 : ccc222 R2函数 : ccc H3函数 : ddd333 R3函数 : ddd H4函数 : ccc444 R4函数 : ccc

第二条链

timeline 初始值 : eee H1函数 : fff555 R1函数 : fff H2函数 : ggg666 R2函数 : ggg H3函数 : aaa777 R3函数 : aaa H3函数 : bbb111 R3函数 : bbb

通过上面的两条链,可以很明显的看出来

  1. 第二条链包含了第一条链的部分节点,如上,假如密文是 bbb111,那么第一、二两条链都可以破解这个密文,这样就形成了冗余
  2. 一条链原本能破解K个密文,但出现了重复,那么单条链能破解的个数可能就远小于K个
  3. 由于只保存链条的首末节点,那么重复链条并不能被迅速地发现,也不能迅速的修正

彩虹表

说了那么多预计算hash链的事儿,那么彩虹表是什么呢。

彩虹表的破解原理就是基于hash链的预计算,只不过是对上文的R函数进行了优化。

上文的R函数是一个我自定义的伪函数,在每一轮循环中,这个伪函数都是相同的,做一个相同的操作。

引用不知道从哪看到的一段话:

在构造哈希链的时候,一个优秀的函数R功不可没。首先R需要能将值域限定在固定的范围------例如给定的长度范围、给定的字符取值范围等等------之内,否则的话,哈希链中大量的计算结果并不在可接受的取值范围内,一条链条无法对应多个明文,链条就失去了意义;其次R必须同哈希函数一样,尽量保证输出值在值域中的均匀分布,减少碰撞的概率

定义

彩虹表的优秀就在于对R函数的改造:

每一轮的循环(循环 指 重复进行 H、R函数计算)中,R函数是不同的。有K个循环,就有 从R1 、R2直到 RK个 一共K个不同的R函数

那么彩虹表为什么叫彩虹表就可以理解了,在一条类似彩虹的链条上,每一个节点上的R函数都不同,像七彩斑斓的色彩一样分布,所以称之为彩虹表。

改进的R函数

彩虹表改进的R函数,可以达到以下效果:

第一条链(链1)

timeline 初始值 : eee H1函数 : fff111 R1函数 : fff H2函数 : ggg222 R2函数 : ggg H3函数 : hhh333 R3函数 : hhh

第二条链(链2)

timeline 初始值 : iii H1函数 : iii111 R1函数 : ggg H2函数 : hhh333 R2函数 : kkk H3函数 : mmm333 R3函数 : nnn

第三条链(链3:丢弃)

timeline 初始值 : ooo H1函数 : ooo111 R1函数 : ppp H2函数 : ppp222 R2函数 : ggg H3函数 : hhh333 R3函数 : hhh

在上图的三条链中:

链2的 R1、H2位置分布着跟 链1的 R2、H3位置相同的值,但由于 链2的R2跟 链1的R3是不同的函数,链2 R2的值是 kkk ,链1 R3的值是 hhh,所以后续位置的值是不会重复的。

链3的 R2、H3的值和链1的 R2、H3的值相同,R函数出现的位置也相同,这是极端情况。那么 链3 这条链就会被丢弃掉。

总结来说,彩虹表算法可以改进这几个地方

  1. 同一条hash链上 不会生成重复值
  2. 不同的hash链上 不同节点生成重复值后,由于R函数的不同生成新值,不会一直重复
  3. 不同的hash链上 相同节点生成重复值后,由于R函数相同生成重复的值,那么这条链会被丢弃掉

使用

网上有很多使用的教程,本篇只探究原理,使用就不细说了,普遍是 下载别人生成好的 彩虹表,并下载 彩虹表计算软件或源码,输入 密文,运算得到明文。

彩虹表的不足

彩虹表无法破解加盐的 hash值。

在上述的例子中,从 预计算的hash链 到彩虹表,改变的只是 R函数。

如果用户加盐了呢,那么针对每一个用户 ,H函数 得出来的结果都是不同,我们想要破解,需要针对每一个加盐用户生成 不同的 H 值。

换言之,每多一个用户,就要多生成 一个彩虹表,这是不现实的。由此也可以受到启发,当我们需要做加密时,加盐可以有效防止密码被撞库破解。

特此记录,以备后用...

相关推荐
Chrikk9 分钟前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*12 分钟前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue12 分钟前
go语言连续监控事件并回调处理
开发语言·后端·golang
杜杜的man15 分钟前
【go从零单排】go语言中的指针
开发语言·后端·golang
好奇龙猫1 小时前
【学习AI-相关路程-mnist手写数字分类-win-硬件:windows-自我学习AI-实验步骤-全连接神经网络(BPnetwork)-操作流程(3) 】
人工智能·算法
sp_fyf_20241 小时前
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-11-01
人工智能·深度学习·神经网络·算法·机器学习·语言模型·数据挖掘
香菜大丸2 小时前
链表的归并排序
数据结构·算法·链表
jrrz08282 小时前
LeetCode 热题100(七)【链表】(1)
数据结构·c++·算法·leetcode·链表
oliveira-time2 小时前
golang学习2
算法
customer082 小时前
【开源免费】基于SpringBoot+Vue.JS周边产品销售网站(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·java-ee·开源