📄 中文rfc1321.txt
字号:
组织:中国互动出版网(http://www.china-pub.com/)
RFC文档中文翻译计划(http://www.china-pub.com/compters/emook/aboutemook.htm)
E-mail:ouyang@china-pub.com
译者:()
译文发布时间:2001-11-7
版权:本中文翻译文档版权归中国互动出版网所有。可以用于非商业用途自由转载,但必须
保留本文档的翻译及版权信息。
Network Working Group R. Rivest
Request for Comments: 1321 MIT Laboratory for Computer Science
and RSA Data Security, Inc.
April 1992
MD5 报文摘要算法
(RFC1321——The MD5 Message-Digest Algorithm)
本文地位
本文并非指定一个Internet标准,而是向互联网提供信息,本文可以任意传播,不受限制。
致谢
Don Coppersmith, Burt Kaliski, Ralph Merkle,David Chaum, 和Noam Nisan向本文提供极大的帮
助,在此本人表示忠心的感谢。
目录
1 执行简介 1
2 术语和符号 1
3 MD5算法描述 2
4 摘要 4
5 MD4和MD5的区别 4
6 参考文献 4
7 附录A-参考应用程序 4
8 安全事项 18
9 作者地址 18
1 执行简介
本文描述了MD5报文摘要算法,此算法将对输入的任意长度的信息进行计算,产生一个128位
长度的“指纹”或“报文摘要”,假定两个不同的文件产生相同的报文摘要或由给定的报文摘要产生
原始信息在计算上是行不通的。MD5算法适合用在数据签名应用中,在此应用中,一个大的文件必
须在类似RSA算法的公用密钥系统中用私人密钥加密前被“压缩”在一种安全模式下。
MD5算法能在32位机器上能以很快的速度运行。另外,MD5算法不需要任何大型的置换列表。
此算法编码很简洁。MD5 算法是MD4报文摘要算法的扩展。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_i代表“x减去I".如果下划线左边的是一个表达式,则用括号括住,如:
x_{i+1}。同样我们用^代表求幂,这样x^i则代表x的i次幂。
符号“+”代表字的加,X <<< s代表32位的值X循环左移s位,not(X)代表X的按位
补运算,X v Y 表示X和Y的按位或运算,XxorY代表X和Y的按位异或运算,XY代表
X和Y的按位与运算。
3 MD5算法描述
我们假设有一个b位长度的输入信号,希望产生它的报文摘要,此处b是一个非负整数,b也可
能是0,不一定必须是8的整数倍,它可能是任意大的长度。我们设想信号的比特流如下所示:
m_0 m_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) = 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))
这一步中 使用一个64元素的常数组T[1 ... 64],它由sine函数构成,T[i]表示数组中的第i个元
素,它的值等于经过4294967296次abs(sin(i))后的值的整数部分(其中i是弧度 )。T[i]为32位
整数用16进制表示,数组元素在附录中给出。
具体过程如下:
/* 处理数据原文 */
For i = 0 to N/16-1 do
/*每一次,把数据原文存放在16个元素的数组X中. */
For j = 0 to 15 do
Set X[j] to M[i*16+j].
end /结束对J的循环
/* Save A as AA, B as BB, C as CC, and D as DD. */
AA = A
BB = B
CC = C
DD = D
/* 第1轮*/
/* 以 [abcd k s i]表示如下操作
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
/* Do the following 16 operations. */
[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]
/* 第2轮* */
/* 以 [abcd k s i]表示如下操作
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
/* Do the following 16 operations. */
[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]
/* 第3轮*/
/* 以 [abcd k s i]表示如下操作
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
/* Do the following 16 operations. */
[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]
/* 第4轮*/
/* 以 [abcd k s i]表示如下操作
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
/* Do the following 16 operations. */
[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的循环*/
(5) 输出结果
报文摘要的产生后的形式为:A,B,C,D。也就是低位字节A开始,高位字节D结束。
现在完成了对MD5的描述,在附录中给出了C形式的程序。
4 摘要
MD5算法实现很容易,它提供了任意长度的信息的“指纹”(或称为报文摘要)。据推测要实现
两个不同的报文产生相同的摘要需要2^64次的操作,要恢复给定摘要的报文则需要2^128次操作。
为寻找缺陷,MD5算法已经过非常细致的检查。最后的结论是还需要相关的更好的算法和更进一步
的安全分析。
5 MD4和MD5的区别
以下是MD5和MD4的不同点:
1. 加上了第四轮循环。
2. 每一步增加了一个唯一的常数值。
第二轮中的函数g从(XY v XZ v YZ)变成了(XZ v Y not(Z)),以减少g函数的均衡性。
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 '90Proceedings, pages 303-311, Springer-Verlag,
1991.
[3] CCITT Recommendation X.509 (1988), "The Directory - Authentication
Framework."
7 附录A-参考应用程序
本附录包括以下文件:(摘自RSAREF: A Cryptographic Toolkit for Privacy-Enhanced Mail:)
global.h - 全局头文件
md5.h -- MD5头文件
md5c.c -- MD5源代码
(要得到更多的RSAREF信息,请发e-mai到: <rsaref@rsa.com>.)
附录中还包括:
mddriver.c-MD2, MD4 and MD5的测试驱动程序。
驱动程序默认情况下编译MD5,但如果在C的编译命令行将MD5参数设成2或4,则也可以编译
MD2和MD4
此应用程序是方便使用的,可用在不同的平台上,在特殊的平台上优化它也并不困难,这留给读
者作为练习。例如,在“little-endian”平台上,此平台32位字的最低地址字节最无意义的字节,
并且没有队列限制,在MD5变换中的解码的命令调用可以被相应的类型替代。
A1 global.h
/* GLOBAL.H - RSAREF 类型和常数*/
/* 当且仅当编译器支持函数原型的声明时,PROTOTYPES必须被设置一次
如果还没有定义C编译器的标记,下面的代码使PROTOTYPES置为0。*/
#ifndef PROTOTYPES
#define PROTOTYPES 0
#endif
/* POINTER 定义成一个普通的指针类型 */
typedef unsigned char *POINTER;
/* UINT2 定义成两字节的字 */
typedef unsigned short int UINT2;
/* UINT4定一成四字节的字 */
typedef unsigned long int UINT4;
/* PROTO_LIST的定义依赖于上面PROTOTYPES的定义,如果使用了PROTOTYPES,那么
PROTO_LIST返回此列表,否则返回一个空列表。*/
#if PROTOTYPES
#define PROTO_LIST(list) list
#else
#define PROTO_LIST(list) ()
#endif
A.2 md5.h
/*MD5.H - MD5C.C头文件*/
/*本软件允许被复制或运用,但必须在所有提及和参考的地方标注“RSA Data Security, Inc. MD5
Message-Digest Algorithm”,也允许产生或运用派生软件,但必须在所有提及和参考的地方标明
“derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm”
RSA数据安全公司(RSA Data Security, Inc.)从来没有出于任何特定目的陈述过关于此
软件的可买性和实用性,它提供了“as is”,没有表达或暗示过任何理由。
此声明必须在任何此文件和软件的任何拷贝中保留。*/
/* MD5 context. */
typedef struct
{
UINT4 state[4]; /* state (ABCD) */
UINT4 count[2]; /* 位数量, 模 2^64 (低位在前) */
unsigned char buffer[64]; /* 输入缓冲器 */
} 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数据安全公司,MD5报文摘要算法*/
/*本软件允许被复制或运用,但必须在所有提及和参考的地方标注“RSA Data Security, Inc. MD5
Message-Digest Algorithm”也允许产生或运用派生软件,但必须在所有提及和参考的地方标明
“derived from the RSA Data RSA数据安全公司(RSA Data Security, Inc.)从来没有出于任何
特定目的陈述过关于此软件的可买性和实用性,它提供了“as is”,没有表达或暗示过任何理由。
此声明必须在任何此文件和软件的任何拷贝中保留。*/
#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 和 I 是基本MD5函数 */
#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 将x循环左移n位 */
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* 循环从加法中分离出是为了防止重复计算*/
#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 初始化. 开始一个MD5操作写一个新的context. */
void MD5Init (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. */
void MD5Update (context, input, inputLen)
MD5_CTX *context; /* context */
unsigned char *input; /* 输入分组*/
unsigned int inputLen; /* 输入的分组的长度 */
{
unsigned int i, index, partLen;
/* 计算字节数模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;
/* 按能达到的最大次数转换*/
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 报文摘要操作结束, 写下报文摘要值 */
void MD5Final (digest, context)
unsigned char digest[16]; /*报文摘要 */
MD5_CTX *context; /* context */
{
unsigned char bits[8];
unsigned int index, padLen;
/* 保存位数值 */
Encode (bits, context->count, 8);
index = (unsigned int)((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基本转换. 转换状态基于分组*/
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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -