RFC-1321 MD5信息-摘要算法

Network Working Group                                        R. Rivest
Request for Comments: 1321           MIT Laboratory for Computer Science
                                            and RSA Data Security, Inc.
                                                           April 1992

備忘錄說明

   
這份備忘錄僅僅為因特網社區提供信息。它不會被指定為因特網的一個標準。發布本備
   
忘錄是不受限制的。

鳴謝

  Don Coppersmith, Burt Kaliski, Ralph Merkle,David Chaum, Noam Nisan向本文
   
提供極大的幫助,在此表示忠心的感謝。


目錄

    1.內容提要                                                              1
    2
.專業術語和符號                                                        2
    3
.MD5算法描述                                                           3
    4.摘要                                                                  6
    5.MD4
MD5的區別                                                       6
   
引用                                                                    7
   
附錄A – 參考實現                                                       7
   
安全性                                                                  21
   
作者地址                                                                21

1.內容提要

    這份文件描述了MD5信息-摘要算法。該算法接收一段任意長度的信息輸入,然后輸出
   
該消息的128比特的“指紋”或者“消息摘要”。可以認為
假定兩個不同的文件產生相
   
同的報文摘要或由給定的報文摘要產生原始信息在計算上是行不通的MD5算法適合用
   
在數據簽名應用中,在此應用中,一個大的文件必須在類似RSA算法的公用密鑰系統中
   
用私人密鑰加密前被壓縮在一種安全模式下


    MD5
算法被設計成能在32位機器上快速運行。特別的是,MD5算法不需要任何巨大的置
   
換表;算法能夠被緊湊的實現。

    MD5
算法是MD4信息-摘要算法的擴展。它比MD4運行慢,但是被設計得更加“保守”。
   
設計MD5算法的原因是感覺到MD4算法的應用速度遠遠快于理論上的證明速度;因為
    MD4
被運算速度非常快,導致它處在遭受成功秘密攻擊的邊緣。
MD5后退了一步,它舍
   
棄了一些速度以求更好的安全性。它集中了不同的評論家提出的建議,并采取了一些附
   
加的優化措施。它被放在公共的地方以求公眾的評論意見,它可能當作一個標準被采納。

   
作為基于OSI的基礎應用,MD5的對象標識符是:
   
    md5 OBJECT IDENTIFIER ::=
        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_ix減去i,如果減數是一個表達式,則用大括號括住,如x_{i+1}。同樣的,
   
我們用^代表冪,因此,x^i代表xi次冪。

   
定義符號“+”為“字”的加法。定義x<<<s32位的x循環左移s位。定義not(s)
   
為對x按位求補,xvyxy按位或,xXORyxy按位異或,xyxy按位與。

3.MD5算法描述

    我們假設有一段b位的信息輸入,并且我們想要找到他的信息摘要。這里b是一個任意
   
的無符號整數;b可能為0;它不一定是8的倍數,也可能是任意大的長度。我們假想
   
信息串的比特流如下:

    m_0 m_1...m_(b-1)

   
接下來的5個步驟描述了如何計算該信息的摘要。

3.1 附加填充位

    消息需要進行填充,使得它的長度()512求余為448,即消息的長度加上64比特
   
后剛好是512的整數倍。填充是必需進行的,即使消息的長度對512求余的結果已經是
    448


   
填充規則如下:先填充一比特的“1”,然后一直填充“0”,直到消息的長度對512求余
   
的結果是448。總共,至少要填充1比特,最多填充512比特。

3.2 附加長度

   
一個64位的無符號整數b(消息被填充前的長度)被附加在先前被填充的消息后面。如
   
b的實際長度超過64位,只附加b的低64(這些比特會被放在兩個32位的字中,
   
填充的時候按照先前的約定,低位優先)

   
此時,目標消息(被填充了附加位和長度b)的長度剛好是512比特的整數倍。即,消息
   
的長度剛好是16個字(32)的整數倍。定義M[0 ... N-1]為目標消息的字串,N16
   
的整數倍。

3.3 初始化MD緩存

   
一個4個字的緩存(A,B,C,D)被用于計算消息的摘要。這里每一個A,B,C,D都是一個32
   
位的寄存器。這些寄存器使用如下的16進制的值進行初始化(低位優先)

    A :
