以前编写的一个程序,当时编了挺长的时间。代码如下:
#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)));就不行了,费解。。。
上图吧,真不容易