MD5生成器源代码,写了几天呀....

本文介绍了一个MD5算法的实现细节,包括如何通过不同方法输入数据生成MD5码,适用于小到单个字符串或文件,大到大型文件的完整性校验。提供了完整的C++代码示例,涵盖设置数据、分步处理及最终输出MD5值的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

//VC2005向导生成一个WIN32控制台工程,设置不使用Unicode字符集

//复制所有文本到你的工程就可以了。记得把所有 ' 替换成 单引号

//写了好几天,本意用来批量验证文件完整性的,这里是关键的算法部分。

#include "stdafx.h"
#include <windows.h>
#include <fcntl.h>
#include <io.h>
#include <conio.h>
#include <stdio.h>
//================================================================================================================
/*
这个MD5生成类的使用有两种方法:
(1)、一次性把数据全部输入生成MD5码,通常对于较少的数据这样做,如生成一个字符串或者一个小文件的MD5。 操作步骤:
  SetData 输入所有数据,传递的是数据缓冲区指针,并指定数据的长度.
  Action 计算MD5值
(2)、逐步把数据分段输入生成MD5码,通常对于比较大量数据,如一个很大的文件,这时采用第一种方法很可能造成内存不足。操作步骤:
  Step 循环调用,按循序每次向其传递一个64字节大小的缓冲区的指针。
  End 末了当数据长度没有64字节时调用,并且指定数据长度
如果要多次使用本类要调用Reset以复位各个参数
*/

typedef unsigned int BUFF[16];
class ShuJu
{
public:
 ShuJu(void);
public:
 ~ShuJu(void);
public:
 void *data;
public:
 void SetData(void * input, unsigned __int32 inlen);
public:
 void Out(void);
public:
 unsigned __int64 data_len;  //原始数据长度,单位是"字节"
 unsigned __int64 data_lenbit; //原始数据长度,单位是"位"
public:
 unsigned __int64 all_len;  //总共要处理的数据的长度,单位"字节",=数据原始长度+补位长度+8
 unsigned __int64 all_lenbit; //总共要处理的数据的长度,单位"位"
public:
 unsigned int A,B,C,D;
public:
 inline UINT F(UINT x,UINT y,UINT z){return (x&y)|((~x)&z);}
 inline UINT G(UINT x,UINT y,UINT z){return (x&z)|(y&(~z));}
 inline UINT H(UINT x,UINT y,UINT z){return x^y^z;}
 inline UINT I(UINT x,UINT y,UINT z){return y^(x|(~z));}
public:
 inline UINT FF(UINT a,UINT b,UINT c,UINT d,UINT x,UINT s,UINT i){UINT e=a+F(b,c,d)+x+i;e=(e<<s)|(e>>(32-s));return b+e;}
 inline UINT GG(UINT a,UINT b,UINT c,UINT d,UINT x,UINT s,UINT i){UINT e=a+G(b,c,d)+x+i;e=(e<<s)|(e>>(32-s));return b+e;}
 inline UINT HH(UINT a,UINT b,UINT c,UINT d,UINT x,UINT s,UINT i){UINT e=a+H(b,c,d)+x+i;e=(e<<s)|(e>>(32-s));return b+e;}
 inline UINT II(UINT a,UINT b,UINT c,UINT d,UINT x,UINT s,UINT i){UINT e=a+I(b,c,d)+x+i;e=(e<<s)|(e>>(32-s));return b+e;}
public:
 void Action(void);
public:
 unsigned char outstr[33]; //以字符串存储的MD5码
 unsigned char outbit[16]; //以数字存储的MD5码
private:
 void Change(void * p);
public:
 unsigned char tail[64*2]; //尾巴,尾巴指的是原始数据对末尾剩余的若干字节数据(长度为原始数据长度字节数除已64的余数个字节),补位数据,8个"存储了以位计算的原始数据长度的"字节。
 UINT tail_len;    //尾巴的长度,单位是"字节"。尾巴长度是64字节(512位)或者128字节(1024位)。
public:
 UINT buwei_len;  //补位的长度,单位是字节
public:
 void Reset(void);
public:
 void End(void * p,UINT plen);
public:
 void Step(void* p);
private:
 void WeiShu(void * p, unsigned int plen);
public:
 unsigned __int64 stepcount;  //累计执行的步数,可以用来指示进度。
};

 

