一、哈希算法的分类
常用的哈希算法有
- MD5 输出长度为16字节
- SHA-1 输出长度为20字节
- SHA-256 输出长度为32字节
- SHA-512 输出长度为64字节
- RipeMD-160 输出长度为10字节
无论哪种算法,对数据进行加密的过程基本一致,只有算法名称和加密后结果长度的区别,所以为了实现代码复用节约资源,将数据加密等步
目录
骤进行封装,处理成一个公用的工具类。
注:所有的算法都是单向加密方式,只存在加密,不存在解密的方式;并且每一个算法加密后得到的加密结果的长度是固定的,无论运行多少次结果的长度都不会改变。
public class HashTools {
private static MessageDigest digest;
public HashTools() {
super();
}
public static String HashCodeMD5(String ceontent) throws NoSuchAlgorithmException {
digest = MessageDigest.getInstance("md5");
String res = Handler(ceontent);
return res;
}
public static String HashCodeSHA1(String content) throws NoSuchAlgorithmException {
digest = MessageDigest.getInstance("SHA-1");
String res = Handler(content);
return res;
}
public static String Handler(String content) {
digest.update(content.getBytes());
String Coderet = ArrByteToHex(digest.digest());
return Coderet;
}
//字节数组转为16进制
public static String ArrByteToHex(byte[] buf) {
StringBuilder res = new StringBuilder();
for(byte b : buf) {
res.append(String.format("%02x", b));
}
return res.toString();
}
}
二、哈希算法的使用
Java为提供了统一的接口进行对哈希算法的调用。MessageDigest是一个抽象类,在具体代码实现中,直接用MessageDigest.getInstance("MD5");参数为算法名称。
1、MD5加密过程:
(1)、创建基于MD5的消息摘要对象
MessageDigest md5 = MessageDigest.getInstance("MD5");
(2)、更新原始数据内容
参数为密码等原始数据,注意是字节
md5.update("天动万象".getBytes());
(3)、进行加密并获取加密后的结果
byte[] buf = md5.digest();
System.out.println("加密后:" + Arrays.toString(buf));
String hexres = HashTransToHex.ArrByteToHex(buf);
System.out.println("十六进制加密后" + hexres);
该方法返回值类型为字节数组,通过工具类可以得到十六进制的字符串结果。
(4)、运行结果
2、利用MD5算法对图片进行加密
(1)、创建基于MD5的消息摘要对象并拿到图片原始字节数据内容
MessageDigest imagemd5 = MessageDigest.getInstance("md5");
byte[] buff = Files.readAllBytes(Paths.get("D:\\Temp\\Test\\Cat.jpg"));
(2)、更新原始数据内容并进行加密
imagemd5.update(buff);//原始数据
byte[] imagebufres = imagemd5.digest();//获取加密摘要(进行加密)
(3)、加密结果输出
System.out.println("加密后:" + Arrays.toString(imagebufres));
String hexres = HashTools.ArrByteToHex(imagebufres);
System.out.println("十六进制加密后" + hexres);
System.out.println("加密后的字节数组长度为:" + imagebufres.length);
(4)、运行结果
3、Hmac算法
该算法的加密结果长度固定为64字节,且每次运行生成的秘钥均不相同
由于MD5加密算法的结果比较稳定且长度一定,所以会有彩虹表等数据表能够进行密码的反推,会导致数据安全问题,在上述MD5算法中采取加随机盐值的方式。
String password = "FJQFY";
MessageDigest md5 = MessageDigest.getInstance("md5");
//加随机盐值
String salt = UUID.randomUUID().toString().substring(0, 3);
md5.update(salt.getBytes());
md5.update(password.getBytes());
String res = HashTools.ArrByteToHex(md5.digest());
System.out.println("加盐值后:" + res);
Hmac算法是一种基于秘钥的认证算法,其关键词是秘钥。具体使用步骤:
(1)、使用秘钥生成器(KeyGenerator)生成秘钥
KeyGenerator key = KeyGenerator.getInstance("HmacMD5");
SecretKey scekey = key.generateKey();
注:generateKey()方法的返回值类型是SecretKey 。
(2)、使用秘钥进行加密
获取要加密的对象,参数为算法名称
Mac mac = Mac.getInstance("HmacMD5");
初始化秘钥
mac.init(scekey);
更新原始加密内容(参数为字节类型),并进行加密操作:doFinal( )方法(返回值类型为字节数组)
mac.update(pwd.getBytes());
byte[] buf = mac.doFinal();
//使用工具类进行输出
System.out.println("使用秘钥加密后:" + Arrays.toString(buf));
System.out.println("使用秘钥加密后(十六进制):" + HashTools.ArrByteToHex(buf));
System.out.println("使用秘钥加密字节长度:" + buf.length);
System.out.println("使用秘钥加密后十六进制字符长度:" + HashTools.ArrByteToHex(buf).length());
运行结果:
4、按照字节数组恢复秘钥
(1)、定义原始密码和秘钥(字节数组的形式)
//原始密码
String pwd = "FJQFY";
//原始秘钥(字节数组)
byte[] keybyte = { };
(2)、恢复秘钥
参数为字节数组和算法名称
//恢复秘钥
SecretKey key = new SecretKeySpec(keybyte, "HmacMD5");
(3)、创建加密算法对象
update()方法中的参数为原始密码(字节类型)
//创建加密算法对象
Mac m = Mac.getInstance("HmacMD5");
m.init(key); //初始化
m.update(pwd.getBytes());//更新数据内容
String res = HashTools.ArrByteToHex(m.doFinal());//使用工具类进行数据处理
5、按照字符串恢复秘钥
和按照字节恢复相比,流程基本一致,只需要初始化一个长度为64的字节数组,在通过循环将字符串的没两位转换成十进制数据放入字节数组中即可;eg;
String keystr = " XXXXXXXXXX";
byte[] buff = new byte[64];
for(int i = 0,k = 0;i<keystr.length();i = i+2,k++) {
String s = keystr.substring(i,i+2);
buff[k] = (byte)Integer.parseInt(s, 16);
}
6、ReipeMD-160
其具体使用步骤和上述算法一致,只是在使用前需要进行如下操作:
Security.addProvider(new BouncyCastleProvider());
此代码目的主要是用来注册BouncyCastleProvider通知类,将提供的消息摘要算法注册至Security
BouncyCastleProvider是一个通知类。