Native cipher, with more smoke tests!
This commit is contained in:
@@ -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>
|
||||
|
@@ -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." );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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
|
||||
|
@@ -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" );
|
||||
|
@@ -1,73 +0,0 @@
|
||||
package net.md_5.bungee.netty;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.ShortBufferException;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
|
||||
@NonNull
|
||||
private final Cipher cipher;
|
||||
private ThreadLocal<byte[]> heapInLocal = new EmptyByteThreadLocal();
|
||||
private ThreadLocal<byte[]> heapOutLocal = new EmptyByteThreadLocal();
|
||||
|
||||
private static class EmptyByteThreadLocal extends ThreadLocal<byte[]>
|
||||
{
|
||||
|
||||
@Override
|
||||
protected byte[] initialValue()
|
||||
{
|
||||
return new byte[ 0 ];
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] bufToByte(ByteBuf in)
|
||||
{
|
||||
byte[] heapIn = heapInLocal.get();
|
||||
int readableBytes = in.readableBytes();
|
||||
if ( heapIn.length < readableBytes )
|
||||
{
|
||||
heapIn = new byte[ readableBytes ];
|
||||
heapInLocal.set( heapIn );
|
||||
}
|
||||
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 ) );
|
||||
}
|
||||
}
|
@@ -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();
|
||||
}
|
||||
}
|
@@ -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();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user