Hmac算法——秘钥的引入


Hmac算法的概述

在学习哈希算法时,为了抵御彩虹表攻击,我们采用了"加盐"的方式:digest = hash(salt + input),这个salt可以看作是一个额外的“认证码”,同样的输入,不同的认证码,会产生不同的输出。因此,要验证输出的哈希,必须同时提供“认证码”。
Hmac算法就是一种基于密钥的消息认证码算法,它的全称是Hash-based Message Authentication Code,是一种更安全的消息摘要算法。


Hmac算法实现原理

Hmac算法是不能单独使用的,它总是和某种哈希算法配合起来用的。例如,我们使用MD5算法,对应的就是HmacMD5算法,它相当于“加盐”的MD5:HmacMD5 ≈ md5(secure_random_key, input);因此,HmacMD5可以看作带有一个安全的key的MD5。
所以,从本质上来讲,Hmac就是把key混入摘要的算法。验证此哈希时,除了原始的输入数据,还要提供key。为了保证安全,我们不会自己指定key,而是通过Java标准库的KeyGenerator生成一个个安全的随机的key。


Hmac算法的实现

代码如下(示例):

//hmac算法
public class HmacDemo{
	public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
		String passWord ="daxigua2024";
		//1.产生秘钥
		//获取HmacMD5秘钥生成器
		KeyGenerator keyGen = KeyGenerator.getInstance("HmacMD5");
		//生成秘钥
		SecretKey key =keyGen.generateKey();
		System.out.println("秘钥:"+Arrays.toString(key.getEncoded()));
		System.out.println("秘钥长度:"+key.getEncoded().length+"字节" );
		System.out.println("秘钥(十六进制字符):"+HashTools.bytesToHex(key.getEncoded()));
		//2.使用秘钥
		//获取HMac加密算法对象
		Mac mac = Mac.getInstance("HmacMD5");
		mac.init(key);//初始化秘钥
		mac.update(passWord.getBytes());//更新原始加密内容
		byte[] bytes = mac.doFinal();//加密处理,并获取加密结果
		String result = HashTools.bytesToHex(bytes);//将加密结果处理成十六进制字符串
		System.out.println("加密结果(十六进制字符串):"+result);
		System.out.println("加密结果(字节长度16字节):"+bytes.length);
		System.out.println("加密结果(字符长度32字符):"+result.length());
	}
}

在这里插入图片描述
通过Hmac算法的秘钥机制,我们不难发现Hmac算法有一下好处:

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

Hmac秘钥的恢复

1.通过字节数组恢复秘钥

如果在一些场景下想要验证加密结果,SecretKey不能从KeyGenerator生成,而是从一个byte[]数组恢复:

//按照字节数组,恢复Hmac秘钥
public class Demo02 {
	public static void main(String[] args) {
		//原始密码
		String passWord = "daxigua2024";
		//秘钥(字节数组)
		byte[] keyBytes = {-66, -52, -119, 29, -107, -128, 78, 
				114, 22, 85, -73, -53, -55, -38, 6, -28, -35, -15,
				95, 7, -119, 15, -92, 28, -8, -99, -99, 107, 90, -37,
				-56, -128, 80, 19, -28, 74, -115, -41, -3, -66, -93, 125,
				103, -35, 56, -48, -125, 55, 111, -14, 107, 1, -37, -73, -43,
				5, -109, 96, -88, -18, -74, -47, -106, -98};
		try {			
			//恢复秘钥
			SecretKey key = new SecretKeySpec(keyBytes, "HmacMD5");
			//获取HMac加密算法对象
			Mac mac = Mac.getInstance("HmacMD5");
			mac.init(key);
			mac.update(passWord.getBytes());			
			String result = HashTools.bytesToHex(mac.doFinal());
			//900ff2d47fd2b01c8dbccbdb0ff9292a
			System.out.println(result);
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		}
		
	}
}

2.通过字符串恢复秘钥

在这里插入图片描述
通过观察可以发现,SecretKey是个接口,所以对密钥对象的恢复只能通过某一个具体的实现类来完成:
在这里插入图片描述
而实现类的构造方法传参只能是字节数组,所以,想通过字符串恢复密钥,只能先将字符串转换成十六进制的字节数组!

		// 秘钥(十六进制字符串)
		String strKey = "47b1f18613702221bc8e947c44a642ac0c2f45d7f507a1b972c18736d9940cea44c5e8d861a7c1a50c95dbd498165af5d79065bdccb402cb9d6431080e9b372a";
		// 将字符串秘钥转换为字节数组密钥(方便恢复密钥对象)
		byte[] keyBytes = new byte[64];
		for (int i = 0, k = 0; i < strKey.length(); i += 2, k++) {
			String s = strKey.substring(i,i+2);
			keyBytes[k] =(byte) Integer.parseInt(s, 16);//转换成16进制byte值
		}

将字符产转换成字节数组,剩下的就是按部就班的进行SecretKey进行对密钥对象的恢复,然后在进行加密,与之前的结果进行比对验证。


总结

  • Hmac算法是一种标准的基于密钥的哈希算法,可以配合MD5、SHA-1等哈希算法,计算的摘长度和原摘要算法长度相同。
  • 恢复密钥需要"字节数组"来进行恢复。
  • 和MD5相比,使用HmacMD5的步骤是:
    1.通过名称HmacMD5获取KeyGenerator实例;
    2.通过KeyGenerator创建一个SecretKey实例;
    3.通过名称HmacMD5获取Mac实例;
    4.用SecretKey初始化Mac实例;
    5.对Mac实例反复调用update(byte[])输入数据;
    6.调用Mac实例的doFinal()获取最终的哈希值。
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值