title: javax.crypto.AEADBadTagException: Tag mismatch! Error when encrypting String
body: <p>I wrote a simple Encryption and Decryption helper class for my android app to encrypt and store Strings securely. </p>
  
  <p>It consists of a single static public method to encrypt, then it calls a private static method to decrypt the encrypted message and returns it. I wrote the method this way to check if the message is intact after encryption/decryption.</p>
  
  <p>I wrote a simple JUnit test with a String and called AssertEquals on the String before and after sending it to the Crypto encryption method.</p>
  
  <p>I get this following errors from running the test:</p>
  
  <pre><code>javax.crypto.AEADBadTagException: Tag mismatch!
  </code></pre>
  
  <p>The error stack:</p>
  
  <pre><code>at com.sun.crypto.provider.GaloisCounterMode.decryptFinal(GaloisCounterMode.java:571)
  at com.sun.crypto.provider.CipherCore.finalNoPadding(CipherCore.java:1046)
  at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:983)
  at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:845)
  at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
  at javax.crypto.Cipher.doFinal(Cipher.java:2165)
  at util.Crypto.decrypt(Crypto.java:94)
  at util.Crypto.encrypt(Crypto.java:64)
  at com.example.ali.meappley.CryptoTest.encryptAndDecryptTest(CryptoTest.java:29)
  </code></pre>
  
  <p>I'm new to cryptography, but I read different stackoverflow replies and couldn't find anything of help. Some users suggested calling <code>cipher.update(someByteArray)</code> before calling <code>cipher.doFinal(someByteArray)</code> but I couldnt manage to get it working. Any suggestions?</p>
  
  <p>This is my helper class</p>
  
  <pre><code>public class Crypto {
  
  //public methods
  
  //public static encrypt method
  public static String encrypt(String messageToEncrypt, @Nullable byte[] associatedData) throws NoSuchPaddingException,
          NoSuchAlgorithmException,
          InvalidAlgorithmParameterException,
          InvalidKeyException,
          BadPaddingException,
          IllegalBlockSizeException {
  
      byte[] plainBytes = messageToEncrypt.getBytes();
  /////////////////////////////////////////////////////////////////
      SecureRandom secureRandom = new SecureRandom();
      byte[] key = new byte[16];
      secureRandom.nextBytes(key);
      SecretKey secretKey = new SecretKeySpec(key, "AES");
  
      byte[] iv = new byte[12]; //NEVER REUSE THIS IV WITH SAME KEY
      secureRandom.nextBytes(iv);
  
      final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
      GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv); //128 bit auth tag length
      cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);
  
      if (associatedData != null) {
          cipher.updateAAD(associatedData);
      }
  
      byte[] cipherText = cipher.doFinal(plainBytes);
  
      ByteBuffer byteBuffer = ByteBuffer.allocate(4 + iv.length + cipherText.length);
      byteBuffer.putInt(iv.length);
      byteBuffer.put(iv);
      byteBuffer.put(cipherText);
      byte[] cipherMessage = byteBuffer.array();
  
      Arrays.fill(key,(byte) 0); //overwrite the content of key with zeros
      ///////////////////////////////////////////////////////////////////
  
      byte[] decrypted = decrypt(cipherMessage, null, key);
  
      return decrypted.toString();
  }
  
  //public static decrypt method
  private static byte[] decrypt(byte[] cipherMessage, @Nullable byte[] associatedData, byte[] key) throws NoSuchPaddingException,
          NoSuchAlgorithmException,
          InvalidAlgorithmParameterException,
          InvalidKeyException,
          BadPaddingException,
          IllegalBlockSizeException {
  
      ByteBuffer byteBuffer = ByteBuffer.wrap(cipherMessage);
      int ivLength = byteBuffer.getInt();
      if(ivLength &lt; 12 || ivLength &gt;= 16) { // check input parameter
          throw new IllegalArgumentException("invalid iv length");
      }
      byte[] iv = new byte[ivLength];
      byteBuffer.get(iv);
      byte[] cipherText = new byte[byteBuffer.remaining()];
      byteBuffer.get(cipherText);
  
      final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
      cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(128, iv));
      if (associatedData != null) {
          cipher.updateAAD(associatedData);
      }
  
      cipher.update(cipherText);
      byte[] plainText= cipher.doFinal(cipherText);
  
      return plainText;
  }
  </code></pre>