0%

浅谈加密和编码:MD5

1.MD5简介

MD5的全称是Message-Digest Algorithm 5(信息摘要算法),经MD2、MD3和MD4发展而来。
所谓信息摘要,就是包含数据关键特性,能(唯一)识别原数据的关键信息。

MD5也称为单向散列算法,这是从其实现方式命名,因为:

  • MD5能对大量数据,进行哈希映射,输出固定长度(128bit)的数据,输出数据也称为原数据的信息摘要。
  • 不能由摘要推测出原数据,即MD5算法是单向的,当加密来用的话,只能加密不能解密。

MD5的特点:

  • 固定长度:输入任意长度的信息,经过MD5处理,输出总是128位的信息。
  • 唯一性:不同的输入得到的不同的结果;同样的输入一定得到相同的结果。
  • 不可逆:根据128位的输出结果不可能反推出输入的信息。

2.MD5的应用

1、防止被篡改:
1)比如A和B发送一个电子文档,发送前,A先自己计算出数据的MD5输出结果a。
然后在B收到电子文档后,B计算得到一个MD5的输出结果b。
如果a与b一样就代表传输中途数据未被篡改。
2)比如A提供文件下载,为了防止不法分子在文件中添加木马,伪装成A的文件。A可以在网站上公布由安装文件得到的MD5输出结果。
要下载文件的人只需要下载后,验证MD5是否和A一致,如果不一致,就是被其他人修改过。

2、防止暴露明文:
基本上存储用户密码的场景,都用到MD5加密明文。
1)例如网站服务器在其数据库存储用户的密码,都是存储用户密码的MD5值。就算不法分子得用户密码的MD5值,也无法知道用户的密码。
2)在UNIX、Linux系统中,用户密码就是以MD5(或其它类似的算法)经加密后存储在文件系统中。当用户登录的时候,系统把用户输入的密码计算成MD5值,然后再去和保存在文件系统中的MD5值进行比较,进而确定输入的密码是否正确。通过这样的步骤,系统在并不知道用户密码的明码的情况下就可以确定用户登录系统的合法性。这不但可以避免用户的密码被具有系统管理员权限的用户知道,而且还在一定程度上增加了密码被破解的难度。

3、防止抵赖(数字签名):
这需要一个存储MD5值的第三方认证机构。例如A写了一个文件,认证机构对此文件用MD5算法产生摘要信息并做好记录。若以后A说这文件不是他写的,权威机构只需对此文件重新产生摘要信息,然后跟记录在册的摘要信息进行比对,相同的话,就证明是A写的了。这就是所谓的“数字签名”。

3.MD5算法实现

对MD5算法简要的叙述可以为:
MD5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。

第一步、填充:如果输入信息的长度(bit)对512求余的结果不等于448,就需要填充使得对512求余的结果等于448。填充的方法是填充一个1和n个0。填充完后,信息的长度就为N512+448(bit);
第二步、记录信息长度:用64位来存储填充前信息长度。这64位加在第一步结果的后面,这样信息长度就变为N
512+448+64=(N+1)*512位。
第三步、装入标准的幻数(四个整数):标准的幻数(物理顺序)是(A=(01234567) 16 ,B=(89ABCDEF) 16 ,C=(FEDCBA98) 16 ,D=(76543210) 16 )。如果在程序中定义应该考虑大小端(A=0X67452301L,B=0XEFCDAB89L,C=0X98BADCFEL,D=0X10325476L)。
第四步、四轮循环运算:循环的次数是分组的个数(N+1)。 最终由4个32bit数据拼成128bit的结果。

image-20221212143002209

4.MD5的安全性

普遍认为MD5是很安全,因为哈希散列是强抗碰撞的:已知原数据和其MD5值,想通过枚举找到一个相同MD5值的数据,基本不可能。如果暴力破解MD5,其运算时间是不可想象的。

但是实际应用上,如果把用户密码仅仅MD5处理后再存储到数据库,其实是很不安全的。因为用户的密码的固有特征,让枚举集合变小了许多,原因:

  • 用户密码是比较短的一般8位左右。
  • 很多用户的密码有规律,例如使用生日,手机号码,或者使用常用数字组合,或某个英文单词。
  • 许多用户的常用密码只有一个,也就是说,泄漏了微信的密码,也很有可能QQ,支付宝密码也泄漏了

如果把常用的密码先MD5处理后存储结果,然后再跟用户的MD5结果匹配,这时就有较大概率“碰撞”,得到明文。这种预先存储的MD5表称为rainbow-table。
因此MD5作为“信息摘要”的用途多一些,作为加密,还需要配合其他的算法(例如AES等几种公钥算法),或者“加盐”。
安全性比较好的网站,都会用一种叫做 “加盐”(salt)的方式来存储密码:

  • 先将用户输入的密码进行一次MD5(或其它哈希算法)加密。
  • 将得到的MD5值前后加上一些只有管理员自己知道的随机串,再进行一次MD5加密。
  • 这个随机串中可以包括某些固定的串,也可以包括用户名(用来保证每个用户加密使用的密钥都不一样)。
  • 在管理员和用户的两个salt没有泄露的情况下,黑客拿到加密串,就几乎不可能推算出原始的密码是什么了。

5.MD5库

在涉及到文件传输的场景,通常用MD5校验文件的一致性,openSSL库提供MD5计算函数:

MD5_Update

1
2
3
int MD5_Init(MD5_CTX *c);
int MD5_Update(MD5_CTX *c, const void *data, unsigned long len);
int MD5_Final(unsigned char *md, MD5_CTX *c);