0
点赞
收藏
分享

微信扫一扫

Java 实现 HMAC

科牛 2021-09-28 阅读 66

本文介绍 Java 语言实现 HMAC Hash 的方法。


目录

  • HMAC 简介
  • 实现方法
    • 基于 Java API
    • 基于 Apache Commons
    • 基于 Google Guava

HMAC 简介

HMAC,Hash-based message authentication code,散列消息认证码,又称密钥散列消息认证码(Keyed-hash message authentication code),是一种通过特别计算方式计算后生成的消息认证码(MAC)。使用密码散列函数(MD5、SHA 等),以 一个密钥一个消息 为输入,生成 一个消息摘要 输出。可用来保证数据完整性,同时可用作某个消息的身份认证。
HMAC 的发送方和接收方都使用相同的 key 进行计算,没有 key 的第三方无法计算出正确的散列值,这样可防止数据被篡改。


实现方法

基于 Java API
package tutorial.java.util;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

public class HmacUtils {

    private Mac mac;

    public HmacUtils(String key, Algorithm algorithm) throws NoSuchAlgorithmException, InvalidKeyException {
        SecretKey secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm.getValue());
        mac = Mac.getInstance(secretKey.getAlgorithm());
        mac.init(secretKey);
    }

    public byte[] sign(byte[] content) {
        return mac.doFinal(content);
    }

    public boolean verify(byte[] signature, byte[] content) {
        byte[] result = mac.doFinal(content);
        return Arrays.equals(signature, result);
    }

    public static enum Algorithm {

        HMAC_MD5("HmacMD5"),
        HMAC_SHA1("HmacSHA1"),
        HMAC_SHA256("HmacSHA256"),
        HMAC_SHA384("HmacSHA384"),
        HMAC_SHA512("HmacSHA512");

        private String value;

        Algorithm(String value) {
            this.value = value;
        }

        public String getValue() {
            return value;
        }
    }
}

单元测试:

package tutorial.java.util;

import org.junit.Assert;
import org.junit.Test;

import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

public class HmacUtilsTest {

    private void test(HmacUtils.Algorithm algorithm) throws InvalidKeyException, NoSuchAlgorithmException {
        String key = "key";
        HmacUtils hmacUtils = new HmacUtils(key, algorithm);
        String original = "ABCDEFG";
        byte[] content = original.getBytes(StandardCharsets.UTF_8);
        byte[] signResult = hmacUtils.sign(content);
        System.out.println(bytesToHex(signResult));
        Assert.assertTrue(hmacUtils.verify(signResult, content));
    }

    @Test
    public void testHmacMD5() throws InvalidKeyException, NoSuchAlgorithmException {
        test(HmacUtils.Algorithm.HMAC_MD5);
    }

    @Test
    public void testHmacSHA1() throws InvalidKeyException, NoSuchAlgorithmException {
        test(HmacUtils.Algorithm.HMAC_SHA1);
    }

    @Test
    public void testHmacSHA256() throws InvalidKeyException, NoSuchAlgorithmException {
        test(HmacUtils.Algorithm.HMAC_SHA256);
    }

    @Test
    public void testHmacSHA384() throws InvalidKeyException, NoSuchAlgorithmException {
        test(HmacUtils.Algorithm.HMAC_SHA384);
    }

    @Test
    public void testHmacSHA512() throws InvalidKeyException, NoSuchAlgorithmException {
        test(HmacUtils.Algorithm.HMAC_SHA512);
    }

    /**
     * 自定义字节到十六进制转换器来获取十六进制的哈希值
     */
    private static String bytesToHex(byte[] hash) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : hash) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }
}
基于 Apache Commons
  1. 添加 Apache Commons Codec 依赖
<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.14</version>
</dependency>
  1. 使用 org.apache.commons.codec.digest.HmacUtils 实现 HMAC Hash
package tutorial.java.util;

import org.apache.commons.codec.digest.HmacAlgorithms;
import org.apache.commons.codec.digest.HmacUtils;
import org.junit.Test;

import javax.crypto.Mac;
import java.nio.charset.StandardCharsets;

public class ApacheCommonsHmacUtilsTest {

    @Test
    public void testHmacMD5() {
        test(HmacAlgorithms.HMAC_MD5);
    }

    @Test
    public void testHmacSHA1() {
        test(HmacAlgorithms.HMAC_SHA_1);
    }

    @Test
    public void testHmacSHA224() {
        test(HmacAlgorithms.HMAC_SHA_224);
    }

    @Test
    public void testHmacSHA256() {
        test(HmacAlgorithms.HMAC_SHA_256);
    }

    @Test
    public void testHmacSHA384() {
        test(HmacAlgorithms.HMAC_SHA_384);
    }

    @Test
    public void testHmacSHA512() {
        test(HmacAlgorithms.HMAC_SHA_512);
    }

    public void test(HmacAlgorithms algorithm) {
        String key = "key";
        Mac mac = HmacUtils.getInitializedMac(algorithm, key.getBytes(StandardCharsets.UTF_8));
        String original = "ABCDEFG";
        byte[] content = original.getBytes(StandardCharsets.UTF_8);
        byte[] signResult = mac.doFinal(content);
        System.out.println(bytesToHex(signResult));
    }

    /**
     * 自定义字节到十六进制转换器来获取十六进制的哈希值
     */
    private static String bytesToHex(byte[] hash) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : hash) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }
}
基于 Google Guava
  1. 添加 Google Guava 依赖
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>28.2-jre</version>
</dependency>
  1. 使用 com.google.common.hash.Hashing 实现 MD5 Hash
package tutorial.java.util;

import com.google.common.hash.HashCode;
import com.google.common.hash.Hashing;
import org.junit.Before;
import org.junit.Test;

import java.nio.charset.StandardCharsets;

public class GoogleGuavaHashingHmacTest {

    private String key;

    private String original;

    @Before
    public void before() {
        this.key = "key";
        this.original = "ABCDEFG";
    }

    @Test
    public void testHmacMd5() {
        HashCode hashCode = Hashing.hmacMd5(key.getBytes(StandardCharsets.UTF_8))
                .hashBytes(original.getBytes(StandardCharsets.UTF_8));
        System.out.println(hashCode.toString());
    }

    @Test
    public void testHmacSha1() {
        HashCode hashCode = Hashing.hmacSha1(key.getBytes(StandardCharsets.UTF_8))
                .hashBytes(original.getBytes(StandardCharsets.UTF_8));
        System.out.println(hashCode.toString());
    }

    @Test
    public void testHmacSha256() {
        HashCode hashCode = Hashing.hmacSha256(key.getBytes(StandardCharsets.UTF_8))
                .hashBytes(original.getBytes(StandardCharsets.UTF_8));
        System.out.println(hashCode.toString());
    }

    @Test
    public void testHmacSha512() {
        HashCode hashCode = Hashing.hmacSha512(key.getBytes(StandardCharsets.UTF_8))
                .hashBytes(original.getBytes(StandardCharsets.UTF_8));
        System.out.println(hashCode.toString());
    }
}
举报

相关推荐

0 条评论