How to Generate a HMAC Signature in Java
1. Overview
Hashed Based Message Authentication Code (HMAC) is a cryptography procedure that generates a code from a given data or String using a secret-key and a hash function like SHA256. The resulting code is called a Message Authentication Code (MAC) or signature.
HMAC does not involve encryption/decryption, as long as the same secret-key is used to sign the same message, the generated signature will always be the same.
This means we can validate the authenticity of HTTP requests, WebSocket messages, events etc. by counter-signing the incoming data and comparing the signatures.
2. Generating a Signature
We only need two components to generate an HMAC signature: a secret-key and the data to hash.
The secret-key can be a simple String of alphanumeric characters. The longer the number of characters, the better. The APIs we will use are already part of the JDK, so we don’t need to install additional libraries or dependencies.
Listing 2.1 HmacService.java
|
|
We converted the final signature bytes to base64 format for easy processing across different systems.
The message
can be JSON, XML or a simple String data; it really doesn’t matter.
Let’s see a typical usage of the function above in a unit test.
Listing 2.2 HmacServiceUnitTest.java
|
|
3. Security Applications
3.1 Request Forgery Protection
By nature of the HMAC mechanism we can use it to protect against request forgery. How? The request Sender and Receiver would have shared the secret-key via a secure channel in a one-time process, and subsequent communications will follow this pattern:
- The Sender intend to send a
Hello World
message - The Sender will generate a HMAC signature of the message using the shared secret-key
- The Sender will send both the resulting signature and the plain
Hello World
message - The Receiver, upon receiving the message, will also generate its own signature for the received plain
Hello World
message with its own copy of the shared secret-key - The Receiver will now compare the received signature with its own generated signature
- If the signature is exactly the same, then the Receiver will process the message. Otherwise, will reject the message
If at any point the message is modified by bad actors between the Sender and the Receiver, the message will have different signatures and become invalid.
3.2 Replay Attack Protection
We can enhance this protocol by adding one more ingredient - the current unix timestamp
.
Both the Sender and the Receiver will agree on a duration for which a request can be considered valid.
For example, any request older than 10 seconds will be deemed stale and won’t be processed.
- The Sender will sign
Hello World
+ current unixtimestamp
in milliseconds with the shared secret-key - The Sender will send
Hello World
,timestamp
andsignature
to the Receiver - The Receiver will compute the time difference between the received
timestamp
and its own current unixtimestamp
- If the time difference is more than the agreed upon limit, the request will be rejected as stale
- The Receiver, upon validating the
timestamp
, will then proceed to sign the messageHello World
+ receivedtimestamp
and compare thesignature
as usual to determine the message authenticity
This protocol will prevent a middleman from replaying old requests or modifying the requests in-flight. These techniques are usually used to secure API endpoints like web callbacks or internal APIs.
4. Conclusion
HMAC has multiple practical applications, simple to use and highly compatible across different programming languages. These attributes make it suitable for system security and more.
Beyond SHA256
, it is also possible to use SHA512
, SHA3-512
etc. The strength of HMAC is related to the
length of the secret-key and the hash function used. It is advisable to use longer secret-key and secure hash functions like SHA256
or SHA512
.
The complete source code is on GitHub.
Happy Coding