1

I am making an instant messaging application where I set up a TLS connection between two phones where one acts as a Server and the other as the Client. When trying to send a message I get this exception at the Client-side where the Server tried to send the message on line inputStream = new ObjectInputStream (sslSocket.getInputStream());

Does anyone know what the problem can be?

    2021-04-07 17:35:58.528 2925-6197/com.example.testaware W/ample.testawar: Long monitor contention with owner Thread-7 (6196) at int com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLInputStream.read(byte[], int, int)(ConscryptFileDescriptorSocket.java:572) waiters=0 in int com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLInputStream.read(byte[], int, int) for 11.871s
2021-04-07 17:35:58.531 2925-6196/com.example.testaware W/System.err: java.io.StreamCorruptedException: invalid stream header: ACED7372
2021-04-07 17:35:58.531 2925-6196/com.example.testaware W/System.err:     at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:862)
2021-04-07 17:35:58.532 2925-6196/com.example.testaware W/System.err:     at java.io.ObjectInputStream.<init>(ObjectInputStream.java:353)
2021-04-07 17:35:58.532 2925-6196/com.example.testaware W/System.err:     at com.example.testaware.AppClient.run(AppClient.java:187)
2021-04-07 17:35:58.532 2925-6196/com.example.testaware W/System.err:     at java.lang.Thread.run(Thread.java:919)
2021-04-07 17:35:58.532 2925-6196/com.example.testaware D/LOG-Test-Aware-Client: Exception in Appclient  in run()
2021-04-07 17:35:58.532 2925-6197/com.example.testaware W/System.err: java.io.StreamCorruptedException: invalid stream header: 0005002A
2021-04-07 17:35:58.533 2925-6197/com.example.testaware W/System.err:     at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:862)
2021-04-07 17:35:58.533 2925-6197/com.example.testaware W/System.err:     at java.io.ObjectInputStream.<init>(ObjectInputStream.java:353)
2021-04-07 17:35:58.533 2925-6197/com.example.testaware W/System.err:     at com.example.testaware.AppClient.run(AppClient.java:187)
2021-04-07 17:35:58.534 2925-6197/com.example.testaware W/System.err:     at java.lang.Thread.run(Thread.java:919)

The AppClient class:

public class AppClient implements Runnable{

    private boolean running;
    @Getter
    private SSLSocket sslSocket;
    private SSLContext sslContext;

    private ObjectInputStream inputStream;
    private ObjectOutputStream outputStream;
    private ExecutorService sendService = Executors.newSingleThreadExecutor();

    @Getter
    private List<ConnectionListener> connectionListeners;

    private String LOG = "LOG-Test-Aware-Client";
    @Getter
    private KeyPair keyPair;

    private Inet6Address inet6Address;

    private int port;

    @Getter
    private MessageReceivedObserver messageReceivedObserver;

    public AppClient(KeyPair keyPair, SSLContext sslContext){
        this.keyPair = keyPair;
        this.sslContext = sslContext;
        this.inet6Address = MainActivity.getPeerIpv6();

        connectionListeners = new ArrayList<>();
    }


    private X509Certificate getServerIdentity() {
        try {
            Certificate[] certs = sslSocket.getSession().getPeerCertificates();
            if(certs.length > 0 && certs[0] instanceof X509Certificate) {
                return (X509Certificate) certs[0];
            }
        } catch (SSLPeerUnverifiedException | NullPointerException ignored) {
            ignored.printStackTrace();

        }
        return null;
    }

  
    @RequiresApi(api = Build.VERSION_CODES.Q)
    public boolean sendMessage(Message message){
        if(outputStream == null){
            Log.d(LOG, "outputstream is null");
            return false;
        }
        Runnable sendMessageRunnable = () -> {
            try {
                MessagePacket messagePacket = (new MessagePacket(message));
                Log.d(LOG, "outputstream " + message);
                outputStream.writeObject(messagePacket);
                outputStream.flush();
            } catch (IOException e) {
                e.printStackTrace();
                Log.d(LOG, "Exception in Appclient  in sendMessage()");
                running = false;
            }
        };
        sendService.submit(sendMessageRunnable);
        return true;
    }


