jhg023 / SimpleNet

An easy-to-use, event-driven, asynchronous network application framework compiled with Java 11.
MIT License
179 stars 19 forks source link

Issues with Encryption #19

Closed bytecod3r closed 4 years ago

bytecod3r commented 4 years ago

There is a problem with Encryption when there are more than 2 clients connected to the same server.

By using the below code, the first client connect to the server without any issues, and there is encryption, but second client onward throwing the below error.

FYI, I am just sending a small amount of bytes, and I am not sure where the below number (e.g. 1892643530) is coming from.

My machine has enough ram and I set "XX:MaxDirectMemorySize=4096m" but it didn't help.

java.lang.OutOfMemoryError: Cannot reserve 1892643530 bytes of direct buffer memory (allocated: 75700, limit: 536870912)
    at java.base/java.nio.Bits.reserveMemory(Unknown Source)
    at java.base/java.nio.DirectByteBuffer.<init>(Unknown Source)
    at java.base/java.nio.ByteBuffer.allocateDirect(Unknown Source)
    at com.github.pbbl.direct.DirectByteBufferPool.allocate(DirectByteBufferPool.java:39)
    at com.github.pbbl.direct.DirectByteBufferPool.allocate(DirectByteBufferPool.java:35)
    at com.github.pbbl.AbstractBufferPool.lambda$take$1(AbstractBufferPool.java:92)
    at java.base/java.util.Optional.orElseGet(Unknown Source)
    at com.github.pbbl.AbstractBufferPool.take(AbstractBufferPool.java:92)
    at net.simplenet.Client$Listener.completed(Client.java:172)
    at net.simplenet.Client$Listener.completed(Client.java:78)
    at java.base/sun.nio.ch.Invoker.invokeUnchecked(Unknown Source)
    at java.base/sun.nio.ch.Invoker.invokeDirect(Unknown Source)
    at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.implRead(Unknown Source)
    at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(Unknown Source)
    at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(Unknown Source)
    at java.base/java.nio.channels.AsynchronousSocketChannel.read(Unknown Source)
    at net.simplenet.Client$Listener.completed(Client.java:173)
    at net.simplenet.Client$Listener.completed(Client.java:78)
    at java.base/sun.nio.ch.Invoker.invokeUnchecked(Unknown Source)
    at java.base/sun.nio.ch.Invoker.invokeDirect(Unknown Source)
    at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.implRead(Unknown Source)
    at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(Unknown Source)
    at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(Unknown Source)
    at java.base/java.nio.channels.AsynchronousSocketChannel.read(Unknown Source)
    at net.simplenet.Client$Listener.completed(Client.java:173)
    at net.simplenet.Client$Listener.completed(Client.java:78)
    at java.base/sun.nio.ch.Invoker.invokeUnchecked(Unknown Source)
    at java.base/sun.nio.ch.Invoker.invokeDirect(Unknown Source)
    at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.implRead(Unknown Source)
    at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(Unknown Source)
    at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(Unknown Source)
    at java.base/java.nio.channels.AsynchronousSocketChannel.read(Unknown Source)
    at net.simplenet.Client$Listener.completed(Client.java:173)
    at net.simplenet.Client$Listener.completed(Client.java:78)
    at java.base/sun.nio.ch.Invoker.invokeUnchecked(Unknown Source)
    at java.base/sun.nio.ch.Invoker.invokeDirect(Unknown Source)
    at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.implRead(Unknown Source)
    at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(Unknown Source)
    at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(Unknown Source)
    at java.base/java.nio.channels.AsynchronousSocketChannel.read(Unknown Source)
    at net.simplenet.Client$Listener.completed(Client.java:173)
    at net.simplenet.Client$Listener.completed(Client.java:78)
    at java.base/sun.nio.ch.Invoker.invokeUnchecked(Unknown Source)
    at java.base/sun.nio.ch.Invoker.invokeDirect(Unknown Source)
    at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.implRead(Unknown Source)
    at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(Unknown Source)
    at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(Unknown Source)
    at java.base/java.nio.channels.AsynchronousSocketChannel.read(Unknown Source)
    at net.simplenet.Client$Listener.completed(Client.java:173)
    at net.simplenet.Client$Listener.completed(Client.java:78)
    at java.base/sun.nio.ch.Invoker.invokeUnchecked(Unknown Source)
    at java.base/sun.nio.ch.Invoker.invokeDirect(Unknown Source)
    at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.implRead(Unknown Source)
    at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(Unknown Source)
    at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(Unknown Source)
    at java.base/java.nio.channels.AsynchronousSocketChannel.read(Unknown Source)
    at net.simplenet.Client$Listener.completed(Client.java:173)
    at net.simplenet.Client$Listener.completed(Client.java:78)
    at java.base/sun.nio.ch.Invoker.invokeUnchecked(Unknown Source)
    at java.base/sun.nio.ch.Invoker.invokeDirect(Unknown Source)
    at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.implRead(Unknown Source)
    at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(Unknown Source)
    at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(Unknown Source)
    at java.base/java.nio.channels.AsynchronousSocketChannel.read(Unknown Source)
    at net.simplenet.Client$Listener.completed(Client.java:173)
    at net.simplenet.Client$Listener.completed(Client.java:78)
    at java.base/sun.nio.ch.Invoker.invokeUnchecked(Unknown Source)
    at java.base/sun.nio.ch.Invoker.invokeDirect(Unknown Source)
    at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.implRead(Unknown Source)
    at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(Unknown Source)
    at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(Unknown Source)
    at java.base/java.nio.channels.AsynchronousSocketChannel.read(Unknown Source)
    at net.simplenet.Client$Listener.completed(Client.java:173)
    at net.simplenet.Client$Listener.completed(Client.java:78)
    at java.base/sun.nio.ch.Invoker.invokeUnchecked(Unknown Source)
    at java.base/sun.nio.ch.Invoker.invokeDirect(Unknown Source)
    at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.implRead(Unknown Source)
    at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(Unknown Source)
    at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(Unknown Source)
    at java.base/java.nio.channels.AsynchronousSocketChannel.read(Unknown Source)
    at net.simplenet.Client$Listener.completed(Client.java:173)
    at net.simplenet.Client$Listener.completed(Client.java:78)
    at java.base/sun.nio.ch.Invoker.invokeUnchecked(Unknown Source)
    at java.base/sun.nio.ch.Invoker$2.run(Unknown Source)
    at java.base/sun.nio.ch.AsynchronousChannelGroupImpl$1.run(Unknown Source)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.base/java.lang.Thread.run(Unknown Source)