const unsigned int T[64]=
{
 0xD76AA478,0xE8C7B756,0x242070DB,0xC1BDCEEE,0xF57C0FAF,0x4787C62A,0xA8304613,0xFD469501,0x698098D8,0x8B44F7AF,0xFFFF5BB1,0x895CD7BE,0x6B901122,0xFD987193,0xA679438E,0x49B40821,
 0xF61E2562,0xC040B340,0x265E5A51,0xE9B6C7AA,0xD62F105D,0x2441453,0xD8A1E681,0xE7D3FBC8,0x21E1CDE6,0xC33707D6,0xF4D50D87,0x455A14ED,0xA9E3E905,0xFCEFA3F8,0x676F02D9,0x8D2A4C8A,
 0xFFFA3942,0x8771F681,0x6D9D6122,0xFDE5380C,0xA4BEEA44,0x4BDECFA9,0xF6BB4B60,0xBEBFBC70,0x289B7EC6,0xEAA127FA,0xD4EF3085,0x4881D05,0xD9D4D039,0xE6DB99E5,0x1FA27CF8,0xC4AC5665,
 0xF4292244,0x432AFF97,0xAB9423A7,0xFC93A039,0x655B59C3,0x8F0CCC92,0xFFEFF47D,0x85845DD1,0x6FA87E4F,0xFE2CE6E0,0xA3014314,0x4E0811A1,0xF7537E82,0xBD3AF235,0x2AD7D2BB,0xEB86D391
};
const unsigned int S[4][4]=
{
 {7,12,17,22},
 {5,9,14,20},
 {4,11,16,23},
 {6,10,15,21}
};

ShuJu::ShuJu(void)
:data(0)
{
 Reset();
}

ShuJu::~ShuJu(void)
{
 if(data)delete data;
}
void ShuJu::Reset(void)
{
 if(data)delete data;
 data=0;
 data_len=0;
 data_lenbit=0;
 all_lenbit=0;
 all_len=0;
 stepcount=0;

 A=0x67452301;
 B=0xefcdab89;
 C=0x98badcfe;
 D=0x10325476;

 outstr[32]=0;
}
void ShuJu::SetData(void * input, unsigned __int32 inlen)
{
 char err[]="错误:内存不足!";
 UINT ys=inlen % 64;
 data_len=inlen-ys;
 if(data)delete data;
 data=NULL;
 data=new BYTE[(UINT)data_len];
 if(!data)
 {
  ::memcpy(outstr,err,32);
  return;
 }
 ::memcpy(data,input,(UINT)data_len);
 WeiShu((((char *)input)+inlen-ys),ys);
}
inline void ShuJu::WeiShu(void * p, unsigned int plen)
{
 data_len+=plen;
 data_lenbit=data_len*8;
 buwei_len=plen<56?56-plen:120-plen;
 tail_len=plen+buwei_len+8;
 all_len=data_len+buwei_len+8;
 all_lenbit=all_len*8;
 ::memcpy(tail,p,plen);
 ::ZeroMemory(tail+plen,buwei_len);
 tail[plen]=0x80;
 *((unsigned __int64*)(&(tail[plen+buwei_len])))=data_lenbit;
}

void ShuJu::Action(void)
{
 unsigned __int64 m;
 unsigned __int64 n;
 n=data_len/64;
 BUFF *p;
 p=(BUFF*)data;
 for(m=0;m<n;m++)
 {
  Change(p);
  p++;
 }
 p=(BUFF *)tail;
 Change(p);
 if(tail_len==128)
 {
  p=(BUFF*)(tail+64);
  Change(p);
 }
 Out();
}

