March 8, 2021
Hot Topics:

Message Authentication: Unlocking the Secrets of the Java Cryptography Extensions

  • By David Thurmond
  • Send Email »
  • More Articles »

Next, the message authentication code object is initialized with the secret key generated:

Mac theMac = Mac.getInstance("HmacMD5");

Finally, the authentication code is generated in one single step:

byte[] theMacCode = theMac.doFinal(plaintext);

Note the similarities of the code above to the code used to encrypt data. Like the Cipher object, the Mac object requires that you get an instance of the class, properly initialized with an acceptable algorithm, and then initialize it with a secret key. The process of generating the MAC is done using the doFinal() method, just as the process of encryption is performed using the Cipher object. These similarities within the JCE make it easier for developers to use all features within the API once they are familiar with a single feature.

Using a third-party library to perform message authentication is just as easy as doing so for a cryptographic cipher. All that would need to be done to use the Bouncy Castle libraries within this code would be to change the lines where the secret key is generated and the Mac object is initialized:

Security.addProvider(new BouncyCastleProvider());
KeyGenerator keygen = KeyGenerator.getInstance("HmacMD5", "BC");
Mac theMac = Mac.getInstance("HmacMD5", "BC");

As with encryption algorithms, if the third-party library does not support the algorithm specified, an exception will be thrown. Using this approach means that one can use a third-party message authentication library without being locked into a particular vendor.

A More Realistic Example

The whole concept of message authentication involves a sender and receiver exchanging a secret message, a secret MAC key, and the MAC itself for verifying the message. The previous example only demonstrates the mechanics of generating the MAC, so now, on to a more complicated example.

Listing 3 shows how the sender would generate the MAC key and code for consumption by the recipient.

Listing 3: MACFileExample.java

package com.dlt.developer.mac;

import javax.crypto.*;
import java.io.*;
public class MACFileExample {
   public static void main(String[] args) throws Exception {
      System.out.println("Generating MAC key and code files..");

      KeyGenerator keygen = KeyGenerator.getInstance("HmacMD5");
      SecretKey macKey = keygen.generateKey();

      byte[] keyBytes = macKey.getEncoded();

      BufferedOutputStream out = new
         BufferedOutputStream(new FileOutputStream("mac_key.txt"));

      Mac theMac = Mac.getInstance("HmacMD5");

      BufferedInputStream in = new
         BufferedInputStream(new FileInputStream("plaintext.txt"));
      while (in.available() > 0) {
         byte[] plaintextBytes = new byte[in.available()];
      }    // while

      BufferedOutputStream macData = new
         BufferedOutputStream(new FileOutputStream(


   }    // main

}       // class MACFileExample

In Listing 3, the sender first creates the MAC key as shown in the earlier simple example. Then, this value is written to a file to be sent to the message recipient; in this case, mac_key.txt. An alternative to this approach would be for the two parties exchanging data to agree on the secret key value ahead of time; this would eliminate the need for the exchange of the MAC key file.

Next, the code loops through the plaintext.txt file. It grabs chunks of plaintext and applies the message authentication algorithm to each chunk. Note that the update() method is used for each chunk of data because the file could be too large to be handled all at once in memory by the Mac.doFinal() method.

This is very similar to the manner in which the Cipher class encrypts and decrypts data, but with one notable difference. When encrypting or decrypting data, the update() method returns plaintext or ciphertext bytes from the update() method. Here, update() simply applies the MAC algorithm to the current instance of the Mac class; no data is returned.

Finally, when all data has been read, the Mac.doFinal() method is invoked. This method returns the bytes for the MAC that were calculated by all of the prior iterations of the update() method earlier.

Page 3 of 4

This article was originally published on December 1, 2008

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date