01 23 45 67
    B :
89 ab cd ef
    C :
fe dc ba 98
    D :
76 54 32 10

3.4 16個字一組處理消息

   
我們首先定義4個輔助函數,每個函數的輸入是332位的字,輸出是132位的字。

    F(X,Y,Z) = XY v not(x) Z
    G(X,Y,Z) = XZ v Y not(Z)
    H(X,Y,Z) = X xor Y xor Z

I(X,Y,Z) = Y xor (X v not(Z))

   
在每一個比特位置,F有約束:如果XY,否則Z(函數F v 可以被符號 + 替代,
   
因為 XY not(x) Z 不可能再同一個比特位置上都為“1) 注意到如果比特流X,Y
   
Z是各自獨立的和公正的,則F(X,Y,Z)的每個比特也是各自獨立的和公正的。

   
函數G,HI與函數F相類似,它們都是“按位平行”從X,Y,Z比特流中產生輸出,這
   
樣的方式使得如果X,Y,Z對應的比特是各自獨立的和公正的,則G(X,Y,Z), H(X,Y,Z),
    I(X,Y,Z)
的每個比特也是各自獨立的和公正的。注意到函數H是一個對輸入進行按位異
   
或或等于的函數(譯者注:原文
Note that the function H is the bit-wise "xor" or
    "parity" function of its inputs
)


   
這一步需要用到一個64位的常數組T[1...64],它有sine函數構造。定義T[i]位常數
   
組中的第i個元素,它的值等于
經過4294967296abs(sin(i))后的值的整數部分(其
   
i是弧度 )
。數組元素在附錄中給出。

        
過程如下:


        
/*16個字節一組處理*/
    For i=0 to N/16-1 do

        /*
把第i組放入X*/
        For j=0 to 15 do
            Set x[j] to M[i*16+j]
        end/*j
的循環*/

        /*
A存入AAB存入BBC存入CCD存入DD*/
        AA = A
        BB = B
        CC = C
        DD = D

        /*
第一次循環*/
        /*
定義[abcd k s i]為操作
          a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s )*/
        /*
執行16次操作*/
       
[ABCD  0 7  1] [DABC  1 12  2] [CDAB  2 17  3] [BCDA  3 22  4]

[ABCD  4 7  5] [DABC  5 12  6] [CDAB  6 17  7] [BCDA  7 22  8]

[ABCD  8 7  9] [DABC  9 12 10] [CDAB 10 17 11] [BCDA 11 22 12]

[ABCD 12 7 13] [DABC 13 12 14] [CDAB 14 17 15] [BCDA 15 22 16]

/*第二次循環*/
/*
定義[abcd k s i]為操作
 a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s )*/
/*
執行16次操作*/
[ABCD  1 5 17] [DABC  6 9 18] [CDAB 11 14 19] [BCDA  0 20 20]

[ABCD  5 5 21] [DABC 10 9 22] [CDAB 15 14 23] [BCDA  4 20 24]

[ABCD  9 5 25] [DABC 14 9 26] [CDAB  3 14 27] [BCDA  8 20 28]

[ABCD 13 5 29] [DABC  2 9 30] [CDAB  7 14 31] [BCDA 12 20 32]

   
/*第三次循環*/
    /*
定義[abcd k s i]為操作
      a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s )*/
    /*
執行16次操作*/
   
[ABCD  5 4 33] [DABC  8 11 34] [CDAB 11 16 35] [BCDA 14 23 36]

[ABCD  1 4 37] [DABC  4 11 38] [CDAB  7 16 39] [BCDA 10 23 40]

[ABCD 13 4 41] [DABC  0 11 42] [CDAB  3 16 43] [BCDA  6 23 44]

[ABCD  9 4 45] [DABC 12 11 46] [CDAB 15 16 47] [BCDA  2 23 48]

   
/*第四次循環*/
    /*
定義[abcd k s i]為操作
      a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s )*/
    /*
執行16次操作*/
   
[ABCD  0 6 49] [DABC  7 10 50] [CDAB 14 15 51] [BCDA  5 21 52]

[ABCD 12 6 53] [DABC  3 10 54] [CDAB 10 15 55] [BCDA  1 21 56]

[ABCD  8 6 57] [DABC 15 10 58] [CDAB  6 15 59] [BCDA 13 21 60]

