MD5的实现

以前编写的一个程序,当时编了挺长的时间。代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

FILE* f_open();//找到所要求的文章(默认在d:\\practise\\*.txt)
unsigned long long int* md5_len(FILE*f,unsigned long long int len[2]);//返回信息的原始长度和处理后的长度
unsigned char* message(unsigned long long int len[2],FILE* f);//返回处理后的信息地址
void Init(unsigned int &A,unsigned int &B,unsigned int &C,unsigned int &D);//初始化链接常量
void FF(unsigned int &a,unsigned int &b,unsigned int &c,unsigned int &d,
    unsigned int M,int s,long long int ti,int F,
    unsigned int (*X)(unsigned int X,unsigned int Y,unsigned int Z,int F));//每轮调用函数
unsigned int F(unsigned int X,unsigned int Y,unsigned int Z,int F);//非线性运算
unsigned int TI(int i);//产生常数ti
unsigned int PP(unsigned int x);//反转结果
void main()
{
unsigned long long int len[2];//文件长度(按字符)
unsigned int ti;//常数ti
unsigned char *S;//字符串指针
unsigned int M[16],s,incre;//M[16]分组,s偏移量,incre数组编号增量
unsigned int A[4]={},a[4]={};//A[4]初始连接常量及返回值,a[4]过程中变量
int I;//数组起始编号
  Init(A[0],A[1],A[2],A[3]);
  unsigned int (*X)(unsigned int X,unsigned int Y,unsigned int Z,int F);
  unsigned long long int s_i=0;
   FILE* f;
   f=f_open();
   if(f==NULL)exit(0);
   md5_len(f,len);
   if(len[0]==-1)
       {
           printf("文件为空!\n");
           exit(0);
        }
   S=message(len,f);
   printf("信息串与补位在内存中的存储:\n");
   for(int i=0;i<len[1];i++)
   printf("%02x",S[i]);
   printf("\n");
    X=F;

   for(int i=0;i<len[1]/64;i++)
   {
       a[0]=A[0];
       a[1]=A[1];
       a[2]=A[2];
       a[3]=A[3];
       //printf("A[0]%x\nA[1]%x\nA[2]%x\nA[3]%x\n",A[0],A[1],A[2],A[3]);
       memset(M,0,64);
       memcpy(M,S+s_i,64);
       s_i+=64;
       //M[i]=(unsigned int)(s+s_i);
       printf("信息串与补位在分组里的形式:\n");
       for(int i=0;i<16;i++)
          printf("%08x",M[i]);
            printf("\n");
     for(int j=0;j<4;j++)
     {
         switch(j)
         {
         case 0:  I=0;incre=1;
                  for(int k=0;k<16;k++)
                  {
                      ti=TI(k+1);
                      //printf("0x%x\n",ti);
                   switch(k%4)
                           {
                           case 0: s=7;FF(a[0],a[1],a[2],a[3],M[(I+k*incre)%16],s,ti,j,X);break;
                           case 1: s=12;FF(a[3],a[0],a[1],a[2],M[(I+k*incre)%16],s,ti,j,X);break;
                           case 2: s=17;FF(a[2],a[3],a[0],a[1],M[(I+k*incre)%16],s,ti,j,X);break;
                           case 3: s=22;FF(a[1],a[2],a[3],a[0],M[(I+k*incre)%16],s,ti,j,X);break;
                           }
                    }break;
         case 1:  I=1;incre=5;
                  for(int k=0;k<16;k++)
                  {
                       ti=TI(k+17);
                       //printf("0x%x\n",ti);
                   switch(k%4)
                           {
                           case 0: s=5;FF(a[0],a[1],a[2],a[3],M[(I+k*incre)%16],s,ti,j,X);break;
                           case 1: s=9;FF(a[3],a[0],a[1],a[2],M[(I+k*incre)%16],s,ti,j,X);break;
                           case 2: s=14;FF(a[2],a[3],a[0],a[1],M[(I+k*incre)%16],s,ti,j,X);break;
                           case 3: s=20;FF(a[1],a[2],a[3],a[0],M[(I+k*incre)%16],s,ti,j,X);break;
                           }
                    }break;
         case 2:  I=5;incre=3;
                  for(int k=0;k<16;k++)
                  {
                       ti=TI(k+33);
                       //printf("0x%x\n",ti);
                   switch(k%4)
                           {
                           case 0: s=4;FF(a[0],a[1],a[2],a[3],M[(I+k*incre)%16],s,ti,j,X);break;
                           case 1: s=11;FF(a[3],a[0],a[1],a[2],M[(I+k*incre)%16],s,ti,j,X);break;
                           case 2: s=16;FF(a[2],a[3],a[0],a[1],M[(I+k*incre)%16],s,ti,j,X);break;
                           case 3: s=23;FF(a[1],a[2],a[3],a[0],M[(I+k*incre)%16],s,ti,j,X);break;
                           }
                    }break;
         case 3:  I=0;incre=7;
                  for(int k=0;k<16;k++)
                  {
                       ti=TI(k+49);
                       //printf("0x%x\n",ti);
                   switch(k%4)
                           {
                           case 0: s=6;FF(a[0],a[1],a[2],a[3],M[(I+k*incre)%16],s,ti,j,X);break;
                           case 1: s=10;FF(a[3],a[0],a[1],a[2],M[(I+k*incre)%16],s,ti,j,X);break;
                           case 2: s=15;FF(a[2],a[3],a[0],a[1],M[(I+k*incre)%16],s,ti,j,X);break;
                           case 3: s=21;FF(a[1],a[2],a[3],a[0],M[(I+k*incre)%16],s,ti,j,X);break;
                           }    
                    }break;
     }
     //printf("F返回值为%u\n",X);        
   }
     A[0]+=a[0];
     A[1]+=a[1];
     A[2]+=a[2];
     A[3]+=a[3];  
  }
   printf("所得MD5编码为%08x%08x%08x%08x\n",PP(A[0]),PP(A[1]),PP(A[2]),PP(A[3]));
   free(S);
   fclose(f);
}