void ShuJu::Step(void* p)
{
 data_len+=64;
 Change(p);
}
void ShuJu::End(void * p,UINT plen)
{
 WeiShu(p,plen);
 BUFF * pp=(BUFF *)tail;
 Change(pp);
 if(tail_len==128)
 {
  pp=(BUFF *)(tail+64);
  Change(pp);
 }
 Out();
}

inline void ShuJu::Change(void * p)
{
 BUFF & x=*((BUFF *)p);

 UINT a=A;
 UINT b=B;
 UINT c=C;
 UINT d=D;

 a=FF(a,b,c,d,x[ 0],S[0][0],T[ 0]);
 d=FF(d,a,b,c,x[ 1],S[0][1],T[ 1]);
 c=FF(c,d,a,b,x[ 2],S[0][2],T[ 2]);
 b=FF(b,c,d,a,x[ 3],S[0][3],T[ 3]);
 a=FF(a,b,c,d,x[ 4],S[0][0],T[ 4]);
 d=FF(d,a,b,c,x[ 5],S[0][1],T[ 5]);
 c=FF(c,d,a,b,x[ 6],S[0][2],T[ 6]);
 b=FF(b,c,d,a,x[ 7],S[0][3],T[ 7]);
 a=FF(a,b,c,d,x[ 8],S[0][0],T[ 8]);
 d=FF(d,a,b,c,x[ 9],S[0][1],T[ 9]);
 c=FF(c,d,a,b,x[10],S[0][2],T[10]);
 b=FF(b,c,d,a,x[11],S[0][3],T[11]);
 a=FF(a,b,c,d,x[12],S[0][0],T[12]);
 d=FF(d,a,b,c,x[13],S[0][1],T[13]);
 c=FF(c,d,a,b,x[14],S[0][2],T[14]);
 b=FF(b,c,d,a,x[15],S[0][3],T[15]);

 a=GG(a,b,c,d,x[ 1],S[1][0],T[16]);
 d=GG(d,a,b,c,x[ 6],S[1][1],T[17]);
 c=GG(c,d,a,b,x[11],S[1][2],T[18]);
 b=GG(b,c,d,a,x[ 0],S[1][3],T[19]);
 a=GG(a,b,c,d,x[ 5],S[1][0],T[20]);
 d=GG(d,a,b,c,x[10],S[1][1],T[21]);
 c=GG(c,d,a,b,x[15],S[1][2],T[22]);
 b=GG(b,c,d,a,x[ 4],S[1][3],T[23]);
 a=GG(a,b,c,d,x[ 9],S[1][0],T[24]);
 d=GG(d,a,b,c,x[14],S[1][1],T[25]);
 c=GG(c,d,a,b,x[ 3],S[1][2],T[26]);
 b=GG(b,c,d,a,x[ 8],S[1][3],T[27]);
 a=GG(a,b,c,d,x[13],S[1][0],T[28]);
 d=GG(d,a,b,c,x[ 2],S[1][1],T[29]);
 c=GG(c,d,a,b,x[ 7],S[1][2],T[30]);
 b=GG(b,c,d,a,x[12],S[1][3],T[31]);

 a=HH(a,b,c,d,x[ 5],S[2][0],T[32]);
 d=HH(d,a,b,c,x[ 8],S[2][1],T[33]);
 c=HH(c,d,a,b,x[11],S[2][2],T[34]);
 b=HH(b,c,d,a,x[14],S[2][3],T[35]);
 a=HH(a,b,c,d,x[ 1],S[2][0],T[36]);
 d=HH(d,a,b,c,x[ 4],S[2][1],T[37]);
 c=HH(c,d,a,b,x[ 7],S[2][2],T[38]);
 b=HH(b,c,d,a,x[10],S[2][3],T[39]);
 a=HH(a,b,c,d,x[13],S[2][0],T[40]);
 d=HH(d,a,b,c,x[ 0],S[2][1],T[41]);
 c=HH(c,d,a,b,x[ 3],S[2][2],T[42]);
 b=HH(b,c,d,a,x[ 6],S[2][3],T[43]);
 a=HH(a,b,c,d,x[ 9],S[2][0],T[44]);
 d=HH(d,a,b,c,x[12],S[2][1],T[45]);
 c=HH(c,d,a,b,x[15],S[2][2],T[46]);
 b=HH(b,c,d,a,x[ 2],S[2][3],T[47]);

 a=II(a,b,c,d,x[ 0],S[3][0],T[48]);
 d=II(d,a,b,c,x[ 7],S[3][1],T[49]);
 c=II(c,d,a,b,x[14],S[3][2],T[50]);
 b=II(b,c,d,a,x[ 5],S[3][3],T[51]);
 a=II(a,b,c,d,x[12],S[3][0],T[52]);
 d=II(d,a,b,c,x[ 3],S[3][1],T[53]);
 c=II(c,d,a,b,x[10],S[3][2],T[54]);
 b=II(b,c,d,a,x[ 1],S[3][3],T[55]);
 a=II(a,b,c,d,x[ 8],S[3][0],T[56]);
 d=II(d,a,b,c,x[15],S[3][1],T[57]);
 c=II(c,d,a,b,x[ 6],S[3][2],T[58]);
 b=II(b,c,d,a,x[13],S[3][3],T[59]);
 a=II(a,b,c,d,x[ 4],S[3][0],T[60]);
 d=II(d,a,b,c,x[11],S[3][1],T[61]);
 c=II(c,d,a,b,x[ 2],S[3][2],T[62]);
 b=II(b,c,d,a,x[ 9],S[3][3],T[63]);

 A=A+a;
 B=B+b;
 C=C+c;
 D=D+d;
 stepcount++;
}