[ABCD  4 6 61] [DABC 11 10 62] [CDAB  2 15 63] [BCDA  9 21 64]

    /*
然后進行如下加法操作。(增加四個寄存器的值)*/

    A = A + AA

B = B + BB

C = C + CC

D = D + DD

end/*i
的循環*/


3.5 輸出

    信息摘要產生后輸出的形式為A,B,C,D。即,以A為低位字節開頭,D為高位字節結束。

   
這些就是MD5的完整描述。在附錄中有以C語言實現的一個例子。

4.摘要

    MD5算法實現簡單,并且對任意長度的消息都能提供它的消息摘要和“指紋”。據推測
   
要實現兩個不同的報文產生相同的摘要需要2^64次的操作,要恢復給定摘要的報文則
   
需要2^128次操作。為尋找缺陷,MD5算法已經過非常細致的檢查。最后的結論是還需
   
要相關的更好的算法和更進一步的安全分析。

5.MD4MD5的區別

    下面是MD4MD5的區別:

       
1.增加了第四步循環。
       
2.每一步增加了一個唯一的常數。
       
3.第二輪循環的g函數從 (XY v XZ v YZ) 變成了 (XZ v Y not(Z)) ,以減
          
g函數的平衡性

      
4.每一步的結果都會被加進上一步的結果中,這樣就加速了“雪崩效應”。
       
5.在第二和第三步循環中,存取輸入字的順序被改變了,使得各個樣式彼此之間
         
的相似度更小
       
6.每個循環中位移的量是經過近似優化的,為了更快的產生“雪崩效應”。每步循
         
環中的位移是截然不同的

引用

   
[1] Rivest, R., "The MD4 Message Digest Algorithm", RFC 1320, MIT and RSA Data
        Security, Inc., April 1992.

[2] Rivest, R., "The MD4 message digest algorithm", in A.J. Menezes and S.A.
Vanstone, editors, Advances in Cryptology - CRYPTO ’90 Proceedings, pages 303-311, Springer-Verlag, 1991.

[3] CCITT Recommendation X.509 (1988), "The Directory - Authentication Framework."


附錄A – 參考實現

   
這份附錄包含如下文件(摘自RSAREFA Cryptographic Toolkit for Privacy-Enhanced
    Mail
)

    global.h --
全局頭文件
    md5.h    -- MD5
頭文件
    md5.c    -- MD5
源代碼

   
要知道更多RSAREF的信息,請發郵件給<rsaref@rsa.com>

   
附錄還包含以下文件:

   
mddiver.c – MD2,MD4,MD5測試驅動。

   
驅動默認編譯MD5,但是如果在C編譯器命令行下定義MD2或者4,則會相應編譯MD2
    MD4


   
這份實現是緊湊的,并且可以工作在多種平臺上面。不過,在特定的平臺上對實現
   
進行優化也不是件困難的事,這作為一個練習留給讀者。例如,在“
little-endian
   
平臺上,低32位的比特是沒有意義的,并且沒有成直線的限制。譯碼函數
MD5Transform
   
能夠被其他調用替代。


A.1 global.h

/* GLOBAL.H - RSAREF types and constants*/

/* PROTOTYPES should be set to one if and only if the compiler
supports function argument prototyping.

   The following makes PROTOTYPES default to 0 if it has not
already

*/

#ifndef PROTOTYPES

#define PROTOTYPES 0

#endif

/* POINTER defines a generic pointer type */

typedef unsigned char *POINTER;

/* UINT2 defines a two byte word */

typedef unsigned short int UINT2;

/* UINT4 defines a four byte word */

typedef unsigned long int UINT4;

/* PROTO_LIST is defined depending on how PROTOTYPES is
defined above.

   If using PROTOTYPES, then PROTO_LIST returns the list,
otherwise it returns an empty list.

*/

#if PROTOTYPES

#define PROTO_LIST(list) list

#else

#define PROTO_LIST(list) ()

#endif


A.2 md5.h

/* MD5.H - header file for MD5C.C*/

/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved.

   License to copy and use this software is granted provided that it is identified as the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing this software or this function.

   License is also granted to make and use derivative works provided that such works are identified as "derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing the derived work.

   RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of thissoftware for any particular purpose. It is provided "as is" without express or implied warranty of

   any kind.

   These notices must be retained in any copies of any part of this documentation and/or software.

