I have a server which let's sockets connect to it to send data over inputstreams, this data is being encrypted with AES/GCM/NoPadding in a class called Cryptographer. The server has threads that hold functionalities for the connected clients, and each thread is being represented in a ConnectionThread class, this class holds a reference to the cryptograhper class which is being initialized in the server class.
Problem:
When I send my first command it works just fine, no problems at all. But somehow when I send my second command if gives the following stacktrace:
javax.crypto.AEADBadTagException: Tag mismatch!
    at java.base/com.sun.crypto.provider.GaloisCounterMode.decryptFinal(GaloisCounterMode.java:595)
    at java.base/com.sun.crypto.provider.CipherCore.finalNoPadding(CipherCore.java:1116)
    at java.base/com.sun.crypto.provider.CipherCore.fillOutputBuffer(CipherCore.java:1053)
    at java.base/com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:853)
    at java.base/com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
    at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2208)
    at com.company.security.Cryptographer.decrypt(Cryptographer.java:53)
    at com.company.client.Reader.run(Reader.java:45)
    at java.base/java.lang.Thread.run(Thread.java:835)
Exception in thread "Thread-3" java.lang.NullPointerException
    at java.base/java.lang.String.<init>(String.java:623)
    at com.company.client.Reader.run(Reader.java:47)
    at java.base/java.lang.Thread.run(Thread.java:835)
These are the classes mentioned in the stacktrace
Cryptographer
package com.company.security;
import javax.crypto.*;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class Cryptographer {
    private Key secretKey;
    private GCMParameterSpec gcmParameterSpec;
    public Cryptographer() {
        byte[] secret = new byte[16]; // 128 bit is 16 bytes, and AES accepts 16 bytes, and a few others.
        byte[] secretBytes = "secret".getBytes();
        byte[] IV = new byte[12];
        gcmParameterSpec = new GCMParameterSpec(16 * 8, IV);
        System.arraycopy(secretBytes, 0, secret, 0, secretBytes.length);
        secretKey = new SecretKeySpec(secret, "AES");
    }
    /**
     * Encrypt data.
     * @param data to encrypt
     * @return encrypted data
     */
    public byte[] encrypt(byte[] data) {
        try {
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, gcmParameterSpec);
            byte[] encrypted = cipher.doFinal(data);
            return encrypted;
        } catch (InvalidKeyException | BadPaddingException
                | IllegalBlockSizeException | NoSuchPaddingException
                | NoSuchAlgorithmException | InvalidAlgorithmParameterException e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * Decrypt data.
     * @param data to decrypt
     * @return decrypted data
     */
    public byte[] decrypt(byte[] data) {
        try {
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmParameterSpec);
            return cipher.doFinal(data);
        } catch (InvalidKeyException | BadPaddingException
                | IllegalBlockSizeException | NoSuchPaddingException
                | NoSuchAlgorithmException | InvalidAlgorithmParameterException e) {
            e.printStackTrace();
            return null;
        }
    }
}
Reader
package com.company.client;
import com.company.FileLoader;
import com.company.client.helpers.ClientFileHelper;
import com.company.client.workers.MessageSender;
import com.company.security.Cryptographer;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
public class Reader implements Runnable {
    private InputStream inputStream;
    private ClientFileHelper fileHelper;
    private Cryptographer cryptographer;
    private FileLoader fileLoader;
    private BufferedReader bufferedReader;
    private MessageSender messageSender;
    private boolean isActive = true;
    private boolean isReceivingFile = false;
    public Reader(BufferedReader bufferedReader, MessageSender messageSender, InputStream inputStream) {
        this.bufferedReader = bufferedReader;
        this.messageSender = messageSender;
        this.inputStream = inputStream;
        cryptographer = new Cryptographer();
    }
    @Override
    public void run() {
        while (isActive) {
            try {
                int count;
                byte[] buffer;
                if(!isReceivingFile) {
                    buffer = new byte[inputStream.available()];
                } else {
                    buffer = new byte[inputStream.available()];
                }
                while ((count = inputStream.read(buffer)) > 0)
                {
                    byte[] decrypted = cryptographer.decrypt(buffer);
                    if(!isReceivingFile) {
                        handleInput(new String(decrypted));
                    } else {
                        if(fileHelper.getFileBytes().length == 0) {
                            fileHelper.setFileBytes(decrypted);
                        } else {
                            fileHelper.saveFile();
                            isReceivingFile = false;
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
                break;
            }
        }
    }
    /**
     * Handle the user input form the console.
     * @param input user input from console
     */
    private void handleInput(String input) {
        try {
            if (input.equals("PING")) { // If we get a PING message we send back a PONG message.
                messageSender.send("PONG");
            } else if (input.contains("FILE")) {
                setupFileAccept(input);
                isReceivingFile = true;
            } else {
                System.out.println(input);
            }
        } catch (Exception ex) {
            isActive = false;
        }
    }
    /**
     * Setup the file helper for the client that's going to receive a file.
     * @param line command
     */
    private void setupFileAccept(String line) {
        String[] args = line.split(" ");
        if(args[0].equals("FILE")) {
            fileHelper = new ClientFileHelper(args[1], Integer.valueOf(args[2]));
        }
    }
}
The ConnectionThread also has a similar read functionality which looks like this:
while (isActive) {
        try {
            int count;
            byte[] buffer;
            if(!isReceivingFile) {
                buffer = new byte[inputStream.available()];
            } else {
                buffer = fileHelper.getFileBytes();
            }
            while ((count = inputStream.read(buffer)) > 0)
            {
                byte[] decrypted = server.cryptographer.decrypt(buffer);
                if(!isReceivingFile) {
                    getInput(new String(decrypted));
                } else {
                    fileHelper.setFileBytes(decrypted);
                    // bytes received, now we can send the file!
                    if(fileHelper.sendToReceiver()) {
                        writeToClient(fileHelper.getReceiverName()
                                + " received " + fileHelper.getFilename());
                        fileHelper = null;
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            break;
        }
    }
In this case just assume that the Server class has the cryptographer property properly initialized, which is always the case.
My guess is that somewhere a value is doing something wrong but I am not sure. I am rather clueless to what I should do to fix this problem. Can somebody help me point out the mistakes and come up with possible solutions to fix this problem? My java version is 12.0.1
 
     
     
    