diff --git a/native/compile-native.sh b/native/compile-native.sh new file mode 100755 index 000000000..99ba41d2b --- /dev/null +++ b/native/compile-native.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +gcc -shared -fPIC -O3 -Werror -I/usr/lib/jvm/default-java/include/ src/main/c/NativeCipherImpl.c -o src/main/resources/native-cipher.so -lcrypto diff --git a/native/nb-configuration.xml b/native/nb-configuration.xml new file mode 100644 index 000000000..7e4659240 --- /dev/null +++ b/native/nb-configuration.xml @@ -0,0 +1,31 @@ + + + + + + project + NEW_LINE + NEW_LINE + NEW_LINE + true + true + true + true + true + true + true + true + true + true + + diff --git a/native/pom.xml b/native/pom.xml new file mode 100644 index 000000000..c6ec0fc52 --- /dev/null +++ b/native/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + + + net.md-5 + bungeecord-parent + 1.7-SNAPSHOT + ../pom.xml + + + net.md-5 + bungeecord-native + 1.7-SNAPSHOT + jar + + BungeeCord-Native + Optional native code to speed up and enhance BungeeCord functionality. + + + + io.netty + netty-transport + ${netty.version} + compile + + + diff --git a/native/src/main/c/NativeCipherImpl.c b/native/src/main/c/NativeCipherImpl.c new file mode 100644 index 000000000..41884025e --- /dev/null +++ b/native/src/main/c/NativeCipherImpl.c @@ -0,0 +1,56 @@ +#include "net_md_5_bungee_NativeCipherImpl.h" +#include +#include +#include +#include +#define BYTE unsigned char + +jlong Java_net_md_15_bungee_NativeCipherImpl_init +(JNIEnv* env, jobject obj, jbyteArray key) +{ + AES_KEY *aes_key = malloc(sizeof(AES_KEY)); + + jboolean isKeyCopy; + BYTE *key_bytes = (*env)->GetByteArrayElements(env, key, &isKeyCopy); + int key_length = (*env)->GetArrayLength(env, key) * 8; // in bits + + AES_set_encrypt_key(key_bytes, key_length, aes_key); + + if (isKeyCopy) { + (*env)->ReleaseByteArrayElements(env, key, (jbyte*)key_bytes, JNI_ABORT); + } + return (long) aes_key; +} +void Java_net_md_15_bungee_NativeCipherImpl_free +(JNIEnv* env, jobject obj, jlong key) +{ + free((AES_KEY*)key); +} +void Java_net_md_15_bungee_NativeCipherImpl_cipher +(JNIEnv* env, jobject obj, jboolean forEncryption, jlong key, jbyteArray iv, jlong in, jlong out, jint length) +{ + AES_KEY *aes_key = (AES_KEY*)key; + + size_t buffer_length = (size_t) length; + + BYTE *input = (BYTE*) in; + BYTE *output = (BYTE*) out; + + jboolean isCopy; + BYTE *iv_bytes = (*env)->GetByteArrayElements(env, iv, &isCopy); + + AES_cfb8_encrypt( + input, // input buffer + output, // output buffer + buffer_length, // readable bytes + aes_key, // encryption key + iv_bytes, // IV + NULL, // not needed + forEncryption ? AES_ENCRYPT : AES_DECRYPT // encryption mode + ); + + // IV has changed, let's copy it back + if (isCopy) { + (*env)->ReleaseByteArrayElements(env, iv, (jbyte*)iv_bytes, 0); + } +} diff --git a/native/src/main/c/net_md_5_bungee_NativeCipherImpl.h b/native/src/main/c/net_md_5_bungee_NativeCipherImpl.h new file mode 100644 index 000000000..87e30b034 --- /dev/null +++ b/native/src/main/c/net_md_5_bungee_NativeCipherImpl.h @@ -0,0 +1,37 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class net_md_5_bungee_NativeCipherImpl */ + +#ifndef _Included_net_md_5_bungee_NativeCipherImpl +#define _Included_net_md_5_bungee_NativeCipherImpl +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: net_md_5_bungee_NativeCipherImpl + * Method: init + * Signature: ([B)J + */ +JNIEXPORT jlong JNICALL Java_net_md_15_bungee_NativeCipherImpl_init + (JNIEnv *, jobject, jbyteArray); + +/* + * Class: net_md_5_bungee_NativeCipherImpl + * Method: free + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_net_md_15_bungee_NativeCipherImpl_free + (JNIEnv *, jobject, jlong); + +/* + * Class: net_md_5_bungee_NativeCipherImpl + * Method: cipher + * Signature: (ZJ[BJJI)V + */ +JNIEXPORT void JNICALL Java_net_md_15_bungee_NativeCipherImpl_cipher + (JNIEnv *, jobject, jboolean, jlong, jbyteArray, jlong, jlong, jint); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/native/src/main/java/net/md_5/bungee/BungeeCipher.java b/native/src/main/java/net/md_5/bungee/BungeeCipher.java new file mode 100644 index 000000000..a165d5ad0 --- /dev/null +++ b/native/src/main/java/net/md_5/bungee/BungeeCipher.java @@ -0,0 +1,21 @@ +package net.md_5.bungee; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import javax.crypto.SecretKey; +import java.security.GeneralSecurityException; + +/** + * Class to expose cipher methods from either native or fallback Java cipher. + */ +public interface BungeeCipher +{ + + void init(boolean forEncryption, SecretKey key) throws GeneralSecurityException; + + void free(); + + void cipher(ByteBuf in, ByteBuf out) throws GeneralSecurityException; + + ByteBuf cipher(ChannelHandlerContext ctx, ByteBuf in) throws GeneralSecurityException; +} diff --git a/proxy/src/main/java/net/md_5/bungee/netty/CipherBase.java b/native/src/main/java/net/md_5/bungee/FallbackCipher.java similarity index 65% rename from proxy/src/main/java/net/md_5/bungee/netty/CipherBase.java rename to native/src/main/java/net/md_5/bungee/FallbackCipher.java index 5679afea2..3c9ee0786 100644 --- a/proxy/src/main/java/net/md_5/bungee/netty/CipherBase.java +++ b/native/src/main/java/net/md_5/bungee/FallbackCipher.java @@ -1,24 +1,17 @@ -package net.md_5.bungee.netty; +package net.md_5.bungee; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import javax.crypto.Cipher; +import javax.crypto.SecretKey; import javax.crypto.ShortBufferException; -import lombok.AccessLevel; -import lombok.NonNull; -import lombok.RequiredArgsConstructor; +import javax.crypto.spec.IvParameterSpec; +import java.security.GeneralSecurityException; -/** - * Class to expose an - * {@link #cipher(io.netty.buffer.ByteBuf, io.netty.buffer.ByteBuf)} method to - * aid in the efficient passing of ByteBuffers through a cipher. - */ -@RequiredArgsConstructor(access = AccessLevel.PROTECTED) -public class CipherBase +public class FallbackCipher implements BungeeCipher { - @NonNull - private final Cipher cipher; + private Cipher cipher; private ThreadLocal heapInLocal = new EmptyByteThreadLocal(); private ThreadLocal heapOutLocal = new EmptyByteThreadLocal(); @@ -32,6 +25,51 @@ public class CipherBase } } + public FallbackCipher() throws GeneralSecurityException + { + this.cipher = Cipher.getInstance( "AES/CFB8/NoPadding" ); + } + + @Override + public void init(boolean forEncryption, SecretKey key) throws GeneralSecurityException + { + int mode = forEncryption ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE; + cipher.init( mode, key, new IvParameterSpec( key.getEncoded() ) ); + } + + @Override + public void cipher(ByteBuf in, ByteBuf out) throws ShortBufferException + { + int readableBytes = in.readableBytes(); + byte[] heapIn = bufToByte( in ); + + byte[] heapOut = heapOutLocal.get(); + int outputSize = cipher.getOutputSize( readableBytes ); + if ( heapOut.length < outputSize ) + { + heapOut = new byte[ outputSize ]; + heapOutLocal.set( heapOut ); + } + out.writeBytes( heapOut, 0, cipher.update( heapIn, 0, readableBytes, heapOut ) ); + } + + @Override + public ByteBuf cipher(ChannelHandlerContext ctx, ByteBuf in) throws ShortBufferException + { + int readableBytes = in.readableBytes(); + byte[] heapIn = bufToByte( in ); + + ByteBuf heapOut = ctx.alloc().heapBuffer( cipher.getOutputSize( readableBytes ) ); + heapOut.writerIndex( cipher.update( heapIn, 0, readableBytes, heapOut.array(), heapOut.arrayOffset() ) ); + + return heapOut; + } + + @Override + public void free() + { + } + private byte[] bufToByte(ByteBuf in) { byte[] heapIn = heapInLocal.get(); @@ -44,30 +82,4 @@ public class CipherBase in.readBytes( heapIn, 0, readableBytes ); return heapIn; } - - protected ByteBuf cipher(ChannelHandlerContext ctx, ByteBuf in) throws ShortBufferException - { - int readableBytes = in.readableBytes(); - byte[] heapIn = bufToByte( in ); - - ByteBuf heapOut = ctx.alloc().heapBuffer( cipher.getOutputSize( readableBytes ) ); - heapOut.writerIndex( cipher.update( heapIn, 0, readableBytes, heapOut.array(), heapOut.arrayOffset() ) ); - - return heapOut; - } - - protected void cipher(ByteBuf in, ByteBuf out) throws ShortBufferException - { - int readableBytes = in.readableBytes(); - byte[] heapIn = bufToByte( in ); - - byte[] heapOut = heapOutLocal.get(); - int outputSize = cipher.getOutputSize( readableBytes ); - if ( heapOut.length < outputSize ) - { - heapOut = new byte[ outputSize ]; - heapOutLocal.set( heapOut ); - } - out.writeBytes( heapOut, 0, cipher.update( heapIn, 0, readableBytes, heapOut ) ); - } } diff --git a/native/src/main/java/net/md_5/bungee/NativeCipher.java b/native/src/main/java/net/md_5/bungee/NativeCipher.java new file mode 100644 index 000000000..41d2d03ad --- /dev/null +++ b/native/src/main/java/net/md_5/bungee/NativeCipher.java @@ -0,0 +1,111 @@ +package net.md_5.bungee; + +import com.google.common.io.ByteStreams; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import lombok.Getter; +import javax.crypto.SecretKey; +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.GeneralSecurityException; + +public class NativeCipher implements BungeeCipher +{ + + @Getter + private final NativeCipherImpl nativeCipher = new NativeCipherImpl(); + private boolean forEncryption; + private byte[] iv; + /*============================================================================*/ + private static boolean loaded; + + private long pointer; + + public static boolean isSupported() + { + return "Linux".equals( System.getProperty( "os.name" ) ) && "amd64".equals( System.getProperty( "os.arch" ) ); + } + + public static boolean load() + { + if ( !loaded && isSupported() ) + { + try ( InputStream lib = BungeeCipher.class.getClassLoader().getResourceAsStream( "native-cipher.so" ) ) + { + // Else we will create and copy it to a temp file + File temp = File.createTempFile( "bungeecord-native-cipher", ".so" ); + try ( OutputStream outputStream = new FileOutputStream( temp ) ) + { + ByteStreams.copy( lib, outputStream ); + System.load( temp.getPath() ); + } + loaded = true; + } catch ( Throwable t ) + { + } + } + + return loaded; + } + + public static boolean isLoaded() + { + return loaded; + } + + @Override + public void init(boolean forEncryption, SecretKey key) throws GeneralSecurityException + { + if ( pointer != 0 ) + { + nativeCipher.free( pointer ); + } + this.forEncryption = forEncryption; + this.iv = key.getEncoded(); // initialize the IV + this.pointer = nativeCipher.init( key.getEncoded() ); + } + + @Override + public void free() + { + if ( pointer != 0 ) + { + nativeCipher.free( pointer ); + pointer = 0; + } + } + + @Override + public void cipher(ByteBuf in, ByteBuf out) throws GeneralSecurityException + { + // Smoke tests + in.memoryAddress(); + out.memoryAddress(); + // Store how many bytes we can cipher + int length = in.readableBytes(); + // It is important to note that in AES CFB-8 mode, the number of read bytes, is the number of outputted bytes + if ( out.writableBytes() < length ) + { + out.capacity( length ); + } + // Cipher the bytes + nativeCipher.cipher( forEncryption, pointer, iv, in.memoryAddress() + in.readerIndex(), out.memoryAddress() + out.writerIndex(), length ); + + // Go to the end of the buffer, all bytes would of been read + in.readerIndex( in.writerIndex() ); + // Add the number of ciphered bytes to our position + out.writerIndex( out.writerIndex() + length ); + } + + @Override + public ByteBuf cipher(ChannelHandlerContext ctx, ByteBuf in) throws GeneralSecurityException + { + int readableBytes = in.readableBytes(); + ByteBuf heapOut = ctx.alloc().directBuffer( readableBytes ); // CFB8 + cipher( in, heapOut ); + + return heapOut; + } +} diff --git a/native/src/main/java/net/md_5/bungee/NativeCipherImpl.java b/native/src/main/java/net/md_5/bungee/NativeCipherImpl.java new file mode 100644 index 000000000..261a84ec4 --- /dev/null +++ b/native/src/main/java/net/md_5/bungee/NativeCipherImpl.java @@ -0,0 +1,32 @@ +package net.md_5.bungee; + +class NativeCipherImpl +{ + + /** + * Initializes the key. + * + * @param key the key to for encryption + * @return the pointer to key + */ + native long init(byte[] key); + + /** + * Frees the key. + * + * @param key the pointer to key + */ + native void free(long key); + + /** + * This method will encrypt some data in AES-CFB8 using the specified key. + * + * @param forEncryption encryption / decryption mode + * @param key the pointer to key + * @param iv the iv to use + * @param in the starting memory address for reading data + * @param out the starting memory address for writing data + * @param length the length of data to read / write + */ + native void cipher(boolean forEncryption, long key, byte[] iv, long in, long out, int length); +} diff --git a/native/src/main/resources/native-cipher.so b/native/src/main/resources/native-cipher.so new file mode 100755 index 000000000..262be07b1 Binary files /dev/null and b/native/src/main/resources/native-cipher.so differ diff --git a/native/src/test/java/net/md_5/bungee/NativeCipherTest.java b/native/src/test/java/net/md_5/bungee/NativeCipherTest.java new file mode 100644 index 000000000..ce820542b --- /dev/null +++ b/native/src/test/java/net/md_5/bungee/NativeCipherTest.java @@ -0,0 +1,74 @@ +package net.md_5.bungee; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.junit.Assert; +import org.junit.Test; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +public class NativeCipherTest +{ + + private final byte[] plainBytes = "This is a test".getBytes(); + private final byte[] cipheredBytes = new byte[] + { + 50, -7, 89, 1, -11, -32, -118, -48, -2, -72, 105, 97, -70, -81 + }; + private final SecretKey secret = new SecretKeySpec( new byte[ 16 ], "AES" ); + + @Test + public void testOpenSSL() throws Exception + { + if ( NativeCipher.isSupported() ) + { + boolean loaded = NativeCipher.load(); + Assert.assertTrue( "Native cipher failed to load!", loaded ); + + NativeCipher cipher = new NativeCipher(); + System.out.println( "Testing OpenSSL cipher..." ); + testACipher( cipher ); + } + } + + @Test + public void testJDK() throws Exception + { + // Create JDK cipher + BungeeCipher cipher = new FallbackCipher(); + + System.out.println( "Testing Java cipher..." ); + testACipher( cipher ); + } + + /** + * Hackish test which can test both native and fallback ciphers using direct + * buffers. + */ + public void testACipher(BungeeCipher cipher) throws Exception + { + // Create input buf + ByteBuf nativePlain = Unpooled.directBuffer( plainBytes.length ); + nativePlain.writeBytes( plainBytes ); + // Create expected buf + ByteBuf nativeCiphered = Unpooled.directBuffer( cipheredBytes.length ); + nativeCiphered.writeBytes( cipheredBytes ); + // Create output buf + ByteBuf out = Unpooled.directBuffer( plainBytes.length ); + + // Encrypt + cipher.init( true, secret ); + cipher.cipher( nativePlain, out ); + Assert.assertEquals( nativeCiphered, out ); + + out.clear(); + + // Decrypt + cipher.init( false, secret ); + cipher.cipher( nativeCiphered, out ); + nativePlain.resetReaderIndex(); + Assert.assertEquals( nativePlain, out ); + + System.out.println( "This cipher works correctly!" ); + } +} diff --git a/pom.xml b/pom.xml index f97ca0d4e..1a1012f42 100644 --- a/pom.xml +++ b/pom.xml @@ -44,6 +44,7 @@ protocol proxy query + native diff --git a/proxy/pom.xml b/proxy/pom.xml index 1369b8527..39eafecdf 100644 --- a/proxy/pom.xml +++ b/proxy/pom.xml @@ -47,6 +47,12 @@ ${project.version} compile + + net.md-5 + bungeecord-native + ${project.version} + compile + net.md-5 bungeecord-protocol diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java index 11b560c5e..b30fdef18 100644 --- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java @@ -158,6 +158,14 @@ public class BungeeCord extends ProxyServer logger.info( "Unable to initialize fancy terminal. To fix this on Windows, install the correct Microsoft Visual C++ 2008 Runtime" ); logger.info( "NOTE: This error is non crucial, and BungeeCord will still function correctly! Do not bug the author about it unless you are still unable to get it working" ); } + + if ( !NativeCipher.load() ) + { + logger.warning( "NOTE: Failed to load native code. Falling back to Java cipher." ); + } else + { + logger.info( "Native code loaded." ); + } } /** diff --git a/proxy/src/main/java/net/md_5/bungee/EncryptionUtil.java b/proxy/src/main/java/net/md_5/bungee/EncryptionUtil.java index eb7fe4f19..dabff27c1 100644 --- a/proxy/src/main/java/net/md_5/bungee/EncryptionUtil.java +++ b/proxy/src/main/java/net/md_5/bungee/EncryptionUtil.java @@ -12,7 +12,6 @@ import java.util.Arrays; import java.util.Random; import javax.crypto.Cipher; import javax.crypto.SecretKey; -import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import lombok.Getter; import net.md_5.bungee.protocol.packet.EncryptionResponse; @@ -64,11 +63,19 @@ public class EncryptionUtil return new SecretKeySpec( cipher.doFinal( resp.getSharedSecret() ), "AES" ); } - public static Cipher getCipher(int opMode, Key shared) throws GeneralSecurityException + public static BungeeCipher getCipher(boolean forEncryption, SecretKey shared) throws GeneralSecurityException { - Cipher cip = Cipher.getInstance( "AES/CFB8/NoPadding" ); - cip.init( opMode, shared, new IvParameterSpec( shared.getEncoded() ) ); - return cip; + BungeeCipher cipher; + if ( NativeCipher.isLoaded() ) + { + cipher = new NativeCipher(); + } else + { + cipher = new FallbackCipher(); + } + + cipher.init( forEncryption, shared ); + return cipher; } public static PublicKey getPubkey(EncryptionRequest request) throws GeneralSecurityException diff --git a/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java b/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java index c9afc3002..473fc0a5a 100644 --- a/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java +++ b/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java @@ -8,14 +8,10 @@ import java.security.MessageDigest; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; -import javax.crypto.Cipher; import javax.crypto.SecretKey; import lombok.Getter; import lombok.RequiredArgsConstructor; -import net.md_5.bungee.BungeeCord; -import net.md_5.bungee.EncryptionUtil; -import net.md_5.bungee.UserConnection; -import net.md_5.bungee.Util; +import net.md_5.bungee.*; import net.md_5.bungee.api.Callback; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ProxyServer; @@ -30,10 +26,10 @@ import net.md_5.bungee.api.event.ProxyPingEvent; import net.md_5.bungee.http.HttpClient; import net.md_5.bungee.netty.HandlerBoss; import net.md_5.bungee.netty.ChannelWrapper; -import net.md_5.bungee.netty.CipherDecoder; -import net.md_5.bungee.netty.CipherEncoder; import net.md_5.bungee.netty.PacketHandler; import net.md_5.bungee.netty.PipelineUtils; +import net.md_5.bungee.netty.cipher.CipherDecoder; +import net.md_5.bungee.netty.cipher.CipherEncoder; import net.md_5.bungee.protocol.DefinedPacket; import net.md_5.bungee.protocol.packet.Login; import net.md_5.bungee.protocol.packet.Handshake; @@ -286,9 +282,9 @@ public class InitialHandler extends PacketHandler implements PendingConnection Preconditions.checkState( thisState == State.ENCRYPT, "Not expecting ENCRYPT" ); sharedKey = EncryptionUtil.getSecret( encryptResponse, request ); - Cipher decrypt = EncryptionUtil.getCipher( Cipher.DECRYPT_MODE, sharedKey ); + BungeeCipher decrypt = EncryptionUtil.getCipher( false, sharedKey ); ch.addBefore( PipelineUtils.FRAME_DECODER, PipelineUtils.DECRYPT_HANDLER, new CipherDecoder( decrypt ) ); - Cipher encrypt = EncryptionUtil.getCipher( Cipher.ENCRYPT_MODE, sharedKey ); + BungeeCipher encrypt = EncryptionUtil.getCipher( true, sharedKey ); ch.addBefore( PipelineUtils.FRAME_PREPENDER, PipelineUtils.ENCRYPT_HANDLER, new CipherEncoder( encrypt ) ); String encName = URLEncoder.encode( InitialHandler.this.getName(), "UTF-8" ); diff --git a/proxy/src/main/java/net/md_5/bungee/netty/CipherDecoder.java b/proxy/src/main/java/net/md_5/bungee/netty/cipher/CipherDecoder.java similarity index 59% rename from proxy/src/main/java/net/md_5/bungee/netty/CipherDecoder.java rename to proxy/src/main/java/net/md_5/bungee/netty/cipher/CipherDecoder.java index e6fe7df92..7fcc323a7 100644 --- a/proxy/src/main/java/net/md_5/bungee/netty/CipherDecoder.java +++ b/proxy/src/main/java/net/md_5/bungee/netty/cipher/CipherDecoder.java @@ -1,24 +1,27 @@ -package net.md_5.bungee.netty; +package net.md_5.bungee.netty.cipher; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageDecoder; +import lombok.RequiredArgsConstructor; +import net.md_5.bungee.BungeeCipher; import java.util.List; -import javax.crypto.Cipher; +@RequiredArgsConstructor public class CipherDecoder extends MessageToMessageDecoder { - private final CipherBase cipher; - - public CipherDecoder(Cipher cipher) - { - this.cipher = new CipherBase( cipher ); - } + private final BungeeCipher cipher; @Override protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List out) throws Exception { out.add( cipher.cipher( ctx, msg ) ); } + + @Override + public void handlerRemoved(ChannelHandlerContext ctx) throws Exception + { + cipher.free(); + } } diff --git a/proxy/src/main/java/net/md_5/bungee/netty/CipherEncoder.java b/proxy/src/main/java/net/md_5/bungee/netty/cipher/CipherEncoder.java similarity index 56% rename from proxy/src/main/java/net/md_5/bungee/netty/CipherEncoder.java rename to proxy/src/main/java/net/md_5/bungee/netty/cipher/CipherEncoder.java index 7e5c0ec60..df89b99bc 100644 --- a/proxy/src/main/java/net/md_5/bungee/netty/CipherEncoder.java +++ b/proxy/src/main/java/net/md_5/bungee/netty/cipher/CipherEncoder.java @@ -1,23 +1,26 @@ -package net.md_5.bungee.netty; +package net.md_5.bungee.netty.cipher; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; -import javax.crypto.Cipher; +import lombok.RequiredArgsConstructor; +import net.md_5.bungee.BungeeCipher; +@RequiredArgsConstructor public class CipherEncoder extends MessageToByteEncoder { - private final CipherBase cipher; - - public CipherEncoder(Cipher cipher) - { - this.cipher = new CipherBase( cipher ); - } + private final BungeeCipher cipher; @Override protected void encode(ChannelHandlerContext ctx, ByteBuf in, ByteBuf out) throws Exception { cipher.cipher( in, out ); } + + @Override + public void handlerRemoved(ChannelHandlerContext ctx) throws Exception + { + cipher.free(); + } }