woaidongmao

文章均收录自他人博客,但不喜标题前加-[转贴],因其丑陋,见谅!~
随笔 - 1469, 文章 - 0, 评论 - 661, 引用 - 0
数据加载中……

数据校验杂谈——CRC,MD5和SHA-1原理、实现及其破解

  数据校验是计算机发展至今的至关重要的部分。但是它一般作为底层、后台或者内置模块出现,因而即使对于多数成天在计算机网络里飘荡的人来也说并不十分了解。前段时间由于特殊原因深入学习了一下MD5,后面接着学习了SHA-1和CRC32,我发觉网络上的资料并不多,尤其是中文的资料大概就那么两三个版本。小奀在这里根据我的学习体会整体的浅谈(扫盲级/入门初级)一下这几种在目前主要使用的数据校验算法,不当之处请高人指正。
当前最常用的三个数据校验算法CRC、MD5和SHA-1当中,强度(这个强度是相对于被破解的困难程度来说的)以CRC最弱,而SHA-1最强。其实三个算法的原理和实现都很简单(CRC优化的算法可能比较费解),下面依次讲起,并对各算法的当前破解情况进行了介绍,在相应之处列有比较详细的参考文档。

CRC
CRC是什么?CRC的全称是Cyclic Redundancy Checksum,即“循环冗余校验码”。简单的说它是一种利用二进制的多项式除法来取得数据的校验和的方法。
CRC有什么用?目前主要使用在哪些地方?一如其名,CRC对数据的处理结果是取得一个校验码,在数据传输的前后分别计算一次,然后进行比较就可以发现是否有错误发生。打一个不是很恰当的比方,你乘车前检查了一下钱包,里面有N张RMB,下车的时候你再检查一次,如果不是N张RMB的话你就会应该意识到出问题了(不过这种情况下一般是会减少吧),但如果还是N张RMB的时候是否能保证没有出问题了呢——很不幸,不一定,有可能被人家换了几张小额的给你,或者换了假币给你,这就类似于后边要讲到的“CRC碰撞”。CRC广泛应用于以太网的数据包检查,PNG,以及我们常用的压缩软件(PKZIP, Zlib,WinRAR……)等。
CRC原理是什么?原理其实非常简单,就是二进制的多项式除法。在后面的参考文档里有不厌其烦的描述,当需要更详细的讲解时建议你参考这些列出的文档。在这里我只简单的说说我在学习过程中觉得比较重要的几点:
1.这个二进制除法的没有优化的伪代码大概可以这样写(设除数有P个bits):
{
任命余数r = 被除数的前(P-1)位;
while(被除数还有剩余bit没有补入到r中)
{
补入一个bit到r中;
r = 补位后的r作为被除数 除以 除数 所得的余数;
}
哈哈,这回完了吧。就是你了,拿起小r就可以跑了;
}
看看吧,是不是觉得很熟悉?的确,跟我们年轻时学过的一模一样。
2.二进制的多项式除法这个东东跟我们小学学过的普通的十进制运算没有多大差别,简单的来说就是不考虑进位退位就可以了,记住这个很重要。那么不够减的时候怎么办呢?直接把本来是0的位看作2就可以了。
3.二进制的多项式除法运算中,对于有T个bit位的被除数除以有P个bit位的除数,应该除多少次才能得到余数呢?如果除数的高位为1时,应该做(T +1-P)次运算(如果T+1<P,那么为0次)。有的人可能会反驳说CRC的实作代码中是(T-P)次,其实问题在于那里使用的除数是把最高位去掉了的。
4.关于除数多项式Poly(以下简称Poly)。我曾经看过一篇中文文档中说,“不要问我为什么Poly的最高位和最低位都是 1,因为这是规定”。规定当然是规定,但是做出这种规定也应当是有原因的吧?根据我的个人理解(当然,也许这是错误的理解),首先最高位必须为1,这个 bit位在英文文档中称为"Active" bit,为什么呢?如果Poly最高位不是1那么除法无法进行下去而得到有我们所需要的位数的余数(当Poly最高位为0而被除数高位为1时无法抵消)。而低位为什么也必须为1呢?在有的使用场合是把CRC的Poly和被除数都做了反射之后再进行的,这种情况下低位反射成了高位,基于前面同样的理由,所以必须保持最低位也为1。
5.关于查表算法,查表法的主要目的是提高运算速度。下面以最常用的CRC32为例。查表法的方案也不同,最长采用的是按照字节(8位)生成码表。这里对应前面所述的最原始的除法方案进行讲述,即没有反射,并把字节中的高位作为被除数的高位。
对于喜欢证明结论的人,或者可以按照如下的思路进行:
在进行除法的过程中,当寄存器移出一个字节的时候,最终对余数的影响相当于其后的四个字节异或上某一个值(设这个值为y),设移出值为x时对应的y为f (x),那么这个f映射是一个双射,这很容易证明。因为这个映射是一系列异或操作的叠加,而异或运算满足交换律和结合律。那么当y后面的四个字节全为0 时,可以推出余数值为:r = y^0 = f(x)^0 = f(x)。利用这个关系,对每个x值算出对应的r,并记录在以x值为下标的数组中,就得到了f映射在x定义域上的所有值。而这个数组就是查表法所使用的码表。
显然,这个f映射是提高效率的关键,它相当于有“预见性”的进行一个字节的除法运算。当然也很容易想到可以有其他位数的查表算法,比如16位、32位等。而且如果你了解了以上的算法,你应该可以想到两点(以16位为例):前面256个元素和8位的应该完全一致;16位的码表可以通过类似的按照位进行运算的方法得到,同样也可以对8位的已经运算出的码表进行运算得到,把一个字节看成一个“位”就行。
CRC的碰撞是什么东东?怎么产生的?CRC“碰撞”实际上是不同的源数据可能对应同一个CRC值的冲突现象。根据前面的讨论,可以把CRC看成一个从无限定义域映射到2的 32次方空间的一个单向函数,很明显这个映射是“多对一”的。这种现象类似于中国目前的男女比率失调状况,根据某甲某乙们预计的结果,到2020年,中国会有几千万的男光棍出现——为啥乜?其实简单的说就是供映射的目标空间不够大,在这种情况下如果保证每个人都不做光棍的话,那么除了从外国(当然也可以是外星球)大力引进适龄女子外,就只能多男共事一妻了^_^(各位兄弟们,你今天汗了吗?)。
CRC被破解了么?是的。实际上要从CRC结果逆向找回数据源几乎是不可行的,因为这是个一对多的映射,因此所谓的“破解”一般指找到一个产生相同CRC结果的数据,但无法判断这个找到的数据和源数据的异同(除非有上下文等信息)。CRC是一个相对简单的数据校验算法,从理论上我们得知只要提供比映射的目标空间的值的个数(CRC32是2的32次方个)更多的互不相同的源数据时,就一定会出现CRC碰撞。实际上破解CRC是有规可循的,看雪论坛上有一篇文章做了理论推导并提供了程序下载,有兴趣的请参考后面列出的参考文档。

CRC 参考文档
1. CRC圣经(注:这是我所找到的一份最全的英文文档,很多其他的英文文档以及几乎目前的所有中文文档都是这份文档的衍生品,我称其为“CRC圣经”实在是一点都不为过)
2. CSDN文章(这是CSDN上选自http://blog.csdn.net/chensheng913/ 的文章,基本上是CRC圣经的节选翻译+读书笔记)
3. 老罗的缤纷天地:原理篇+实践篇(注:老罗其实没有老,文章非常好:-),这里另外还有汇编代码)
4. RFC3309 中的讲述
5. PNG中用到的CRC的实作代码
6. Koders上的实作代码(注:在此MHASH模块中包含了CRC和本文中另外所提到的MD5和SHA-1,非常值得一看)
7. 看雪论坛上的破解文章

源地址未知。

posted on 2008-07-08 12:08 肥仔 阅读(3150) 评论(0)  编辑 收藏 引用 所属分类: C++ 基础


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理