MD5加密的概念
MD5加密是一种常用的信息摘要算法,主要用于保证数据的一致性以及签名验证,他是一种不可逆的加密算法。
MD5加密是将任意的字节数组加密成32个字节的数据,然后他们在形式上表现为32位的16进制数。
MD5加密的简单使用
我们来看下MD5加密在Java上的简单应用。
Java已经帮我们实现好了MD5加密,我们只需要调用系统函数就可以实现了。调用顺序按如下步骤:
第一步
获取MD5加密的对象:
try {
messagedigest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException nsaex) {
System.err.println(MD5Util.class.getName() + "初始化失败,MessageDigest不支持MD5Util。");
nsaex.printStackTrace();
}
第二步
传入要加密的数据:
byte[] secretBytes = messagedigest.digest(str.getBytes());
加密的数据也可以分次传入:
InputStream fis;
fis = new FileInputStream(file);
byte[] buffer = new byte[1024];
int numRead = 0;
while ((numRead = fis.read(buffer)) > 0) {
messagedigest.update(buffer, 0, numRead);
}
fis.close();
byte[] secretBytes = messagedigest.digest();
返回的byte数组是长度为16的数组。
第三步
将加密得到的byte数组转换为我们通常见到的MD5加密后的样子:
protected static char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
private static String bufferToHex(byte bytes[], int m, int n) {
StringBuffer stringbuffer = new StringBuffer(2 * n);
int k = m + n;
for (int l = m; l < k; l++) {
appendHexPair(bytes[l], stringbuffer);
}
return stringbuffer.toString();
}
private static void appendHexPair(byte bt, StringBuffer stringbuffer) {
char c0 = hexDigits[(bt & 0xf0) >>> 4];// 取字节中高 4 位的数字转换
char c1 = hexDigits[bt & 0xf];// 取字节中低 4 位的数字转换
stringbuffer.append(c0);
stringbuffer.append(c1);
}
如此就得到了加密后的字符串。
注意我们通常见到的将byte转换为加密后的字符串还有一种写法,就是使用BigInteger这个类:
String md5code = new BigInteger(1, secretBytes).toString(16);
但是这种写法有一个问题,就是如果加密后字符串最高位数0,就会被省略:
String str = new BigInteger(1, new byte[]{0, 16}).toString(16);
System.out.println(str);
//输出10
所以使用BigInteger正确做法如下:
String md5code = new BigInteger(1, secretBytes).toString(16);
for (int i = 0; i < 32 - md5code.length(); i++) {
md5code = "0" + md5code;
}
以上就是MD5在Java上的简单实现。
MD5加密的实用场景
我们来看下MD5加密的应用场景。
由于MD5是不可逆的,所以对于一些加密后传输,然后在另一端解密的场景都不适用,它主要运用于对信息的隐藏以及保障数据的一致性等。
下面我们举几个具体的使用MD5加密的场景。
用户密码
用户的密码是非常敏感的数据,它传输或者存储的时候,如果直接使用明文会造成安全隐患。
例如明文存在客户端本地,客户端被root破解后就能够直接拿到文件从而找到密码,存在服务器数据库里面的密码也有被破解服务器后拿到密码的风险,而且能够被后台管理人员看到密码,而在传输过程中,如果发生DNS劫持,也能够被拿到密码。
所以密码如果进行传输和存储最好是使用MD5加密后,客户端和服务端比对加密字符串,如果一致密码校验就通过。
接口签名
网络接口如果不做限制,任意一方都能够调用到接口并且实现一些业务,会带来很大的安全隐患,为了避免这种情况,可以选择在接口添加一个签名参数。
例如,对于网络接口https://wanandroid.com/wxarticle/chapters/json ,如果再添加一个签名参数sign,他的值取“be happy”+全路径MD5签名后的字符串,然后后台在收到请求后,对签名进行验证,就能够很好的防止第三方恶意调用。
文件一致性校验
文件在传输过程中的损坏等情况时有发生,在保证文件一致的时候可以使用MD5校验。
例如,在客户端下载大文件的时候,一般会做断点续存的机制,那么就要这样的一个场景:文件下载了一部分后,被终止了下载,然后在此期间服务器的文件更新了,客户端在此下载的时候,下载的文件就是有问题的了,这样如果不做校验就会发生错误,而如果服务端在下发文件的时候,还下发一个MD5值,客户端在下载完成后检验下载完的文件的MD5与服务端下发的MD5值,不一致就删掉文件重新下载,就能够避免这种情况。
MD5加密的安全与破解
以加密密码为例,由于MD5加密是不可逆的,且加密字符串之间的相似度与原始字符串无关,不能通过加密字符串的相识度比对来修正原始字符串,所以对于MD5的破解一般是基于暴力破解,而MD5加密的结果共有16的32次方种,想要暴力破解这么大数据量现在的计算机还做不到,所以常规意义下MD5的安全性是很高的。
那么现在市面上盛行的MD5密码的破解是如何做的呢?这是由于大部分人设置的密码都是相对简单的,一般为纯数字或者英文加数字等,这样在暴力破解的时候,不要按部就班的去尝试,直接用常用的密码加密后去比对,就能够减少很多的计算量,从而达到破解的目的。
为了对抗这种情况,保护用户的密码信息,可以在用户的密码上加上一些通用的前后缀,例如用户设置密码为 123456,这种如果被拿到加密后的字符串,很容易被撞库破解,但是我们手动给其加上前后缀,使用 abc123456xyz ,这样被破解的概率就会低很多。