【密码学5】MD5信息摘要算法详解
2023-3-4 08:31:52 Author: 白帽子(查看原文) 阅读量:16 收藏


MD5信息摘要算法一种被广泛使用的密码散列函数,提供消息完整性,MD5的长度为128位(按照16进制编码,16字节,得到32个字符)是一个散列值(hash value)。

MD5由美国密码学家罗纳德·李维斯特(Ronald Linn Rivest)设计,于1992年公开,用以取代MD4算法。这套算法的程序在 RFC 1321 标准中被加以规范。
1996年后该算法被证实存在弱点,可以被加以破解,对于需要高度安全性的数据,专家一般建议改用其他算法,如SHA-2。
2004年,证实MD5算法无法防止碰撞(collision),因此不适用于安全性认证,如SSL公开密钥认证或是数字签名等用途[1]。

  1. 长度固定,任意长度的数据都会输出相同长度的md5值

  2. 不可逆

  1. 对原数据进行任何改动,改变一个字节输出数据也会有很大差异

在浏览各种博客的时候,发现很多很多评论都在指出各种文章中,作者定义md5为加密算法,在这里,我非常认同其中一篇[2]的观点:

认为MD5属于加密算法的人觉得MD5与其他加密算法相似,都为将明文进行运算等各种操作得到与明文完全不相同的数据,而认为MD5不属于加密算法的人认为没有解密算法,无法称为加密算法,当然,第二种相比来说更加严谨,默认情况下不称为加密算法。

  1. 密码保护

“如果直接将密码信息以明码方式保存在数据库中,不使用任何保密措施,系统管理员就很容易能得到原来的密码信息,这些信息一旦泄露, 密码也很容易被破译。”,利用MD5,在后台可以不记录密码本身,并且在后台进行校验密码

  1. 电子签名通过检查文件前后 MD5 值是否发生了改变,就可以知道源文件是否被改动。

  2. 在百科上还看到一个很有用的应用实例,就是筛选垃圾邮件,

1)建立邮件MD5库,分别储存邮件的 MD5 值、允许出现的次数(假定为 3)和出现次数(初值为零)。
2)对每一封收到的邮件进行MD5计算,并与MD5库中的值进行比较
3)如未发现相同的 MD5 值,说明此邮件是第一次收到,将此 MD5 值存入资料库,并将出现次数置为1
4)如发现相同的 MD5 值,说明收到过同样内容的邮件,将出现次数+1[3]

首先需要对信息进行填充,对输入数据进行按位(bit)数据填充,长度进行补齐使消息的长度 X 变成

X = n*512+448

也就是

X mod 512=448

在进行填充时,在消息后面进行填充,填充第一位为1,其余为0
如果数据长度正好为:n*512+448

我们也要对数据进行填充,变成 (n+1)*512+448


之后的448为(448 = 512-64),64位用于填充原消息的长度。

最终被用来处理的数据就为

n*512+448+64 = N*512

四个幻数在内存地址上从低到高为:

A = 0×01234567B = 0×89ABCDEFC = 0xFEDCBA98D = 0×76543210

大小为 4*4 = 16字节

每个标准幻数的大小 与 md5输出大小一致

在程序中,使用小端字节序,md5为四个标准幻数进行多轮哈希运算

(小端模式:高字节在前,低字节在后)

则在程序中应该为:

A = 0x67452301B = 0xEFCDAB89C = 0x98BADCFED = 0x10325476

--------------------------------------------------------------

此处插播一下大端小端问题

关于大小端字节序错误的观念比如

  • 大小端字节序指的是数据在电脑上的二进制顺序

这里一定要记住:大小端字节序指的是数据在电脑上存储的字节顺序!!!

例如:数据 0x 11 22 33 44

小端存储为:44 33 22 11(低位放在低地址,高位放在高地址)

大端存储为:11 22 33 44(低位放在高地址,高位放在低地址)

为什么会有大小端模式之分呢?

在之前听过鹏哥的C语言课程中有详细的解释过:

