Hash算法MD5 实验报告

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

哈尔滨工程大学
实验报告
实验名称: Hash 算法MD5 班级:
学号:
姓名:
实验时间: 2014年6月
成绩:
指导教师:
实验室名称:
哈尔滨工程大学实验室与资产管理处制
一、实验名称
Hash算法MD5
二、实验目的
通过实际编程了解MD5 算法的加密和解密过程,加深对Hash 算法的认识。

三、实验环境(实验所使用的器件、仪器设备名称及规格)
运行Windows 或Linux 操作系统的PC 机,具有gcc(Linux)、VC(Windows)等C 语言编译环境。

四、任务及其要求
(1)利用自己所编的MD5 程序对一个文件进行处理,计算它的Hash 值,提交程序代程和运算结果。

(2)微软的系统软件都有MD5 验证,尝试查找软件的MD5 值。

同时,在Windows 操作系统中,通过开始→运行→sigverif 命令,利用数字签名查找验证非Windows 的系
统软件。

__
五、实验设计(包括原理图、真值表、分析及简化过程、卡诺图、源代码等)
在MD5 算法中,首先需要对信息进行填充,使其字节长度与448 模512 同余,即信息的字节长度扩展至n*512+448,n 为一个正整数。

填充的方法如下:在信息的后面填充第一位为1,其余各位均为0,直到满足上面的条件时才停止用0 对信息填充。

然后,再在这个结果后面附加一个以64 位二进制表示的填充前信息长度。

经过这两步的处理,现在的信息字节长度为n*512+448= (n+1)*512,即长度恰好是512 的整数倍,这样做的目的是为满足后面处理中后面处理中对信息长度的要求。

n 个分组中第q 个分组表示为Yq。

MD5 中有A、B、C、D,4 个32 位被称作链接变量的整数参数,它们的初始值分别为:
A=01234567B=89abcdef,C=fedcba98,D=76543210
当设置好这个4 个链接变量后,就开始进入算法的4 轮循环运算。

循环的次数是信息中512 位信息分组数目。

首先将上面4 个链接变量复制到另外4 个变量中A 到AA,B 到BB,C 到CC,D 到DD,以备后面进行处理。

然后进入主循环,主循环
有4 轮,每轮循环都很相似。

第1 轮进行16 次操作,每次操作对A、B、C 和D 中的其中3 个作一次非线性函数运算,然后将所得结果加上第4 个变量,文本的一个子分组和一个常数。

再将所得结果向左循环移S 位,并加上A、B、C 或D 其中之一。

最后用该结果取代A、B、C 或D 其中之一。

以下是每次操作中用到的4 个非线性函数(每轮一个)。

F(B,C,D)=(B∧C)∨__________(B∧D)(此处需修改)
G(B,C,D)=(B∧D)∨(C∧D)
H(B,C,D)=B⊕C⊕D
I (B,C,D)=C⊕(B∨D)
(注:∧是与,∨是或,是非,⊕是异或。


2
下面为每一轮16 步操作中的4 次操作,16 步操作按照一定次序顺序进行。

FF(A,B,C,D,M[j],S,T[i])表示A=B+(A+(F(B,C,D)+M[j]+T[i])<<<S)
GG(A,B,C,D,M[j],S,T[i])表示A=B+(A+(G(G,C,D)+M[j]+T[i] )<<<S)
HH(A,B,C,D,M[j],S,T[i])表示A=B+(A+(H(B,C,D)+M[j]+T[i] )<<<S)
II (A,B,C,D,M[j],S,T[i])表示A=B+(A+(I (B,C,D)+M[j]+T[i] )<<<S) (注:“+”定义为mod 232 的模运算。

)
M[j]表示在第q 个512 位数据块中的第j 个32 位子分组,0≤j≤15。

常数T[i]可以有如下选择,在第i 步中,T[i]是4294967296*abs(sin(i))的整数部分(注:4294967296= 232 。

),i 的单位是弧度。

其中,T[i]是32 位的随机数源,它消除了输入数据中任何规律性的特征。

表1-4 说明了四轮主循环中每轮16 步操作的具体步骤。

所有这些完成之后,将A、B、C、D 分别加上AA、BB、CC、DD。

然后用下一分组数据继续运行算法,最后的输出是A、B、C 和D 的级联。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
typedef unsigned char *POINTER;
typedef unsigned short int UINT2;
typedef unsigned long int UINT4;
typedef struct
{
UINT4 state[4];
UINT4 count[2];
unsigned char buffer[64];
} MD5_CTX;
void MD5Init(MD5_CTX *);
void MD5Update(MD5_CTX *, unsigned char *, unsigned int);
void MD5Final(unsigned char [16], MD5_CTX *);
#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 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
};
#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)))
#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); }
inline void Encode(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);
}
}
inline void Decode(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);
}
inline void MD5Transform (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);
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 */
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 */
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 */
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;
memset ((POINTER)x, 0, sizeof (x));
}
inline void MD5Init(MD5_CTX *context)
{
context->count[0] = context->count[1] = 0;
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}
inline void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int inputLen)
{
unsigned int i, index, partLen;
index = (unsigned int)((context->count[0] >> 3) & 0x3F);
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) {
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;
memcpy((POINTER)&context->buffer[index],
(POINTER)&input[i], inputLen-i);
}
inline void MD5Final(unsigned char digest[16], MD5_CTX *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);
Encode (digest, context->state, 16);
memset ((POINTER)context, 0, sizeof (*context)); }
void MD5Digest(char *pszInput, unsigned long nInputSize, char *pszOutPut)
{
MD5_CTX context;
unsigned int len = strlen (pszInput);
MD5Init (&context);
MD5Update (&context, (unsigned char *)pszInput, len);
MD5Final ((unsigned char *)pszOutPut, &context); }
Int main()
{ char szDigest[16];
char encrypt[200];
printf("请输入要计算MD5值的字符串:");
gets(encrypt);
printf("\n加密结果:");
MD5Digest(encrypt,strlen(encrypt),szDigest);
int i;
for (i=0;i<16;i++) printf ("%02X",(unsigned char)szDigest[i]);
getchar();
}
六、实验步骤
1.算法分析
在光盘中附加了有关MD5 算法的头文件md5.h 和md5.c,根据所提供的文件分析MD5 算法的实现过程。

