哈希(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)。正因为这些特性,hash算法经常被用来保存密码,这样既不会泄露密码明文,又可以校验输入的密码是否正确。常用的hash算法有MD5、SHA1等。
破解Hash的任务就是给出一个q,反推出一个p来满足q=H(p)。通常我们能想到两个办法,一种就是暴力破解法,把每个p都算下H(p),知道结果等于q;另一种是查表法,搞一个很大的数据库,把每个p和对应的q都记录下来,按q做一下索引,查下表就行。理论上两种办法都行,但是实际操作上,前一种需要海量时间,后一种需要海量空间,以至于人类资源无法实现
彩虹表的根本原理就是组合暴力法和查表法,并在这两者一种取得一个折中。
它的做法是,对于一个Q=H(P),建立另一个算法R使得P=R(Q),然后对于一个p,这样进行计算:
p0 - H - > q1 - R -> p1 ... - H - > qn - R -> pn
简单的说,就是q用H、R依次迭代运算,最后得到pn,n可能比较大。最后我们把p0和pn都存储下来,其他的结果都丢弃。然后用不同的p0代入计算,得到多个这样的p的对子
破解的时候,给出一个q,我们来寻找p,先把q做一次R运算得到一个值c1,假如和某一个pn相等,那么就可能这个pn对应的p(n-1)就是我们寻找的p,为了验证我们把pn对应的p0再做一次链式计算,比对qn是否就是给出的q,如果是,很明显p(n-1)就是我们在追寻的p,如果不是就继续遍历所有的p0pn对
如果还没有,我们再算q - R -> c1 - H -> qx - R -> c2,再对比c2是否是pn如果是,那么p(n-2)就可能是p,依次类推
总的来说,就是用一个p0pn对来存储一个链子的数据,如果n很大,就可以大大减小存储空间。这样带来的问题是必须做n次对比,事件更长,不过我们不需要瞬间破解,等待几秒乃至几天破解一个密码都是可以接受的
当然这只是最粗浅的原理,仔细想还有很多问题,比如R的选择,Hash冲突的处理,如何选择po来实现足够的覆盖,如何在有限资源下生成彩虹表等。感兴趣的可以看看RainbowCrack的源码http://www.project-rainbowcrack.com/