一、哈希算法的简述
-
概念
哈希算法(Hash Algorithm)是一种将任意长度的消息压缩到一个固定长度的摘要(digest)的函数。
-
主要应用
哈希算法的最主要的应用是对于一段数据,通过一定的算法,生成一个固定长度的哈希值,这个哈希值通常用于数据校验、数据完整性验证等领域。
-
常见算法
- MD5---Message Digest Algorithm 5
- SHA-1---Secure Hash Algorithm 1
- SHA-256---Secure Hash Algorithm 256
- SHA-512---Secure Hash Algorithm 512
- RipeMD160
-
特点
- 相同的输入一定会得到相同的输出
- 不同的输入大概率得到不同的输出。
- 给定的哈希值无法反向推出原始输入内容
二、哈希碰撞
-
概念
不同的输入得到了相同的输出称为哈希碰撞。这种情况是避免不了的,因为输出的哈希数据长度是固定的(最多只有4294967296种输出)但是输入的数据长度确实不固定的,有无数种输入。
-
安全的哈希算法需要满足
- 抗碰撞性:相同的输入应该得到相同的输出,不同的输入应该尽可能得到不同的输出,即使输入之间只有微小的差异
- 无法逆推性:不应该能够通过哈希输出结果推导出输入。
- 抗修改性:输入的任何改动都应该导致输出的改动,且无法通过修改输出来推导出修改后的输入。
三、哈希算法的常见算法代码实现
-
MD5---Message Digest Algorithm 5
- 中文加密
//创建基于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); //1、何事西 //2、风悲画扇 //分两次更新数据只要顺序相同获得的加密结果也是一样的
- 图片加密
//获取图片信息
byte[] bs = Files.readAllBytes(Paths.get("D:\\3yue\\vv.jpg"));
//创建基于MD5的基本摘要信息
MessageDigest digest = MessageDigest.getInstance("MD5");
//更新数据
digest.update(bs);
//获得加密数组结果并输出
byte[] digestBytes = digest.digest();
System.out.println("加密后的结果:"+Arrays.toString(digestBytes));
//此处为一个Hashtools类写有BytestoHex
//是一个将数据转换为16进制的方法
System.out.println("加密后的结果(16进制):"+Hashtools.BytestoHex(digestBytes));
System.out.println("加密结果长度:"+digestBytes.length);
-
SHA---Secure Hash Algorithm
- SHA-1---Secure Hash Algorithm 1
- SHA-256---Secure Hash Algorithm 256
- SHA-512---Secure Hash Algorithm 512
因为这些常见算法的实现操作都基本大差不差,为了方便我们进行快速操作, 所以创建了一个Hashtools类,详细代码如下:
//创建私有类方便操作避免代码冗余
private static MessageDigest digest;
//无参构造方法
private Hashtools() {}
//通过消息摘要对象,处理加密内容
private static String hanler(String source) {
digest.update(source.getBytes());
byte[] bytes = digest.digest();
String hash = BytestoHex(bytes);
return hash;
}
//字节数组转换16进制字符串
public static String BytestoHex(byte[] b) {
StringBuilder builder = new StringBuilder();
for (byte c : b) {
//将字节值转换为2位十六进制字符串
builder.append(String.format("%02x", c));
}
return builder.toString();
}
//按照sha-1加密
public static String DigestBySha1(String source) throws NoSuchAlgorithmException {
digest = MessageDigest.getInstance("sha-1");
return hanler(source);
}
//按照sha-256加密
public static String DigestBySha256(String source) throws NoSuchAlgorithmException {
digest = MessageDigest.getInstance("sha-256");
return hanler(source);
}
//按照sha-512加密
public static String DigestBySha512(String source) throws NoSuchAlgorithmException {
digest = MessageDigest.getInstance("sha-512");
return hanler(source);
}
//按照md5加密
public static String DigestByMd5(String source) throws NoSuchAlgorithmException {
digest = MessageDigest.getInstance("md5");
return hanler(source);
}
有了这个Hashtools事半功倍,算法实现代码就变得简洁明了。算法输出结果如下:
String str = "edefrev";
String md5 = Hashtools.DigestByMd5(str);
String sha-1 = Hashtools.DigestBySha1(str);
String sha-256 = Hashtools.DigestBySha256(str);
String sha-512 = Hashtools.DigestBySha512(str);
System.out.println("md5="+md5);
System.out.println("sha-1="+sha-1);
System.out.println("sha-256="+sha-256);
System.out.println("sha-512="+sha5-12);
-
RipeMD160算法
Java标准库提供了一系列常用的哈希算法,但是没有RipeMD160算法,所以为了实现它我们需要找到一个现成的第三方库bouncycastle去使用这个方法。在使用前我们需要去官方网站bouncycastle.org下载我们要使用jar包,然后Build Path>>>add....。
Java标准库的java.security包提供了一种标准机制,允许第三方提供商无缝接入。我们要使用BouncyCastle提供的RipeMD160算法,需要先把BouncyCastle注册一下:
//注册BouncyCastle BouncyCastleProvider通知类
//将提供的消息摘要算法注册至Security
Security.addProvider(new BouncyCastleProvider());
然后就可以实现算法啦~
//获取RipeMd160算法的信息摘要对象
MessageDigest digest = MessageDigest.getInstance("ripemd160");
//更新数据
digest.update("dddd".getBytes());
//获取信息加密
byte[] result = digest.digest();
//信息摘要字节长度玉内容
System.out.println("加密结果字节长度"+result.length);
System.out.println("加密结果字节内容"+Arrays.toString(result));
//16进制内容字符串
String hex = new BigInteger(1,result).toString(16);
System.out.println("加密结果字符串长度"+hex.length());
System.out.println("加密结果字符串内容"+hex);
四、小总结
哈希算法具有以下优点:
-
不可逆:无法从摘要中推算出原始数据。
-
唯一性:不同的输入会得到不同的摘要。
-
敏感性:原始数据的微小变化也会导致摘要的大幅变化。
-
固定长度:输出的摘要长度是固定的。
哈希算法也有以下缺点:
-
取决于输入长度:输入长度不同,输出长度也不同。
-
可能存在碰撞:不同的输入可能会产生相同的摘要。
-
不能解密:无法通过摘要找到原始数据。