彩虹表
1.彩虹表产生背景
起初黑客们通过字典穷举的方法进行破解,这对简单的密码和简单的密码系统是可行的,但对于复杂的密码和密码系统,则会产生无穷大的字典。
哈希加密算法是不可逆的,也就是说无论是网站的数据库管理员还是获取了密码数据的黑客,能看到的只是一长串毫无意义的字符,不可能将它还原成真正的密码。可以解决此问题的办法有两个,一是穷举法,二是对照表法。
第一种方法需要大量的计算,因此破解速度非常慢,以14位字母和数字的组合密码为例,共有1.24×10^25种可能,即使电脑每秒钟能进行10亿次运算,也需要4亿年才能破解。举个简单的例子就是,现在给你一把锁,你要用一块铁片,不断地磨成钥匙的形状,显然这是非常耗费时间的;
第二种方法需要海量的磁盘空间来储存数据,仍以14位字母和数字的组合密码为例,生成的密码32位哈希串的对照表将占用5.7×10^14 TB的存储空间。如何增加密码长度或添加符号,需要的时间或磁盘空间将更加难以想象。这个方法对应上面的例子就是,给你一把锁,你现在带了所有可能的钥匙来开锁,显然你会根据钥匙孔的形状,很快找到钥匙,但是携带这么多钥匙,是比较费空间的。
显然这两种方法是难以让人满意的,彩虹表是对这两种方法的折中,也就是时间复杂度和空间复杂度都不会达到那种无法满足的程度。
2.彩虹表实现原理
介绍彩虹表的原理之前,先简单说一下哈希加密算法。哈希(Hash)算法就是单向散列算法,它把某个较大的集合P映射到另一个较小的集合Q中,假如这个算法叫H,那么就有Q = H(P)。对于P中任何一个值p都有唯一确定的q与之对应,但是一个q可以对应多个p。作为一个有用的Hash算法,H还应该满足:H(p)速度比较快; 给出一个q,很难算出一个p满足q = H(p);给出一个p1,很难算出一个不等于p1的p2使得 H(p1)=H(p2)。
彩虹表的根本原理就是组合了暴力法和查表法,并在这两者之中取得一个折中,用我们可以承受的时间和存储空间进行破解。它的做法是,对于一个Q = H(P),建立另一个算法R使得 P = R(Q),然后对于一个p,这样进行计算:
p0 -H-> q1 -R->p1 -H-> q2 -R->p2 -H-> q3 -R->p3 … -H-> q(n-1) -R->p(n-1) -H-> qn -R->pn
简单的说,就是把q用H、R依次迭代运算,最后得到pn,n可能比较大。最后我们把p0和pn都存储下来,把其他的结果都丢弃。然后用不同的p0代入计算,得到多个这样的p的对子。
彩虹表对应于上面钥匙与锁的例子就是,给你一把锁,你现在带了很多个钥匙串,每个钥匙串上面只有一两把钥匙。如果发现钥匙孔与其中某一个钥匙串上的钥匙形状类似,然后便用这把钥匙去磨出与钥匙孔类似的钥匙。(也就是方法一与方法二的组合)
3.链碰撞问题与解决办法
但是在实际实现的过程中,会经常出现不同的哈希链出现相同结果的情况,这就是发生了“碰撞”,也就是“链碰撞”。比如下面的例子:
解决链碰撞问题,办法是采用R函数列(一系列的R函数,而不是一个)
使用了R函数列之后,就算在运算过程中,两条不同的链产生了相同的中间结果,但是由于所处的阶段不同,那么下一阶段使用的R函数肯定不同,这就避免了后面产生相同结果的情况发生。如果把每条这样的哈希链,用不同的颜色标识,这就产生了彩虹表。(这也就是彩虹表名称的由来)
4.彩虹表的获取
1)常见的彩虹表:http://project-rainbowcrack.com/table.htm
2)R函数举例:假设明文为5位数字,则R函数是取哈希值中前5个数字。参见https://crypto.stackexchange.com/questions/5900/example-rainbow-table-generation
彩虹表可以自己生成,也可以自己在网上直接下载,常用的彩虹表大小在120G左右。
5.具体算法
①假设要破解的密文位于某一链条的k-1位置处,对其进行Rk运算,看是否能够在末节点中找到对应的值。
②如果找到,则可以如前所述,使用起节点验证其正确性。
③否则,继续假设密文位于k-2位置处,这时就需要进行Rk-1、H、Rk两步运算,然后在末节点中查找结果。
④反复②③,最不利条件下需要将密文进行完整的R1、H、…Rk运算后,才能得知密文是否存在于彩虹表之中。
6.防御彩虹表
由4中的表格可以得知,利用彩虹表进行密码破解,有着惊人的效率。那么,针对彩虹表的攻击,如何防御呢?
一个比较成熟并且简单的方法是“加盐”,即在密码特定位置插入特定字符串,这个特定字符串就是“盐”。为什么这种方法可以防御住彩虹表的攻击的?因为彩虹表在生成的过程中,针对的是特定的函数H,H如果发生了改变,则已有的彩虹表数据就完全无法使用。如果每个用户都用一个不同的盐值,那么每个用户的H函数都不同,则必须要为每个用户都生成一个不同的彩虹表,这大大提高了破解难度。这就相当于自己花很小的代价(插入字符串),但是攻击者却需要花费巨大的代价(重新生成彩虹表),这是比较好的一种方法。