RFC1321 about MD5

来源:互联网 发布:怎么在淘宝找阿里旺旺 编辑:程序博客网 时间:2024/06/14 01:45

RFC 1321 (RFC1321)

Internet RFC/STD/FYI/BCP Archives

[ RFC Index | RFC Search | Usenet FAQs | Web FAQs | Documents | Cities ]

Alternate Formats: rfc1321.txt | rfc1321.txt.pdf

Comment on RFC 1321

RFC 1321 - The MD5 Message-Digest Algorithm


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

The MD5 Message-Digest Algorithm

Status of this Memo

This memo provides information for the Internet community. It does
not specify an Internet standard. Distribution of this memo is
unlimited.

Acknowlegements

We would like to thank Don Coppersmith, Burt Kaliski, Ralph Merkle,
David Chaum, and Noam Nisan for numerous helpful comments and
suggestions.

Table of Contents

1. Executive Summary 1
2. Terminology and Notation 2
3. MD5 Algorithm Description 3
4. Summary 6
5. Differences Between MD4 and MD5 6
References 7
APPENDIX A - Reference Implementation 7
Security Considerations 21
Author's Address 21

1. Executive Summary

本文档描述MD5 报文摘译(message-digest)算法。MD5算法接受任意长度的输入信
息,为输入产生一个128-bit 的“指纹”或“报文摘译。“似乎”以当前的计算能力来
说,无法为两个报文产生相同的报文摘译, 或是在预先给定报文摘译的情况下
无法给出原报文。MD5算法用于数字签名程序,在这种应用中,将一个巨大文件在
公钥密码系统(比如RSA)下以私钥加密之前,文件必须被“压缩”成一个可靠的
样子(manner)。

MD5算法被设计成在32位机器上非常的快。另外,MD5算法不需要任何替代表
(substitution tables);算法可以被编写的相当紧凑。

MD5算法是MD4报文摘译算法[1,2]的扩展。MD5比MD4稍微慢一点,但在设计上更“保
守”。之所以设计MD5是因为:人们觉得MD4可能被采用的过于迅速,尤其是在还没
有证明它是正确之前;因为MD4被设计的过于迅速,它在被密码分析破解的“边缘”。
MD5后退一位,放弃一点速度来换取向“最终安全”前进的一大步。 它合并了来自不同
批评家的各种建议,还包括另外的优化。 MD5算法被放在公共领域接受回顾和批评,
有可能成为标准。

对于OSI-based 应用程序,MD5的对象标示是

md5 OBJECT IDENTIFIER ::=
iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 5}

在X.509 类型的 AlgorithmIdentifier [3], MD5的参数必须是NULL类型。

2. 术语和符号

本文档中,"word" 是32位,"byte"是8位。一个位序列可以被表示成一个字节序列,
其中每8个位表示为一个字节,字节以高位bit开始顺序构造(most significant)。
类似 的,一个字节序列可以表示为一个32位words的序列,以低位字节开始构造。

令 x_i 表示 "x 减 i"。如果下划线是表达式的一部分,我们将用大括号,如
x_{i+1}。类似的,我们使用 ^表示求幂,所以 x^i 表示x 的i次幂。

令符号"+" 表示words加(例如,modulo-2^32加)。令 X <<< s 表示
将X循环左移s位。令not(X)表示按位非X,令 X v Y 表示 X、Y按位OR。令
X xor Y 表示将X、Y进行按位XOR,令 XY表示X、Y按位AND。

3. MD5 算法描述

首先我们假设我们有一个b位的输入信息,我们想获得其报文摘要。这里 b 是
任意非负整数;b可以是0,且不需要是8的整数倍,而且可以任意大。我们将
报文的位写成如下形式:

m_0 m_1 ... m_{b-1}

下面的五步将得到报文的报文摘要。

3.1 Step 1. 添加填充位

报文将被“填补”(扩展),以使它的长度(以位计算)以512为模同余448。就是
说,扩展报文以使它被512除之后余64。填充总是执行的,即使报文已经以512为
模同余448。

填充以如下方式进行:单个“1”bit附加到报文,之后附加“0”bits以使附加后的消
息的长度(以位记)达到以512为模同余448。最终,最少1bit最多512bit被附加。

3.2 Step 2. 附加长度

以64-bit 表示的b(还没有附加填充字节之前的长度)被附加了前一步产生的结果。
有时候b大于2^64 ,那么只有低位的64位被采用了。(这些bits被附加两个32bit的
words,低位顺序,与先前的习惯一样。)

到此时为止报文(在附加bits和b之后)的长度恰好是512bits的整数倍。同样的,
这个报文的长度也是16words的整数倍。令M[0... N-1]表示消息的结果报文,这里N
是16的整数倍。

3.3 Step 3. 初始化 MD 缓冲

计算报文摘要需要一个4words大的缓冲(A,B,C,D)。这里ABCD都是一个32位寄存器。
寄存器首先要初始化成下列值,低位顺序:

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

3.4 Step 4. 以16-Word 为块处理报文

我们首先定义4个辅助函数,每个接受3个32bits的words作为输入,产生一个32bit的
word作为输出。

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的每一个bit作为一个条件:if X then Y else Z。既然XY and not(X)Z永远不会
在同一个位置有1,函数F也可以使用+来代替v。有趣的是,如果X,Y,Z的bits都是
独立,无偏的(unbiased),F(X,Y,Z)的每一个bit也是独立无偏的。

