HmacSHA256 Signature in Java

Upasana | July 25, 2020 | 4 min read | 952 views


In this tutorial we will learn how to generate Hmac256 signature in Java using standard library, Google Guava and Apache commons codec library.

MAC is a Message Authentication Code algorithm, which provides a way to check integrity of information transmitted over or stored in an unreliable medium. Typically, message authentication codes are used between two parties that share a secret key in order to validate information transmitted between these parties.

A MAC mechanism that is based on cryptographic hash functions is referred to as HMAC. HMAC can be used with any cryptographic hash function, e.g., SHA256 or SHA384, in combination with a secret shared key. HMAC is specified in RFC 2104.

Most commonly used HMAC implementations are:

  • HmacMD5

  • HmacSHA1

  • HmacSHA256

Now we will create HmacSHA256 signature using 3 different libraries - Java Standard Library, Google Guava and Apache Commons Codec.

1. Using JDK Standard Library

Java/Android has everything in cryptography libraries that is required to generate a Hmac256.

HmacUtils.java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import static java.nio.charset.StandardCharsets.UTF_8;

public class HmacUtils {

    String generateHmac256(String message, byte[] key) throws InvalidKeyException, NoSuchAlgorithmException {
        byte[] bytes = hmac("HmacSHA256", key, message.getBytes());
        return bytesToHex(bytes);   (1)
    }

    byte[] hmac(String algorithm, byte[] key, byte[] message) throws NoSuchAlgorithmException, InvalidKeyException {
        Mac mac = Mac.getInstance(algorithm);
        mac.init(new SecretKeySpec(key, algorithm));
        return mac.doFinal(message);
    }

    String bytesToHex(byte[] bytes) {   (2)
        final char[] hexArray = "0123456789abcdef".toCharArray();
        char[] hexChars = new char[bytes.length * 2];
        for (int j = 0, v; j < bytes.length; j++) {
            v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }

     public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
        String valueToDigest = "The quick brown fox jumps over the lazy dog";
        byte[] key = "secret".getBytes();

        HmacUtils hm = new HmacUtils();
        String messageDigest = hm.generateHmac256(valueToDigest, key);
        System.out.println(messageDigest);
    }
}
1 Default return type for Mac function is byte array, so we need to convert it to Hex format.
2 Our custom method to convert a byte array to hex, optionally we can use Apache Commons Codec’s Hex utility to convert byte array to hex in single line.

Converting byte[] to hex

There are so many libraries in Java ecosystem that can convert a byte array to hex encoded string:

a) Apache Commons Codec

You can use org.apache.commons.codec.binary.Hex class to convert given byte array to Hex encoded string using single line code:

Apache Commons Codec’s Hex utility
import org.apache.commons.codec.binary.Hex;
...
String hexHmac = Hex.encodeHexString(bytes);

b) Spring Security

If you are using Spring Security in your project, you can use org.springframework.security.crypto.codec.Hex utility to encode and decode byte array into string and vice versa.

import org.springframework.security.crypto.codec.Hex;
...
String hexValue = new String(Hex.encode(bytes));

c) Google Guava

Google Guava provides BaseEncoding for handlign encoding and decoding to Base16 format.

import com.google.common.io.BaseEncoding;
...
String hexValue = BaseEncoding.base16().lowerCase().encode(bytes);  (1)
1 Default is Upper case hex caharacters.

d) Bouncy Castle

If you are already using Bouncy Castle security framework, then you can use this Hex util:

import org.bouncycastle.util.encoders.Hex;
...
String hexValue = Hex.toHexString(bytes);

You can also follow this stackoverflow discussion.

2. Using Google Guava

Google Guava library provides static hashing related utilities in class com.google.common.hash.Hashing.

build.gradle
dependencies {
// https://mvnrepository.com/artifact/com.google.guava/guava
    compile group: 'com.google.guava', name: 'guava', version: '29.0-jre'
}
Hmac256 using Google Guava
import com.google.common.hash.Hashing;

public class HMacTest {

    public void hmac256() {
        String valueToDigest = "The quick brown fox jumps over the lazy dog";
        byte[] key = "secret".getBytes();

        String gHmac = Hashing.hmacSha256(key)
                .newHasher()    (1)
                .putString(valueToDigest, UTF_8)
                .hash()
                .toString();    (2)
        System.out.println(gHmac);
    }
}
1 A hasher can be used only once and must be created for next Hmac256 calculation.
2 This will convert the byte array to hex encoded string
Output
54cd5b827c0ec938fa072a29b177469c843317b095591dc846767aa338bac600

3. Apache Commons Codec

Apache Commons Codec provides a utility class for Hmac operations.

org.apache.commons.codec.digest.HmacUtils

build.gradle
dependencies {
    // https://mvnrepository.com/artifact/commons-codec/commons-codec
    compile group: 'commons-codec', name: 'commons-codec', version: '1.14'
}
Hmac256 using Apache Commons Codec
import org.apache.commons.codec.digest.HmacAlgorithms;
import org.apache.commons.codec.digest.HmacUtils;

public class HMacTest {

    public void hmac256() {
        String valueToDigest = "The quick brown fox jumps over the lazy dog";
        byte[] key = "secret".getBytes();

        HmacUtils hm256 = new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key);
        //hm256 object can be used again and again
        String hmac = hm256.hmacHex(valueToDigest);
        System.out.println(hmac);
    }
}
Output
54cd5b827c0ec938fa072a29b177469c843317b095591dc846767aa338bac600

Similarly, you can compute Hmac256 for the entire file.

Hmac256 for a file
 String hexPom = hm256.hmacHex(new File("pom.xml"));

Top articles in this category:
  1. Allow insecure SSL in Java 11 HttpClient
  2. Secure OTP generation in Java
  3. What is left shift right shift and unsigned rght shift operator in Java
  4. Discuss internals of a ConcurrentHashmap (CHM) in Java
  5. Is Java Pure Object Oriented Language?
  6. Design an Immutable class that has an java.util.Date member
  7. What will happen if we don't synchronize getters/accessors of a shared mutable object in multi-threaded applications

Recommended books for interview preparation:

Find more on this topic:
Buy interview books

Java & Microservices interview refresher for experienced developers.