    @RequiresApi(api = Build.VERSION_CODES.Q)
    @Override
    public void run() {
        running = true;
        sslSocket = null;

        this.port = Constants.SERVER_PORT;

        SSLSocketFactory socketFactory = sslContext.getSocketFactory();
        try {
            while(running){
                sslSocket = (SSLSocket) socketFactory.createSocket(inet6Address, Constants.SERVER_PORT);


                outputStream = new ObjectOutputStream(sslSocket.getOutputStream());
                inputStream = new ObjectInputStream (sslSocket.getInputStream());
                outputStream.writeUTF("clientHello");
                outputStream.flush();

                while(running){
                    if (inputStream != null){
                        AbstractPacket abstractPacket = (AbstractPacket) inputStream.readObject();
                        MessagePacket messagePacket = (MessagePacket) abstractPacket;
                        Message message = messagePacket.getMessage() ;

                        new Handler(Looper.getMainLooper()).post(()-> {
                            TestChatActivity.setChat(message);

                        });
                    }
                }
            }
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
            Log.d(LOG, "Exception in Appclient  in run()");
           
            if(sslSocket != null){
                try {
                    sslSocket.close();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }
    } 

The ClientHandler class acting as Server:

public class ClientHandler extends Thread  {
    private String LOG = "LOG-Test-Aware-Client-handler";
    private ObjectInputStream in;
    private ObjectOutputStream out;

    private boolean running;

    private SSLSocket sslSocket;

    @Getter
    private List<ConnectionListener> connectionListeners;

  
    public ClientHandler(ObjectInputStream in, ObjectOutputStream out, SSLSocket sslSocket, List<ConnectionListener> listener)  {
        this.in = in;
        this.out = out;
        this.sslSocket = sslSocket;
    }


    @Override
    public void run(){
        running = true;
         try {
             while (running) {
                 
                 AbstractPacket abstractPacket = (AbstractPacket) in.readObject();
                 MessagePacket messagePacket = (MessagePacket) abstractPacket;
                 Message message = messagePacket.getMessage() ;

                 Log.d(LOG, message.toString());
                 String plainText = message.getPlaintext(IdentityHandler.getKeyPair().getPrivate());
                 Log.d(LOG, "Plaintext:" +  plainText);
                 onPacket(message);
                 new Handler(Looper.getMainLooper()).post(()-> {
                     TestChatActivity.setChat(message);
                 });
            }

        } catch (IOException | ClassNotFoundException e) {
             e.printStackTrace();
         }
    }

The AbstractPacket class

package com.example.testaware.models;

import java.io.Serializable;

public abstract class AbstractPacket implements Serializable {
}

The MessagePacket class

package com.example.testaware.models;

import lombok.Getter;

public class MessagePacket extends AbstractPacket {
    private static final long serialVersionUID = 2545855896325861508L;

    @Getter
    Message message;

    public MessagePacket(Message message) {
        this.message = message;
    }
}

The Messageclass

public class Message implements Serializable {
    private byte[] ciphertext;
    private String plaintext;

    @Getter
    private byte[] signature;

    @Getter
    private PublicKey to;
    @Getter
    private PublicKey from;

    public Message(PublicKey to, PublicKey from, String message, PrivateKey privateKey) {
        this.to = to;
        this.from = from;

        Cipher cipher = null;
        try {
            byte[] key = new byte[16];
            (new SecureRandom()).nextBytes(key);

            cipher = Cipher.getInstance("AES/GCM/NoPadding");
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"));
            this.ciphertext = cipher.doFinal(message.getBytes(StandardCharsets.UTF_8));

            // Signature
            ByteArrayOutputStream signatureStream = new ByteArrayOutputStream();
            signatureStream.write(to.getEncoded());
            signatureStream.write(from.getEncoded());
            signatureStream.write(this.ciphertext);

            Signature signature = Signature.getInstance(Constants.SIGNATURE_ALGORITHM);
            signature.initSign(privateKey);
            signature.update(signatureStream.toByteArray());
            this.signature = signature.sign();
            this.plaintext = message;

        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IOException | SignatureException | BadPaddingException | IllegalBlockSizeException e) {
            e.printStackTrace();
        }
    }


    public String getPlaintext(PrivateKey privateKey) {
        if(plaintext != null){
            return plaintext;
        }
        Cipher cipher = null;
        try {
            cipher = Cipher.getInstance(Constants.ENCRYPTION_ALGORITHM_AES);
            byte[] key = new byte[16];
            (new SecureRandom()).nextBytes(key);

            byte[] iv = cipher.getIV();
            GCMParameterSpec gcmspec = cipher.getParameters().getParameterSpec(GCMParameterSpec.class);
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(128, iv));

            return new String(cipher.doFinal(this.ciphertext), StandardCharsets.UTF_8);
        } catch (BadPaddingException | IllegalBlockSizeException | InvalidKeyException | InvalidParameterSpecException | InvalidAlgorithmParameterException | NoSuchAlgorithmException | NoSuchPaddingException e) {
            e.printStackTrace();
        }
        return "Decryption failed.";
    }

Thanks!

1 Answer 1

0

Your Message class is not Serializable.

Sign up to request clarification or add additional context in comments.

1 Comment

But it implements Serializable, doesn’t that make it serializable?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.