*/

 

/* MD5 context. */

typedef struct {

   UINT4 state[4]; /* state (ABCD) */

   UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */

   unsigned char buffer[64]; /* input buffer */

} MD5_CTX;

void MD5Init PROTO_LIST ((MD5_CTX *));

void MD5Update PROTO_LIST

((MD5_CTX *, unsigned char *, unsigned int));

void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));


A.3 md5.c

/* MD5C.C - RSA Data Security, Inc., MD5 message-digest   
   algorithm*/

/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved.

   License to copy and use this software is granted provided that it is identified as the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing this software or this function.

   License is also granted to make and use derivative works provided that such works are identified as "derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing the derived work.

   RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided "as is" without express or implied warranty of any kind.

   These notices must be retained in any copies of any part of this documentation and/or software.

*/

 

#include "global.h"

#include "md5.h"

 

/* Constants for MD5Transform routine.*/

#define S11 7

#define S12 12

#define S13 17

#define S14 22

#define S21 5

#define S22 9

#define S23 14

#define S24 20

#define S31 4

#define S32 11

#define S33 16

#define S34 23

#define S41 6

#define S42 10

#define S43 15

#define S44 21

static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));

static void Encode PROTO_LIST

((unsigned char *, UINT4 *, unsigned int));

static void Decode PROTO_LIST

((UINT4 *, unsigned char *, unsigned int));

static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));

static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));

static unsigned char PADDING[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 and I are basic MD5 functions.*/

#define F(x, y, z) (((x) & (y)) | ((˜x) & (z)))

#define G(x, y, z) (((x) & (z)) | ((y) & (˜z)))

#define H(x, y, z) ((x) ^ (y) ^ (z))

#define I(x, y, z) ((y) ^ ((x) | (˜z)))

/* ROTATE_LEFT rotates x left n bits.*/

#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))

/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.

   Rotation is separate from addition to prevent recomputation.

*/

#define FF(a, b, c, d, x, s, ac) { \

   (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \

   (a) = ROTATE_LEFT ((a), (s)); \

   (a) += (b); \

   }

#define GG(a, b, c, d, x, s, ac) { \

   (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \

   (a) = ROTATE_LEFT ((a), (s)); \

   (a) += (b); \

}

#define HH(a, b, c, d, x, s, ac) { \

   (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \

   (a) = ROTATE_LEFT ((a), (s)); \

   (a) += (b); \

}

#define II(a, b, c, d, x, s, ac) { \

   (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \

   (a) = ROTATE_LEFT ((a), (s)); \

   (a) += (b); \

}

/* MD5 initialization. Begins an MD5 operation, writing a new context.

*/

void MD5Init (context)

   MD5_CTX *context; /* context */

{

   context->count[0] = context->count[1] = 0;

   /* Load magic initialization constants.*/

   context->state[0] = 0x67452301;

   context->state[1] = 0xefcdab89;

   context->state[2] = 0x98badcfe;

   context->state[3] = 0x10325476;

}

/* MD5 block update operation. Continues an MD5 message-digest

   operation, processing another message block, and updating thecontext.

*/

void MD5Update (context, input, inputLen)

   MD5_CTX *context; /* context */

   unsigned char *input; /* input block */

   unsigned int inputLen; /* length of input block */

{

   unsigned int i, index, partLen;

   /* Compute number of bytes mod 64 */

   index = (unsigned int)((context->count[0] >> 3) & 0x3F);

   /* Update number of bits */

   if ((context->count[0] += ((UINT4)inputLen << 3))< ((UINT4)inputLen << 3))

      context->count[1]++;

   context->count[1] += ((UINT4)inputLen >> 29);

   partLen = 64 - index;

   /* Transform as many times as possible.*/

   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;

   /* Buffer remaining input */

   MD5_memcpy((POINTER)&context->buffer[index], (POINTER)&input[i],inputLen-i);

}

/* MD5 finalization. Ends an MD5 message-digest operation, writing the the message digest and zeroizing the context.

*/

void MD5Final (digest, context)

   unsigned char digest[16]; /* message digest */

   MD5_CTX *context; /* context */

{

   unsigned char bits[8];

   unsigned int index, padLen;

   /* Save number of bits */

   Encode (bits, context->count, 8);

   /* Pad out to 56 mod 64.*/

   index = (unsigned int)((context->count[0] >> 3) & 0x3f);

   padLen = (index < 56) ? (56 - index) : (120 - index);

   MD5Update (context, PADDING, padLen);

   /* Append length (before padding) */

   MD5Update (context, bits, 8);

   /* Store state in digest */

   Encode (digest, context->state, 16);

   /* Zeroize sensitive information.*/

   MD5_memset ((POINTER)context, 0, sizeof (*context));

}

/* MD5 basic transformation. Transforms state based on block.

*/

static void MD5Transform (state, block)

   UINT4 state[4];

   unsigned char block[64];

{

   UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];

   Decode (x, block, 64);

   /* Round 1 */

   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 */

   /* Round 2 */

   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 */

   /* Round 3 */

   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 */

   /* Round 4 */

   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;

   /* Zeroize sensitive information.*/

   MD5_memset ((POINTER)x, 0, sizeof (x));

}

