阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

Hmac算法

30次阅读
没有评论

共计 2270 个字符,预计需要花费 6 分钟才能阅读完成。

在前面讲到哈希算法时,我们说,存储用户的哈希口令时,要加盐存储,目的就在于抵御彩虹表攻击。

我们回顾一下哈希算法:

digest = hash(input)

正是因为相同的输入会产生相同的输出,我们加盐的目的就在于,使得输入有所变化:

digest = hash(salt + input)

这个 salt 可以看作是一个额外的“认证码”,同样的输入,不同的认证码,会产生不同的输出。因此,要验证输出的哈希,必须同时提供“认证码”。

Hmac 算法就是一种基于密钥的消息认证码算法,它的全称是 Hash-based Message Authentication Code,是一种更安全的消息摘要算法。

Hmac 算法总是和某种哈希算法配合起来用的。例如,我们使用 MD5 算法,对应的就是 HmacMD5 算法,它相当于“加盐”的 MD5:

HmacMD5 ≈ md5(secure_random_key, input)

因此,HmacMD5 可以看作带有一个安全的 key 的 MD5。使用 HmacMD5 而不是用 MD5 加 salt,有如下好处:

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

可见,Hmac 本质上就是把 key 混入摘要的算法。验证此哈希时,除了原始的输入数据,还要提供 key。

为了保证安全,我们不会自己指定 key,而是通过 Java 标准库的 KeyGenerator 生成一个安全的随机的 key。下面是使用 HmacMD5 的代码:

import javax.crypto.*;
import java.util.HexFormat;

public class Main {public static void main(String[] args) throws Exception {KeyGenerator keyGen = KeyGenerator.getInstance("HmacMD5");
        SecretKey key = keyGen.generateKey();
        // 打印随机生成的 key:
        byte[] skey = key.getEncoded();
        System.out.println(HexFormat.of().formatHex(skey));
        Mac mac = Mac.getInstance("HmacMD5");
        mac.init(key);
        mac.update("HelloWorld".getBytes("UTF-8"));
        byte[] result = mac.doFinal();
        System.out.println(HexFormat.of().formatHex(result));
    }
}

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

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

我们可以用 Hmac 算法取代原有的自定义的加盐算法,因此,存储用户名和口令的数据库结构如下:

username secret_key (64 bytes) password
bob a8c06e05f92e…5e16 7e0387872a57c85ef6dddbaa12f376de
alice e6a343693985…f4be c1f929ac2552642b302e739bc0cdbaac
tim f27a973dfdc0…6003 af57651c3a8a73303515804d4af43790

有了 Hmac 计算的哈希和 SecretKey,我们想要验证怎么办?这时,SecretKey 不能从 KeyGenerator 生成,而是从一个 byte[] 数组恢复:

import javax.crypto.*;
import javax.crypto.spec.*;
import java.util.HexFormat;

public class Main {public static void main(String[] args) throws Exception {byte[] hkey = HexFormat.of().parseHex("b648ee779d658c420420d86291ec70f5" + 
                "cf97521c740330972697a8fad0b55f5c" + 
                "5a7924e4afa99d8c5883e07d7c3f9ed0" + 
                "76aa544d25ed2f5ceea59dcc122babc8");
        SecretKey key = new SecretKeySpec(hkey, "HmacMD5");
        Mac mac = Mac.getInstance("HmacMD5");
        mac.init(key);
        mac.update("HelloWorld".getBytes("UTF-8"));
        byte[] result = mac.doFinal();
        System.out.println(HexFormat.of().formatHex(result)); // 4af40be7864efaae1473a4c601b650ae
    }
}

恢复 SecretKey 的语句就是new SecretKeySpec(hkey, "HmacMD5")

小结

Hmac 算法是一种标准的基于密钥的哈希算法,可以配合 MD5、SHA- 1 等哈希算法,计算的摘要长度和原摘要算法长度相同。

正文完
星哥说事-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2024-08-05发表,共计2270字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中