函数G,H和I与函数F类似,这里他们以"bitwise parallel"来从X,Y,Z的bits来产
生他们的输出,以这样的方式时如果X,Y,Z的对应bits是独立,无偏的,则G(X,Y,Z),
H(X,Y,Z), 和I(X,Y,Z)的每一个bit都将是独立无偏的。

这一步使用从sin函数构造的64元表T[1 ... 64]。令T[i]指示表的第i个元素,第i个
元素等于4294967296*abs(sin(i))的整数部分,i是弧度。表的元素在附录中给出。

进行下列步骤:

/* 处理每一个 16-word 块 */
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 /* of loop on j */

/* 保存 A 到 AA, B 到 BB, C 到 CC, D 到 DD. */
AA = A
BB = B

CC = C
DD = D

/* Round 1. */
/* 令 [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]

/* Round 2. */
/* 令 [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]

/* Round 3. */
/* 令 [abcd k s t] 表示
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]

/* Round 4. */
/* 令 [abcd k s t] 表示
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]

/* 然后执行下面的最后步骤。 (That is increment each
of the four registers by the value it had before this block
was started.) */
A = A + AA
B = B + BB
C = C + CC
D = D + DD

end /* of loop on i */

3.5 Step 5. 输出

报文摘要的输出就是A,B,C,D。低位是A高位是D。

MD5算法描述完成。附录中给出了C语言的一个实现。

4. 总结

MD5报文摘译算法易于实现,为任意长度的报文得到一个“指纹”或报文摘要。猜想
给出两个由相同报文摘要的的报文需要 2^64 规模的操作,而给出一个有指定的
报文摘要报文需要2^128 规模的操作。MD5 算法已经被小心谨慎的检查了弱点。然
而,一个相关的新算法和近一步的安全分析也在进行中,任何建议都可以提出。

5. MD5 与 MD4的不同之处

下面是MD5 与 MD4的不同:

1. 增加了第四个round。

2. 每一步现在有一个附加常数。

3. round 2中的函数g 从 (XY v XZ v YZ) 改为(XZ v Y not(Z))使得g的
均衡性降低。

4. 每一步的结果现在加上了前一步的结果。这促使了一个更快的
"avalanche effect".

5. The order in which input words are accessed in rounds 2 and
3 is changed, to make these patterns less like each other.

6. The shift amounts in each round have been approximately
optimized, to yield a faster "avalanche effect." The shifts in
different rounds are distinct.

References?

[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."

APPENDIX A - Reference Implementation

This appendix contains the following files taken from RSAREF: A
Cryptographic Toolkit for Privacy-Enhanced Mail:

global.h -- global header file

md5.h -- header file for MD5

md5c.c -- source code for MD5

For more information on RSAREF, send email to <rsaref@rsa.com>.

The appendix also includes the following file:

mddriver.c -- test driver for MD2, MD4 and MD5

The driver compiles for MD5 by default but can compile for MD2 or MD4
if the symbol MD is defined on the C compiler command line as 2 or 4.

The implementation is portable and should work on many different
plaforms. However, it is not difficult to optimize the implementation
on particular platforms, an exercise left to the reader. For example,
on "little-endian" platforms where the lowest-addressed byte in a 32-
bit word is the least significant and there are no alignment
restrictions, the call to Decode in MD5Transform can be replaced with
a typecast.

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

been defined with C compiler flags.
*/
#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 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.
*/

/* 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 md5c.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 the
context.
*/
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 Test suite

The MD5 test suite (driver option "-x") should print the following
results:

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

Security Considerations

The level of security discussed in this memo is considered to be
sufficient for implementing very high security hybrid digital-
signature schemes based on MD5 and a public-key cryptosystem.

Author's Address

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

Comment on RFC 1321

 

Comments about this RFC:

  • RFC 1321: mddriver.c - MDTrial() there should be a if ( endTime-startTime > 0 ) ... by puma99 (7/13/2004)
  • RFC 1321: hgdhfgdhfdgfhdjgfd hugrnjrkgyou are a stinky butthead! i hate you! you smell... by bla bla bla bla (2/6/2004)
  • RFC 1321: There appears to be a slight error in the hash macro description for Rounds 3 &... by paranoia (3/30/2004)
  • RFC 1321: The code does not compile. I am almost sure of it, I may be wrong, but someone... by Student (5/11/2004)
  • RFC 1321: In the document, where algorythm is analysed, is small mistake. In roudn 1,... by Modestas Kapusinskas (11/30/2003)
  • RFC 1321: It's better to put "(long)TEST_BLOCK_LEN * (long)TEST_BLOCK_COUNT/((endTime-st... by Shar CMC MSU (6/3/2004)
  • RFC 1321: For finding RAT's not handled by today's AV vendors, I suspect basic knowledge... by longneckedhorse (1/27/2004)
  • RFC 1321: i want the contain of md5context by agad (5/9/2004)
  • RFC 1321: printf("MD%d time trial. Digesting %d %d-byte blocks ...", MD, TEST_BLOCK_... by FvdMarkt (6/14/2004)
  • RFC 1321: Small error on line 19 of mddriver.c: There is #define MD MD5 instead of ... by phil (5/17/2004)

Previous: RFC 1320 - The MD4 Message-Digest Algorithm

 

Next: RFC 1322 - A Unified Approach to Inter-Domain Routing

 


[ RFC Index | RFC Search | Usenet FAQs | Web FAQs | Documents | Cities ]
 
原创粉丝点击