/* Encodes input (UINT4) into output (unsigned char). Assumes len is a multiple of 4.

*/

static void Encode (output, input, len)

   unsigned char *output;

   UINT4 *input;

   unsigned int len;

{

   unsigned int i, j;

   for (i = 0, j = 0; j < len; i++, j += 4) {

      output[j] = (unsigned char)(input[i] & 0xff);

      output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);

      output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);

      output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);

   }

}

/* Decodes input (unsigned char) into output (UINT4). Assumes len is a multiple of 4.

*/

static void Decode (output, input, len)

   UINT4 *output;

   unsigned char *input;

   unsigned int len;

{

   unsigned int i, 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);

}

/* Note: Replace "for loop" with standard memcpy if possible.*/

static void MD5_memcpy (output, input, len)

   POINTER output;

   POINTER input;

   unsigned int len;

{

   unsigned int i;

   for (i = 0; i < len; i++)

      output[i] = input[i];

}

/* Note: Replace "for loop" with standard memset if possible.

*/

static void MD5_memset (output, value, len)

   POINTER output;

   int value;

   unsigned int len;

{

   unsigned int i;

   for (i = 0; i < len; i++)

      ((char *)output)[i] = (char)value;

}


A.4 mddriver.c


/* MDDRIVER.C - test driver for MD2, MD4 and MD5*/

/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All rights reserved.

   RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided "as is" without express or implied warranty of any kind.

   These notices must be retained in any copies of any part of this documentation and/or software.

*/

/* The following makes MD default to MD5 if it has not already been defined with C compiler flags.

*/

#ifndef MD

#define MD MD5

#endif

#include <stdio.h>

#include <time.h>

#include <string.h>

#include "global.h"

#if MD == 2

#include "md2.h"

#endif

#if MD == 4

#include "md4.h"

#endif

#if MD == 5

#include "md5.h"

#endif

/* Length of test block, number of test blocks.*/

#define TEST_BLOCK_LEN 1000

#define TEST_BLOCK_COUNT 1000

static void MDString PROTO_LIST ((char *));

static void MDTimeTrial PROTO_LIST ((void));

static void MDTestSuite PROTO_LIST ((void));

static void MDFile PROTO_LIST ((char *));

static void MDFilter PROTO_LIST ((void));

static void MDPrint PROTO_LIST ((unsigned char [16]));

#if MD == 2

#define MD_CTX MD2_CTX

#define MDInit MD2Init

#define MDUpdate MD2Update

#define MDFinal MD2Final

#endif

#if MD == 4

#define MD_CTX MD4_CTX

#define MDInit MD4Init

#define MDUpdate MD4Update

#define MDFinal MD4Final

#endif

#if MD == 5

#define MD_CTX MD5_CTX

#define MDInit MD5Init

#define MDUpdate MD5Update

#define MDFinal MD5Final

#endif

/* Main driver.

   Arguments (may be any combination):

   -sstring - digests string

   -t - runs time trial

   -x - runs test script

   filename - digests file

   (none) - digests standard input

*/

int main (argc, argv)

int argc;

char *argv[];

