Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams
  • Encrypt string using AES Encryption(with GCMParameterSpec and nonce).
  • Append nonce to Encrypted String to use it later for decryption.
  • Decrypt string by extracting nonce and the string to decrypt.
  • I have written the code to encrypt and decrypt the string as required but i am facing "Error while decrypting Tag mismatch!"

    Could someone please help me identify the problem. Thanks!

    import java.io.UnsupportedEncodingException;
    import java.nio.ByteBuffer;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.security.SecureRandom;
    import java.util.Arrays;
    import java.util.Base64;
    import javax.crypto.Cipher;
    import javax.crypto.spec.GCMParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    public class AES {
        private static SecretKeySpec secretKey;
        private static byte[] key;
        private static final String ENCODING_TYPE = "UTF-8";
        private static final String ALGORITHM = "AES";
        private static final String TRANSFORMATION_VALUE = "AES/GCM/NoPadding";
        public static void setKey(String myKey, String hashingType) {
            MessageDigest sha = null;
            try {
                key = myKey.getBytes(ENCODING_TYPE);
                sha = MessageDigest.getInstance(hashingType);
                key = sha.digest(key);
                key = Arrays.copyOf(key, 16);
                secretKey = new SecretKeySpec(key, ALGORITHM);
            } catch (NoSuchAlgorithmException e) {
                System.out.println("NoSuchAlgorithmException "+e.getMessage());
            } catch (UnsupportedEncodingException e) {
                System.out.println("UnsupportedEncodingException "+e.getMessage());
            } catch (Exception e) {
                System.out.println("Exception Occured! "+e.getMessage());
        public static String encrypt(String strToEncrypt, String secret, String hashingType) {
            String encryptedString = null;
            try {
                byte[] nonce = new byte[12];
                setKey(secret,hashingType);
                SecureRandom random = SecureRandom.getInstanceStrong();
                random.nextBytes(nonce);
                final Cipher encryptCipher = Cipher.getInstance(TRANSFORMATION_VALUE);
                encryptCipher.init(Cipher.ENCRYPT_MODE, secretKey, new GCMParameterSpec(16 * 8, nonce));
                byte[] cipheredString = encryptCipher.doFinal(strToEncrypt.getBytes());
                ByteBuffer byteBuffer = ByteBuffer.allocate(nonce.length + cipheredString.length);
                byteBuffer.put(nonce);
                byteBuffer.put(cipheredString);
                encryptedString = Base64.getEncoder().encodeToString(byteBuffer.array());       //Encoding the ByteArrayOutputStream result object to Base64 format
            } catch (NoSuchAlgorithmException e) {
                System.out.println("NoSuchAlgorithmException "+e.getMessage());
            } catch (Exception e) {
                System.out.println("Error while encrypting "+e.getMessage());
            return encryptedString;
        public static String decrypt(String strToDecrypt, String secret, String hashingType) {
            String decryptedString = null;
            try {
                byte[] nonce = new byte[12];
                setKey(secret,hashingType);
                final Cipher decryptCipher = Cipher.getInstance(TRANSFORMATION_VALUE);
                ByteBuffer byteBuffer = ByteBuffer.wrap(Base64.getDecoder().decode(strToDecrypt));
                byteBuffer.get(nonce);
                byte[] cipheredString = new byte[byteBuffer.remaining()];
                byteBuffer.get(cipheredString);
                decryptCipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(16 * 8, nonce));
                decryptedString = new String(decryptCipher.doFinal(cipheredString));
            } catch (Exception e) {
                System.out.println("Error while decrypting "+e.getMessage());
            return decryptedString;
        public class TestAESEncrypt {
            public static void main(String[] args) {
                final String secretKey = "NEWTEST@Key123";
                String originalString = "Gamer_123.aa01@gmail.com";
                String encryptedString = AESEncryption.encrypt(originalString, secretKey, "SHA-256");
                System.out.println("String to Encrypt : "+originalString);
                System.out.println("Encrypted String : "+encryptedString);
        public class TestAESDecryption {
            public static void main(String[] args) {
                final String secretKey = "NEWTEST@Key123";
                String encryptedData = "ey4E+5zNPx4WLx5q0Srf7d1TN/sAzsdYuVmnihXQoA/yoYoxAO/ygrtuh+Zr9rZQ"; //Paste the encrypted string here
                String decryptedString = AESEncryption.decrypt(encryptedData, secretKey, "SHA-256") ;
                System.out.println("Encrypted String : "+encryptedData);
                System.out.println("Decrypted String: "+decryptedString);
    

    This will never work:

    encryptedString = new String(cipher.doFinal(strToEncrypt.getBytes()));  //Creating a ciphered string
    encryptedString += new String(nonce); //Appending nonce to the encrypted string
    encryptedString = new String(Base64.getEncoder().encode(encryptedString.getBytes()));   //Encoding ciphered string to Base64 format
    

    Once you attempt to convert the raw bytes to a string you have likely corrupted the data. Base64 encoding it afterward will not save you. Instead, you must do something like:

    ByteArrayOutputStream result = new ByteArrayOutputStream();
    result.write(nonce);
    result.write(cipher.doFinal(strToEncrypt.getBytes()));
    String encryptedString = Base64.getEncoder().encodeToString(result.toByteArray());
    

    Also, I noticed your nonce is only 8 bytes. That's probably too short, you should make it 12 bytes.

    It is not decryption.. I have just rearranged the result storage. I am still getting AEAD Bad Tag Exception. ByteArrayOutputStream result = new ByteArrayOutputStream(); result.write(cipher.doFinal(strToEncrypt.getBytes())); result.write(nonce); encryptedString = Base64.getEncoder().encodeToString(result.toByteArray()); @James – Sammy Jun 10, 2019 at 14:32 Could you please suggest the changes required? As per the code mentioned by you.. I have made the necessary changes - Changed the byte size to 12 final byte[] extractedNonce = strToDecrypt.substring(0, 11).getBytes(); strToDecrypt = strToDecrypt.substring(12, strToDecrypt.length()); – Sammy Jun 10, 2019 at 15:08 Well, did you update the encryptedData value in your TestAESDecryption class? Your code as it now stands worked for me. Good use of ByteBuffer by the way. – President James K. Polk Jun 11, 2019 at 14:09
    import java.io.UnsupportedEncodingException;
    import java.nio.ByteBuffer;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.security.SecureRandom;
    import java.util.Arrays;
    import java.util.Base64;
    import javax.crypto.Cipher;
    import javax.crypto.spec.GCMParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    public class AES {
        private static SecretKeySpec secretKey;
        private static byte[] key;
        private static final String ENCODING_TYPE = "UTF-8";
        private static final String ALGORITHM = "AES";
        private static final String TRANSFORMATION_VALUE = "AES/GCM/NoPadding";
        public static void setKey(String myKey, String hashingType) {
            MessageDigest sha = null;
            try {
                key = myKey.getBytes(ENCODING_TYPE);
                sha = MessageDigest.getInstance(hashingType);
                key = sha.digest(key);
                key = Arrays.copyOf(key, 16);
                secretKey = new SecretKeySpec(key, ALGORITHM);
            } catch (NoSuchAlgorithmException e) {
                System.out.println("NoSuchAlgorithmException "+e.getMessage());
            } catch (UnsupportedEncodingException e) {
                System.out.println("UnsupportedEncodingException "+e.getMessage());
            } catch (Exception e) {
                System.out.println("Exception Occured! "+e.getMessage());
        public static String encrypt(String strToEncrypt, String secret, String hashingType) {
            String encryptedString = null;
            try {
                byte[] nonce = new byte[12];
                setKey(secret,hashingType);
                SecureRandom random = SecureRandom.getInstanceStrong();
                random.nextBytes(nonce);
                final Cipher encryptCipher = Cipher.getInstance(TRANSFORMATION_VALUE);
                encryptCipher.init(Cipher.ENCRYPT_MODE, secretKey, new GCMParameterSpec(16 * 8, nonce));
                byte[] cipheredString = encryptCipher.doFinal(strToEncrypt.getBytes());
                ByteBuffer byteBuffer = ByteBuffer.allocate(nonce.length + cipheredString.length);
                byteBuffer.put(nonce);
                byteBuffer.put(cipheredString);
                encryptedString = Base64.getEncoder().encodeToString(byteBuffer.array());       //Encoding the ByteArrayOutputStream result object to Base64 format
            } catch (NoSuchAlgorithmException e) {
                System.out.println("NoSuchAlgorithmException "+e.getMessage());
            } catch (Exception e) {
                System.out.println("Error while encrypting "+e.getMessage());
            return encryptedString;
        public static String decrypt(String strToDecrypt, String secret, String hashingType) {
            String decryptedString = null;
            try {
                byte[] nonce = new byte[12];
                setKey(secret,hashingType);
                final Cipher decryptCipher = Cipher.getInstance(TRANSFORMATION_VALUE);
                ByteBuffer byteBuffer = ByteBuffer.wrap(Base64.getDecoder().decode(strToDecrypt));
                byteBuffer.get(nonce);
                byte[] cipheredString = new byte[byteBuffer.remaining()];
                byteBuffer.get(cipheredString);
                decryptCipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(16 * 8, nonce));
                decryptedString = new String(decryptCipher.doFinal(cipheredString));
            } catch (Exception e) {
                System.out.println("Error while decrypting "+e.getMessage());
            return decryptedString;
            

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.