typedef unsigned int ABCD[4];
void ShuJu::Out(void)
{
 ABCD abcd;
 abcd[0]=A;
 abcd[1]=B;
 abcd[2]=C;
 abcd[3]=D;
 unsigned char * p;
 for(int m=0;m<4;m++)
 {
  p=(unsigned char *)(&abcd[m]);
  for(int n=0;n<4;n++)
  {
   outbit[m*4+n]=p[n];
  }
 }
 unsigned char c;
 for(int m=0;m<16;m++)
 {
  c=outbit[m]>>4;
  outstr[2*m]=c<10?c+48:c+55;
  c=outbit[m]&0x0F;
  outstr[2*m+1]=c<10?c+48:c+55;
 }
 outstr[32]=0;
}
//==================================================================================================================

char * help[]=
{
"------本软件为学习测试用,你可以随意复制,但不得做商业发行。------/n/
版本:1.0 作者:LH /n/n/
调用格式:md5 [参数1] [参数2] [参数3] [参数4]/n/
参数1: 用来指定要生成MD5码的数据,可以是文件名或者字符串。/n/
        如果是字符串要在前加斜杠(/),内部处理时这个字符会被去除的。/n/
参数2: 用来指定以小写输出的MD5码中字母,或者显示完成百分比。/n/
        本参数可以是字母(L)或(P)或(H)。/n/
参数3: 与[参数2]作用一样。/n/
参数4: 与[参数2]作用一样。/n/
参数n: 忽略。/n/
  (P)显示完成百分比。(L)以小写输出。(H)隐藏控制台窗口,用于脚本时可能需要。/n/
  参数间以空格来分隔,参数不区分大小写,自[参数2]起所有参数不分先后顺序。/n/
  关于参数本身带空格和双引号的情况请参照WINDOWS命令行相关说明。/n/
示例: /n/
md5 c://boot.ini      计算文件boot.ini的md5值/n/
md5 c://boot.ini L    计算文件boot.ini的md5值并输出小写的十六进制字符/n/
md5 d://ghost//sys.gho P L /n/
计算文件sys.gho的md5值且在计算过程中显示完成百分比,输出小写的十六进制字符/n/
md5 /42C://Program Files//Internet Explorer//iexplore.exe/42 /n/
计算文件C://Program Files//Internet Explorer//iexplore.exe的MD5值。/n/
md5 /ABCDEFG         计算字符串 ABCDEFG 的MD5值/n/
-------------------------------------------------------------------------"
};
//==================================================================================================================
class Parament
{
public:
 Parament(void);
public:
 ~Parament(void);
public:
 bool trace;
public:
 bool low;
public:
 bool hide;
public:
 char *instr;
public:
 bool isstr;
public:
 void Process(int argc, char * * argv);
public:
 bool help;
};