{

   int i;

   if (argc > 1)

      for (i = 1; i < argc; i++)

        if (argv[i][0] == - && argv[i][1] == ’s’)

           MDString (argv[i] + 2);

        else if (strcmp (argv[i], "-t") == 0)

           MDTimeTrial ();

        else if (strcmp (argv[i], "-x") == 0)

           MDTestSuite ();

        else

           MDFile (argv[i]);

   else

      MDFilter ();

   return (0);

}

/* Digests a string and prints the result.*/

static void MDString (string)

char *string;

{

   MD_CTX context;

   unsigned char digest[16];

   unsigned int len = strlen (string);

   MDInit (&context);

   MDUpdate (&context, string, len);

   MDFinal (digest, &context);

   printf ("MD%d (\"%s\") = ", MD, string);

   MDPrint (digest);

   printf ("\n");

}

/* Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte

   blocks.

*/

static void MDTimeTrial ()

{

   MD_CTX context;

   time_t endTime, startTime;

   unsigned char block[TEST_BLOCK_LEN], digest[16];

   unsigned int i;

   printf

      ("MD%d time trial. Digesting %d %d-byte blocks ...", MD,

      TEST_BLOCK_LEN, TEST_BLOCK_COUNT);

   /* Initialize block */

   for (i = 0; i < TEST_BLOCK_LEN; i++)

      block[i] = (unsigned char)(i & 0xff);

   /* Start timer */

   time (&startTime);

   /* Digest blocks */

   MDInit (&context);

   for (i = 0; i < TEST_BLOCK_COUNT; i++)

      MDUpdate (&context, block, TEST_BLOCK_LEN);

   MDFinal (digest, &context);

   /* Stop timer */

   time (&endTime);

   printf (" done\n");

   printf ("Digest = ");

   MDPrint (digest);

   printf ("\nTime = %ld seconds\n", (long)(endTime-startTime));

   printf

      ("Speed = %ld bytes/second\n",

      (long)TEST_BLOCK_LEN * (long)TEST_BLOCK_COUNT/(endTime-startTime));

}

/* Digests a reference suite of strings and prints the results.*/

static void MDTestSuite ()

{

   printf ("MD%d test suite:\n", MD);

   MDString ("");

   MDString ("a");

   MDString ("abc");

   MDString ("message digest");

   MDString ("abcdefghijklmnopqrstuvwxyz");

   MDString

      ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");

   MDString

      ("1234567890123456789012345678901234567890\

       1234567890123456789012345678901234567890");

}

/* Digests a file and prints the result.*/

static void MDFile (filename)

char *filename;

{

   FILE *file;

   MD_CTX context;

   int len;

   unsigned char buffer[1024], digest[16];

   if ((file = fopen (filename, "rb")) == NULL)

      printf ("%s can’t be opened\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");

   }

}

/* Digests the standard input and prints the result.*/

static void MDFilter ()

{

   MD_CTX context;

   int len;

   unsigned char buffer[16], digest[16];

   MDInit (&context);

   while (len = fread (buffer, 1, 16, stdin))

      MDUpdate (&context, buffer, len);

   MDFinal (digest, &context);

   MDPrint (digest);

   printf ("\n");

}

/* Prints a message digest in hexadecimal.*/

static void MDPrint (digest)

unsigned char digest[16];

{

   unsigned int i;

   for (i = 0; i < 16; i++)

      printf ("%02x", digest[i]);

}


A.5.MD5測試的理論結果


MD5
驅動的測試結果(驅動操作符號“-x)如下:

MD5 test suite:
MD5 ("") = d41d8cd98f00b204e9800998ecf8427e
MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661
MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72
MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0
MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b
MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") =
d174ab98d277d9f5a5611c2c9f419d9f

MD5 ("123456789012345678901234567890123456789012345678901234567890123456
78901234567890") = 57edf4a22be3c955ac49da2e2107b67a


安全性


   
這份備忘錄中提及的安全性的水平足以實現基于MD5和公鑰加密系統的非常高水平的混
   
合數字簽名方案。

作者地址


Ronald L. Rivest
Massachusetts Institute of Technology
Laboratory for Computer Science
NE43-324
545 Technology Square
Cambridge, MA 02139-1986
Phone: (617) 253-5880
EMail: rivest@theory.lcs.mit.edu