一、MD5加密算法的原理分析
md5的输入是512位的倍数,输出是128位,首先填充消息,使其长度为与448 mod 512同余,即长度是512的倍数减去64,填充的消息第一位是1,后面全部都是0,即使原来的消息长度刚好与448 mod 512同余(64),仍然需要填充,即使原来的消息长度刚好是512的整数倍,仍需要填充。
再将这剩余的64位填充为原来消息的长度(二进制),如果原来的消息长度大于64位,则只填充低64位,之后的序列长度就是512的倍数了,这里每一个512位称为一个分组,又将每一个512分为16个32位,称为一个子分组(M0-M15),之后进行4轮运算,每一轮进行16次操作,分别针对这16个子分组。
原消息有几个分组就进行几次循环,循环这4轮运算,每一次循环需要一个128位序列当“种子”(A=0x67452301;B=0xefcdab89;C=0x98badcfe;D=0x10325476,很明显是小端序存储),之后输出一个128位的序列,这个序列与下一分组继续作用产生下一次的128位的输出。
下面说说具体的每次循环的4轮运算是怎么样的:
这4轮运算需要用到一个常数表T[i] (i = 1-64),等于4294967296*abs(sin(i))所得结果的整数部分,其中i用弧度表示,这样做是为了通过正弦函数和幂函数来进一步消除变换中的线性,这也是不可逆的一个原因。
下面利用这个常数表进行运算:
首先将我们的初始输入ABCD存起来:
1 | INPUT_A = A |
用到的函数:F(X,Y,Z) =(X&Y)|((~X)&Z),很明显这又是一个不可逆向的操作,下面进行运算:
循环左移:7,12,17,22,每4个为1组,一共16个数,所以进行4组
第一轮:
1 | A = B+((A+F(B,C,D)+M[0]+T[1])<<<7) |
这里进行了移位操作和迭代操作,也是不可逆的,后面的道理是一样的。
第二轮:用到的移位是5,9,14,20,间隔为递增的4,5,6
用到的函数:G(X,Y,Z) =(X&Z)|(Y&(~Z))
1 | A = B+((A+G(B,C,D)+M[1]+T[17])<<<5) |
第三轮:
用到的函数:H(X,Y,Z) =X^Y^Z
移位规则为7,5,7
1 | A = B+((A+H(B,C,D)+M[5]+T[33])<<<4) |
第四轮:移位规则为4,5,6
用到的函数:I(X,Y,Z)=Y^(X|(~Z))
1 | A = B+((A+I(B,C,D)+M[0]+T[49])<<<6) |
至此,一个512位分组,分为M[16],每个是32位,然后种子为A,B,C,D,常数表是T[64],一共4大轮,每一个大轮进行了16次不同的操作,得到最新的A,B,C,D,然后我们加上之前的ABCD。
1 | A = A + INPUT_A |
最终输出了A,B,C,D作为新一轮的种子序列,依次列推,最后全部输出完成,就会得到最新的ABCD作为最终的输出,也就是我们的密文,这里我个人理解,输入感觉更像是参与了加密过程,像是其中的一个key一般。
在python中已经集成了md5的算法模块,可以直接使用:
1 | #coding=utf8 |
*要是想要强行碰撞的话,概率是很低的,只有1/2^64。
md5加密算法的c实现
1 | void md5(const uint8_t *initial_msg, size_t initial_len, uint8_t *digest) |
下面来个完整的md5算法的实现:
首先是MD5.c的实现
1 |
|
然后是MD5.h
1 |
|
最后是使用方法:
1 |
|
主要就是Init再Update最后再Final就可以实现加密了,上面是个简单的例子。
二、Hash函数研究
hash函数又称为散列函数,其主要目的是将不定长度的消息转成固定长度的消息,一般存在着一种映射关系,有个映射表,一般有2个特点需要记住的是:
1、抗碰撞能力:
对于任意两个不同的数据块,其hash值相同的可能性极小;对于一个给定的数据块,找到和它hash值相同的数据块极为困难。
但是并不是说没有,可以举个MD5的例子:
1 | import hashlib |
2、抗篡改能力:
对于一个数据块,哪怕只改动其一个比特位,其hash值的改动也会很大
1 | MD5("version1") = "966634ebf2fc135707d6753692bf4b1e"; |
经常使用的构造散列函数的方法
散列函数能使对一个数据序列的訪问过程更加迅速有效,通过散列函数,数据元素将被更快地定位:
直接寻址法:取keyword或keyword的某个线性函数值为散列地址。即H(key)=key或H(key) = a•key + b,当中a和b为常数(这样的散列函数叫做自身函数)
数字分析法:分析一组数据,比方一组员工的出生年月日,这时我们发现出生年月日的前几位数字大体同样,这种话,出现冲突的几率就会非常大,可是我们发现年月日的后几位表示月份和详细日期的数字区别非常大,假设用后面的数字来构成散列地址,则冲突的几率会明显减少。因此数字分析法就是找出数字的规律,尽可能利用这些数据来构造冲突几率较低的散列地址。
平方取中法:取keyword平方后的中间几位作为散列地址。
折叠法:将keyword切割成位数同样的几部分,最后一部分位数能够不同,然后取这几部分的叠加和(去除进位)作为散列地址。
随机数法:选择一随机函数,取keyword的随机值作为散列地址,通经常使用于keyword长度不同的场合。
除留余数法:取keyword被某个不大于散列表表长m的数p除后所得的余数为散列地址。即 H(key) = key MOD p, p<=m。不仅能够对keyword直接取模,也可在折叠、平方取中等运算之后取模。对p的选择非常重要,一般取素数或m,若p选的不好,容易产生同义词。
目前流行的 Hash 算法包括 MD5、SHA-1 和 SHA-2。
- MD4(RFC 1320)是 MIT 的 Ronald L. Rivest 在 1990 年设计的,MD 是 Message Digest 的缩写。其输出为 128 位。MD4 已证明不够安全。
- MD5(RFC 1321)是 Rivest 于1991年对 MD4 的改进版本。它对输入仍以 512 位分组,其输出是 128 位。MD5 比 MD4 复杂,并且计算速度要慢一点,更安全一些。MD5 已被证明不具备”强抗碰撞性”。
- SHA (Secure Hash Algorithm)是一个 Hash 函数族,由 NIST(National Institute of Standards and Technology)于 1993 年发布第一个算法。目前知名的 SHA-1 在 1995 年面世,它的输出为长度 160 位的 hash 值,因此抗穷举性更好。SHA-1 设计时基于和 MD4 相同原理,并且模仿了该算法。SHA-1 已被证明不具”强抗碰撞性”。
- 为了提高安全性,NIST 还设计出了 SHA-224、SHA-256、SHA-384,和 SHA-512 算法(统称为 SHA-2),跟 SHA-1 算法原理类似。SHA-3 相关算法也已被提出。
3、sha256的c语言实现:
1 |
|
以后看table行事,猜测出加密的算法。