这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为 8bit ,但是在C语言中除了 8bit 的 char 之外,还有 16bit 的 short 型,  32bit 的 long 型(要看具体的编泽器),另外 ,对于位数大于8位的处理器,例如 16 位或者 32 位的处理器,由于寄存器宽度大于个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。

当然也可以自己检测大小端:

//因为使用共用体,所以返回值就可以判断大小端int check_sys(){    union    {        char c;//1        int i;//4    }u;    u.i = 1;    //返回1,表示小端    //返回0,表示大端    return u.c;}int main(){    int ret = check_sys();
if(1 == ret) { printf("小端"); } else { printf("大端"); } return 0;}

--------------------------------------------------------------

回归正题:

在数据填充部分,我们知道,我们已经将原始数据填充为:N个512位(n个64字节)

然后将每个64字节分成16份

每份4字节

好后,定义4个函数

FF(a,b,c,d,Mi,s,tj)GG(a,b,c,d,Mi,s,tj)HH(a,b,c,d,Mi,s,tj)II(a,b,c,d,Mi,s,tj)

其中,a,b,c,d表示4个标准幻数

第五个为每一份的四字节数据,也就是第i个子分组(一共有16个分组)

第六个和第七个表示为固定长度,用于执行逻辑与、或、非、异或运算、加法运算、移位运算

也就是每个512位(64字节)的分组,划分成16份,每份都运行一次FF,GG,HH,II中的一个函数

每个函数为一轮的话,要运行4*16=64次,每一次改变第一个参数的值

比如在第一轮的第一次运算[3]:

FF(a,b,c,d,M0,s,t1)a = a+(F(b,c,d)+M0+t1);a = (s<<a) | (s>>(32-a));a = a + b;

在第一轮的第一次运算:

FF(b,c,d,a,M1,s,t2)b = b+(F(c,d,a)+M1+t2);b = (s<<b) | (s>>(32-b));b = b + c;

而我们运行的64次则为:

第一轮 

FF(a,b,c,d,M0,7,0xd76aa478)FF(d,a,b,c,M1,12,0xe8c7b756)FF(c,d,a,b,M2,17,0×242070db)FF(b,c,d,a,M3,22,0xc1bdceee)FF(a,b,c,d,M4,7,0xf57c0faf)FF(d,a,b,c,M5,12,0×4787c62a)FF(c,d,a,b,M6,17,0xa8304613)FF(b,c,d,a,M7,22,0xfd469501)FF(a,b,c,d,M8,7,0×698098d8)FF(d,a,b,c,M9,12,0×8b44f7af)FF(c,d,a,b,M10,17,0xffff5bb1)FF(b,c,d,a,M11,22,0×895cd7be)FF(a,b,c,d,M12,7,0×6b901122)FF(d,a,b,c,M13,12,0xfd987193)FF(c,d,a,b,M14,17,0xa679438e)FF(b,c,d,a,M15,22,0×49b40821)

第二轮 

GG(a,b,c,d,M1,5,0xf61e2562)GG(d,a,b,c,M6,9,0xc040b340)GG(c,d,a,b,M11,14,0×265e5a51)GG(b,c,d,a,M0,20,0xe9b6c7aa)GG(a,b,c,d,M5,5,0xd62f105d)GG(d,a,b,c,M10,9,0×02441453)GG(c,d,a,b,M15,14,0xd8a1e681)GG(b,c,d,a,M4,20,0xe7d3fbc8)GG(a,b,c,d,M9,5,0×21e1cde6)GG(d,a,b,c,M14,9,0xc33707d6)GG(c,d,a,b,M3,14,0xf4d50d87)GG(b,c,d,a,M8,20,0×455a14ed)GG(a,b,c,d,M13,5,0xa9e3e905)GG(d,a,b,c,M2,9,0xfcefa3f8)GG(c,d,a,b,M7,14,0×676f02d9)GG(b,c,d,a,M12,20,0×8d2a4c8a)

第三轮 