Server.java:

private Cipher[] initCiphers(String cipher) throws GeneralSecurityException {
        byte[] raw = { (byte) 0xA5, (byte) 0x01, (byte) 0x7B, (byte) 0xE5,
                (byte) 0x23, (byte) 0xCA, (byte) 0xD4, (byte) 0xD2,
                (byte) 0x23, (byte) 0xCA, (byte) 0xD4, (byte) 0xD2,
                (byte) 0x23, (byte) 0xCA, (byte) 0xD4, (byte) 0xD2,
               };

        var ivSpec = new IvParameterSpec(raw);
        var keySpec = new SecretKeySpec(raw, "AES");

        var serverEncryption = Cipher.getInstance(cipher);
        var serverDecryption = Cipher.getInstance(cipher);

        serverEncryption.init(Cipher.ENCRYPT_MODE, keySpec,ivSpec);
        serverDecryption.init(Cipher.DECRYPT_MODE, keySpec,ivSpec);

        return new Cipher[] { serverEncryption, serverDecryption };
    }

public void startServer()  {
        var ciphers = initCiphers("AES/CFB8/NoPadding");
        server.onConnect(client -> {
            client.setEncryption(ciphers[0], UPDATE);
            client.setDecryption(ciphers[1], UPDATE);
            client.readByteAlways(opcode -> {
                  switch (opcode) {            
                  ..........
                  }
             } 
         }

Client:

 private Cipher[] initCiphers(String cipher) throws GeneralSecurityException {
        byte[] raw = {(byte) 0xA5, (byte) 0x01, (byte) 0x7B, (byte) 0xE5,
                (byte) 0x23, (byte) 0xCA, (byte) 0xD4, (byte) 0xD2,
                (byte) 0x23, (byte) 0xCA, (byte) 0xD4, (byte) 0xD2,
                (byte) 0x23, (byte) 0xCA, (byte) 0xD4, (byte) 0xD2,
        };

        var ivSpec = new IvParameterSpec(raw);
        var keySpec = new SecretKeySpec(raw, "AES");

        var clientEncryption = Cipher.getInstance(cipher);
        var clientDecryption = Cipher.getInstance(cipher);

        clientEncryption.init(Cipher.ENCRYPT_MODE, keySpec,ivSpec);
        clientDecryption.init(Cipher.DECRYPT_MODE, keySpec,ivSpec);

        return new Cipher[]{clientEncryption, clientDecryption};
    }

var ciphers = initCiphers("AES/CFB8/NoPadding");

            client.onConnect(() -> {

                client.setEncryption(ciphers[0], UPDATE);
                client.setDecryption(ciphers[1], UPDATE);

                client.readByteAlways(opcode -> {
                    switch (opcode) {
                         .........
                   }
                }
            }
jhg023 commented 4 years ago

@bytecod3r I have a feeling that you're experiencing this issue because you're attempting to reuse the same Cipher[] for every Client that connects to your Server. However, because you've specified UPDATE instead of DO_FINAL, then you need to provide every Client with their own unique Cipher[].

The solution should be as simple as moving var ciphers = initCiphers("AES/CFB8/NoPadding"); into Server#onConnect in your startServer() method.

bytecod3r commented 4 years ago

Thanks, the suggestion above solved the problem.