巨人大哥谈Java面试中常考的信息安全方面知识(MD5)
Java MD5 加密算法介绍以及使用
MD5 算法的介绍
特点 1、压缩性:任意长度的数据,算出的MD5值长度都是固定的。
2、容易计算:从原数据计算出MD5值很容易。
3、抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
4、强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。
用途
1.可以用于加密用户密码
2.可以用于应用安装包的一致性验证
MD5 的简单使用
public class MessageDigestUtil {
public static String encryptMD5(byte[] data)
throws NoSuchAlgorithmException {
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(data);// data 是要加密的信息,格式为 byte 数组
byte[] resultBytes = md5.digest();//即是经过 MD5 加密过后生成的 byte 数组
String resultString = resultBytes.toString();
return resultString;
}
}
写完之后我们想验证一下数据经过 MD5 加密后回生成怎样的信息,写个主函数类似如下
public class Main {
public static final String DATA = "hwaphon";
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
String result = MessageDigestUtil.encryptMD5(DATA.getBytes());
System.out.println(result);
}
}
运行程序,输出如下
这个时候我们发现这好像不是我们平常见到的 MD5 格式,对的,我们平常所见的都是 16进制的,而现在是 byte 形式,所以我们需要将其转换为 十六进制,怎么转换呢?
public class Helper {
public static String bytesToHexString(byte[] src) {
StringBuilder stringBuilder = new StringBuilder("");
if (src == null || src.length <= 0) {
return null;
}
for (int i = 0; i < src.length; i++) {
int v = src[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
}
为什么这么转换呢?大家都知道,16进制每个字符需要 4位 2进制来表示,而 byte 用二进制则占8位,所以我们只需要将每个 byte 转化位两个 16进制表示即可。你可能还对int v = src[i] & 0xFF;
这一行有疑问.
经过上述转化后,将 String resultString = resultBytes.toString();
转化为 String resultString = Helper.bytesToHexString(resultBytes);
再次运行程序,输出结果为 0dcd7314898e812f223ad0c61bc8a903
, 恩,貌似是那么回事了。
转化成这样又有什么用啊?首先我们想到,当我们写客户端程序时,用户登陆总不能用明文表示吧?如果真是这样的话,那么只要登录的时候数据流被截获,那么我们客户的数据信息可谓是一丝不挂。所以为了安全考虑,我们可以在对用户名和密码都进行MD5加密,注意 MD5 算法是不可逆的,也就是说就算MD5加密过后的数据被截获了,也不可能还原原数据。
验证一致性
当我们下载程序安装包的过程中,程序可能会被非法篡改,怎么判断自己下载的程序由没有被篡改呢? 有些程序在下载的时候,官方就会给出 MD5 的值,那么我们下载过后怎么用来验证呢?下面拿搜狗拼音安装包来举例,获取它的MD5值
public static String getMD5OfFile(String path) throws Exception {
FileInputStream stream = new FileInputStream(new File(path));
DigestInputStream digestInputStream = new DigestInputStream(stream,
MessageDigest.getInstance("MD5"));
byte[] buffer = new byte[1024];
int read = digestInputStream.read(buffer, 0, 1024);
while (read != -1) {
read = digestInputStream.read(buffer, 0, 1024);
}
MessageDigest dis = digestInputStream.getMessageDigest();
byte[] resultBytes = dis.digest();
String resultString = Helper.bytesToHexString(resultBytes);
return resultString;
}
测试一下
public class Main {
public static final String PATH = "sogoupinyin_2.0.0.0078_amd64.deb";
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
String result = MessageDigestUtil.getMD5OfFile(PATH);
System.out.println(result);
}
}
输出结果
0a4e81d7a9cae7e8597371b1fa3674aa
这个时候,如果我在下载的时候官方也提供给一个 MD5值,那么我现在就可以去比对了,如果完全吻合,说明我下载的程序没有被非法篡改,如果不一样,那么说明。。。。