#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
//循环左移n位
int cir_left(int source,int n)
{
unsigned int tmp = source;
return (tmp << n)|(tmp >> (32-n));
}
//transfer char array[] to int array[]
void encode_c2i(char C_array[],int I_array[],int length)
{
int i,j;
for(i = 0; i < length; i++)
{
I_array[i] = (C_array[i*4]&0x000000ff) + ((C_array[i*4+1]<<8)&0x0000ff00)
+ ((C_array[i*4+2]<<16)&0x00ff0000) + ((C_array[i*4+3]<<24)&0xff000000);
I_array[i] = 0;
for(j = 3; j >= 0; j--)
{
I_array[i] = I_array[i] << 8;
I_array[i] += ((int)C_array[i*4+j])&0x000000ff;
}
}
}
//transfer int array[16] to char array[64]
void decode_i2c(int I_array[],char C_array[],int length)
{
int i;
for(i = 0; i < length; i++)
{
C_array[i*4] = I_array[i];
C_array[i*4+1] = I_array[i] >> 8;
C_array[i*4+2] = I_array[i] >> 16;
C_array[i*4+3] = I_array[i] >> 24;
}
}
int fun_F(int in, int y, int z)
{
return (in&y)|(~(in)&z);
}
int fun_G(int in, int y, int z)
{
return (in&z)|(y&~(z));
}
int fun_H(int in, int y, int z)
{
return in^y^z;
}
int fun_I(int in, int y, int z)
{
return y^(in|~(z));
}
int fun_FF(int a, int b,int c, int d, int Xk, int s, int Ti)
{
int tmp;
tmp = a + fun_F(b,c,d) + Xk + Ti;
return b + cir_left(tmp,s);
}
int fun_GG(int a, int b,int c, int d, int Xk, int s, int Ti)
{
int tmp;
tmp = a + fun_G(b,c,d) + Xk + Ti;
return b + cir_left(tmp,s);
}
int fun_HH(int a, int b,int c, int d, int Xk, int s, int Ti)
{
int tmp;
tmp = a + fun_H(b,c,d) + Xk + Ti;
return b + cir_left(tmp,s);
}
int fun_II(int a, int b,int c, int d, int Xk, int s, int Ti)
{
int tmp;
tmp = a + fun_I(b,c,d) + Xk + Ti;
return b + cir_left(tmp,s);
}
//实现64个字节的转换
void MD5_kerl(int in[16],int out[4],int T[64])
{
int out_cpy[4];
int i;
for(i = 0; i < 4; i++)
{
out_cpy[i] = out[i];
}
//first loop
out[0] = fun_FF(out[0],out[1],out[2],out[3],in[0],7,T[0]);
out[3] = fun_FF(out[3],out[0],out[1],out[2],in[1],12,T[1]);
out[2] = fun_FF(out[2],out[3],out[0],out[1],in[2],17,T[2]);
out[1] = fun_FF(out[1],out[2],out[3],out[0],in[3],22,T[3]);
out[0] = fun_FF(out[0],out[1],out[2],out[3],in[4],7,T[4]);
out[3] = fun_FF(out[3],out[0],out[1],out[2],in[5],12,T[5]);
out[2] = fun_FF(out[2],out[3],out[0],out[1],in[6],17,T[6]);
out[1] = fun_FF(out[1],out[2],out[3],out[0],in[7],22,T[7]);
out[0] = fun_FF(out[0],out[1],out[2],out[3],in[8],7,T[8]);
out[3] = fun_FF(out[3],out[0],out[1],out[2],in[9],12,T[9]);
out[2] = fun_FF(out[2],out[3],out[0],out[1],in[10],17,T[10]);
out[1] = fun_FF(out[1],out[2],out[3],out[0],in[11],22,T[11]);
out[0] = fun_FF(out[0],out[1],out[2],out[3],in[12],7,T[12]);
out[3] = fun_FF(out[3],out[0],out[1],out[2],in[13],12,T[13]);
out[2] = fun_FF(out[2],out[3],out[0],out[1],in[14],17,T[14]);
out[1] = fun_FF(out[1],out[2],out[3],out[0],in[15],22,T[15]);
//second loop
out[0] = fun_GG(out[0],out[1],out[2],out[3],in[1],5,T[16]);
out[3] = fun_GG(out[3],out[0],out[1],out[2],in[6],9,T[17]);
out[2] = fun_GG(out[2],out[3],out[0],out[1],in[11],14,T[18]);
out[1] = fun_GG(out[1],out[2],out[3],out[0],in[0],20,T[19]);
out[0] = fun_GG(out[0],out[1],out[2],out[3],in[5],5,T[20]);
out[3] = fun_GG(out[3],out[0],out[1],out[2],in[10],9,T[21]);
out[2] = fun_GG(out[2],out[3],out[0],out[1],in[15],14,T[22]);
out[1] = fun_GG(out[1],out[2],out[3],out[0],in[4],20,T[23]);
out[0] = fun_GG(out[0],out[1],out[2],out[3],in[9],5,T[24]);
out[3] = fun_GG(out[3],out[0],out[1],out[2],in[14],9,T[25]);
out[2] = fun_GG(out[2],out[3],out[0],out[1],in[3],14,T[26]);
out[1] = fun_GG(out[1],out[2],out[3],out[0],in[8],20,T[27]);
out[0] = fun_GG(out[0],out[1],out[2],out[3],in[13],5,T[28]);
out[3] = fun_GG(out[3],out[0],out[1],out[2],in[2],9,T[29]);
out[2] = fun_GG(out[2],out[3],out[0],out[1],in[7],14,T[30]);
out[1] = fun_GG(out[1],out[2],out[3],out[0],in[12],20,T[31]);
//third loop
out[0] = fun_HH(out[0],out[1],out[2],out[3],in[5],4,T[32]);
out[3] = fun_HH(out[3],out[0],out[1],out[2],in[8],11,T[33]);
out[2] = fun_HH(out[2],out[3],out[0],out[1],in[11],16,T[34]);
out[1] = fun_HH(out[1],out[2],out[3],out[0],in[14],23,T[35]);
out[0] = fun_HH(out[0],out[1],out[2],out[3],in[1],4,T[36]);
out[3] = fun_HH(out[3],out[0],out[1],out[2],in[4],11,T[37]);
out[2] = fun_HH(out[2],out[3],out[0],out[1],in[7],16,T[38]);
out[1] = fun_HH(out[1],out[2],out[3],out[0],in[10],23,T[39]);
out[0] = fun_HH(out[0],out[1],out[2],out[3],in[13],4,T[40]);
out[3] = fun_HH(out[3],out[0],out[1],out[2],in[0],11,T[41]);
out[2] = fun_HH(out[2],out[3],out[0],out[1],in[3],16,T[42]);
out[1] = fun_HH(out[1],out[2],out[3],out[0],in[6],23,T[43]);
out[0] = fun_HH(out[0],out[1],out[2],out[3],in[9],4,T[44]);
out[3] = fun_HH(out[3],out[0],out[1],out[2],in[12],11,T[45]);
out[2] = fun_HH(out[2],out[3],out[0],out[1],in[15],16,T[46]);
out[1] = fun_HH(out[1],out[2],out[3],out[0],in[2],23,T[47]);
//fourth loop
out[0] = fun_II(out[0],out[1],out[2],out[3],in[0],6,T[48]);
out[3] = fun_II(out[3],out[0],out[1],out[2],in[7],10,T[49]);
out[2] = fun_II(out[2],out[3],out[0],out[1],in[14],15,T[50]);
out[1] = fun_II(out[1],out[2],out[3],out[0],in[5],21,T[51]);
out[0] = fun_II(out[0],out[1],out[2],out[3],in[12],6,T[52]);
out[3] = fun_II(out[3],out[0],out[1],out[2],in[3],10,T[53]);
out[2] = fun_II(out[2],out[3],out[0],out[1],in[10],15,T[54]);
out[1] = fun_II(out[1],out[2],out[3],out[0],in[1],21,T[55]);
out[0] = fun_II(out[0],out[1],out[2],out[3],in[8],6,T[56]);
out[3] = fun_II(out[3],out[0],out[1],out[2],in[15],10,T[57]);
out[2] = fun_II(out[2],out[3],out[0],out[1],in[6],15,T[58]);
out[1] = fun_II(out[1],out[2],out[3],out[0],in[13],21,T[59]);
out[0] = fun_II(out[0],out[1],out[2],out[3],in[4],6,T[60]);
out[3] = fun_II(out[3],out[0],out[1],out[2],in[11],10,T[61]);
out[2] = fun_II(out[2],out[3],out[0],out[1],in[2],15,T[62]);
out[1] = fun_II(out[1],out[2],out[3],out[0],in[9],21,T[63]);
for(i = 0; i < 4; i++)
{
out[i] += out_cpy[i];
}
}
//获取T数组
void get_T_Array(int T[64])
{
int i,tmp;
for(i = 0; i < 64; i++)
{
tmp = 1;
tmp = tmp << 16;
T[i] = (unsigned int)(fabs(sin((double)i+1)) * tmp * tmp);
}
}
//输入明文,返回密文,通过参数返回密文长度
char* MD5_fun(char* str_plain, int* o_len)
{
int len;
int len_bit;
char* str_padding;
char * str_cypher;
int len_cypher;
int len_padding;
int i;
int j;
int T[64];
int in[16];
int out[4];
char* tmp1 = (char*)malloc(64);
char* tmp2 = (char*)malloc(16);
len = strlen(str_plain);
if(len % 64 > 56)
{
len_padding = (len/64 + 2) * 64;//?
}
else
{
len_padding = (len/64 + 1) * 64;
}
str_padding = (char*)malloc(len_padding);
len_cypher = len_padding / 4;//?
str_cypher = (char*)malloc(len_cypher);
for(i = 0; i < len; i++)
{
str_padding[i] = str_plain[i];
}
str_padding[len] = 0x80;
for(i = len+1; i < len_padding; i++)
{
str_padding[i] = 0;
}
len_bit = len * 8;
str_padding[len_padding-8] = len_bit ;
str_padding[len_padding-7] = len_bit >> 8;
str_padding[len_padding-6] = len_bit >> 16;
str_padding[len_padding-5] = len_bit >> 24;
get_T_Array(T);
for(i = 0; i < len_padding / 64; i++)
{
for(j = 0; j < 64; j++)
{
tmp1[j] = str_padding[i*64+j];
}
encode_c2i(tmp1,in,16);
out[0] = 0x67452301;
out[1] = 0xefcdab89;
out[2] = 0x98badcfe;
out[3] = 0x10325476;
MD5_kerl(in,out,T);
decode_i2c(out,tmp2,4);
for(j = 0; j < 16; j++)
{
str_cypher[i*16+j] = tmp2[j];
}
}
*o_len = len_cypher;
return str_cypher;
}
int main()
{
int v1,v2,len;
int i;
char* result = MD5_fun("abc",&len);
//以十六进制的形式输出密文
for(i = 0; i < len; i++)
{
v1 = result[i] & 0x000000ff;
v2 = v1 >> 4;
v1 = v1 & 0x0000000f;
if(v2 >= 10)
{
printf("%c",0x61-10+v2);
}
else
{
printf("%c",0x30+v2);
}
if(v1 >= 10)
{
printf("%c",0x61-10+v1);
}
else
{
printf("%c",0x30+v1);
}
}
return 0;
}
我们假设有一段b位的信息输入,并且我们想要找到他的信息摘要。这里b是一个任意
的无符号整数;b可能为0;它不一定是8的倍数,也可能是任意大的长度。我们假想
信息串的比特流如下:
m_0 m_1...m_(b-1)
接下来的5个步骤描述了如何计算该信息的摘要。
3.1 附加填充位
消息需要进行填充,使得它的长度(位)对512求余为448,即消息的长度加上64比特
后刚好是512的整数倍。填充是必需进行的,即使消息的长度对512求余的结果已经是
448。
填充规则如下:先填充一比特的“1”,然后一直填充“0”,直到消息的长度对512求余
的结果是448。总共,至少要填充1比特,最多填充512比特。
3.2 附加长度 一个64位的无符号整数b(消息被填充前的长度)被附加在先前被填充的消息后面。如
果b的实际长度超过64位,只附加b的低64位(这些比特会被放在两个32位的字中填充的时候按照先前的约定,低位优先)。 此时,目标消息(被填充了附加位和长度b)的长度刚好是512比特的整数倍。即,消息
的长度刚好是16个字(32位)的整数倍。定义M[0 ... N-1]为目标消息的字串,N是16
的整数倍。
3.3 初始化MD缓存 一个4个字的缓存(A,B,C,D)被用于计算消息的摘要。这里每一个A,B,C,D都是一个32
位的寄存器。这些寄存器使用如下的16进制的值进行初始化(低位优先): A : 01 23 45 67
B : 89 ab cd ef
C : fe dc ba 98
D : 76 54 32 10
3.4 16个字一组处理消息
我们首先定义4个辅助函数,每个函数的输入是3个32位的字,输出是1个32位的字。
F(X,Y,Z) = XY v not(x) Z
G(X,Y,Z) = XZ v Y not(Z)
H(X,Y,Z) = X xor Y xor Z
I(X,Y,Z) = Y xor (X v not(Z))
在每一个比特位置,F有约束:如果X则Y,否则Z。(函数F中 v 可以被符号 + 替代,
因为 XY 与 not(x) Z 不可能再同一个比特位置上都为“1”) 注意到如果比特流X,Y
和Z是各自独立的和公正的,则F(X,Y,Z)的每个比特也是各自独立的和公正的。
函数G,H和I与函数F相类似,它们都是“按位平行”从X,Y,Z比特流中产生输出,这
样的方式使得如果X,Y,Z对应的比特是各自独立的和公正的,则G(X,Y,Z), H(X,Y,Z),
I(X,Y,Z)的每个比特也是各自独立的和公正的。注意到函数H是一个对输入进行按位异
或或等于的函数(译者注:原文Note that the function H is the bit-wise "xor" or
"parity" function of its inputs)。
这一步需要用到一个64位的常数组T[1...64],它有sine函数构造。定义T[i]位常数
组中的第i个元素,它的值等于经过4294967296次abs(sin(i))后的值的整数部分(其
中i是弧度 )。数组元素在附录中给出。
过程如下:
/*16个字节一组处理*/
For i=0 to N/16-1 do
/*把第i组放入X中*/
For j=0 to 15 do
Set x[j] to M[i*16+j]
end/*j的循环*/
/*将A存入AA,B存入BB,C存入CC,D存入DD*/
AA = A
BB = B
CC = C
DD = D
/*第一次循环*/
/*定义[abcd k s i]为操作
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s )*/
/*执行16次操作*/
[ABCD 0 7 1] [DABC 1 12 2] [CDAB 2 17 3] [BCDA 3 22 4]
[ABCD 4 7 5] [DABC 5 12 6] [CDAB 6 17 7] [BCDA 7 22 8]
[ABCD 8 7 9] [DABC 9 12 10] [CDAB 10 17 11] [BCDA 11 22 12]
[ABCD 12 7 13] [DABC 13 12 14] [CDAB 14 17 15] [BCDA 15 22 16]
/*第二次循环*/
/*定义[abcd k s i]为操作
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s )*/
/*执行16次操作*/
[ABCD 1 5 17] [DABC 6 9 18] [CDAB 11 14 19] [BCDA 0 20 20]
[ABCD 5 5 21] [DABC 10 9 22] [CDAB 15 14 23] [BCDA 4 20 24]
[ABCD 9 5 25] [DABC 14 9 26] [CDAB 3 14 27] [BCDA 8 20 28]
[ABCD 13 5 29] [DABC 2 9 30] [CDAB 7 14 31] [BCDA 12 20 32]
/*第三次循环*/
/*定义[abcd k s i]为操作
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s )*/
/*执行16次操作*/
[ABCD 5 4 33] [DABC 8 11 34] [CDAB 11 16 35] [BCDA 14 23 36]
[ABCD 1 4 37] [DABC 4 11 38] [CDAB 7 16 39] [BCDA 10 23 40]
[ABCD 13 4 41] [DABC 0 11 42] [CDAB 3 16 43] [BCDA 6 23 44]
[ABCD 9 4 45] [DABC 12 11 46] [CDAB 15 16 47] [BCDA 2 23 48]
/*第四次循环*/
/*定义[abcd k s i]为操作
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s )*/
/*执行16次操作*/
[ABCD 0 6 49] [DABC 7 10 50] [CDAB 14 15 51] [BCDA 5 21 52]
[ABCD 12 6 53] [DABC 3 10 54] [CDAB 10 15 55] [BCDA 1 21 56]
[ABCD 8 6 57] [DABC 15 10 58] [CDAB 6 15 59] [BCDA 13 21 60]
[ABCD 4 6 61] [DABC 11 10 62] [CDAB 2 15 63] [BCDA 9 21 64]
/*然后进行如下加法操作。(增加四个寄存器的值)*/
A = A + AA
B = B + BB
C = C + CC
D = D + DD
end/*i的循环*/
3.5 输出
信息摘要产生后输出的形式为A,B,C,D。即,以A为低位字节开头,D为高位字节结束。
这些就是MD5的完整描述。在附录中有以C语言实现的一个例子