提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
主要是为了快速回忆之前工作的一些记录,不至于完全忘记。因此此处不会有完整的代码展示,需要的话可以直接网上搜索,挺多的。
MD5算法和MD4算法比较接近,这里同样以上节的明文密码“123994”作为研究对象。
从网上下载HashCalc工具,打开后按照文本字符串格式123994输入数值框中,选中MD5加密,再点击计算,如下图所示。
MD5算法流程
(1)待加密信息处理
显而易见,我们要对一个字符串进行MD5计算,那么肯定要从这个字符串的处理入手。我们知道一个字符的长度是一个字节,即8位(bit)的长度。MD5对待加密的字符串的处理是将一个字符串分割成每512位为一个分组,形如N512+R,这里的R是余下的位数。这个R分为几种情况:
R=0时,需要补位,单补上一个512位的分组,因为还要加入最后64个位的字符串长度。
R<448时,则需要补位到448位,后面添加64位的字符串长度。
R>448时,除了补满这一分组外,还要再补上一个512位的分组后面添加64位的字符串长度。
补位的形式是先填充一个1,再接无数个0,直到补足512位。
(2)MD5的链接变量及基本操作
MD5有四个32位的被称作链接变量的整数参数,这是个参数我们定义为A、B、C、D其取值为:A=0x01234567,B=0x89abcdef,C=0xfedcba98,D=0x76543210。但考虑到内存数据存储大小端的问题我们将其赋值为:A=0x67452301,B=0xefcdab89,C=0x98badcfe,D=0x10325476。
同时MD5算法规定了四个非线性操作函数(&是与,|是或,~是非,^是异或):
F(X,Y,Z) =(X&Y)|((~X)&Z)
G(X,Y,Z) =(X&Z)|(Y&(~Z))
H(X,Y,Z) =XYZ
I(X,Y,Z)=Y^(X|(~Z))
这些函数是这样设计的:如果X、Y和Z的对应位是独立和均匀的,那么结果的每一位也应是独立和均匀的。
利用上面的四种操作,生成四个重要的计算函数。首先我们声明四个中间变量a,b,c,d,赋值:a = A, b = B, c = C, d = D。然后定义这四个计算函数为:
FF(a, b, c, d, M[j], s, ti)表示 a = b + ((a + F(b, c, d) + Mj + ti) <<< s)
GG(a, b, c, d, M[j], s, ti)表示 a = b + ((a + G(b, c, d) + Mj + ti) <<< s)
HH(a, b, c, d, M[j], s, ti)表示 a = b + ((a + H(b, c, d) + Mj + ti) <<< s)
II(a, b, c, d, M[j], s, ti)表示 a = b + ((a + I(b, c, d) + Mj + ti) <<< s)
其中M[j]表示消息的第j个子分组(从0到15),<<表示循环左移s,常数ti是4294967296abs(sin(i))的整数部分,i取值从1到64,单位是弧度。
(3)循环计算
定义好上述的四个计算函数后,就可以实现MD5的真正循环计算了。这个循环的循环次数为512位分组的个数。每次循环执行64不计算,上述4个函数每个16次,具体直接看代码
不多说了,直接给出代码关键部分解释
部分C模型代码,方便快速回忆
套用之前NTHASH的模板直接改,这里是输入
int tmpPwdLen = 0;
for (int i = 0; pwd[i] != 0; ++i)
{
*tmpPwdPtr++ = pwd[i];
tmpPwdLen += 1;
}
md5(tmpPwd, tmpPwdLen, ntlmhash);
MD5算法依次经过了
由16次FF函数,16次GG函数,16次HH函数,16次II函数
//FF、GG、HH、II宏定义
#define rotate_left(x,s) (((x) << s)|((x) >> (32-s)))
#define F(x,y,z) (((x)&(y))|(~(x)&(z)))
#define G(x,y,z) (((x)&(z))|((y)&~(z)))
#define H(x,y,z) ((x)^(y)^(z))
#define I(x,y,z) ((y)^((x)|~(z)))
#define FF(A,X,Y,Z,M,s,K) (A)=rotate_left((F((X),(Y),(Z))+(M)+(K)+(A)),(s))+(X)
#define GG(A,X,Y,Z,M,s,K) (A)=rotate_left((G((X),(Y),(Z))+(M)+(K)+(A)),(s))+(X)
#define HH(A,X,Y,Z,M,s,K) (A)=rotate_left((H((X),(Y),(Z))+(M)+(K)+(A)),(s))+(X)
#define II(A,X,Y,Z,M,s,K) (A)=rotate_left((I((X),(Y),(Z))+(M)+(K)+(A)),(s))+(X)
初值:
A=output[0];
B=output[1];
C=output[2];
D=output[3];
终值:
output[0]+=A;
output[1]+=B;
output[2]+=C;
output[3]+=D;
同时为了方便FPGA实现,将C模型改造成:
FF(A,B,C,D,md5Input[0],7,0xd76aa478);
FF(D,A,B,C,md5Input[1],12,0xe8c7b756);
FF(C,D,A,B,md5Input[2],17,0x242070db);
FF(B,C,D,A,md5Input[3],22,0xc1bdceee);
如下形式,这样
A=output[0];
B=output[1];
C=output[2];
D=output[3];
A_in=output[0];
B_in=output[1];
C_in=output[2];
D_in=output[3];
A_out=A_in;
B_out=B_in;
C_out=C_in;
D_out=D_in;
X_out = ((B_in&C_in)|((~B_in)&D_in));
Y_out = md5Input[0] + 0xd76aa478 + A_in ;
Z_out = B_in;
//1
X_in = X_out;
Y_in = Y_out;
Z_in = Z_out;
A_in = A_out;
B_in = B_out;
C_in = C_out;
D_in = D_out;
A_out = D_in;
B_out = rotate_left((X_in+Y_in),7) + Z_in;
D_out = C_in;
C_out = B_in;
X_out = (((rotate_left((X_in+Y_in),7) + Z_in)&B_in)|((~(rotate_left((X_in+Y_in),7) + Z_in))&C_in));
Y_out = md5Input[1] + 0xe8c7b756 + D_in ;
Z_out = rotate_left((X_in+Y_in),7) + Z_in;
//2
A_in = A_out;
B_in = B_out;
C_in = C_out;
D_in = D_out;
X_in = X_out;
Y_in = Y_out;
Z_in = Z_out;
temp = rotate_left((X_in+Y_in),12) + Z_in;//rotate_left(((((B_in)&(C_in))|(~(B_in)&(D_in))) + md5Input[1] + 0xe8c7b756 + A_in),12) + B_in;
A_out = D_in;
D_out = C_in;
C_out = B_in;
B_out = temp;
//3
A_in = A_out;
B_in = B_out;
C_in = C_out;
D_in = D_out;
temp = rotate_left(((((B_in)&(C_in))|(~(B_in)&(D_in))) + md5Input[2] + 0x242070db + A_in),17) + B_in;
A_out = D_in;
D_out = C_in;
C_out = B_in;
B_out = temp;
//4
A_in = A_out;
B_in = B_out;
C_in = C_out;
D_in = D_out;
temp = rotate_left(((((B_in)&(C_in))|(~(B_in)&(D_in))) + md5Input[3] + 0xc1bdceee + A_in),22) + B_in;
A_out = D_in;
D_out = C_in;
C_out = B_in;
B_out = temp;
//5
A_in = A_out;
B_in = B_out;
C_in = C_out;
D_in = D_out;
A = A_out;
B = B_out;
C = C_out;
D = D_out;
注意几点,
1、 因为FF和GG和HH和II是比较大的组合逻辑,因此将这三个函数均拆成X_in、Y_in、Z_in
2、 该算法并行化耗费大量的触发器资源,打拍要省着点;但不打拍组合逻辑又比较大可能会影响系统频率,因此需要做权衡和试验,确定最优方法
总结
MD5算法的流程是:
1、填充成制定格式的数据
2、进行4轮函数运算,每轮16次