📄 md5的介绍,算法和实现.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0047)http://www.pediy.com/bbshtml/BBS4/kanxue202.htm -->
<HTML><HEAD><TITLE>MD5的介绍,算法和实现</TITLE>
<META http-equiv=Content-Type content="text/html; charset=gb2312">
<STYLE type=text/css></STYLE>
<LINK href="MD5的介绍,算法和实现.files/css.css" type=text/css rel=stylesheet>
<META content="MSHTML 5.50.4134.100" name=GENERATOR></HEAD>
<BODY class=p9 bgColor=#ffffff background=MD5的介绍,算法和实现.files/back.gif><FONT
color=blue>标 题:</FONT>MD5的介绍,算法和实现。 ————娃娃/[CCG] (23千字)<BR><FONT
color=blue>发信人:</FONT>1212<BR><FONT color=blue>时 间:</FONT>2001-11-4 14:36:12
<BR><FONT color=blue>详细信息:</FONT><BR>
<BLOCKQUOTE>MD5的介绍,算法和实现 <BR>
Wrote By 娃娃/[CCG]
<BR><BR><BR><BR>最近对各种加密算法很感兴趣
原因有好多:破解TMG的KeyGenme失败;羡慕伪哥的万象注册机;佩服夜月大哥和Stkman大哥的密码学功力…………
偶然间跟Stkman大哥谈起来MD5,他给了我很多帮助 使得我可以写出这篇文章。 <BR><BR>MD5简介:
<BR><BR>MD5的全称是Message-Digest Algorithm 5,在90年代初由MIT的计算机科学实验室和RSA Data
Security Inc发明,经MD2、MD3和MD4发展而来。
<BR><BR>Message-Digest泛指字节串(Message)的Hash变换,就是把一个任意长度的字节串变换成一定长的大整数。请注意我使用了“字节串”而不是“字符串”这个词,是因为这种变换只与字节的值有关,与字符集或编码方式无关。
<BR><BR>MD5将任意长度的“字节串”变换成一个128bit的大整数,并且它是一个不可逆的字符串变换算法,(我刚开始还愚蠢的认为MD5是可逆的算法
感谢Stkman大哥的讲解)换句话说就是,即使你看到源程序和算法描述,也无法将一个MD5的值变换回原始的字符串,从数学原理上说,是因为原始的字符串有无穷多个,这有点象不存在反函数的数学函数。
<BR><BR>MD5的典型应用是对一段Message(字节串)产生fingerprint(指纹),以防止被“篡改”。举个例子,你将一段话写在一个叫readme.txt文件中,并对这个readme.txt产生一个MD5的值并记录在案,然后你可以传播这个文件给别人,别人如果修改了文件中的任何内容,你对这个文件重新计算MD5时就会发现。如果再有一个第三方的认证机构,用MD5还可以防止文件作者的“抵赖”,这就是所谓的数字签名应用。
<BR><BR>MD5还广泛用于加密和解密技术上,在很多操作系统中,用户的密码是以MD5值(或类似的其它算法)的方式保存的,
用户Login的时候,系统是把用户输入的密码计算成MD5值,然后再去和系统中保存的MD5值进行比较,而系统并不“知道”用户的密码是什么。
<BR><BR>一些黑客破获这种密码的方法是一种被称为“跑字典”的方法。有两种方法得到字典,一种是日常搜集的用做密码的字符串表,另一种是用排列组合方法生成的,先用MD5程序计算出这些字典项的MD5值,然后再用目标的MD5值在这个字典中检索。
<BR><BR>即使假设密码的最大长度为8,同时密码只能是字母和数字,共26+26+10=62个字符,排列组合出的字典的项数则是P(62,1)+P(62,2)….+P(62,8),那也已经是一个很天文的数字了,存储这个字典就需要TB级的磁盘组,而且这种方法还有一个前提,就是能获得目标账户的密码MD5值的情况下才可以。
<BR><BR>在软件的加密保护中 很多软件采用MD5保护 但是由于MD5算法为不可逆算法
所以所有的软件都是使用MD5算法作为一个加密的中间步骤,比如对用户名做一个MD5变换,结果再进行一个可逆的加密变换,做注册机时也只要先用MD5变换,然后再用一个逆算法。所以对于破解者来说只要能看出是MD5就很容易了。
<BR><BR>MD5代码的特点明显,跟踪时很容易发现,如果软件采用MD5算法,在数据初始化的时候必然用到以下的四个常数 <BR>0x67452301;
<BR>0xefcdab89; <BR>0x98badcfe; <BR>0x10325476; <BR>若常数不等 则可能是变形的MD5算法
或者根本就不是这个算法。在内存了也就是 <BR>01 23 45 67 89 ab cd ef fe dc ......32 10
16个字节 <BR>———————————————————————————————————————————— <BR><BR>MD5算法:
<BR><BR>第一步:增加填充
<BR>增加padding使得数据长度(bit为单位)模512为448。如果数据长度正好是模512为448,增加512个填充bit,也就是说填充的个数为1-512。第一个bit为1,其余全部为0。
<BR>第二步:补足长度
<BR>将数据长度转换为64bit的数值,如果长度超过64bit所能表示的数据长度的范围,值保留最后64bit,增加到前面填充的数据后面,使得最后的数据为512bit的整数倍。也就是32bit的16倍的整数倍。在RFC1321中,32bit称为一个word。
<BR>第三步:初始化变量: <BR>用到4个变量,分别为A、B、C、D,均为32bit长。初始化为: <BR>A: 01 23 45 67 <BR>B:
89 ab cd ef <BR>C: fe dc ba 98 <BR>D: 76 54 32 10 <BR>第四步:数据处理:
<BR>首先定义4个辅助函数: <BR>F(X,Y,Z) = XY v not(X) Z <BR>G(X,Y,Z) = XZ v Y not(Z)
<BR>H(X,Y,Z) = X xor Y xor Z <BR>I(X,Y,Z) = Y xor (X v not(Z))
<BR>其中:XY表示按位与,X v Y表示按位或,not(X)表示按位取反。xor表示按位异或。 <BR>函数中的X、Y、Z均为32bit。
<BR><BR>定义一个需要用到的数组:T(i),i取值1-64,T(i)等于abs(sin(i))的4294967296倍的整数部分,i为弧度。
<BR>假设前三步处理后的数据长度为32*16*Nbit <BR><BR>第五步:输出:
<BR>最后得到的ABCD为输出结果,共128bit。A为低位,D为高位。 <BR><BR><BR><BR><BR><BR>MD5在编程中的实现
<BR><BR><BR>下面来看看如何在C语言和VB中实现MD5算法
<BR>———————————————————————————————————————————— <BR><BR>*/ <BR>#ifndef
PROTOTYPES <BR>#define PROTOTYPES 0 <BR>#endif <BR>typedef unsigned char
*POINTER; <BR>typedef unsigned short int UINT2; <BR>typedef unsigned long int
UINT4; <BR>#if PROTOTYPES <BR>#define PROTO_LIST(list) list <BR>#else
<BR>#define PROTO_LIST(list) () <BR>#endif <BR><BR>——————————
MD5.h———————————————————————————— <BR><BR>typedef struct { <BR> UINT4
state[4]; <BR> UINT4 count[2];
<BR> unsigned char buffer[64];
<BR>} MD5_CTX; <BR><BR>void MD5Init
PROTO_LIST ((MD5_CTX *)); <BR>void MD5Update PROTO_LIST <BR> ((MD5_CTX
*, unsigned char *, unsigned int)); <BR>void MD5Final PROTO_LIST ((unsigned
char [16], MD5_CTX *)); <BR><BR>※※※※※※※※※MD5C.C※※※※※※※※※※※※※※※※※※※※※※※※
<BR>#include "global.h" <BR>#include "md5.h" <BR>#define S11 7 <BR>#define S12
12 <BR>#define S13 17 <BR>#define S14 22 <BR>#define S21 5 <BR>#define S22 9
<BR>#define S23 14 <BR>#define S24 20 <BR>#define S31 4 <BR>#define S32 11
<BR>#define S33 16 <BR>#define S34 23 <BR>#define S41 6 <BR>#define S42 10
<BR>#define S43 15 <BR>#define S44 21 <BR><BR>static void MD5Transform
PROTO_LIST ((UINT4 [4], unsigned char [64])); <BR>static void Encode
PROTO_LIST <BR> ((unsigned char *, UINT4 *, unsigned int)); <BR>static
void Decode PROTO_LIST <BR> ((UINT4 *, unsigned char *, unsigned int));
<BR>static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
<BR>static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
<BR><BR>static unsigned char PADDING[64] = { <BR> 0x80, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, <BR> 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, <BR> 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 <BR>}; <BR><BR>/* 定义F G H I 为四个基数
<BR><BR>#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) <BR>#define
G(x, y, z) (((x) & (z)) | ((y) & (~z))) <BR>#define H(x, y, z) ((x) ^
(y) ^ (z)) <BR>#define I(x, y, z) ((y) ^ ((x) | (~z))) <BR>#define
ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) <BR>#define
FF(a, b, c, d, x, s, ac) { \ <BR>(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac);
\ <BR>(a) = ROTATE_LEFT ((a), (s)); \ <BR>(a) += (b); \ <BR> }
<BR>#define GG(a, b, c, d, x, s, ac) { \ <BR>(a) += G ((b), (c), (d)) + (x) +
(UINT4)(ac); \ <BR>(a) = ROTATE_LEFT ((a), (s)); \ <BR>(a) += (b); \
<BR> } <BR>#define HH(a, b, c, d, x, s, ac) { \ <BR>(a) += H ((b), (c),
(d)) + (x) + (UINT4)(ac); \ <BR>(a) = ROTATE_LEFT ((a), (s)); \ <BR>(a) +=
(b); \ <BR> } <BR>#define II(a, b, c, d, x, s, ac) { \ <BR>(a) += I
((b), (c), (d)) + (x) + (UINT4)(ac); \ <BR>(a) = ROTATE_LEFT ((a), (s)); \
<BR>(a) += (b); \ <BR> } <BR><BR>/*开始进行MD5计算 <BR>void MD5Init (context)
<BR>MD5_CTX *context;
<BR>{ <BR>
context->count[0] = context->count[1] = 0; <BR> /*
在这里定义四个常数,也就是我们刚才讲到的四个特征数. <BR><BR> context->state[0] = 0x67452301;
<BR> context->state[1] = 0xefcdab89; <BR> context->state[2]
= 0x98badcfe; <BR> context->state[3] = 0x10325476; <BR>} <BR><BR>void
MD5Update (context, input, inputLen) <BR>MD5_CTX *context;
<BR>unsigned char *input;
<BR>unsigned
int inputLen;
<BR>{ <BR> unsigned int i, index, partLen; <BR><BR> index =
(unsigned int)((context->count[0] >> 3) & 0x3F); <BR><BR>
if ((context->count[0] += ((UINT4)inputLen << 3)) <
((UINT4)inputLen << 3)) <BR>context->count[1]++; <BR>
context->count[1] += ((UINT4)inputLen >> 29); <BR><BR> partLen
= 64 - index; <BR><BR> if (inputLen >= partLen) { <BR>MD5_memcpy
<BR> ((POINTER)&context->buffer[index], (POINTER)input, partLen);
<BR>MD5Transform (context->state, context->buffer); <BR><BR>for (i =
partLen; i + 63 < inputLen; i += 64) <BR> MD5Transform
(context->state, &input[i]); <BR><BR>index = 0; <BR> } <BR>
else <BR>i = 0; <BR><BR> MD5_memcpy
<BR>((POINTER)&context->buffer[index], (POINTER)&input[i],
<BR> inputLen-i); <BR>} <BR><BR>void MD5Final (digest, context)
<BR>unsigned char digest[16];
<BR>MD5_CTX *context;
<BR>{
<BR> unsigned char bits[8]; <BR> unsigned int index, padLen;
<BR><BR> Encode (bits, context->count, 8); <BR><BR> index =
(unsigned int)((context->count[0] >> 3) & 0x3f); <BR>
padLen = (index < 56) ? (56 - index) : (120 - index); <BR> MD5Update
(context, PADDING, padLen); <BR> MD5Update (context, bits, 8);
<BR><BR> Encode (digest, context->state, 16); <BR> MD5_memset
((POINTER)context, 0, sizeof (*context)); <BR>} <BR><BR>static void
MD5Transform (state, block) <BR>UINT4 state[4]; <BR>unsigned char block[64];
<BR>{ <BR> UINT4 a = state[0], b = state[1], c = state[2], d = state[3],
x[16]; <BR><BR> Decode (x, block, 64); <BR><BR> /* 第一轮循环 */
<BR> FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ <BR> FF (d,
a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ <BR> FF (c, d, a, b, x[ 2],
S13, 0x242070db); /* 3 */ <BR> FF (b, c, d, a, x[ 3], S14, 0xc1bdceee);
/* 4 */ <BR> FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ <BR>
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ <BR> FF (c, d, a, b, x[
6], S13, 0xa8304613); /* 7 */ <BR> FF (b, c, d, a, x[ 7], S14,
0xfd469501); /* 8 */ <BR> FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9
*/ <BR> FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ <BR> FF
(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ <BR> FF (b, c, d, a,
x[11], S14, 0x895cd7be); /* 12 */ <BR> FF (a, b, c, d, x[12], S11,
0x6b901122); /* 13 */ <BR> FF (d, a, b, c, x[13], S12, 0xfd987193); /*
14 */ <BR> FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ <BR>
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ <BR><BR>/* 第二轮循环 */
<BR> GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ <BR> GG (d,
a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ <BR> GG (c, d, a, b, x[11],
S23, 0x265e5a51); /* 19 */ <BR> GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -