明文处理,经常会谈到MD5加密。MD5使用比较广泛的一种加密算法。
本文探讨下,MD5的安全性如何?
先从算法的特点出发。
MD5的特点:
- 快速计算:设计初衷就是追求效率。
- 哈希冲突:不同的输入,可以生成同样的哈希值。
- 长度限制:128位长度。 减少了哈希值的组合数量。
MD5加密后的字符串特征:
- 长度固定,32位、16位。其中,16位是截取32位的第9~24位。
- 由a-zA-Z和0-9组成的字符串。字母区分大小写,可以分成:16位[小写字母]、16位[大写字母]、32位[小写字母]、32位[大写字母]。
下面我们看看MD5安全性如何。
解密都是有成本的,如果解密成本非常的大,时间成本或存储成本非常的大。解密成本越大,加密算法安全性越高。
下面我们从三种方法看,该算法破解的成本如何:(以12位长度上限的密码大小写字母为例)
1.暴力破解
我们先看例子。电影《模仿游戏》讲述的是二战期间主角被招去破解军事密码,一群顶尖人才做破解工作。主角想到了用机器来代替人做运算,最终密码也破解了。
遍历尝试每一个字符,直到找到正确值为止。 这种方法效率很低,每个字符都需要进行md5计算,再把结果和密文对比。 小结,存储成本较低,只需要一个程序不断的计算即可;密码越长,计算成本越大。
需要运算:(26+26+10)^12+(26+26+10)^11+...个,计算成本大。
2.字典法
把所有可能的密文都算出来,放在一张表里,然后查对应的密文即可。 如果按照12位密码长度(仅大小写字母+数字),就有 (26+26+10)的14次方。 也就是这个表要存那么多数据,才能进行定位查询。 小结,存储成本非常高,需要存储巨大的表数据;密码越长,需要覆盖的字符集越多,存储成本越大。
需要把运算结果都存储起来:(26+26+10)^12+(26+26+10)^11+...个,存储成本大。
3.彩虹表
结合暴力破解和字典法。针对密码的组合,需要预先计算好哈希值的集合。 根据加密算法的特征(比如利用md5的哈希冲突),优化哈希函数,可以有效的减少计算的次数。 通过一种称为“彩虹链”的技术对数据进行压缩,不需要存储所有可能的哈希值集合,只需要存储链表的头和尾,可以节省更多的存储空间。
上图就是彩虹表的过程。
H是摘要信息的哈希函数,也是要破解算法的函数。
R是构建这条链的时候定义的一个函数,它的值域和定义域与 H 函数相反。通过该函数可以将哈希值约简为一个与原文相同格式的值。
重复的部分(上图的虚线部分),通过算法即可优化。这也是彩虹表的方法,通过优化算法,也就是H函数和R函数优化,进一步优化计算能力。
彩虹表破解MD5的成本大大减少,这也导致网上有大量的”在线解密MD5“。
如果项目还是要用MD5加密,建议在原字符串的基础上,拼接多一串静态的字符串或者动态字符串,也就是加盐。
用”在线解密MD5“也只能得到,组合过的字符串;管理好”盐“,安全性大大提高。
小结:
如果项目是决定用MD5,建议”加盐“提高安全性。在原字符串的基础上,拼接多一串静态的字符串或者动态字符串。
如果不是必须使用MD5,建议还是使用sha256等加密。毕竟MD5,已经被破解了。在专业的项目中使用,显得我们不是很专业。
最后,附上CryptoJS中的md5源码,也可以点击下面链接查看。
(function (Math) {
// Shortcuts
var C = CryptoJS;
var C_lib = C.lib;
var WordArray = C_lib.WordArray;
var Hasher = C_lib.Hasher;
var C_algo = C.algo;
// Constants table
var T = [];
// Compute constants
(function () {
for (var i = 0; i < 64; i++) {
T[i] = (Math.abs(Math.sin(i + 1)) * 0x100000000) | 0;
}
}());
/**
* MD5 hash algorithm.
*/
var MD5 = C_algo.MD5 = Hasher.extend({
_doReset: function () {
this._hash = new WordArray.init([
0x67452301, 0xefcdab89,
0x98badcfe, 0x10325476
]);
},
_doProcessBlock: function (M, offset) {
...
},
_doFinalize: function () {
...
},
clone: function () {
...
}
});
function FF(a, b, c, d, x, s, t) {
var n = a + ((b & c) | (~b & d)) + x + t;
return ((n << s) | (n >>> (32 - s))) + b;
}
function GG(a, b, c, d, x, s, t) {
var n = a + ((b & d) | (c & ~d)) + x + t;
return ((n << s) | (n >>> (32 - s))) + b;
}
function HH(a, b, c, d, x, s, t) {
var n = a + (b ^ c ^ d) + x + t;
return ((n << s) | (n >>> (32 - s))) + b;
}
function II(a, b, c, d, x, s, t) {
var n = a + (c ^ (b | ~d)) + x + t;
return ((n << s) | (n >>> (32 - s))) + b;
}
C.MD5 = Hasher._createHelper(MD5);
C.HmacMD5 = Hasher._createHmacHelper(MD5);
}(Math));