什么是MD5算法
MD5讯息摘要演算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码杂凑函数,可以产生出一个128位元(16位元组)的散列值(hash value),用于确保信息传输完整一致。
实质上,MD5 只是一种哈希算法
哈希算法,即 hash,又叫散列算法,是一类把任意数据转换为定长(或限制长度)数据的算法统称。例如我叫张三,你叫李四,那么「人 -> 人名」的算法就叫属于一种哈希算法。哈希算法通常用于制作数字指纹,数字指纹的意思就是「你看到这个东西就像看到原数据一样」,例如我们在一些网站下载大文件的时候,网站提供给我们验证文件完整性的 MD5 或者 SHA1 码,就是原文件的哈希值。哈希算法有很多种,MD5 是其中的一种,这就是 MD5。所以,优秀的哈希算法通常需要具有低碰撞概率(即不同数据的哈希值通常也不一样)。
Java中的Object.hashCode()
方法就是一个摘要算法,它可以输入任意数据,它的输出是一个int类型,即4个字节的固定长度数据,同时,相同的输入会得到相同的输出,这也是重写equals方法必须重写hashCode方法的原因。
MD5属不属于加密算法
认为不属于的人是因为他们觉得不能从密文(散列值)反过来得到原文,即没有解密算法,所以这部分人认为MD5只能属于算法,不能称为加密算法;
认为属于的人是因为他们觉得经过MD5处理后看不到原文,即已经将原文加密,所以认为MD5属于加密算法;我个人支持前者,正如认为BASE64算法只能算编码一样。
加密,指的是对数据进行转换以后,数据变成了另一种格式,并且除了拿到解密方法的人,没人能把数据转换回来。因此,加密通常用于网络通信。因为网络上的通信数据,任何人都有可能会拿到,把数据加密后再传送,送达以后由对方解密后再查看,就可以防止网络上的偷窥。
MD5算法是否可逆?
MD5不可逆的原因是其是一种散列函数,使用的是hash算法,在计算过程中原文的部分信息是丢失了的。即从明文到密文的不可逆映射,只有加密过程没有解密过程,哈希函数可以将任意长度的输入经过变化后得到固定长度的输出,这个固定长度的输出称为原消息的散列或消息映射。 理想的哈希函数可以针对不同的输入得到不同的输出,如果存在两个不同的消息得到了相同的哈希值,那我们称这是一个碰撞)
不过有个地方值得指出的是,一个MD5理论上的确是可能对应无数多个原文的,因为MD5是有限多个的而原文可以是无数多个。比如主流使用的MD5将任意长度的“字节串映射为一个128bit的大整数。也就是一共有2^128种可能,大概是3.4*10^38,这个数字是有限多个的,而但是世界上可以被用来加密的原文则会有无数的可能性。
不过需要注意的一点是,尽量这是一个理论上的有限对无限,不过问题是这个无限在现实生活中并不完全成立,因为一方面现实中原文的长度往往是有限的(以常用的密码为例,一般人都在20位以内),另一方面目前想要发现两段原文对应同一个MD5(专业的说这叫杂凑冲撞)值非常困难,因此某种意义上来说,在一定范围内想构建MD5值与原文的一一对应关系是完全有可能的。所以对于MD5目前最有效的攻击方式就是彩虹表。
MD5用途
1.防止被篡改:
1)比如发送一个电子文档,发送前,我先得到MD5的输出结果a。然后在对方收到电子文档后,对方也得到一个MD5的输出结果b。如果a与b一样就代表中途未被篡改。
2)比如我提供文件下载,为了防止不法分子在安装程序中添加木马,我可以在网站上公布由安装文件得到的MD5输出结果。
3)SVN在检测文件是否在CheckOut后被修改过,也是用到了MD5.
2.防止直接看到明文:
现在很多网站在数据库存储用户的密码的时候都是存储用户密码的MD5值。这样就算不法分子得到数据库的用户密码的MD5值,也无法知道用户的密码。(比如在UNIX系统中用户的密码就是以MD5(或其它类似的算法)经加密后存储在文件系统中。当用户登录的时候,系统把用户输入的密码计算成MD5值,然后再去和保存在文件系统中的MD5值进行比较,进而确定输入的密码是否正确。通过这样的步骤,系统在并不知道用户密码的明码的情况下就可以确定用户登录系统的合法性。这不但可以避免用户的密码被具有系统管理员权限的用户知道,而且还在一定程度上增加了密码被破解的难度。)
3.防止抵赖(数字签名):
这需要一个第三方认证机构。例如A写了一个文件,认证机构对此文件用MD5算法产生摘要信息并做好记录。若以后A说这文件不是他写的,权威机构只需对此文件重新产生摘要信息,然后跟记录在册的摘要信息进行比对,相同的话,就证明是A写的了。这就是所谓的“数字签名”。
MD5安全性
普遍认为MD5是很安全,因为暴力破解的时间是一般人无法接受的。实际上如果把用户的密码MD5处理后再存储到数据库,其实是很不安全的。因为用户的密码是比较短的,而且很多用户的密码都使用生日,手机号码,身份证号码,电话号码等等。或者使用常用的一些吉利的数字,或者某个英文单词。如果我把常用的密码先MD5处理,把数据存储起来,然后再跟你的MD5结果匹配,这时我就有可能得到明文。比如某些MD5破解网站,所以现在大多数网站密码的策略是强制要求用户使用数字大小写字母的组合的方式提高用户密码的安全度。
目前常用的摘要算法:
java中对MD5算法的使用:
public class SummaryAlgorithm { public static void main(String[] args) throws UnsupportedEncodingException {
String str = "MD5摘要算法";
byte[] testByte = toMD5(str.getBytes());
System.out.println(String.format("%32x", new BigInteger(1, testByte))); String salt = "random";
byte[] digest = toMD5((str + salt).getBytes("UTF-8"));
// %x表示返回的是16进制,而32表示16个字节
System.out.println(String.format("%32x", new BigInteger(1, digest)));
} public static byte[] toMD5(byte[] input) {
MessageDigest md = null;
try {
md = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
md.update(input);
return md.digest();
}
}
MD5算法实现:
输入:不定长度信息(要加密的信息)
输出:固定长度128-bits。由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。
基本方式为:求余、取余、调整长度、与链接变量进行循环运算。得出结果。
具体过程请查看MD5算法。算法的的设计目的就是防碰撞,不可逆。