初探MD5原理及哈希拓展攻击
学点密码学。
前言
MD5消息摘要算法一种被广泛使用的密码散列函数,输入长度小于2^64【18446744073709551616位的消息,输出一个128位【16Byte的散列值,输入信息以512位一组的分组为单位处理。一般128位的MD5散列被表示为32个字符的十六进制数字。
原理
末尾填充
首先是对原文求余,判断原文位数模除512的结果是否为448。
若不满足以上条件,则对其进行填充,第一位填充1,剩余位数填充0,直到满足最后结果长度模除512的值为448,若取余结果大于448,则再填充一组512长度的值。
需要注意的是,这边填充的内容是小端序,如下。
1 | 1 > 00 00 00 01 > 01 00 00 00 > 0x80 |
因此在Python中填充第一位的内容为,实现代码如下。
1 | message = "south" |
剩下的64位是记录原文的真实长度的,因为MD5处理的是长度小于2^64位的数据。
1 | # 计算消息长度 |
变量初始化
用4个32位的寄存器A,B,C,D存放4个固定的32位整型参数【0123456789abcdeffedcba9876543210,用于第一轮迭代,注意是小端序。
1 | A, B, C, D = 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 |
分组处理
在根据原文长度按512位一组分组后,每一组再按32位一组分16组,然后以16个子分组为一轮,依次经过函数计算后,再同上一步定义的ABCD四个初始变量计算生成新的ABCD变量,用于下一次计算。
这是MD5官方使用的四个函数,在512位分组的32位子分组中运算的时候,第一轮使用F函数,第二轮使用G函数,第三轮次使用H函数,在第四轮次使用I函数,每次都只用到BCD三个变量。
1 | F(B, C, D) = (B & C) | ((~B) & D) |
调用函数之后,田字格是相加,Mi是32位分组的原文,Ki是伪随机数生成的常数,把它们相加,和0xffffffff做与运算是为保证结果不超过32位。
1 | # 伪随机数k |
然后将相加结果左移s【常量位,再加上B的值,同作与运算后赋值给B,同时,把D赋值给原A,B赋值给原C,C赋值给原D,如下。
1 | # 左移 |
最后拼接ABCD即可。
完整代码
代码修改自MD5原理及Python实现。
1 | import struct |
哈希拓展攻击
例题。
1 |
|
已知secret长度,已知md5($secret . urldecode("admin" . "admin"))的值。
那么根据MD5的原理可知,实际加密数据如下。
1 | message = secret + "adminadmin" |
而MD5是根据消息长度分组加密的,上一组计算的输出作为下一组的输入,那么在这里只需要将已知md5($secret . urldecode("admin" . "admin"))的值作为初始化的ABCD输入,设加密消息为"south",就可以不需要知道前面secret的值得到如下加密数据。
1 | # 接上文代码 |
后面的\(username**和**\)password可控,那么使得\(username=admin**,**\)password=admin00south即可。
此时,满足例题的绕过。