Implement new, high-performance cipher in native code. Currently available only for Linux-x64, other platforms will fallback to Java cipher.

This commit is contained in:
ninja- 2013-11-05 09:38:16 +01:00 committed by md_5
parent aaa8b4a53d
commit fc189e81d5
18 changed files with 499 additions and 69 deletions

3
native/compile-native.sh Executable file
View File

@ -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

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
</properties>
</project-shared-configuration>

29
native/pom.xml Normal file
View File

@ -0,0 +1,29 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-native</artifactId>
<version>1.7-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-Native</name>
<description>Optional native code to speed up and enhance BungeeCord functionality.</description>
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport</artifactId>
<version>${netty.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,56 @@
#include "net_md_5_bungee_NativeCipherImpl.h"
#include <openssl/aes.h>
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#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);
}
}

View File

@ -0,0 +1,37 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* 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

View File

@ -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;
}

View File

@ -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<byte[]> heapInLocal = new EmptyByteThreadLocal();
private ThreadLocal<byte[]> 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 ) );
}
}

View File

@ -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;
}
}

View File

@ -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);
}

Binary file not shown.

View File

@ -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!" );
}
}

View File

@ -44,6 +44,7 @@
<module>protocol</module>
<module>proxy</module>
<module>query</module>
<module>native</module>
</modules>
<scm>

View File

@ -47,6 +47,12 @@
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-native</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-protocol</artifactId>

View File

@ -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." );
}
}
/**

View File

@ -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

View File

@ -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" );

View File

@ -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<ByteBuf>
{
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<Object> out) throws Exception
{
out.add( cipher.cipher( ctx, msg ) );
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception
{
cipher.free();
}
}

View File

@ -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<ByteBuf>
{
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();
}
}