📄 md5信息-摘要加算法(翻译).html
字号:
((char *)output)[i] = (char)value;<br>
}<br>
<br>
<font color="#FF0000"><a name="A.4 mddriver.c">A.4 mddriver.c</a></font><br>
<br>
/* MDDRIVER.C - MD2, MD4 及 MD5 的测试驱动<br>
*/<br>
<br>
/* 如果没有用C语言编译器的标志定义的话,默认是进行MD5测试驱动<br>
*/<br>
#ifndef MD<br>
#define MD MD5<br>
#endif<br>
<br>
#include <stdio.h><br>
#include <time.h><br>
#include <string.h><br>
#include "global.h"<br>
#if MD == 2<br>
#include "md2.h"<br>
#endif<br>
#if MD == 4<br>
#include "md4.h"<br>
#endif<br>
#if MD == 5<br>
#include "md5.h"<br>
#endif<br>
<br>
/* 测试块的长度, 测试块的数目。<br>
*/<br>
#define TEST_BLOCK_LEN 1000<br>
#define TEST_BLOCK_COUNT 1000<br>
<br>
static void MDString PROTO_LIST ((char *));<br>
static void MDTimeTrial PROTO_LIST ((void));<br>
static void MDTestSuite PROTO_LIST ((void));<br>
static void MDFile PROTO_LIST ((char *));<br>
static void MDFilter PROTO_LIST ((void));<br>
static void MDPrint PROTO_LIST ((unsigned char [16]));<br>
<br>
#if MD == 2<br>
#define MD_CTX MD2_CTX<br>
#define MDInit MD2Init<br>
#define MDUpdate MD2Update<br>
#define MDFinal MD2Final<br>
#endif<br>
#if MD == 4<br>
#define MD_CTX MD4_CTX<br>
#define MDInit MD4Init<br>
#define MDUpdate MD4Update<br>
#define MDFinal MD4Final<br>
#endif<br>
#if MD == 5<br>
#define MD_CTX MD5_CTX<br>
#define MDInit MD5Init<br>
#define MDUpdate MD5Update<br>
#define MDFinal MD5Final<br>
#endif<br>
<br>
/* 主驱动<br>
<br>
参数定义 (可以合起来使用):<br>
-sstring - 摘要字符串<br>
-t - 进行时间测试<br>
-x - 运行测试脚本<br>
filename - 摘要文件<br>
(none) - 摘要标准输入<br>
*/<br>
int main (argc, argv)<br>
int argc;<br>
char *argv[];<br>
{<br>
int i;<br>
<br>
if (argc > 1)<br>
for (i = 1; i < argc; i++)<br>
if (argv[i][0] == '-' && argv[i][1] == 's')<br>
MDString (argv[i] + 2);<br>
else if (strcmp (argv[i], "-t") == 0)<br>
MDTimeTrial ();<br>
else if (strcmp (argv[i], "-x") == 0)<br>
MDTestSuite ();<br>
else<br>
MDFile (argv[i]);<br>
else<br>
MDFilter ();<br>
<br>
return (0);<br>
}<br>
<br>
/* 计算一个字符串信息摘要,并输出结果<br>
*/<br>
static void MDString (string)<br>
char *string;<br>
{<br>
MD_CTX context;<br>
unsigned char digest[16];<br>
unsigned int len = strlen (string);<br>
<br>
MDInit (&context);<br>
MDUpdate (&context, string, len);<br>
MDFinal (digest, &context);<br>
<br>
printf ("MD%d (\"%s\") = ", MD, string);<br>
MDPrint (digest);<br>
printf ("\n");<br>
}<br>
<br>
/* 测量对 TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte 数据块进行摘要计算所需的时间<br>
*/<br>
static void MDTimeTrial ()<br>
{<br>
MD_CTX context;<br>
time_t endTime, startTime;<br>
unsigned char block[TEST_BLOCK_LEN], digest[16];<br>
unsigned int i;<br>
printf<br>
("MD%d time trial. Digesting %d %d-byte blocks ...", MD,<br>
TEST_BLOCK_LEN, TEST_BLOCK_COUNT);<br>
<br>
/* Initialize block */<br>
for (i = 0; i < TEST_BLOCK_LEN; i++)<br>
block[i] = (unsigned char)(i & 0xff);<br>
<br>
/* Start timer */<br>
time (&startTime);<br>
<br>
/* Digest blocks */<br>
MDInit (&context);<br>
for (i = 0; i < TEST_BLOCK_COUNT; i++)<br>
MDUpdate (&context, block, TEST_BLOCK_LEN);<br>
MDFinal (digest, &context);<br>
<br>
/* Stop timer */<br>
time (&endTime);<br>
<br>
printf (" done\n");<br>
printf ("Digest = ");<br>
MDPrint (digest);<br>
printf ("\nTime = %ld seconds\n", (long)(endTime-startTime));<br>
printf<br>
("Speed = %ld bytes/second\n",<br>
(long)TEST_BLOCK_LEN * (long)TEST_BLOCK_COUNT/(endTime-startTime));<br>
}<br>
<br>
/* 计算一系列字符串的信息摘要,并输出结果<br>
*/<br>
static void MDTestSuite ()<br>
{<br>
printf ("MD%d test suite:\n", MD);<br>
<br>
MDString ("");<br>
MDString ("a");<br>
MDString ("abc");<br>
MDString ("message digest");<br>
MDString ("abcdefghijklmnopqrstuvwxyz");<br>
MDString<br>
("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");<br>
MDString<br>
("1234567890123456789012345678901234567890\<br>
1234567890123456789012345678901234567890");<br>
}<br>
<br>
/* 计算一个文件的信息摘要,并输出结果<br>
*/<br>
static void MDFile (filename)<br>
char *filename;<br>
{<br>
FILE *file;<br>
MD_CTX context;<br>
int len;<br>
unsigned char buffer[1024], digest[16];<br>
<br>
if ((file = fopen (filename, "rb")) == NULL)<br>
printf ("%s can't be opened\n", filename);<br>
<br>
else {<br>
MDInit (&context);<br>
while (len = fread (buffer, 1, 1024, file))<br>
MDUpdate (&context, buffer, len);<br>
MDFinal (digest, &context);<br>
<br>
fclose (file);<br>
<br>
printf ("MD%d (%s) = ", MD, filename);<br>
MDPrint (digest);<br>
printf ("\n");<br>
}<br>
}<br>
<br>
/* 计算标准输入的信息摘要,并输出结果<br>
*/<br>
static void MDFilter ()<br>
{<br>
MD_CTX context;<br>
int len;<br>
unsigned char buffer[16], digest[16];<br>
<br>
MDInit (&context);<br>
while (len = fread (buffer, 1, 16, stdin))<br>
MDUpdate (&context, buffer, len);<br>
MDFinal (digest, &context);<br>
<br>
MDPrint (digest);<br>
printf ("\n");<br>
}<br>
<br>
/* 以16进制的形式输出一份信息摘要<br>
*/<br>
static void MDPrint (digest)<br>
unsigned char digest[16];<br>
{<br>
unsigned int i;<br>
<br>
for (i = 0; i < 16; i++)<br>
printf ("%02x", digest[i]);<br>
}<br>
<br>
<a name="A.5 对编写好的MD5程序进行一系列测试"><font color="#FF0000">A.5 对编写好的MD5程序进行一系列测试</font></a><br>
<br>
MD5 系列测试(驱动参数 "-x") 得到的结果应该为:<br>
<br>
MD5 系列测试:<br>
MD5 ("") = d41d8cd98f00b204e9800998ecf8427e<br>
MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661<br>
MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72<br>
MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0<br>
MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b<br>
MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") =<br>
d174ab98d277d9f5a5611c2c9f419d9f<br>
MD5 ("123456789012345678901234567890123456789012345678901234567890123456<br>
78901234567890") = 57edf4a22be3c955ac49da2e2107b67a<br>
<br>
<b><font size="4" color="#FFFF00"><span style="background-color: #000000"><a name="安全考虑">安全考虑</a>及常用的攻击方式</span></font></b><br>
<br>
在这份备忘录里讨论的MD5安全级别,主要是考虑将MD5加密算法与公钥加密系统相配合,构成混合的签名认证机制,将具有极高的安全。</font>
</p>
<p align="left" style="line-height: 150%"><font size="2"> MD5是被用来单向变换用户口令和对信息签名的单向散列算法。一种单向散列的强度体现在它能把任意的输入随机化到什么程度并且能产生唯一的输出。对单向散列的直接攻击可以分为普通直接攻击和“生日”攻击。 <br>
<br>
<font color="#FF0000"> ●</font> <font color="#FF0000"> 对MD5的普通直接攻击</font> <br>
<br>
所谓直接攻击又叫野蛮攻击。攻击者为了找到一份和原始明文 m 散列结果相同的明文 m' ,就是
H(m)=H(m') 。普通直接攻击,顾名思义就是穷举可能的明文去产生一个和 H(m) 相同的散列结果。对MD5来说散列结果为128-bits,就是说如果攻击者有一台每秒尝试1,000,000,000条明文的机器需要算约10^22年,同时兴许会同时发现m本身:))。</font>
</p>
<p align="left" style="line-height: 150%"><font color="#FF0000"><font size="2">●</font></font> <font size="2"> <font color="#FF0000"> 对MD5的生日攻击</font> <br>
<br>
生日攻击实际上只是为了找到两条能产生同样散列结果的明文。记得那个有名的概率生日问题吗?在 N 个人中至少有两个人生日相同的概率是多少?所谓生日攻击实际上只是用概率来指导散列冲突的发现,对于MD5来说如果尝试2^64条明文,那么它们之间至少有一对发生冲突的概率就是 50%。仅此而已,对当今的科技能力来说,它也是不可能的。一台上面谈到的机器平均需要运行585年才能找到一对,而且并不能马上变成实际的攻击成果。因为码长和速度的关系,对crypt(3)的生日攻击就成功得多。</font>
</p>
<p align="left" style="line-height: 150%"><font color="#FF0000"><font size="2">● 其他对MD5的攻击</font></font><font size="2"> <br>
<br>
微分攻击被证明对MD5的一次循环是有效的,但对全部4次循环无效。(微分攻击是通过比较分析有特定区别的明文在通过加密后的变化传播情况来攻击加密体系的。)有一种成功的MD5攻击,不过它是对MD5代码本身做了手脚,是一种crack而不是hack更算不上cryptanalysis了。</font>
</p>
<p align="left" style="line-height: 150%"><font color="#FF0000"><font size="2">● 口令长度和信息论 </font></font><font size="2"><br>
<br>
根据传统信息论,英语的每个8-bits字母的信息熵为1.3bits。如果口令足够长,MD5的结果就会足够随机。对 128-bits 的MD5输出来说,一个长达98个字符的口令将给出一个随机的密匙。(8/1.3)*(128/8) = 98.46 chars可是谁会用一个象下面这样长的口令呢? <br>
<br>
12345678901234567890123456789012345678901235678901234567890 <br>
1234567890123456789012345678 <br>
<br>
1.3 bits 的信息熵来自于英语语法的规律性这个事实,字母出现概率的不等造成了熵的减小。如果26个拉丁字母出现的概率均等,信息熵将会增至log(26)/log(2) = 4.7 bits </font>
</p>
<p align="left" style="line-height: 150%"><font size="2">这样一个随机密匙所需口令长度就减为 27.23 chars 了,如果再加上大小写和几个符号还可以减少。关于选择口令的问题可以参考任何关于安全性的书籍,它们都适用。 <br>
<br>
<br>
<a name="作者通讯地址"><font color="#FFFF00" size="4"><b>作者通讯地址</b></font></a>(<font color="#00FF00">newlaos</font>:未翻译:)<br>
<br>
Ronald L. Rivest<br>
Massachusetts Institute of Technology<br>
Laboratory for Computer Science<br>
NE43-324<br>
545 Technology Square<br>
Cambridge, MA 02139-1986<br>
<br>
Phone: (617) 253-5880<br>
EMail: rivest@theory.lcs.mit.edu</font><br>
<br>
</p>
</body>
<script language="JavaScript"></script>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -