1 执行简介
本文描述了MD5报文摘要算法,此算法将对输入的任意长度的信息进行计算,产生一个128位
长度的“指纹”或“报文摘要”,假定两个不同的文件产生相同的报文摘要或由给定的报文摘要产生
原始信息在计算上是行不通的。MD5算法适合用在数据签名应用中,在此应用中,一个大的文件必
须在类似RSA算法的公用密钥系统中用私人密钥加密前被“压缩”在一种安全模式下。
MD5算法能在32位机器上能以很快的速度运行。另外,MD5算法不需要任何大型的置换列表。
此算法编码很简洁。MD5算法是MD4报文摘要算法的扩展。MD5算法稍慢于MD4算法,但是在设
计上比MD4算法更加“保守”。设计MD5是因为MD4算法被采用的速度太快,以至于还无法证实
它的正确性,因为MD4算法速度非常快,它处在遭受成功秘密攻击的“边缘”。MD5后退了一步,
它舍弃了一些速度以求更好的安全性。它集中了不同的评论家提出的建议,并采取了一些附加的优化
措施。它被放在公共的地方以求公众的评论意见,它可能当作一个标准被采纳。
作为基于OSI的应用,MD5的对象标识符是:
md5OBJECTIDENTIFIER::=
iso(1)member-body(2)US(840)rsadsi(113549)digestAlgorithm(2)5}
在X.509类型AlgorithmIdentifier[3]中,MD5算法参数应该包括NULL类型。
2 术语和符号
本文中一个“字”是32位,一个“字节”是8位。一系列位串可看成是一系列字节的普通形式,
其中的连续的8位看成一个字节,高位在前,同理一系列字节串可看成是一系列32位的字,其中每
个连续的4个字节当作一个字,地位在前。
我们定义x_i代表“x减去I".假如下划线左边的是一个表达式,则用括号括住,如:
x_{i+1}。同样我们用^代表求幂,这样x^i则代表x的i次幂。
符号“+”代表字的加,X<<<s代表32位的值X循环左移s位,not(X)代表X的按位
补运算,XvY表示X和Y的按位或运算,XxorY代表X和Y的按位异或运算,XY代表
X和Y的按位与运算。
3 MD5算法描述
我们假设有一个b位长度的输入信号,希望产生它的报文摘要,此处b是一个非负整数,b也可
能是0,不一定必须是8的整数倍,它可能是任意大的长度。我们设想信号的比特流如下所示:
m_0m_1...m_{b-1}
下面的5步计算信息的报文摘要。
(1)补位
MD5算法是对输入的数据进行补位,使得假如数据位长度LEN对512求余的结果是448。即数
据扩展至K*512+448位。即K*64+56个字节,K为整数。补位操作始终要执行,即使数据长度LEN
对512求余的结果已是448。
具体补位操作:补一个1,然后补0至满足上述要求。总共最少要补一位,最多补512位。
(2)补数据长度
用一个64位的数字表示数据的原始长度b,把b用两个32位数表示。那么只取B的低64位。
当碰到b大于2^64这种极少碰到的情况时,这时,数据就被填补成长度为512位的倍数。也就是说,
此时的数据长度是16个字(32位)的整数倍数。用M[0...N-1]表示此时的数据,其中的N是16
的倍数。
(3)初始化MD缓冲器
用一个四个字的缓冲器(A,B,C,D)来计算报文摘要,A,B,C,D分别是32位的寄存器,初
始化使用的是十六进制表示的数字
A=0X01234567
B=0X89abcdef
C=0Xfedcba98
D=0X76543210
(4)处理位操作函数
首先定义4个辅助函数,每个函数的输入是三个32位的字,输出是一个32位的字。
X,Y,Z为32位整数。
F(X,Y,Z)=XYvnot(X)Z
G(X,Y,Z)=XZvYnot(Z)
H(X,Y,Z)=XxorYxorZ
I(X,Y,Z)=Yxor(Xvnot(Z))
这一步中使用一个64元素的常数组T[1...64],它由sine函数构成,T[i]表示数组中的第i个元
素,它的值等于经过4294967296次abs(sin(i))后的值的整数部分(其中i是弧度)。T[i]为32位
整数用16进制表示,数组元素在附录中给出。
具体过程如下:
/*处理数据原文*/
Fori=0toN/16-1do
/*每一次,把数据原文存放在16个元素的数组X中.*/
Forj=0to15do
SetX[j]toM[i*16+j].
end/结束对J的循环
/*SaveAasAA,BasBB,CasCC,andDasDD.*/
AA=A
BB=B
CC=C
DD=D
/*第1轮*/
/*以[abcdksi]表示如下操作
a=b+((a+F(b,c,d)+X[k]+T[i])<<<s).*/
/*Dothefollowing16operations.*/
[ABCD071][DABC1122][CDAB2173][BCDA3224]
[ABCD475][DABC5126][CDAB6177][BCDA7228]
[ABCD879][DABC91210][CDAB101711][BCDA112212]
[ABCD12713][DABC131214][CDAB141715][BCDA152216]
/*第2轮**/
/*以[abcdksi]表示如下操作
a=b+((a+G(b,c,d)+X[k]+T[i])<<<s).*/
/*Dothefollowing16operations.*/
[ABCD1517][DABC6918][CDAB111419][BCDA02020]
[ABCD5521][DABC10922][CDAB151423][BCDA42024]
[ABCD9525][DABC14926][CDAB31427][BCDA82028]
[ABCD13529][DABC2930][CDAB71431][BCDA122032]
/*第3轮*/
/*以[abcdksi]表示如下操作
a=b+((a+H(b,c,d)+X[k]+T[i])<<<s).*/
/*Dothefollowing16operations.*/
[ABCD5433][DABC81134][CDAB111635][BCDA142336]
[ABCD1437][DABC41138][CDAB71639][BCDA102340]
[ABCD13441][DABC01142][CDAB31643][BCDA62344]
[ABCD9445][DABC121146][CDAB151647][BCDA22348]
/*第4轮*/
/*以[abcdksi]表示如下操作
a=b+((a+I(b,c,d)+X[k]+T[i])<<<s).*/
/*Dothefollowing16operations.*/
[ABCD0649][DABC71050][CDAB141551][BCDA52152]
[ABCD12653][DABC31054][CDAB101555][BCDA12156]
[ABCD8657][DABC151058][CDAB61559][BCDA132160]
[ABCD4661][DABC111062][CDAB21563][BCDA92164]
/*然后进行如下操作*/
A=A+AA
B=B+BB
C=C+CC
D=D+DD
end/*结束对I的循环*/
(5)输出结果
报文摘要的产生后的形式为:A,B,C,D。也就是低位字节A开始,高位字节D结束。
现在完成了对MD5的描述,在附录中给出了C形式的程序。
4 摘要
MD5算法实现很轻易,它提供了任意长度的信息的“指纹”(或称为报文摘要)。据推测要实现
两个不同的报文产生相同的摘要需要2^64次的操作,要恢复给定摘要的报文则需要2^128次操作。
为寻找缺陷,MD5算法已经过非常细致的检查。最后的结论是还需要相关的更好的算法和更进一步
的安全分析。
5 MD4和MD5的区别
以下是MD5和MD4的不同点:
1. 加上了第四轮循环。
2. 每一步增加了一个唯一的常数值。
第二轮中的函数g从(XYvXZvYZ)变成了(XZvYnot(Z)),以减少g函数的均衡性。
6 参考文献
[1]Rivest,R.,"TheMD4MessageDigestAlgorithm",RFC1320,MITandRSADataSecurity,
Inc.,April1992.
[2]Rivest,R.,"TheMD4messagedigestalgorithm",inA.J.MenezesandS.A.Vanstone,
editors,AdvancesinCryptology-CRYPTO'90Proceedings,pages303-311,Springer-Verlag,
1991.
[3]CCITTRecommendationX.509(1988),"TheDirectory-Authentication
Framework."
7 附录A-参考应用程序
本附录包括以下文件:(摘自RSAREF:ACryptographicToolkitforPrivacy-EnhancedMail:)
global.h-全局头文件
md5.h--MD5头文件
md5c.c--MD5源代码
(要得到更多的RSAREF信息,请发e-mai到:<rsaref@rsa.com>.)
附录中还包括:
mddriver.c-MD2,MD4andMD5的测试驱动程序。
驱动程序默认情况下编译MD5,但假如在C的编译命令行将MD5参数设成2或4,则也可以编译
MD2和MD4
此应用程序是方便使用的,可用在不同的平台上,在非凡的平台上优化它也并不困难,这留给读
者作为练习。例如,在“little-endian”平台上,此平台32位字的最低地址字节最无意义的字节,
并且没有队列限制,在MD5变换中的解码的命令调用可以被相应的类型替代。
A1global.h
/*GLOBAL.H-RSAREF类型和常数*/
/*当且仅当编译器支持函数原型的声明时,PROTOTYPES必须被设置一次
假如还没有定义C编译器的标记,下面的代码使PROTOTYPES置为0。*/
#ifndefPROTOTYPES
#definePROTOTYPES0
#endif
/*POINTER定义成一个普通的指针类型*/
typedefunsignedchar*POINTER;
/*UINT2定义成两字节的字*/
typedefunsignedshortintUINT2;
/*UINT4定一成四字节的字*/
typedefunsignedlongintUINT4;
/*PROTO_LIST的定义依靠于上面PROTOTYPES的定义,假如使用了PROTOTYPES,那么
PROTO_LIST返回此列表,否则返回一个空列表。*/
#ifPROTOTYPES
#definePROTO_LIST(list)list
#else
#definePROTO_LIST(list)()
#endif
A.2md5.h
/*MD5.H-MD5C.C头文件*/
/*本软件答应被复制或运用,但必须在所有提及和参考的地方标注“RSADataSecurity,Inc.MD5
Message-DigestAlgorithm”,也答应产生或运用派生软件,但必须在所有提及和参考的地方标明
“derivedfromtheRSADataSecurity,Inc.MD5Message-DigestAlgorithm”
RSA数据安全公司(RSADataSecurity,Inc.)从来没有出于任何特定目的陈述过关于此
软件的可买性和实用性,它提供了“asis”,没有表达或暗示过任何理由。
此声明必须在任何此文件和软件的任何拷贝中保留。*/
/*MD5context.*/
typedefstrUCt
{
UINT4state[4];/*state(ABCD)*/
UINT4count[2];/*位数量,模2^64(低位在前)*/
unsignedcharbuffer[64];/*输入缓冲器*/
}MD5_CTX;
voidMD5InitPROTO_LIST((MD5_CTX*));
voidMD5UpdatePROTO_LIST
((MD5_CTX*,unsignedchar*,unsignedint));
voidMD5FinalPROTO_LIST((unsignedchar[16],MD5_CTX*));
A.3md5c.c
/*MD5C.C–RSA数据安全公司,MD5报文摘要算法*/
/*本软件答应被复制或运用,但必须在所有提及和参考的地方标注“RSADataSecurity,Inc.MD5
Message-DigestAlgorithm”也答应产生或运用派生软件,但必须在所有提及和参考的地方标明
“derivedfromtheRSADataRSA数据安全公司(RSADataSecurity,Inc.)从来没有出于任何
特定目的陈述过关于此软件的可买性和实用性,它提供了“asis”,没有表达或暗示过任何理由。
此声明必须在任何此文件和软件的任何拷贝中保留。*/
#include"global.h"
#include"md5.h"
/*ConstantsforMD5Transformroutine.
*/
#defineS117
#defineS1212
#defineS1317
#defineS1422
#defineS215
#defineS229
#defineS2314
#defineS2420
#defineS314
#defineS3211
#defineS3316
#defineS3423
#defineS416
#defineS4210
#defineS4315
#defineS4421
staticvoidMD5TransformPROTO_LIST((UINT4[4],unsignedchar[64]));
staticvoidEncodePROTO_LIST
((unsignedchar*,UINT4*,unsignedint));
staticvoidDecodePROTO_LIST
((UINT4*,unsignedchar*,unsignedint));
staticvoidMD5_memcpyPROTO_LIST((POINTER,POINTER,unsignedint));
staticvoidMD5_memsetPROTO_LIST((POINTER,int,unsignedint));
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
};
/*F,G,H和I是基本MD5函数*/
#defineF(x,y,z)(((x)&(y))((~x)&(z)))
#defineG(x,y,z)(((x)&(z))((y)&(~z)))
#defineH(x,y,z)((x)^(y)^(z))
#defineI(x,y,z)((y)^((x)(~z)))
/*ROTATE_LEFT将x循环左移n位*/
#defiNeroTATE_LEFT(x,n)(((x)<<(n))((x)>>(32-(n))))
/*循环从加法中分离出是为了防止重复计算*/
#defineFF(a,b,c,d,x,s,ac){(a)+=F((b),(c),(d))+(x)+(UINT4)(ac);(a)=ROTATE_LEFT((a),(s));(a)+=(b);}
#defineGG(a,b,c,d,x,s,ac){(a)+=G((b),(c),(d))+(x)+(UINT4)(ac);(a)=ROTATE_LEFT((a),(s));(a)+=(b);}
#defineHH(a,b,c,d,x,s,ac){(a)+=H((b),(c),(d))+(x)+(UINT4)(ac);(a)=ROTATE_LEFT((a),(s));(a)+=(b);}
#defineII(a,b,c,d,x,s,ac){(a)+=I((b),(c),(d))+(x)+(UINT4)(ac);(a)=ROTATE_LEFT((a),(s));(a)+=(b);}
/*MD5初始化.开始一个MD5操作写一个新的context.*/
voidMD5Init(context)
MD5_CTX*context;/*context*/
{
context->count[0]=context->count[1]=0;
context->state[0]=0x67452301;
context->state[1]=0xefcdab89;
context->state[2]=0x98badcfe;
context->state[3]=0x10325476;
}
/*MD5分组更新操作.继续一个MD5操作,处理另一个消息分组并更新context.*/
voidMD5Update(context,input,inputLen)
MD5_CTX*context;/*context*/
unsignedchar*input;/*输入分组*/
unsignedintinputLen;/*输入的分组的长度*/
{
unsignedinti,index,partLen;
/*计算字节数模64的值*/
index=(unsignedint)((context->count[0]>>3)&0x3F);
/*Updatenumberofbits*/
if((context->count[0]+=((UINT4)inputLen<<3))
<((UINT4)inputLen<<3))
context->count[1]++;
context->count[1]+=((UINT4)inputLen>>29);
partLen=64-index;
/*按能达到的最大次数转换*/
if(inputLen>=partLen){
MD5_memcpy
((POINTER)&context->buffer[index],(POINTER)input,partLen);
MD5Transform(context->state,context->buffer);
for(i=partLen;i+63<inputLen;i+=64)
MD5Transform(context->state,&input[i]);
index=0;
}
else
i=0;
/*缓冲器保留输入值*/
MD5_memcpy
((POINTER)&context->buffer[index],(POINTER)&input[i],
inputLen-i);
}
/*MD5最终结果.以一个MD5报文摘要操作结束,写下报文摘要值*/
voidMD5Final(digest,context)
unsignedchardigest[16];/*报文摘要*/
MD5_CTX*context;/*context*/
{
unsignedcharbits[8];
unsignedintindex,padLen;
/*保存位数值*/
Encode(bits,context->count,8);
index=(unsignedint)((context->count[0]>>3)&0x3f);
padLen=(index<56)?(56-index):(120-index);
MD5Update(context,PADDING,padLen);
/*附加长度(在补位之前)*/
MD5Update(context,bits,8);
/*将state存入digest中*/
Encode(digest,context->state,16);
MD5_memset((POINTER)context,0,sizeof(*context));
}
/*MD5基本转换.转换状态基于分组*/
staticvoidMD5Transform(state,block)
UINT4state[4];
unsignedcharblock[64];
{
UINT4a=state[0],b=state[1],c=state[2],d=state[3],x[16];
Decode(x,block,64);
/*Round1*/
FF(a,b,c,d,x[0],S11,0xd76aa478);/*1*/
FF(d,a,b,c,x[1],S12,0xe8c7b756);/*2*/
FF(c,d,a,b,x[2],S13,0x242070db);/*3*/
FF(b,c,d,a,x[3],S14,0xc1bdceee);/*4*/
FF(a,b,c,d,x[4],S11,0xf57c0faf);/*5*/
FF(d,a,b,c,x[5],S12,0x4787c62a);/*6*/
FF(c,d,a,b,x[6],S13,0xa8304613);/*7*/
FF(b,c,d,a,x[7],S14,0xfd469501);/*8*/
FF(a,b,c,d,x[8],S11,0x698098d8);/*9*/
FF(d,a,b,c,x[9],S12,0x8b44f7af);/*10*/
FF(c,d,a,b,x[10],S13,0xffff5bb1);/*11*/
FF(b,c,d,a,x[11],S14,0x895cd7be);/*12*/
FF(a,b,c,d,x[12],S11,0x6b901122);/*13*/
FF(d,a,b,c,x[13],S12,0xfd987193);/*14*/
FF(c,d,a,b,x[14],S13,0xa679438e);/*15*/
FF(b,c,d,a,x[15],S14,0x49b40821);/*16*/
/*Round2*/
GG(a,b,c,d,x[1],S21,0xf61e2562);/*17*/
GG(d,a,b,c,x[6],S22,0xc040b340);/*18*/
GG(c,d,a,b,x[11],S23,0x265e5a51);/*19*/
GG(b,c,d,a,x[0],S24,0xe9b6c7aa);/*20*/
GG(a,b,c,d,x[5],S21,0xd62f105d);/*21*/
GG(d,a,b,c,x[10],S22,0x2441453);/*22*/
GG(c,d,a,b,x[15],S23,0xd8a1e681);/*23*/
GG(b,c,d,a,x[4],S24,0xe7d3fbc8);/*24*/
GG(a,b,c,d,x[9],S21,0x21e1cde6);/*25*/
GG(d,a,b,c,x[14],S22,0xc33707d6);/*26*/
GG(c,d,a,b,x[3],S23,0xf4d50d87);/*27*/
GG(b,c,d,a,x[8],S24,0x455a14ed);/*28*/
GG(a,b,c,d,x[13],S21,0xa9e3e905);/*29*/
GG(d,a,b,c,x[2],S22,0xfcefa3f8);/*30*/
GG(c,d,a,b,x[7],S23,0x676f02d9);/*31*/
GG(b,c,d,a,x[12],S24,0x8d2a4c8a);/*32*/
/*Round3*/
HH(a,b,c,d,x[5],S31,0xfffa3942);/*33*/
HH(d,a,b,c,x[8],S32,0x8771f681);/*34*/
HH(c,d,a,b,x[11],S33,0x6d9d6122);/*35*/
HH(b,c,d,a,x[14],S34,0xfde5380c);/*36*/
HH(a,b,c,d,x[1],S31,0xa4beea44);/*37*/
HH(d,a,b,c,x[4],S32,0x4bdecfa9);/*38*/
HH(c,d,a,b,x[7],S33,0xf6bb4b60);/*39*/
HH(b,c,d,a,x[10],S34,0xbebfbc70);/*40*/
HH(a,b,c,d,x[13],S31,0x289b7ec6);/*41*/
HH(d,a,b,c,x[0],S32,0xeaa127fa);/*42*/
HH(c,d,a,b,x[3],S33,0xd4ef3085);/*43*/
HH(b,c,d,a,x[6],S34,0x4881d05);/*44*/
HH(a,b,c,d,x[9],S31,0xd9d4d039);/*45*/
HH(d,a,b,c,x[12],S32,0xe6db99e5);/*46*/
HH(c,d,a,b,x[15],S33,0x1fa27cf8);/*47*/
HH(b,c,d,a,x[2],S34,0xc4ac5665);/*48*/
/*Round4*/
II(a,b,c,d,x[0],S41,0xf4292244);/*49*/
II(d,a,b,c,x[7],S42,0x432aff97);/*50*/
II(c,d,a,b,x[14],S43,0xab9423a7);/*51*/
II(b,c,d,a,x[5],S44,0xfc93a039);/*52*/
II(a,b,c,d,x[12],S41,0x655b59c3);/*53*/
II(d,a,b,c,x[3],S42,0x8f0ccc92);/*54*/
II(c,d,a,b,x[10],S43,0xffeff47d);/*55*/
II(b,c,d,a,x[1],S44,0x85845dd1);/*56*/
II(a,b,c,d,x[8],S41,0x6fa87e4f);/*57*/
II(d,a,b,c,x[15],S42,0xfe2ce6e0);/*58*/
II(c,d,a,b,x[6],S43,0xa3014314);/*59*/
II(b,c,d,a,x[13],S44,0x4e0811a1);/*60*/
II(a,b,c,d,x[4],S41,0xf7537e82);/*61*/
II(d,a,b,c,x[11],S42,0xbd3af235);/*62*/
II(c,d,a,b,x[2],S43,0x2ad7d2bb);/*63*/
II(b,c,d,a,x[9],S44,0xeb86d391);/*64*/
state[0]+=a;
state[1]+=b;
state[2]+=c;
state[3]+=d;
MD5_memset((POINTER)x,0,sizeof(x));
}
/*将输入(UINT4)编码输出(unsignedchar).假设len是4的倍数*/
staticvoidEncode(output,input,len)
unsignedchar*output;
UINT4*input;
unsignedintlen;
{
unsignedinti,j;
for(i=0,j=0;j<len;i++,j+=4){
output[j]=(unsignedchar)(input[i]&0xff);
output[j+1]=(unsignedchar)((input[i]>>8)&0xff);
output[j+2]=(unsignedchar)((input[i]>>16)&0xff);
output[j+3]=(unsignedchar)((input[i]>>24)&0xff);
}
}
/*将输入(unsignedchar)解码输出(UINT4).假设len是4的倍数*/
staticvoidDecode(output,input,len)
UINT4*output;
unsignedchar*input;
unsignedintlen;
{
unsignedinti,j;
for(i=0,j=0;j<len;i++,j+=4)
output[i]=((UINT4)input[j])(((UINT4)input[j+1])<<8)
(((UINT4)input[j+2])<<16)(((UINT4)input[j+3])<<24);
}
staticvoidMD5_memcpy(output,input,len)
POINTERoutput;
POINTERinput;
unsignedintlen;
{
unsignedinti;
for(i=0;i<len;i++)
output[i]=input[i];
}
staticvoidMD5_memset(output,value,len)
POINTERoutput;
intvalue;
unsignedintlen;
{
unsignedinti;
for(i=0;i<len;i++)
((char*)output)[i]=(char)value;
}
A.4mddriver.c
/*MDDRIVER.C-MD2,MD4andMD5测试程序*/
/*RSA数据安全公司(RSADataSecurity,Inc.)从来没有出于任何特定目的陈述过关于此软
件的可买性和实用性,它提供了“asis”,没有表达或暗示过任何理由。
此声明必须在任何此文件和软件的任何拷贝中保留。*/
/*假如没有定义C编译标志的值,则MD5缺省状态下为MD5*/
#ifndefMD
#defineMDMD5
#endif
#include<stdio.h>
#include<time.h>
#include<string.h>
#include"global.h"
#ifMD==2
#include"md2.h"
#endif
#ifMD==4
#include"md4.h"
#endif
#ifMD==5
#include"md5.h"
#endif
/*测试分组长度和数量*/
#defineTEST_BLOCK_LEN1000
#defineTEST_BLOCK_COUNT1000
staticvoidMDStringPROTO_LIST((char*));
staticvoidMDTimeTrialPROTO_LIST((void));
staticvoidMDTestSuitePROTO_LIST((void));
staticvoidMDFilePROTO_LIST((char*));
staticvoidMDFilterPROTO_LIST((void));
staticvoidMDPrintPROTO_LIST((unsignedchar[16]));
#ifMD==2
#defineMD_CTXMD2_CTX
#defineMDInitMD2Init
#defineMDUpdateMD2Update
#defineMDFinalMD2Final
#endif
#ifMD==4
#defineMD_CTXMD4_CTX
#defineMDInitMD4Init
#defineMDUpdateMD4Update
#defineMDFinalMD4Final
#endif
#ifMD==5
#defineMD_CTXMD5_CTX
#defineMDInitMD5Init
#defineMDUpdateMD5Update
#defineMDFinalMD5Final
#endif
/*主程序.
变量:
-sstring–摘要字符串
-t-运行时间测试
-x-运行测试脚本
filename–摘要文件
(none)-摘要标准输入
*/
intmain(argc,argv)
intargc;
char*argv[];
{
inti;
if(argc>1)
for(i=1;i<argc;i++)
if(argv[i][0]=='-'&&argv[i][1]=='s')
MDString(argv[i]+2);
elseif(strcmp(argv[i],"-t")==0)
MDTimeTrial();
elseif(strcmp(argv[i],"-x")==0)
MDTestSuite();
else
MDFile(argv[i]);
else
MDFilter();
return(0);
}
/*计算字符串的摘要并打印其值*/
staticvoidMDString(string)
char*string;
{
MD_CTXcontext;
unsignedchardigest[16];
unsignedintlen=strlen(string);
MDInit(&context);
MDUpdate(&context,string,len);
MDFinal(digest,&context);
printf("MD%d(\"%s\")=",MD,string);
MDPrint(digest);
printf("\n");
}
/*测试计算TEST_BLOCK_COUNTTEST_BLOCK_LEN-byte
分组摘要的时间*/
staticvoidMDTimeTrial()
{
MD_CTXcontext;
time_tendTime,startTime;
unsignedcharblock[TEST_BLOCK_LEN],digest[16];
unsignedinti;
printf
("MD%dtimetrial.Digesting%d%d-byteblocks...",MD,
TEST_BLOCK_LEN,TEST_BLOCK_COUNT);
/*初始化分组*/
for(i=0;i<TEST_BLOCK_LEN;i++)
block[i]=(unsignedchar)(i&0xff);
/*开始时钟*/
time(&startTime);
/*摘要分组*/
MDInit(&context);
for(i=0;i<TEST_BLOCK_COUNT;i++)
MDUpdate(&context,block,TEST_BLOCK_LEN);
MDFinal(digest,&context);
/*停止时钟*/
time(&endTime);
printf("done\n");
printf("Digest=");
MDPrint(digest);
printf("\nTime=%ldseconds\n",(long)(endTime-startTime));
printf
("Speed=%ldbytes/second\n",
(long)TEST_BLOCK_LEN*(long)TEST_BLOCK_COUNT/(endTime-startTime));
}
/*计算一个参考组件串的摘要并打印结果*/
staticvoidMDTestSuite()
{
printf("MD%dtestsuite:\n",MD);
MDString("");
MDString("a");
MDString("abc");
MDString("messagedigest");
MDString("abcdefghijklmnopqrstuvwxyz");
MDString
("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
MDString
("12345678901234567890123456789012345678901234567890123456789012345678901234567890");
}
/*计算一个文件的摘要并打印结果*/
staticvoidMDFile(filename)
char*filename;
{
FILE*file;
MD_CTXcontext;
intlen;
unsignedcharbuffer[1024],digest[16];
if((file=fopen(filename,"rb"))==NULL)
printf("%scan'tbeopened\n",filename);
else{
MDInit(&context);
while(len=fread(buffer,1,1024,file))
MDUpdate(&context,buffer,len);
MDFinal(digest,&context);
fclose(file);
printf("MD%d(%s)=",MD,filename);
MDPrint(digest);
printf("\n");
}
}
/*计算标准输入的摘要并打印结果*/
staticvoidMDFilter()
{
MD_CTXcontext;
intlen;
unsignedcharbuffer[16],digest[16];
MDInit(&context);
while(len=fread(buffer,1,16,stdin))
MDUpdate(&context,buffer,len);
MDFinal(digest,&context);
MDPrint(digest);
printf("\n");
}
/*打印一个16进制的摘要*/
staticvoidMDPrint(digest)
unsignedchardigest[16];
{
unsignedinti;
for(i=0;i<16;i++)
printf("%02x",digest[i]);
}
A.5测试组件
MD5测试组件(驱动程序选项"-x")应打印以下值:
MD5testsuite:
MD5("")=d41d8cd98f00b204e9800998ecf8427e
MD5("a")=0cc175b9c0f1b6a831c399e269772661
MD5("abc")=900150983cd24fb0d6963f7d28e17f72
MD5("messagedigest")=f96b697d7cb7938d525a2f31aaf161d0
MD5("abcdefghijklmnopqrstuvwxyz")=c3fcd3d76192e4007dfb496cca67e13b
MD5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")=
d174ab98d277d9f5a5611c2c9f419d9f
MD5("123456789012345678901234567890123456789012345678901234567890123456
78901234567890")=57edf4a22be3c955ac49da2e2107b67a
8 安全事项
本文中讨论的安全标准被认为已足够实现很高要求的基于公用密钥系统和MD5算法的数字签名
系统中。
9 作者地址
RonaldL.Rivest
MassachusettsInstituteofTechnology
LaboratoryforComputerScience
NE43-324
545TechnologySquare
Cambridge,MA02139-1986
Phone:(617)253-5880
EMail:rivest@theory.lcs.mit.edu