当前位置:   article > 正文

Hmac算法

hmac算法


前言

在之前的文章中(哈希算法及加密实现)提到加盐可以防止彩虹表攻击,本章将使用更好的方法来防止彩虹表攻击。


一、Hmac算法

Hmac算法是一种基于密钥的消息认证码算法,它的全称是Hash-based Message Authentication Code,是一种更安全的消息摘要算法。
Hmac算法总是和某种哈希算法配合起来用。例如,我们使用MD5算法,对应的就是Hmac MD5算法,它相当于”加盐“的MD5: HmacMD5≈md5(secure_random_key,input)
因此,HmacMD5可以看作带有一个安全的key的MD5.使用HmacMD5而不是用MD5加salt,有如下好处:

  • HmacMD5使用的key长度是64个字节,更安全;
  • Hmac是标准算法,同样适用于SHA-1等其他哈希算法;
  • Hmac输出和原有的哈希算法长度一致。

二、使用HmacMD5

1.参考代码

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;

public class Demo08 {
	public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
		// 产生密钥
		// 获取HmacMD5密钥生成器
		KeyGenerator keyGen = KeyGenerator.getInstance("HmacMD5");
		// 生成密钥
		SecretKey key = keyGen.generateKey();
		System.out.println("密钥" + Arrays.toString(key.getEncoded()));
		System.out.println("密钥长度(64字节)" + key.getEncoded().length);
		System.out.println("密钥:" + HashTool.byteToHex(key.getEncoded()));

		// 使用密钥进行加密
		// 获取HMac加密算法对象
		Mac mac = Mac.getInstance("HmacMD5");
		// 初始化密钥
		mac.init(key);
		// 更新原始加密内容
		mac.update("wbjxxmy".getBytes());
		// 加密处理,并获取加密结果
		byte[] doFinal = mac.doFinal();
		// 加密结果处理成十六进制字符串
		String ret = HashTool.byteToHex(doFinal);
		System.out.println("加密结果:" + ret);
		System.out.println("字节长度:" + doFinal.length);
		System.out.println("字符长度:" + ret.length());
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

执行结果如图(图1):
在这里插入图片描述

2.使用步骤

MD5相比,使用HmacMD5的步骤是:

  1. 通过HmacMD5获取KeyGenerator实例keyGen;
  2. 通过KeyGenerator创建一个SecretKey实例key;
  3. 通过HmacMD5获取Mac实例mac;
  4. SecretKey初始化Mac实例
  5. 对Mac实例反复调用update(byte[])方法输入数据
  6. 调用Mac实例的doFinal()方法获取最终的哈希值。

3.验证

有了Hmac计算的哈希和SecretKey,我们想要验证的话,该怎么办?这时,SecretKey不能从KeyGenerator生成,而是以下的方式恢复。

3.1 字节数组验证

例如我的密码为wbjxxmy,由加密后转化成密钥的字节数组为[5, -11, 36, -15, -59, -53, -25, -18, 7, -10, -50, 3, -86, 16, 95, 93, -32, 5, 5, -2, -39, 91, 27, -117, 92, -17, -99, 49, -3, 51, 23, -58, 112, -95, 49, 9, -109, -5, 106, 41, -22, -14, 32, 10, 127, -87, 36, 116, -112, -112, -49, -77, 44, -18, -65, -91, 121, 38, -91, 41, 118, -111, 50, 69]
若要将字节数组恢复,可以调用SecretKey key = new SecretKeySpec(字节数组, 加密类型)构造方法恢复成key。代码如下:

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
public class Demo09 {
	public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
		String password = "wbjxxmy";
		byte[] miyao = new byte[] { 5, -11, 36, -15, -59, -53, -25, -18, 7, -10, -50, 3, -86, 16, 95, 93, -32, 5, 5, -2, -39, 91, 27, -117, 92, -17, -99, 49, -3, 51, 23, -58, 112, -95, 49, 9, -109, -5, 106, 41, -22, -14, 32, 10, 127, -87, 36, 116, -112, -112, -49, -77, 44, -18, -65, -91, 121, 38, -91, 41, 118, -111, 50, 69 };
		// 恢复密钥(字节数组)
		SecretKey key = new SecretKeySpec(miyao, "HmacMD5");
		// 床架你Hmac加密算法对象
		Mac mac = Mac.getInstance("HmacMD5");
		mac.init(key);
		mac.update(password.getBytes());
		System.out.println(HashTool.byteToHex("加密结果:"+mac.doFinal()));
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

运行结果如图(图2):
在这里插入图片描述

图2加密结果的内容与图1加密结果的内容相同,所以验证成功。

3.2 十六进制字符串的验证

若给定的密钥是一串十六进制的字符串,该如何验证呢?
道理很简单,我们可以先将十六进制的字符串转换成字节数组,再用以上的方法恢复key,就可以完成验证。代码如下:

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

public class Demo10 {
	public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
		//将字符串还原成密钥字节数组
		String s = "05f524f1c5cbe7ee07f6ce03aa105f5de00505fed95b1b8b5cef9d31fd3317c670a1310993fb6a29eaf2200a7fa924749090cfb32ceebfa57926a52976913245";
		byte[] keyBytes = new byte[64];
		for (int i = 0, k = 0; i < s.length(); i += 2, k++) {
			keyBytes[k] = (byte) Integer.parseInt(s.substring(i, i + 2), 16);
		}
		SecretKey key = new SecretKeySpec(keyBytes, "HmacMD5");
		Mac mac = Mac.getInstance("HmacMD5");
		mac.init(key);
		mac.update("wbjxxmy".getBytes());
		// 7e0ed3f9ca30fae85273d86515fff8f1
		System.out.println(HashTool.byteToHex(mac.doFinal()));

	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

我通过将字符串两个两个截取,再通过Integer工具类的parseInt方法以十六进制的方式转换为int,再强制转换成byte类型,放入KeyBytes字节数组中,恢复成原来的字节数组,再通过之前的方法,得到恢复的密钥。
效果如图(图3):
在这里插入图片描述图3恢复的加密结果与图1中加密的结果相同,所以验证通过。


总结

以上就是通过用Hmac算法配合MD5的方式对于密码的加密,Hmac算法是一种标准的基于密钥的哈希算法,可以配合MD5,SHA-1等哈希算法,计算的摘要长度和原摘要算法长度相同。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/447856
推荐阅读
相关标签
  

闽ICP备14008679号