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輪**/
a=b+((a+G(b,c,d)+X[k]+T[i])<<<s).*/
[ABCD1517][DABC6918][CDAB111419][BCDA02020]
[ABCD5521][DABC10922][CDAB151423][BCDA42024]
[ABCD9525][DABC14926][CDAB31427][BCDA82028]
[ABCD13529][DABC2930][CDAB71431][BCDA122032]
/*第3輪*/
a=b+((a+H(b,c,d)+X[k]+T[i])<<<s).*/
[ABCD5433][DABC81134][CDAB111635][BCDA142336]
[ABCD1437][DABC41138][CDAB71639][BCDA102340]
[ABCD13441][DABC01142][CDAB31643][BCDA62344]
[ABCD9445][DABC121146][CDAB151647][BCDA22348]
/*第4輪*/
a=b+((a+I(b,c,d)+X[k]+T[i])<<<s).*/
[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到:<[email][email protected][/email]>.)
附錄中還包括:
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)()
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封包摘要算法*/
Message-DigestAlgorithm”也允許産生或運用派生軟體,但必須在所有提及和參考的地方标明
“derivedfromtheRSADataRSA資料安全公司(RSADataSecurity,Inc.)從來沒有出于任何
特定目的陳述過關于此軟體的可買性和實用性,它提供了“asis”,沒有表達或暗示過任何理由。
#i nclude"global.h"
#i nclude"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);\
#defineHH(a,b,c,d,x,s,ac){\
(a)+=H((b),(c),(d))+(x)+(UINT4)(ac);\
#defineII(a,b,c,d,x,s,ac){\
(a)+=I((b),(c),(d))+(x)+(UINT4)(ac);\
/*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)
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;
/*緩沖器保留輸入值*/
((POINTER)&context->buffer[index],(POINTER)&input[i],
inputLen-i);
/*MD5最終結果.以一個MD5封包摘要操作結束,寫下封包摘要值*/
voidMD5Final(digest,context)
unsignedchardigest[16];/*封包摘要*/
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;
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;
unsignedinti;
for(i=0;i<len;i++)
output[i]=input[i];
staticvoidMD5_memset(output,value,len)
intvalue;
((char*)output)[i]=(char)value;
A.4mddriver.c
/*MDDRIVER.C-MD2,MD4andMD5測試程式*/
/*RSA資料安全公司(RSADataSecurity,Inc.)從來沒有出于任何特定目的陳述過關于此軟
件的可買性和實用性,它提供了“asis”,沒有表達或暗示過任何理由。
/*如果沒有定義C編譯标志的值,則MD5預設狀态下為MD5*/
#ifndefMD
#defineMDMD5
#i nclude<stdio.h>
#i nclude<time.h>
#i nclude<string.h>
#ifMD==2
#i nclude"md2.h"
#ifMD==4
#i nclude"md4.h"
#ifMD==5
/*測試分組長度和數量*/
#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]));
#defineMD_CTXMD2_CTX
#defineMDInitMD2Init
#defineMDUpdateMD2Update
#defineMDFinalMD2Final
#defineMD_CTXMD4_CTX
#defineMDInitMD4Init
#defineMDUpdateMD4Update
#defineMDFinalMD4Final
#defineMD_CTXMD5_CTX
#defineMDInitMD5Init
#defineMDUpdateMD5Update
#defineMDFinalMD5Final
/*主程式.
變量:
-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();
MDFile(argv[i]);
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()
time_tendTime,startTime;
unsignedcharblock[TEST_BLOCK_LEN],digest[16];
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);
/*摘要分組*/
for(i=0;i<TEST_BLOCK_COUNT;i++)
MDUpdate(&context,block,TEST_BLOCK_LEN);
/*停止時鐘*/
time(&endTime);
printf("done\n");
printf("Digest=");
printf("\nTime=%ldseconds\n",(long)(endTime-startTime));
("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");
("1234567890123456789012345678901234567890\
1234567890123456789012345678901234567890");
/*計算一個檔案 的摘要并列印結果*/
staticvoidMDFile(filename)
char*filename;
FILE*file;
intlen;
unsignedcharbuffer[1024],digest[16];
if((file=fopen(filename,"rb"))==NULL)
printf("%scan'tbeopened\n",filename);
else{
while(len=fread(buffer,1,1024,file))
MDUpdate(&context,buffer,len);
fclose(file);
printf("MD%d(%s)=",MD,filename);
/*計算标準輸入的摘要并列印結果*/
staticvoidMDFilter()
unsignedcharbuffer[16],digest[16];
while(len=fread(buffer,1,16,stdin))
/*列印一個16進制的摘要*/
staticvoidMDPrint(digest)
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:[email protected]
本文轉自loveme2351CTO部落格,原文連結:http://blog.51cto.com/loveme23/8217 ,如需轉載請自行聯系原作者