Parament::Parament(void)
: trace(false)
, low(false)
, hide(false)
, instr(NULL)
, isstr(false)
, help(false)
{

}

Parament::~Parament(void)
{
}

void Parament::Process(int argc, char ** argv)
{
 if(argc==1)
 {
  help=true;
  return ;
 }
 instr=argv[1];
 if(instr[0]==&apos;/&apos;)
 {
  instr++;
  isstr=true;
 }
 for(int m=2;m<argc;m++)
 {
  if(m>3)continue;
  switch(argv[m][0])
  {
  case &apos;l&apos;:
  case &apos;L&apos;:
   low=true;
   break;
  case &apos;p&apos;:
  case &apos;P&apos;:
   trace=true;
   break;
  case &apos;h&apos;:
  case &apos;H&apos;:
   hide=true;
   break;
  }
 }
 if(hide)trace=false;
}
//===================================================================================================================
Parament para;
ShuJu data;
char outstr[33];
__int64 filelen;

void Action(int fr);
void Md5(char * instr);
void Help();

extern "C" WINBASEAPI HWND WINAPI GetConsoleWindow ();
int _tmain(int argc, _TCHAR* argv[])
{
 para.Process(argc,argv);
 if(para.help)
 {
  Help();
  return &apos;H&apos;;
 }
 if(para.hide)FreeConsole();
 Md5(para.instr);
 if(para.low)strlwr(outstr);
 printf("/15%s",outstr);
 return 0;
}
#define BS 1024*10
#if !(BS%64==0)
 #error BS必须是64的整数倍!
#endif

inline void Action(int fr)
{
 size_t n;
 size_t m;
 unsigned char buff[BS];
 unsigned char *p;
 __int64 segment=filelen/1000;
 __int64 seg=0;
 int percent=0;
 while((n=_read(fr,buff,BS))==BS)
 {
  p=buff;
  for(m=0;m<n;m+=64)
  {
   data.Step(p);
   p+=64;
  }
  if(para.trace)
  {
   seg+=BS;
   if(seg>=segment*percent)
   {
    percent++;
    printf("/15%d.%d%%",percent/10,percent-percent/10*10);
   }
  }
 }
 p=buff;
 for(m=0;m<n/64;m++)
 {
  data.Step(p);
  p+=64;
 }
 data.End(p,(UINT)n%64);
}

void Md5(char * instr)
{
 if(para.isstr)
 {
  data.SetData(instr,(unsigned int)strlen(instr));
  data.Action();
  memcpy(outstr,data.outstr,32);
  outstr[32]=0;
 }
 else
 {
  int fr=_open(instr,_O_BINARY|_O_RDONLY);
  if(!(fr==-1))
  {
   filelen=_lseeki64(fr,0,SEEK_END);
   _lseeki64(fr,0,SEEK_SET);
   Action(fr);
   _close(fr);
   memcpy(outstr,data.outstr,32);
   outstr[32]=0;
  }
  else
  {
   printf("%s%s%s/n%s%s","错误:文件 ",instr," 未能打开!","Error:Can&apos;t open file ",instr);
   return;
  }
 }
}

void Help()
{
 for(int m=0;m<sizeof(help)/4;m++)
 {
  printf("%s/n",help[m]);
  printf("---------------ESC键退出,其它键继续显示MD5算法介绍-----------------/n");
  char c=_getch();
  if(c==27)break;
 }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值