title: How to verify a GMAC?
body: <p>According to section 5.2 (Two GCM Functions) of the <a href="https://csrc.nist.gov/publications/detail/sp/800-38d/final" rel="nofollow noreferrer">Recommendation for Block Cipher Modes of Operation: Galois/Counter Mode (GCM) and GMAC</a>, it mentions  that for the case of GMAC, <em>the authenticated encryption and decryption functions become the functions for generating and verifying an authentication tag on the non-confidential data</em>. </p>
  
  <p>Looking online and on the JCA reference page, I understand that GMAC is generated like this:</p>
  
  <pre><code>Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5Padding");
  cipher.init(ENCRYPT_MODE, encryptionKey, new GCMParameterSpec(96, iv), new SecureRandom());
  cipher.updateAAD(aadData);
  byte[] gmac = cipher.doFinal();
  </code></pre>
  
  <p>However, I have doubts regarding the GMAC verification. Is this the right way of verifying a GMAC?</p>
  
  <pre><code>Cipher decryptCipher = Cipher.getInstance("AES/GCM/PKCS5Padding");
  decryptCipher.init(DECRYPT_MODE, encryptionKey, new GCMParameterSpec(96, iv), new SecureRandom());
  decryptCipher.updateAAD(aadData);
  decryptCipher.update(gmac);
  byte[] verifiedGmac = decryptCipher.doFinal();
  </code></pre>
  
  <p>Where verifiedGmac size == 0?</p>
  
  <p>Here is the full code with inputs and outputs:</p>
  
  <pre><code>import org.hamcrest.core.Is;
  import org.junit.Test;
  
  import javax.crypto.Cipher;
  import javax.crypto.spec.GCMParameterSpec;
  import javax.crypto.spec.SecretKeySpec;
  import java.io.ByteArrayOutputStream;
  import java.io.IOException;
  import java.security.SecureRandom;
  
  import static javax.crypto.Cipher.DECRYPT_MODE;
  import static javax.crypto.Cipher.ENCRYPT_MODE;
  import static javax.xml.bind.DatatypeConverter.parseHexBinary;
  import static javax.xml.bind.DatatypeConverter.printHexBinary;
  import static org.junit.Assert.assertThat;
  
  public class TestGmac {
  
      @Test
      public void generateAndVerifyGmac() throws Exception {
          final byte[] message = parseHexBinary("AAAAAAAAAAAA");
          final byte[] authenticatedKey = parseHexBinary("63509E5A672C092CAD0B1DC6CE009A61");
          final byte[] aadData = buildAadForAuthenticationOnly(message, authenticatedKey);
          final byte[] iv = parseHexBinary("BBBBBBBBBBBBBBBBBBBBBBBB");
          SecretKeySpec encryptionKey = new SecretKeySpec(parseHexBinary("55804F3AEB4E914DC91255944A1F565A"), "AES");
  
          // Generate GMAC
          Cipher cipher = Cipher.getInstance("AES/GCM/PKCS5Padding");
          cipher.init(ENCRYPT_MODE, encryptionKey, new GCMParameterSpec(96, iv), new SecureRandom());
          cipher.updateAAD(aadData);
          byte[] gmac = cipher.doFinal();
          assertThat(printHexBinary(gmac), Is.is("44C955D63799428524E97993"));
  
          // Verify GMAC
          Cipher decryptCipher = Cipher.getInstance("AES/GCM/PKCS5Padding");
          decryptCipher.init(DECRYPT_MODE, encryptionKey, new GCMParameterSpec(96, iv), new SecureRandom());
          decryptCipher.updateAAD(aadData);
          decryptCipher.update(gmac);
          byte[] verifiedGmac = decryptCipher.doFinal();
          assertThat(printHexBinary(verifiedGmac), Is.is(""));
      }
  
      private byte[] buildAadForAuthenticationOnly(byte[] message, byte[] authenticatedKey) throws IOException {
          ByteArrayOutputStream aaDoutputStream = new ByteArrayOutputStream();
          aaDoutputStream.write(parseHexBinary("10"));
          aaDoutputStream.write(authenticatedKey);
          aaDoutputStream.write(message);
          return aaDoutputStream.toByteArray();
      }
  
  }
  </code></pre>