Web Security Homework2
MD5 即 Message-Digest Algorithm 5 (信息-摘要算法 5)
MD4 (1990)、MD5(1992, RFC 1321) 作者 Ron Rivest,是广泛使用的散列算法,经常用于确保信息传输的完整性和一致性。MD5 使用 little-endian,输入任意不定长度信息,以512位长进行分组,生成四个32位数据,最后联合起来输出固定128位长的信息摘要。MD5 算法的基本过程为:求余、取余、调整长度、与链接变量进行循环运算、得出结果。
- MD5 不是足够安全的
- Hans Dobbertin 在1996年找到了两个不同的 512-bit 块,它们在 MD5 计算下产生相同的 hash 值。
MD5是一个hash算法,它通过吧任意长度的消息哈希成一个128位长的字符串,但是人们很难将这128位的字符串解出原来的字符串,因为有很多种组合的方式,而且在大部分的情况来看,至今还没有真正找到两个不同的消息,它们的 MD5 的 hash值相等。所以说它是可以保护密码的安全的。
1. 算法原理概述
1.1 算法原理图
1.2 自然语言描述
对MD5算法简要的叙述可以为:MD5以 512 位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个 32 位分组组成,将这四个 32 位分组级联后将生成一个 128 位散列值,其具体步骤为:
- step 1 -> 填充数据
- step 2 -> 记录输入信息长度
- step 3 -> 装入标准的幻数 A B C D
- step 4 -> 设置轮转算式,完成循环运算
- step 5 -> 拼凑A B C D ,完成输出
2. 总体结构
main.cpp
:测试MD5算法有效性文件,来源于RCF 1321
MD5.h
: 定义了MD5类以及宏定义了一些计算方法MD5.cpp
:实现了MD5.h
中的类方法,包括
1 | //声明构造函数 |
3. 模块分解
3.1 标准输入模块
在main函数中,我选择使用了RCF 1321
中给出的标准测试样例进行测试,这样做的好处在于,标准测试样例已经给出了正确的加密结果,只需要将所求的与已知的进行对比,即可得到答案。
1 | // 标准输入: |
3.2 init 模块
由于在测试程序中需要多次建立新的对象,所以我们需要对上一次运算的结果进行清除,而初始化模块就是将每一次的运算的前一次过程进行清除,保证运算结果的正确性。
1 | //先清除原先存在输入信息 |
3.3 Padding 模块
在 Padding 模块中,要做的工作就是补位(不包括加上数据长度的64位),若输入信息的长度对 512 求余的结果不等于 448 ,就需要填充使得对 512 求余的结果等于448。填充的方法是填充一个 1 和 n 个 0 。填充完后,信息的长度就为N * 512 + 448
1 | int difference = 0 ; |
3.4 appendLength 模块
在 appendLength 模块中,对于原始信息(不包括第一步padding补充的位数)的位数长度b,化成二进制表示后选取低64位,每个word按照小端规则添加到第一步处理后的消息数据的尾部。例如,对于消息”a”,消息长度应该是8(8位代表一个字符串),所以二进制表示是”0000…0001000”, 接着补充的情况是”0000…1000 000…000(32个0)”
1 | //采用小端存储的方式插入 |
3.5 transform 模块
在 transform 模块中,使用之前的宏定义完成四轮轮转运算,随后在末尾分别再加上原始数据,即可得到初步加密运算结果A B C D;轮转运算的具体规则如下:
1 | // Round 1 |
3.6 output 模块
在最后输出阶段,使用snprintf
函数对加密完成的数据进行格式规范与处理,将数据从小端存储转移到大端存储,8位8位进行还原,最终得到我们所需要的加密序列
1 | for (int i = 0; i < 4; ++i) |
4. 数据结构
4.1 MD5类
这里为了方便多次进行序列的加密测试,我创建了一个MD5类,在编写具体方法和数据类型时候对类的定义与使用也进行了复习;选择使用类的好处在于我们可以将需要用到的方法和数据(如vector
和bitset
)进行封装,这样就可以进一的保证程序的严整性,同时在测试时候进行初始化操作也会比较快。
1 | class MD5 |
4.2 轮转计算数据
在定义轮转方法时候,我直接使用了RCF 1321
中给出的宏定义,使用宏随可以加快程序运行的速度,但是不太方便源码的阅读;刚从RCF 1321
复制过来,自己也是费了一点功夫去理解这段代码,但是在熟悉之后进入编写函数的步骤,这时候自己写代码的效率就可以提高很多。
1 |
|
5. 运行结果
main.cpp文件为测试算法正确性的文件,其使用RCF 1321
中main.c的测试代码,并在此基础上略做修改,进而来验证加密算法的正确性。
程序编译运行结果如图:
这里有个问题:
由于我的函数方法里面使用了snprintf方法,在windows环境下编译时即使是加入了头文件