古代皇帝权力有多大:使用md5校验和算法保护文件

来源:百度文库 编辑:中财网 时间:2024/05/01 08:12:02
使用md5校验和算法保护文件 发布于:软件开发网 来源:互联网 作者:佚名 时间:2009-02-26 00:02

近日要用到文件校验算法,查看了一下相关资料,得到以下理论与实践经验。
一、理论部分:
1、预备知识
1.1什么是数据校验
通俗的说,就是为保证数据的完整性,用一种指定的算法对原始数据计算出的一个校验值。接收方用同样的算法计算一次校验值,如果和随数据提供的校验值一样,就说明数据是完整的。
1.2最简单的检验
实现方法:最简单的校验就是把原始数据和待比较数据直接进行比较,看是否完全一样这种方法是最安全最准确的。同时也是效率最低的。
适用范围:简单的数据量极小的通讯。
应用例子:龙珠CPU在线调试工具bbug.exe。它和龙珠cpu间通讯时,bbug发送一个字节cpu返回收到的字节,bbug确认是刚才发送字节后才继续发送下一个字节的。
1.3奇偶校验ParityCheck
实现方法:在数据存储和传输中,字节中额外增加一个比特位,用来检验错误。校验位可以通过数据位异或计算出来。
应用例子:单片机串口通讯有一模式就是8位数据通讯,另加第9位用于放校验值。
1.4bcc异或校验法(blockcheckcharacter)
实现方法:很多基于串口的通讯都用这种既简单又相当准确的方法。它就是把所有数据都和一个指定的初始值(通常是0)异或一次,最后的结果就是校验值,通常
把她附在通讯数据的最后一起发送出去。接收方收到数据后自己也计算一次异或和校验值,如果和收到的校验值一致就说明收到的数据是完整的。
校验值计算的代码类似于:
unsigneduCRC=0;//校验初始值
for(inti=0;i适用范围:适用于大多数要求不高的数据通讯。
应用例子:ic卡接口通讯、很多单片机系统的串口通讯都使用。
1.5crc循环冗余校验(CyclicRedundancyCheck)
实现方法:这是利用除法及余数的原理来进行错误检测的.将接收到的码组进行除法运算
,如果除尽,则说明传输无误;如果未除尽,则表明传输出现差错。crc校验
具还有自动纠错能力。
crc检验主要有计算法和查表法两种方法,网上很多实现代码。
适用范围:CRC-12码通常用来传送6-bit字符串;CRC-16及CRC-CCITT码则用是来传送
8-bit字符。CRC-32:硬盘数据,网络传输等
应用例子:rar,以太网卡芯片、MPEG解码芯片中
1.6md5校验和数字签名
实现方法:主要有md5和des算法。
适用范围:数据比较大或要求比较高的场合。如md5用于大量数据、文件校验,des用于保密数据的校验(数字签名)等等。
应用例子:文件校验、银行系统的交易数据

2、具体的实现理论
2.1算法概述
MD5算法是MD4算法的改进算法。RonRivest于1990年提出MD4单向散列函数,MD表示消息摘要(MessageDigest),对输入消息,算法产生128位散列值。该算法首次公布之后,BertdenBoer和AntoonBosselaers对算法三轮中的后两轮进行了成功的密码分析。在一个不相关的分析结果中,RalphMerKle成功地攻击了前两轮。尽管这些攻击都没有扩展到整个算法,但Rivest还是改进了其算法,结果就是MD5算法。
MD5算法是MD4的改进算法,它比MD4更复杂,但设计思想相似,输入的消息可任意长,输出结果也仍为128位,特别适用于高速软件实现,是基于32-位操作数的一些简单的位操作。
2.2算法步骤
l 将输入消息按512-位分组,最后要填充成为512位的整数倍,且最后一组的后64位用来填充消息长度(填充前)。填充方法为附一个1在消息后,后接所要求的多个0。这样可以确保不同消息在填充后不相同。
l 由于留出64位用来表示消息长度,那么消息的长度最多可达264字节,相当于4G×4G字节,文件的长度是不可能达到这么大,因此通常都是只采用64位中的低32位来表示消息长度,高32位填充0。
l 初始化MD变量。由于每轮输出128位,这128位可用下面四个32位字A,B,C,D来表示。其初始值设为:

A=0x01234567
B=0x89ABCDEF
C=0xFEDCBA98
D=0x76543210
l 开始进入算法主循环,循环的次数是消息中512位消息分组的数目。先将上面A、B、C、D四个变量分别复制到另外四个变量a、b、c、d中去。主循环有四轮,每轮很相似。每轮进行16次操作,每次操作对a、b、c、d四个变量中的三个作一次非线性函数运算,然后将所得结果加上第四个变量,消息的一个子分组和一个常数。再将所得结果向右环移一个不定的数,并加上a,b,c或d中之一。最后用该结果取代a,b,c或d中之一。
以下是每次操作中用到的四个非线性函数(每轮一个)。
F(X,Y,Z)=(X∧Y)∨((X)∧Z)
G(X,Y,Z)=(X∧Z)∨(Y∧(Z))
H(X,Y,Z)=X⊕Y⊕Z
I(X,Y,Z)=Y⊕(X∨(Z))
其中,⊕是异或,∧是与,∨是或,是反符号。
这些函数是这样设计的:如果X、Y和Z的对应位是独立和均匀的,那么结果的每一位也应是独立和均匀的。函数F是按逐位方式操作:如果X,那么Y,否则Z。函数H是逐位奇偶操作符。
设Mj表示消息的第j个子分组(从0到15),<<FF(a,b,c,d,Mj,s,ti)表示a=b ((a F(b,c,d) Mj ti)<<GG(a,b,c,d,Mj,s,ti)表示a=b ((a G(b,c,d) Mj ti)<<HH(a,b,c,d,Mj,s,ti)表示a=b ((a H(b,c,d) Mj ti)<<II(a,b,c,d,Mj,s,ti)表示a=b ((a I(b,c,d) Mj ti)<<四轮(64步)结果略。
注:常数ti的选择:
第i步中,ti是232×abs(sin(i))的整数部分,i的单位是弧度。
所有这些完成之后,将A,B,C,D分别加上a,b,c,d。然后用下一分组数据继续运行算法,最后的输出是A,B,C和D的级联。
l 最后得到的A,B,C,D就是输出结果,A是低位,D为高位,DCBA组成128位输出结果。
2.3MD5的安全性
RonRivest概述了MD5安全性[8]:
l 与MD4相比,增加了第四轮。
l 每一步均有唯一的加法常数。
l 为减弱第二轮中函数G的对称性从((X∧Y)∨(X∧Z)∨(Y∧Z))变为((X∧Z)∨(Y∧(Z)))。
l 每一步加上了上一步的结果,引起更快的雪崩效应。
l 改变了第二轮和第三轮中访问消息子分组的次序,使其形式更不相似。
l 近似优化了每一轮中的循环左移位移量以实现更快的雪崩效应。各轮的位移量互不相同。
从安全角度讲,MD5的输出为128位,若采用纯强力攻击寻找一个消息具有给定Hash值的计算困难性为2128,用每秒可试验1000000000个消息的计算机需时1.07×1022年。若采用生日攻击法,寻找有相同Hash值的两个消息需要试验264个消息,用每秒可试验1000000000个消息的计算机需时585年。

二、实现方法
由于此处的文件校验用到要求比较高的场合,故采用了方法6,md5校验算法,从CodeGuru下载了一个md5校验算法的实现模块,加入自己要校验的文件名,实现完成。下面具体描述一下实现过程:
1、创建一个简单的对话框程序;
2、设置CString类型的变量m_filename和m_strFileChecksum以存放要校验的文件名和校验和;
3、在对话框类中创建ChecksumSelectedFile()函数,调用md5校验和类(附录中有其实现文件)中的GetMD5计算文件校验和。
4、使用定时器定时巡检该文件的校验和,一旦发现校验和发生变化,立刻出现提示。
三、附录(md5算法实现的源码)
以下代码实现均来自www.codeguru.com。
1、MD5ChecksumDefines.h(定义相关常量的头文件)
//Magicinitializationconstants
#defineMD5_INIT_STATE_00x67452301
#defineMD5_INIT_STATE_10xefcdab89
#defineMD5_INIT_STATE_20x98badcfe
#defineMD5_INIT_STATE_30x10325476

//ConstantsforTransformroutine.
#defineMD5_S11 7

#defineMD5_S1212
#defineMD5_S1317
#defineMD5_S1422
#defineMD5_S21 5
#defineMD5_S22 9
#defineMD5_S2314
#defineMD5_S2420
#defineMD5_S31 4
#defineMD5_S3211
#defineMD5_S3316
#defineMD5_S3423
#defineMD5_S41 6
#defineMD5_S4210
#defineMD5_S4315
#defineMD5_S4421

//TransformationConstants-Round1
#defineMD5_T01 0xd76aa478//TransformationConstant1
#defineMD5_T02 0xe8c7b756//TransformationConstant2
#defineMD5_T03 0x242070db//TransformationConstant3
#defineMD5_T04 0xc1bdceee//TransformationConstant4
#defineMD5_T05 0xf57c0faf//TransformationConstant5
#defineMD5_T06 0x4787c62a//TransformationConstant6
#defineMD5_T07 0xa8304613//TransformationConstant7
#defineMD5_T08 0xfd469501//TransformationConstant8
#defineMD5_T09 0x698098d8//TransformationConstant9
#defineMD5_T10 0x8b44f7af//TransformationConstant10
#defineMD5_T11 0xffff5bb1//TransformationConstant11
#defineMD5_T12 0x895cd7be//TransformationConstant12
#defineMD5_T13 0x6b901122//TransformationConstant13
#defineMD5_T14 0xfd987193//TransformationConstant14
#defineMD5_T15 0xa679438e//TransformationConstant15
#defineMD5_T16 0x49b40821//TransformationConstant16

//TransformationConstants-Round2
#defineMD5_T17 0xf61e2562//TransformationConstant17
#defineMD5_T18 0xc040b340//TransformationConstant18
#defineMD5_T19 0x265e5a51//TransformationConstant19
#defineMD5_T20 0xe9b6c7aa//TransformationConstant20
#defineMD5_T21 0xd62f105d//TransformationConstant21
#defineMD5_T22 0x02441453//TransformationConstant22
#defineMD5_T23 0xd8a1e681//TransformationConstant23
#defineMD5_T24 0xe7d3fbc8//TransformationConstant24
#defineMD5_T25 0x21e1cde6//TransformationConstant25
#defineMD5_T26 0xc33707d6//TransformationConstant26
#defineMD5_T27 0xf4d50d87//TransformationConstant27
#defineMD5_T28 0x455a14ed//TransformationConstant28
#defineMD5_T29 0xa9e3e905//TransformationConstant29
#defineMD5_T30 0xfcefa3f8//TransformationConstant30
#defineMD5_T31 0x676f02d9//TransformationConstant31
#defineMD5_T32 0x8d2a4c8a//TransformationConstant32

//TransformationConstants-Round3
#defineMD5_T33 0xfffa3942//TransformationConstant33
#defineMD5_T34 0x8771f681//TransformationConstant34
#defineMD5_T35 0x6d9d6122//TransformationConstant35
#defineMD5_T36 0xfde5380c//TransformationConstant36
#defineMD5_T37 0xa4beea44//TransformationConstant37
#defineMD5_T38 0x4bdecfa9//TransformationConstant38
#defineMD5_T39 0xf6bb4b60//TransformationConstant39
#defineMD5_T40 0xbebfbc70//TransformationConstant40
#defineMD5_T41 0x289b7ec6//TransformationConstant41
#defineMD5_T42 0xeaa127fa//TransformationConstant42
#defineMD5_T43 0xd4ef3085//TransformationConstant43
#defineMD5_T44 0x04881d05//TransformationConstant44
#defineMD5_T45 0xd9d4d039//TransformationConstant45
#defineMD5_T46 0xe6db99e5//TransformationConstant46
#defineMD5_T47 0x1fa27cf8//TransformationConstant47
#defineMD5_T48 0xc4ac5665//TransformationConstant48

//TransformationConstants-Round4
#defineMD5_T49 0xf4292244//TransformationConstant49
#defineMD5_T50 0x432aff97//TransformationConstant50
#defineMD5_T51 0xab9423a7//TransformationConstant51
#defineMD5_T52 0xfc93a039//TransformationConstant52
#defineMD5_T53 0x655b59c3//TransformationConstant53
#defineMD5_T54 0x8f0ccc92//TransformationConstant54
#defineMD5_T55 0xffeff47d//TransformationConstant55
#defineMD5_T56 0x85845dd1//TransformationConstant56
#defineMD5_T57 0x6fa87e4f//TransformationConstant57
#defineMD5_T58 0xfe2ce6e0//TransformationConstant58
#defineMD5_T59 0xa3014314//TransformationConstant59
#defineMD5_T60 0x4e0811a1//TransformationConstant60
#defineMD5_T61 0xf7537e82//TransformationConstant61
#defineMD5_T62 0xbd3af235//TransformationConstant62
#defineMD5_T63 0x2ad7d2bb//TransformationConstant63
#defineMD5_T64 0xeb86d391//TransformationConstant64


//Nulldata(exceptforfirstBYTE)usedtofinalisethechecksumcalculation
staticunsignedcharPADDING[64]={
0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
2、CountChecksum.h(md5校验和类的头文件)
classCMD5Checksum 
{
public:
//interfacefunctionsfortheRSAMD5calculation
staticCStringGetMD5(BYTE*PBuf,UINTnLength);
staticCStringGetMD5(CFile&File);
staticCStringGetMD5(constCString&strFilePath);

protected:
//constructor/destructor
CMD5Checksum();
virtual~CMD5Checksum(){};

//RSAMD5implementation
voidTransform(BYTEBlock[64]);
voidUpdate(BYTE*Input,ULONGnInputLen);
CStringFinal();
inlineDWORDRotateLeft(DWORDx,intn);
inlinevoidFF(DWORD&A,DWORDB,DWORDC,DWORDD,DWORDX,DWORDS,DWORDT);
inlinevoidGG(DWORD&A,DWORDB,DWORDC,DWORDD,DWORDX,DWORDS,DWORDT);
inlinevoidHH(DWORD&A,DWORDB,DWORDC,DWORDD,DWORDX,DWORDS,DWORDT);
inlinevoidII(DWORD&A,DWORDB,DWORDC,DWORDD,DWORDX,DWORDS,DWORDT);

//utilityfunctions
voidDWordToByte(BYTE*Output,DWORD*Input,UINTnLength);
voidByteToDWord(DWORD*Output,BYTE*Input,UINTnLength);

private:
BYTE m_lpszBuffer[64]; //inputbuffer
ULONGm_nCount[2]; //numberofbits,modulo2^64(lsbfirst)
ULONGm_lMD5[4]; //MD5checksum
};

#endif//!defined(AFX_MD5CHECKSUM_H__2BC7928E_4C15_11D3_B2EE_A4A60E20D2C3__INCLUDED_)
3、CountChecksum.cpp(md5校验和类的实现文件)
/*****************************************************************************************
FUNCTION: CMD5Checksum::GetMD5
DETAILS: static,public
DESCRIPTION: GetstheMD5checksumforaspecifiedfile
RETURNS: CString:thehexadecimalMD5checksumforthespecifiedfile
ARGUMENTS: CString&strFilePath:thefullpathnameofthespecifiedfile
NOTES: ProvidesaninterfacetotheCMD5Checksumclass.'strFilePath'nameshould
holdthefullpathnameofthefile,egC:\MyDocuments\Arcticle.txt.
NB.Ifanyproblemsoccurwithopeningorreadingthisfile,aCFileException

willbethrown;callersofthisfunctionshouldbereadytocatchthis
exception.
*****************************************************************************************/
CStringCMD5Checksum::GetMD5(constCString&strFilePath)
{
//openthefileasabinaryfileinreadonlymode,denyingwriteAccess
CFileFile(strFilePath,CFile::shareDenyNone);
//thefilehasbeensuccessfullyopened,sonowgetandreturnitschecksum
returnGetMD5(File);
}


/*****************************************************************************************
FUNCTION: CMD5Checksum::GetMD5
DETAILS: static,public
DESCRIPTION: GetstheMD5checksumforaspecifiedfile
RETURNS: CString:thehexadecimalMD5checksumforthespecifiedfile
ARGUMENTS: CFile&File:thespecifiedfile
NOTES: ProvidesaninterfacetotheCMD5Checksumclass.'File'shouldbeopenin
binaryreadonlymodebeforecallingthisfunction.
NB.CallersofthisfunctionshouldbereadytocatchanyCFileException
thrownbytheCFilefunctions
*****************************************************************************************/
CStringCMD5Checksum::GetMD5(CFile&File)
{
try
{
CMD5ChecksumMD5Checksum; //checksumobject 
intnLength=0; //numberofbytesreadfromthefile
constintnBufferSize=1024; //checksumthefileinblocksof1024bytes
BYTEBuffer[nBufferSize]; //bufferfordatareadfromthefile

//checksumthefileinblocksof1024bytes
while((nLength=File.Read(Buffer,nBufferSize))>0)
{
MD5Checksum.Update(Buffer,nLength);
}

//finalisethechecksumandreturnit
returnMD5Checksum.Final();
}

//reportanyfileexceptionsindebugmodeonly
catch(CFileException*e)
{
TRACE0("CMD5Checksum::GetMD5:CFileExceptioncaught"); 
throwe;
}
}


/*****************************************************************************************
FUNCTION: CMD5Checksum::GetMD5
DETAILS: static,public
DESCRIPTION: GetstheMD5checksumfordatainaBYTEarray
RETURNS: CString:thehexadecimalMD5checksumforthespecifieddata
ARGUMENTS: BYTE*pBuf : pointertotheBYTEarray
UINTnLength: numberofBYTEsofdatatobechecksumed
NOTES: ProvidesaninterfacetotheCMD5Checksumclass.Anydatathatcan
becasttoaBYTEarrayofknownlengthcanbechecksummedbythis
function.Typically,CStringandchararrayswillbechecksumed,
althoughthisfunctioncanbeusedtochecktheintegrityofanyBYTEarray.
Abufferofzerolengthcanbechecksummed;allbuffersofzerolength
willreturnthesamechecksum.
*****************************************************************************************/
CStringCMD5Checksum::GetMD5(BYTE*pBuf,UINTnLength)
{
//entryinvariants
AfxIsValidAddress(pBuf,nLength,FALSE);

//calculateandreturnthechecksum
CMD5ChecksumMD5Checksum;
MD5Checksum.Update(pBuf,nLength);
returnMD5Checksum.Final();
}


/*****************************************************************************************

FUNCTION: CMD5Checksum::RotateLeft
DETAILS: private
DESCRIPTION: Rotatesthebitsina32bitDWORDleftbyaspecifiedamount
RETURNS: TherotatedDWORD
ARGUMENTS: DWORDx:thevaluetoberotated
intn :thenumberofbitstorotateby
*****************************************************************************************/
DWORDCMD5Checksum::RotateLeft(DWORDx,intn)
{
//checkthatDWORDis4byteslong-trueinVisualC 6and32bitWindows
ASSERT(sizeof(x)==4);

//rotateandreturnx
return(x<>(32-n));
}


/*****************************************************************************************
FUNCTION: CMD5Checksum::FF
DETAILS: protected
DESCRIPTION: ImplementationofbasicMD5transformationalgorithm
RETURNS: none
ARGUMENTS: DWORD&A,B,C,D:Current(partial)checksum
DWORDX :Inputdata
DWORDS :MD5_SXXTransformationconstant
DWORDT : MD5_TXXTransformationconstant
NOTES: None
*****************************************************************************************/
voidCMD5Checksum::FF(DWORD&A,DWORDB,DWORDC,DWORDD,DWORDX,DWORDS,DWORDT)
{
DWORDF=(B&C)|(~B&D);
A =F X T;
A=RotateLeft(A,S);
A =B;
}


/*****************************************************************************************
FUNCTION: CMD5Checksum::GG
DETAILS: protected
DESCRIPTION: ImplementationofbasicMD5transformationalgorithm
RETURNS: none
ARGUMENTS: DWORD&A,B,C,D:Current(partial)checksum
DWORDX :Inputdata
DWORDS :MD5_SXXTransformationconstant
DWORDT : MD5_TXXTransformationconstant
NOTES: None
*****************************************************************************************/
voidCMD5Checksum::GG(DWORD&A,DWORDB,DWORDC,DWORDD,DWORDX,DWORDS,DWORDT)
{
DWORDG=(B&D)|(C&~D);
A =G X T;
A=RotateLeft(A,S);
A =B;
}


/*****************************************************************************************
FUNCTION: CMD5Checksum::HH
DETAILS: protected
DESCRIPTION: ImplementationofbasicMD5transformationalgorithm
RETURNS: none
ARGUMENTS: DWORD&A,B,C,D:Current(partial)checksum
DWORDX :Inputdata
DWORDS :MD5_SXXTransformationconstant
DWORDT : MD5_TXXTransformationconstant
NOTES: None
*****************************************************************************************/
voidCMD5Checksum::HH(DWORD&A,DWORDB,DWORDC,DWORDD,DWORDX,DWORDS,DWORDT)
{
DWORDH=(B^C^D);
A =H X T;
A=RotateLeft(A,S);
A =B;
}


/*****************************************************************************************
FUNCTION: CMD5Checksum::II
DETAILS: protected
DESCRIPTION: ImplementationofbasicMD5transformationalgorithm
RETURNS: none
ARGUMENTS: DWORD&A,B,C,D:Current(partial)checksum
DWORDX :Inputdata
DWORDS :MD5_SXXTransformationconstant

DWORDT : MD5_TXXTransformationconstant
NOTES: None
*****************************************************************************************/
voidCMD5Checksum::II(DWORD&A,DWORDB,DWORDC,DWORDD,DWORDX,DWORDS,DWORDT)
{
DWORDI=(C^(B|~D));
A =I X T;
A=RotateLeft(A,S);
A =B;
}


/*****************************************************************************************
FUNCTION: CMD5Checksum::ByteToDWord
DETAILS: private
DESCRIPTION: Transfersthedatainan8bitarraytoa32bitarray
RETURNS: void
ARGUMENTS: DWORD*Output:the32bit(unsignedlong)destinationarray
BYTE*Input :the8bit(unsignedchar)sourcearray
UINTnLength :thenumberof8bitdataitemsinthesourcearray
NOTES: FourBYTESfromtheinputarrayaretransferredtoeachDWORDentry
oftheoutputarray.ThefirstBYTEistransferredtothebits(0-7)
oftheoutputDWORD,thesecondBYTEtobits8-15etc.
Thealgorithmassumesthattheinputarrayisamultipleof4byteslong
sothatthereisaperfectfitintothearrayof32bitwords.
*****************************************************************************************/
voidCMD5Checksum::ByteToDWord(DWORD*Output,BYTE*Input,UINTnLength)
{
//entryinvariants
ASSERT(nLength%4==0);
ASSERT(AfxIsValidAddress(Output,nLength/4,TRUE));
ASSERT(AfxIsValidAddress(Input,nLength,FALSE));

//initialisations
UINTi=0; //indextoOutputarray
UINTj=0; //indextoInputarray

//transferthedatabyshiftingandcopying
for(;j{
Output[i]=(ULONG)Input[j] |
(ULONG)Input[j 1]<<8 |
(ULONG)Input[j 2]<<16|
(ULONG)Input[j 3]<<24;
}
}

/*****************************************************************************************
FUNCTION: CMD5Checksum::Transform
DETAILS: protected
DESCRIPTION: MD5basictransformationalgorithm; transforms'm_lMD5'
RETURNS: void
ARGUMENTS: BYTEBlock[64]
NOTES: AnMD5checksumiscalculatedbyfourroundsof'Transformation'.
TheMD5checksumcurrentlyheldinm_lMD5ismergedbythe
transformationprocesswithdatapassedin'Block'. 
*****************************************************************************************/
voidCMD5Checksum::Transform(BYTEBlock[64])
{
//initialiselocaldatawithcurrentchecksum
ULONGa=m_lMD5[0];
ULONGb=m_lMD5[1];
ULONGc=m_lMD5[2];
ULONGd=m_lMD5[3];

//copyBYTESfrominput'Block'toanarrayofULONGS'X'
ULONGX[16];
ByteToDWord(X,Block,64);

//PerformRound1ofthetransformation
FF(a,b,c,d,X[0],MD5_S11,MD5_T01);
FF(d,a,b,c,X[1],MD5_S12,MD5_T02);
FF(c,d,a,b,X[2],MD5_S13,MD5_T03);
FF(b,c,d,a,X[3],MD5_S14,MD5_T04);
FF(a,b,c,d,X[4],MD5_S11,MD5_T05);
FF(d,a,b,c,X[5],MD5_S12,MD5_T06);
FF(c,d,a,b,X[6],MD5_S13,MD5_T07);
FF(b,c,d,a,X[7],MD5_S14,MD5_T08);
FF(a,b,c,d,X[8],MD5_S11,MD5_T09);
FF(d,a,b,c,X[9],MD5_S12,MD5_T10);
FF(c,d,a,b,X[10],MD5_S13,MD5_T11);
FF(b,c,d,a,X[11],MD5_S14,MD5_T12);

FF(a,b,c,d,X[12],MD5_S11,MD5_T13);
FF(d,a,b,c,X[13],MD5_S12,MD5_T14);
FF(c,d,a,b,X[14],MD5_S13,MD5_T15);
FF(b,c,d,a,X[15],MD5_S14,MD5_T16);

//PerformRound2ofthetransformation
GG(a,b,c,d,X[1],MD5_S21,MD5_T17);
GG(d,a,b,c,X[6],MD5_S22,MD5_T18);
GG(c,d,a,b,X[11],MD5_S23,MD5_T19);
GG(b,c,d,a,X[0],MD5_S24,MD5_T20);
GG(a,b,c,d,X[5],MD5_S21,MD5_T21);
GG(d,a,b,c,X[10],MD5_S22,MD5_T22);
GG(c,d,a,b,X[15],MD5_S23,MD5_T23);
GG(b,c,d,a,X[4],MD5_S24,MD5_T24);
GG(a,b,c,d,X[9],MD5_S21,MD5_T25);
GG(d,a,b,c,X[14],MD5_S22,MD5_T26);
GG(c,d,a,b,X[3],MD5_S23,MD5_T27);
GG(b,c,d,a,X[8],MD5_S24,MD5_T28);
GG(a,b,c,d,X[13],MD5_S21,MD5_T29);
GG(d,a,b,c,X[2],MD5_S22,MD5_T30);
GG(c,d,a,b,X[7],MD5_S23,MD5_T31);
GG(b,c,d,a,X[12],MD5_S24,MD5_T32);

//PerformRound3ofthetransformation
HH(a,b,c,d,X[5],MD5_S31,MD5_T33);
HH(d,a,b,c,X[8],MD5_S32,MD5_T34);
HH(c,d,a,b,X[11],MD5_S33,MD5_T35);
HH(b,c,d,a,X[14],MD5_S34,MD5_T36);
HH(a,b,c,d,X[1],MD5_S31,MD5_T37);
HH(d,a,b,c,X[4],MD5_S32,MD5_T38);
HH(c,d,a,b,X[7],MD5_S33,MD5_T39);
HH(b,c,d,a,X[10],MD5_S34,MD5_T40);
HH(a,b,c,d,X[13],MD5_S31,MD5_T41);
HH(d,a,b,c,X[0],MD5_S32,MD5_T42);
HH(c,d,a,b,X[3],MD5_S33,MD5_T43);
HH(b,c,d,a,X[6],MD5_S34,MD5_T44);
HH(a,b,c,d,X[9],MD5_S31,MD5_T45);
HH(d,a,b,c,X[12],MD5_S32,MD5_T46);
HH(c,d,a,b,X[15],MD5_S33,MD5_T47);
HH(b,c,d,a,X[2],MD5_S34,MD5_T48);

//PerformRound4ofthetransformation
II(a,b,c,d,X[0],MD5_S41,MD5_T49);
II(d,a,b,c,X[7],MD5_S42,MD5_T50);
II(c,d,a,b,X[14],MD5_S43,MD5_T51);
II(b,c,d,a,X[5],MD5_S44,MD5_T52);
II(a,b,c,d,X[12],MD5_S41,MD5_T53);
II(d,a,b,c,X[3],MD5_S42,MD5_T54);
II(c,d,a,b,X[10],MD5_S43,MD5_T55);
II(b,c,d,a,X[1],MD5_S44,MD5_T56);
II(a,b,c,d,X[8],MD5_S41,MD5_T57);
II(d,a,b,c,X[15],MD5_S42,MD5_T58);
II(c,d,a,b,X[6],MD5_S43,MD5_T59);
II(b,c,d,a,X[13],MD5_S44,MD5_T60);
II(a,b,c,d,X[4],MD5_S41,MD5_T61);
II(d,a,b,c,X[11],MD5_S42,MD5_T62);
II(c,d,a,b,X[2],MD5_S43,MD5_T63);
II(b,c,d,a,X[9],MD5_S44,MD5_T64);

//addthetransformedvaluestothecurrentchecksum
m_lMD5[0] =a;
m_lMD5[1] =b;
m_lMD5[2] =c;
m_lMD5[3] =d;
}


/*****************************************************************************************
CONSTRUCTOR: CMD5Checksum
DESCRIPTION: Initialisesmemberdata
ARGUMENTS: None
NOTES: None
*****************************************************************************************/
CMD5Checksum::CMD5Checksum()
{
//zeromembers
memset(m_lpszBuffer,0,64);
m_nCount[0]=m_nCount[1]=0;

//Loadmagicstateinitializationconstants
m_lMD5[0]=MD5_INIT_STATE_0;
m_lMD5[1]=MD5_INIT_STATE_1;
m_lMD5[2]=MD5_INIT_STATE_2;
m_lMD5[3]=MD5_INIT_STATE_3;
}

/*****************************************************************************************
FUNCTION: CMD5Checksum::DWordToByte
DETAILS: private

DESCRIPTION: Transfersthedatainan32bitarraytoa8bitarray
RETURNS: void
ARGUMENTS: BYTE*Output :the8bitdestinationarray
DWORD*Input :the32bitsourcearray
UINTnLength :thenumberof8bitdataitemsinthesourcearray
NOTES: OneDWORDfromtheinputarrayistransferredintofourBYTES
intheoutputarray.Thefirst(0-7)bitsofthefirstDWORDare
transferredtothefirstoutputBYTE,bitsbits8-15aretransferredfrom
thesecondBYTEetc.

Thealgorithmassumesthattheoutputarrayisamultipleof4byteslong
sothatthereisaperfectfitof8bitBYTESintothe32bitDWORDs.
*****************************************************************************************/
voidCMD5Checksum::DWordToByte(BYTE*Output,DWORD*Input,UINTnLength)
{
//entryinvariants
ASSERT(nLength%4==0);
ASSERT(AfxIsValidAddress(Output,nLength,TRUE));
ASSERT(AfxIsValidAddress(Input,nLength/4,FALSE));

//transferthedatabyshiftingandcopying
UINTi=0;
UINTj=0;
for(;j{
Output[j]= (UCHAR)(Input[i]&0xff);
Output[j 1]=(UCHAR)((Input[i]>>8)&0xff);
Output[j 2]=(UCHAR)((Input[i]>>16)&0xff);
Output[j 3]=(UCHAR)((Input[i]>>24)&0xff);
}
}


/*****************************************************************************************
FUNCTION: CMD5Checksum::Final
DETAILS: protected
DESCRIPTION: ImplementationofmainMD5checksumalgorithm;endsthechecksumcalculation.
RETURNS: CString:thefinalhexadecimalMD5checksumresult
ARGUMENTS: None
NOTES: PerformsthefinalMD5checksumcalculation('Update'doesmostofthework,
thisfunctionjustfinishesthecalculation.)
*****************************************************************************************/
CStringCMD5Checksum::Final()
{
//Savenumberofbits
BYTEBits[8];
DWordToByte(Bits,m_nCount,8);

//Padoutto56mod64.
UINTnIndex=(UINT)((m_nCount[0]>>3)&0x3f);
UINTnPadLen=(nIndex<56)?(56-nIndex):(120-nIndex);
Update(PADDING,nPadLen);

//Appendlength(beforepadding)
Update(Bits,8);

//Storefinalstatein'lpszMD5'
constintnMD5Size=16;
unsignedcharlpszMD5[nMD5Size];
DWordToByte(lpszMD5,m_lMD5,nMD5Size);

//ConvertthehexadecimalchecksumtoaCString
CStringstrMD5;
for(inti=0;i{
CStringStr;
if(lpszMD5[i]==0){
Str=CString("00");
}
elseif(lpszMD5[i]<=15) {
Str.Format("0%x",lpszMD5[i]);
}
else{
Str.Format("%x",lpszMD5[i]);
}

ASSERT(Str.GetLength()==2);
strMD5 =Str;
}
ASSERT(strMD5.GetLength()==32);
returnstrMD5;
}


/*****************************************************************************************
FUNCTION: CMD5Checksum::Update
DETAILS: protected
DESCRIPTION: ImplementationofmainMD5checksumalgorithm
RETURNS: void
ARGUMENTS: BYTE*Input :inputblock
UINTnInputLen:lengthofinputblock

NOTES: ComputesthepartialMD5checksumfor'nInputLen'bytesofdatain'Input'
*****************************************************************************************/
voidCMD5Checksum::Update(BYTE*Input, ULONGnInputLen)
{
//Computenumberofbytesmod64
UINTnIndex=(UINT)((m_nCount[0]>>3)&0x3F);

//Updatenumberofbits
if((m_nCount[0] =nInputLen<<3) < (nInputLen<<3))
{
m_nCount[1] ;
}
m_nCount[1] =(nInputLen>>29);

//Transformasmanytimesaspossible.
UINTi=0; 
UINTnPartLen=64-nIndex;
if(nInputLen>=nPartLen) 
{
memcpy(&m_lpszBuffer[nIndex],Input,nPartLen);
Transform(m_lpszBuffer);
for(i=nPartLen;i 63{
Transform(&Input[i]);
}
nIndex=0;
}
else
{
i=0;
}

//Bufferremaininginput
memcpy(&m_lpszBuffer[nIndex],&Input[i],nInputLen-i);
}