下面简单介绍所用到的结构体变量和函数。

程序中用到的结构体变量如下:typedef struct md5_state{
ulong64 lengty;
ulong32 state[4],curlen;
unsigned char buf[64];
}md5_state;
length 记录已经处理过的位数,curlen 记录已经处理过的字节数,数组state 存储上
面所说的4 个链接变量,buf 作为处理过程中的缓存。

程序中用到的函数如下:
(1) void md5_init(md5_state *md)
函数名称:初始化函数
参数说明:
md 指向一个上面所提到的结构体变量。

初始化时把curlen 和length 置为0,并把4 个
链接变量储存到state 中。

(2)int md5_process(md5_state *md, const unsigned char *buf, unsigned long len)
函数名称:处理函数
参数说明:
md 指向经过初过初始化函数处理过的一个结构体变量。

3
buf 指向待处理的信息。

len 是buf 中信息的长度,以字节为单位。

这个函数对待处理的信息以512 位为单位进行压缩,不足的部分存储在结构体中的buf
中,并且用len 来指示信息的末尾,这样下次调用时会接着上一次的结果进行。

(3)int md5_done(md5_state *md, unsigned char *Hash)
函数名称:完成函数
参数说明:md 指向上面所处理过的结构体。

Hash 指向存储结果的缓冲区。

这个函数对未完成的信息先进行padding 操作,然后处理,并把最终结果存在Hash 指
向的缓冲区中。

(1) int md5_text(void)
函数名称:测试函数
这个函数对上面的3 个函数进行测试。

函数内部定义了一组信息和Hash 结果一一对应
的数组。

通过调用上面的3 个函数,并把结果和正确结果相比较,可以判断程序正确与
否。

2.使用实例分析
下面的程序实现了对”hello,world”进行MD5 处理的功能,可以作为调用MD5 函数接口
的参考。

#include “md5.h”
int main( int argc,char *argv[])
{
md5_state md;
unsigned char *in=”hello, world!”,out[16];
md5_init(&md);
md5_process(&md,in,strlen(in));
md5_done(&md,out);
printf(“%s”,out);
system(“PAUSE”);
return 0;
}
说明:由于程序中所用的结构体只在初始化函数中赋初始值,其中间过程可以保留下来,
所以对一段信息分多次处理可以得到同样的结果。

比如说使用下面的语句可以得到和上
面例子相同的结果:
md5_init(&md);
md5_process(&md, “hello,”,6);
md5_process(&md, “world”,5);
md5_done(&md, out);
七、实验过程与分析
八、实验结果总结
Hash 函数是将任意长的数据块转换成一个较短的定长输出数字串的函数,
输出的结果称为Hash 值。

MD5 算法对任意长度的输入值处理后产生128 位的输出值。

九、心得体会
MD5对单个512bit分组的执行将得到相同的输出(伪冲突),MD5比MD4复杂,并且速度较MD4降低了近30%,,但在抗安全性分析方面表现更好
学生自评
注:根据自己所做实验情况,实事求是的给出“评定结果”和“实验成绩”,在相应等级的()内填入■。

相关文档
最新文档