目录
一、Hmac算法概念
在Hash算法中,为了抵御彩虹表攻击,需要对口令加盐存储,而Hmac算法相当于加盐的Hhash算法。
1.特点
(1)Hmac算法总是搭配Hash算法使用
(2)输出与原Hash算法长度一致
2.实现
在Hmac算法中,使用key代替盐的位置,在使用时,除了原始口令,还需要提供key,但这个key并不由用户提供,而是通过Java库的KeyGenerator生成。
String password="aaaaaaheimaojingzhang";
//1.生成密钥
//获取密钥生成器
KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacMD5");
SecretKey key = keyGenerator.generateKey();
System.out.println("密钥==>"+Arrays.toString(key.getEncoded()));
System.out.println("密钥长度==>"+key.getEncoded().length);
System.out.println("16进制==>"+HashTools.bytesToHex(key.getEncoded()));
//2.使用密钥进行加密
Mac mac = Mac.getInstance("HmacMD5");
mac.init(key);//初始化密钥
mac.update(password.getBytes());//更新原始加密内容
byte[] bytes = mac.doFinal();//加密处理并获取加密结果
final String result = HashTools.bytesToHex(bytes);
System.out.println(Arrays.toString(bytes));
System.out.println("加密后长度(字节)==>"+bytes.length);
System.out.println("16进制字符串==>"+result);
System.out.println("16进制字符串长度==>"+result.length());
运行结果:
3.验证
在验证时,也需要用到SecretKey,但此时的SecretKey不能由KeyGenerator生成,而需要从密钥字节数组中恢复
3.1根据密钥字节数组恢复密钥字符串
//根据密钥字节数组恢复密钥并再次加密
String password="aaaaaaheimaojingzhang";
//密钥字节数组
byte[] keyBytes={119, 125, -66, -92, -35, 88, 92, -27, 101, -21, 97, -103, -111, 24, -103, 64, 16, 84, 65, 71, -5, -60, -78, 92, 89, 74, 100, 39, -99, -83, 109, -60, 8, -23, 101, 22, 62, -82, 49, -44, -53, -33, 24, 4, 65, -25, -24, -126, -91, -111, -78, -123, 107, 112, 30, 87, 96, 0, 107, 110, -2, -32, -111, -91};
//恢复密钥
try {
//包装密钥对象
SecretKeySpec key = new SecretKeySpec(keyBytes, "HmacMD5");
//创建加密对象
Mac mac = Mac.getInstance("HmacMD5");
mac.init(key);//初始化密钥
mac.update(password.getBytes());//更新数据
String res=HashTools.bytesToHex(mac.doFinal());//计算消息摘要并转换为16进制字符串
System.out.println(res);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
运行结果:
3.2根据密钥字符串恢复密钥数组
//密钥字符串
String keyStr="7a32e1f610671e05b0aaa2de1b4c31281ee5cd12c4ab4ea250ec12a2e2b848a2760cb276b89b51a61d1eec2472eb220f7756eee5741cd156d395325d4ae83567";
//用于保存密钥的字节数组,密钥128位,字节数组长度64
byte[] keyBytes=new byte[64];
for(int i=0,k=0;i<keyStr.length();i+=2,k++){
String s = keyStr.substring(i, i + 2);
keyBytes[k]=(byte)Integer.parseInt(s,16);
}
System.out.println("密钥==>"+ Arrays.toString(keyBytes));