FILE* f_open()
{
FILE *f;
    printf("请输入文件名称:\n");
    char f_name[50]={};
    scanf("%s",f_name);
    char f_path[100]={};
    sprintf(f_path,"D:\\practise\\%s.txt",f_name);
    f=fopen(f_path,"rb");
    if(f==NULL)
    {
        printf("找不到文件\n");
            return NULL;
    }
    return f;
}

unsigned long long int* md5_len(FILE*f,unsigned long long int len[2])
{
   fseek(f,0L,SEEK_END);
   len[0]=ftell(f);
   fseek(f,0L,SEEK_SET);
   if(len[0]%64==56)//判断信息长度是否为N*512+448
      len[1]= (len[0]+8);//信息长度余数是448,只需加上64位二进制长度
   else 
       if(len[0]%64<56)
       len[1]= (len[0]+56-len[0]%64+8);//信息长度余数小于448,补足
       else
           if(len[0]%64>56)
           len[1]= (len[0]+64-len[0]%64+56+8);//信息长度余数大于448,补满512后再补448
     return len;
}

void Init( unsigned int &A,unsigned int &B,unsigned int &C,unsigned int &D)
{
 A=0x67452301;
 B=0xefcdab89;
 C=0x98badcfe;
 D=0x10325476;
}


unsigned int TI(int i)
{
long long int ti;
 ti=(long long int)4294967296*abs(sin((double)i));
 return ti;
}

unsigned int F(unsigned int X,unsigned int Y,unsigned int Z,int F)
{
    switch(F)
    {
    case 0: return (X&Y)|((~X)&Z);
    case 1: return (X&Z)|(Y&(~Z));
    case 2: return X^Y^Z;
    case 3: return Y^(X|(~Z));
    default : return 0;
    }
}

void FF(unsigned int &a,unsigned int &b,unsigned int &c,unsigned int &d,
    unsigned int M,int s,long long int ti,int F,
    unsigned int (*X)(unsigned int X,unsigned int Y,unsigned int Z,int F))
{
    a+=X(b,c,d,F)+M+ti;
    a=(a<<s)|(a>>(32-s));
        a+=b;
    //a=b+(((a+X(b,c,d,F)+M+ti)<<s)|((a+X(b,c,d,F)+M+ti)>>(32-s)));不知为何不行
 //printf("%08x\n",a);
}

 unsigned char* message(unsigned long long int len[2],FILE* f)
{
    unsigned char *s;
    unsigned int flen[2];
   s=(unsigned char*)malloc((sizeof(char)*len[1]));
   memset(s,0,len[1]);
   fread(s,len[0],1,f);
   printf("信息串为:\n");
   printf("%s\n",s);
   fseek(f,0L,SEEK_SET);
   printf("文件长度是:%lld字节\n md5长度是:%lld字节\n",len[0],len[1]);
   flen[1]=len[0]/0x20000000;//按低位在前,高位在后的顺序存储该长度
   flen[0]=(len[0]%0x20000000)*8;

   printf("填入长度是%08x%08x\n",flen[1],flen[0]);
   if(len[1]-len[0]-8>0)
   {    
       s[len[0]]=128;//是信息后首个位赋1,并不是整个字符
      for( int i=1;i<len[1]-len[0]-8;i++)
        s[len[0]+i]=0;
   }
   memcpy(s+len[1]-8,flen,8);
   return s;
}

 unsigned int PP(unsigned int x)
 {
 return (x<<24)|((x<<8)&0xff0000)|((x>>8)&0xff00)|(x>>24);
 }

难点就是字符在unsigned int 和long long int 中的存储和表现形式吧,说实话,还不太了解。。。 百度百科不太给力吧。还有一个点就是移位的公式有些不太理解。①
a+=X(b,c,d,F)+M+ti;②a=(a<<s)|(a>>(32-s));③ a+=b;分开就可以,而a=b+(((a+X(b,c,d,F)+M+ti)<<s)|((a+X(b,c,d,F)+M+ti)>>(32-s)));就不行了,费解。。。
上图吧,真不容易 



原文地址:https://www.cnblogs.com/idealing/p/3068672.html