HH(a,b,c,d,M5,4,0xfffa3942)HH(d,a,b,c,M8,11,0×8771f681)HH(c,d,a,b,M11,16,0×6d9d6122)HH(b,c,d,a,M14,23,0xfde5380c)HH(a,b,c,d,M1,4,0xa4beea44)HH(d,a,b,c,M4,11,0×4bdecfa9)HH(c,d,a,b,M7,16,0xf6bb4b60)HH(b,c,d,a,M10,23,0xbebfbc70)HH(a,b,c,d,M13,4,0×289b7ec6)HH(d,a,b,c,M0,11,0xeaa127fa)HH(c,d,a,b,M3,16,0xd4ef3085)HH(b,c,d,a,M6,23,0×04881d05)HH(a,b,c,d,M9,4,0xd9d4d039)HH(d,a,b,c,M12,11,0xe6db99e5)HH(c,d,a,b,M15,16,0×1fa27cf8)HH(b,c,d,a,M2,23,0xc4ac5665)

第四轮 

II(a,b,c,d,M0,6,0xf4292244)II(d,a,b,c,M7,10,0×432aff97)II(c,d,a,b,M14,15,0xab9423a7)II(b,c,d,a,M5,21,0xfc93a039)II(a,b,c,d,M12,6,0×655b59c3)II(d,a,b,c,M3,10,0×8f0ccc92)II(c,d,a,b,M10,15,0xffeff47d)II(b,c,d,a,M1,21,0×85845dd1)II(a,b,c,d,M8,6,0×6fa87e4f)II(d,a,b,c,M15,10,0xfe2ce6e0)II(c,d,a,b,M6,15,0xa3014314)II(b,c,d,a,M13,21,0×4e0811a1)II(a,b,c,d,M4,6,0xf7537e82)II(d,a,b,c,M11,10,0xbd3af235)II(c,d,a,b,M2,15,0×2ad7d2bb)II(b,c,d,a,M9,21,0xeb86d39

4个函数都执行了16次

然后再将计算得到的4个标准幻数的值与上一轮或开始值相加,然后作为第二轮输入,重复每一次

最终得到的更新后的标准幻数,按顺序得出我们的md5值,这里再强调一下,前面也说了是小端排序,所以应该是这样的

当然了md5的c语言实现代码在之后进行详细补充,加密流程可以参考[4]是个非常详细的过程

https://www.cmd5.com/

参考链接[1] https://baike.baidu.com/item/MD5/212708?fr=aladdin[2] https://blog.csdn.net/u012611878/article/details/54000607[3] https://blog.csdn.net/Oliver_xpl/article/details/90214896?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164493954316780269867160%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=164493954316780269867160&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_ulrmf~default-2-90214896.pc_search_insert_ulrmf&utm_term=MD5&spm=1018.2226.3001.4187[4] https://www.bilibili.com/video/BV1u44y1z7t1?from=search&seid=18258260943716626789&spm_id_from=333.337.0.0

除此之外,Tide安全团队还有更多丰富的Wiki知识体系:

红蓝对抗、移动安全、应急响应、代码审计、工控安全、物联网安全等9个技术wiki,目前共计对外撰文累计620篇。

链接地址:https://www.yuque.com/tidesec


E

N

D

Tide安全团队正式成立于2019年1月,是新潮信息旗下以互联网攻防技术研究为目标的安全团队,团队致力于分享高质量原创文章、开源安全工具、交流安全技术,研究方向覆盖网络攻防、系统安全、Web安全、移动终端、安全开发、物联网/工控安全/AI安全等多个领域。

团队作为“省级等保关键技术实验室”先后与哈工大、齐鲁银行、聊城大学、交通学院等多个高校名企建立联合技术实验室。团队公众号自创建以来,共发布原创文章370余篇,自研平台达到26个,目有15个平台已开源。此外积极参加各类线上、线下CTF比赛并取得了优异的成绩。如有对安全行业感兴趣的小伙伴可以踊跃加入或关注我们。


文章来源: http://mp.weixin.qq.com/s?__biz=MzAwMDQwNTE5MA==&mid=2650246551&idx=2&sn=0191ce955514edfa8984ec6ff8285668&chksm=82ea563eb59ddf288e3c6f991e133a3edcdb93aad2627c5c7daa18dfa2acc6c7a39c7d3f883e#rd
如有侵权请联系:admin#unsafe.sh