哈希算法
哈希算法基本内容
概述
哈希算法(Hash)又称摘要算法(Digest),它的作用是:对任意一组输入数据进行计算,得到一个固定长度的输出摘要。
特点
- 相同的输入一定得到相同的输出;
- 不同的输入大概率得到不同的输出;
目的
为了验证原始数据是否被篡改。
哈希碰撞
两个不同的输入得到了相同的输出。
例如:
"AaAaAa".hashCode(); // 0x7460e8c0
"BBAaBB".hashCode(); // 0x7460e8c0
"通话".hashCode(); // 0x11ff03
"重地".hashCode(); // 0x11ff03
注意:
哈希碰撞不能避免。
原因:哈希算法是把一个无限的输入集合映射到一个有限的输出集合,输入的字节长度固定,必然会产生碰撞。
安全的哈希算法
碰撞的高低概率关系到哈希算法的安全性。
安全的哈希算法需要满足的条件
- 碰撞概率低
- 不能被猜测出
常用的哈希算法
MD5
- 输出长度(位):128 bits
- 输出长度(字节):16 bytes
基于MD5算法对数据进行加密
//创建基于MD5算法的消息摘要对象
MessageDigest md5 = MessageDigest.getInstance("MD5");
//更新原始数据
md5.update("天王盖地虎宝塔镇河妖".getBytes());
//获取加密后的结果
byte[] digestBytes = md5.digest();
System.out.println("加密后的结果(字节数组):" + Arrays.toString(digestBytes));
System.out.println("加密后的结果(16进制字符串):" + HashTools.bytesToHex(digestBytes));
System.out.println("加密后的长度:" + digestBytes.length);
基于MD5算法对图片进行“加密”
//图片的原始字节内容
byte[] imageBuf = Files.readAllBytes(Paths.get("D:\\seventeen\\1.jpg"));
//创建基于MD5算法的消息摘要对象
MessageDigest md5 = MessageDigest.getInstance("MD5");
//原始字节内容(图片)
md5.update(imageBuf);
//获取加密摘要
byte[] digestBytes = md5.digest();
System.out.println("加密后的结果(字节数组):" + Arrays.toString(digestBytes));
System.out.println("加密后的结果(16进制字符串):" + HashTools.bytesToHex(digestBytes));
System.out.println("加密后的长度:" + digestBytes.length);
注:
需通过随机加盐,解决彩虹表攻击问题
SHA-1
- 输出长度(位):160 bits
- 输出长度(字节):20 bytes
基于SHA-1算法对数据进行加密
//原始密码
String password = "seventeen";
//随机产生的盐值
String salt = UUID.randomUUID().toString().substring(0,4);
//创建基于SHA-1算法的消息摘要对象
MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
sha1.update(password.getBytes());
sha1.update(salt.getBytes());
//计算结果加密,SHA-1的输出结果为20个字节(40个字符)
String digestHex = HashTools.bytesToHex(sha1.digest());
System.out.println(digestHex);
RipeMD-160
- 输出长度(位):160 bits
- 输出长度(字节):20 bytes
SHA-256
- 输出长度(位):256 bits
- 输出长度(字节):32 bytes
SHA-512
- 输出长度(位):512 bits
- 输出长度(字节):64 bytes
Hash算法(消息摘要算法)工具类
public class HashTools {
//消息摘要对象
private static MessageDigest digest;
//构造方法私有
private HashTools() {}
//将字节数组转换为16进制字符串
public static String bytesToHex(byte[] bytes) {
StringBuilder ret = new StringBuilder();
for (byte b : bytes){
//将字节值转换为2位十六进制字符串
ret.append(String.format("%02x", b));
}
return ret.toString();
}
//按照MD5进行消息摘要计算(哈希计算)
public static String digestByMD5(String source) throws NoSuchAlgorithmException {
digest = MessageDigest.getInstance("MD5");
return handler(source);
}
//按照SHA-1进行消息摘要计算(哈希计算)
public static String digestBySHA1(String source) throws NoSuchAlgorithmException {
digest = MessageDigest.getInstance("SHA-1");
return handler(source);
}
//通过消息摘要对象,处理加密内容
private static String handler(String source){
digest.update(source.getBytes());
byte[] bytes = digest.digest();
String hash = bytesToHex(bytes);
return hash;
}
}
总结
- 哈希算法是单向的,只能进行加密,不能进行解密。
- 哈希算法可用于校验下载文件。
- 哈希算法可用于存储用户密码。