Implement BouncyCastle as the cipher engine.
This commit is contained in:
parent
927a295add
commit
66de4c95ef
@ -67,6 +67,12 @@
|
|||||||
<version>5.1.24</version>
|
<version>5.1.24</version>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcprov-jdk15on</artifactId>
|
||||||
|
<version>1.49</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.javassist</groupId>
|
<groupId>org.javassist</groupId>
|
||||||
<artifactId>javassist</artifactId>
|
<artifactId>javassist</artifactId>
|
||||||
|
@ -7,16 +7,22 @@ import java.security.KeyPair;
|
|||||||
import java.security.KeyPairGenerator;
|
import java.security.KeyPairGenerator;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
|
import java.security.Security;
|
||||||
import java.security.spec.X509EncodedKeySpec;
|
import java.security.spec.X509EncodedKeySpec;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import javax.crypto.Cipher;
|
import javax.crypto.Cipher;
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
import javax.crypto.spec.IvParameterSpec;
|
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import net.md_5.bungee.protocol.packet.PacketFCEncryptionResponse;
|
import net.md_5.bungee.protocol.packet.PacketFCEncryptionResponse;
|
||||||
import net.md_5.bungee.protocol.packet.PacketFDEncryptionRequest;
|
import net.md_5.bungee.protocol.packet.PacketFDEncryptionRequest;
|
||||||
|
import org.bouncycastle.crypto.BufferedBlockCipher;
|
||||||
|
import org.bouncycastle.crypto.engines.AESFastEngine;
|
||||||
|
import org.bouncycastle.crypto.modes.CFBBlockCipher;
|
||||||
|
import org.bouncycastle.crypto.params.KeyParameter;
|
||||||
|
import org.bouncycastle.crypto.params.ParametersWithIV;
|
||||||
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class containing all encryption related methods for the proxy.
|
* Class containing all encryption related methods for the proxy.
|
||||||
@ -31,6 +37,7 @@ public class EncryptionUtil
|
|||||||
|
|
||||||
static
|
static
|
||||||
{
|
{
|
||||||
|
Security.addProvider( new BouncyCastleProvider() );
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
keys = KeyPairGenerator.getInstance( "RSA" ).generateKeyPair();
|
keys = KeyPairGenerator.getInstance( "RSA" ).generateKeyPair();
|
||||||
@ -64,10 +71,10 @@ public class EncryptionUtil
|
|||||||
return new SecretKeySpec( cipher.doFinal( resp.getSharedSecret() ), "AES" );
|
return new SecretKeySpec( cipher.doFinal( resp.getSharedSecret() ), "AES" );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Cipher getCipher(int opMode, Key shared) throws GeneralSecurityException
|
public static BufferedBlockCipher getCipher(boolean forEncryption, Key shared)
|
||||||
{
|
{
|
||||||
Cipher cip = Cipher.getInstance( "AES/CFB8/NoPadding" );
|
BufferedBlockCipher cip = new BufferedBlockCipher( new CFBBlockCipher( new AESFastEngine(), 8 ) );
|
||||||
cip.init( opMode, shared, new IvParameterSpec( shared.getEncoded() ) );
|
cip.init( forEncryption, new ParametersWithIV( new KeyParameter( shared.getEncoded() ), shared.getEncoded(), 0, 16 ) );
|
||||||
return cip;
|
return cip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ import java.io.DataInput;
|
|||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import javax.crypto.Cipher;
|
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
@ -39,6 +38,7 @@ import net.md_5.bungee.protocol.packet.PacketFCEncryptionResponse;
|
|||||||
import net.md_5.bungee.protocol.packet.PacketFDEncryptionRequest;
|
import net.md_5.bungee.protocol.packet.PacketFDEncryptionRequest;
|
||||||
import net.md_5.bungee.protocol.packet.PacketFFKick;
|
import net.md_5.bungee.protocol.packet.PacketFFKick;
|
||||||
import net.md_5.bungee.protocol.packet.forge.Forge1Login;
|
import net.md_5.bungee.protocol.packet.forge.Forge1Login;
|
||||||
|
import org.bouncycastle.crypto.BufferedBlockCipher;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class ServerConnector extends PacketHandler
|
public class ServerConnector extends PacketHandler
|
||||||
@ -219,7 +219,7 @@ public class ServerConnector extends PacketHandler
|
|||||||
|
|
||||||
ch.write( new PacketFCEncryptionResponse( shared, token ) );
|
ch.write( new PacketFCEncryptionResponse( shared, token ) );
|
||||||
|
|
||||||
Cipher encrypt = EncryptionUtil.getCipher( Cipher.ENCRYPT_MODE, secretkey );
|
BufferedBlockCipher encrypt = EncryptionUtil.getCipher( true, secretkey );
|
||||||
ch.addBefore( PipelineUtils.PACKET_DECODE_HANDLER, PipelineUtils.ENCRYPT_HANDLER, new CipherEncoder( encrypt ) );
|
ch.addBefore( PipelineUtils.PACKET_DECODE_HANDLER, PipelineUtils.ENCRYPT_HANDLER, new CipherEncoder( encrypt ) );
|
||||||
|
|
||||||
thisState = State.ENCRYPT_RESPONSE;
|
thisState = State.ENCRYPT_RESPONSE;
|
||||||
@ -234,7 +234,7 @@ public class ServerConnector extends PacketHandler
|
|||||||
{
|
{
|
||||||
Preconditions.checkState( thisState == State.ENCRYPT_RESPONSE, "Not expecting ENCRYPT_RESPONSE" );
|
Preconditions.checkState( thisState == State.ENCRYPT_RESPONSE, "Not expecting ENCRYPT_RESPONSE" );
|
||||||
|
|
||||||
Cipher decrypt = EncryptionUtil.getCipher( Cipher.DECRYPT_MODE, secretkey );
|
BufferedBlockCipher decrypt = EncryptionUtil.getCipher( false, secretkey );
|
||||||
ch.addBefore( PipelineUtils.PACKET_DECODE_HANDLER, PipelineUtils.DECRYPT_HANDLER, new CipherDecoder( decrypt ) );
|
ch.addBefore( PipelineUtils.PACKET_DECODE_HANDLER, PipelineUtils.DECRYPT_HANDLER, new CipherDecoder( decrypt ) );
|
||||||
|
|
||||||
ch.write( user.getPendingConnection().getForgeLogin() );
|
ch.write( user.getPendingConnection().getForgeLogin() );
|
||||||
|
@ -14,7 +14,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.crypto.Cipher;
|
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -53,6 +52,7 @@ import net.md_5.bungee.protocol.packet.PacketFDEncryptionRequest;
|
|||||||
import net.md_5.bungee.protocol.packet.PacketFEPing;
|
import net.md_5.bungee.protocol.packet.PacketFEPing;
|
||||||
import net.md_5.bungee.protocol.packet.PacketFFKick;
|
import net.md_5.bungee.protocol.packet.PacketFFKick;
|
||||||
import net.md_5.bungee.reconnect.AbstractReconnectManager;
|
import net.md_5.bungee.reconnect.AbstractReconnectManager;
|
||||||
|
import org.bouncycastle.crypto.BufferedBlockCipher;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class InitialHandler extends PacketHandler implements PendingConnection
|
public class InitialHandler extends PacketHandler implements PendingConnection
|
||||||
@ -240,7 +240,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
Preconditions.checkState( thisState == State.ENCRYPT, "Not expecting ENCRYPT" );
|
Preconditions.checkState( thisState == State.ENCRYPT, "Not expecting ENCRYPT" );
|
||||||
|
|
||||||
sharedKey = EncryptionUtil.getSecret( encryptResponse, request );
|
sharedKey = EncryptionUtil.getSecret( encryptResponse, request );
|
||||||
Cipher decrypt = EncryptionUtil.getCipher( Cipher.DECRYPT_MODE, sharedKey );
|
BufferedBlockCipher decrypt = EncryptionUtil.getCipher( false, sharedKey );
|
||||||
ch.addBefore( PipelineUtils.PACKET_DECODE_HANDLER, PipelineUtils.DECRYPT_HANDLER, new CipherDecoder( decrypt ) );
|
ch.addBefore( PipelineUtils.PACKET_DECODE_HANDLER, PipelineUtils.DECRYPT_HANDLER, new CipherDecoder( decrypt ) );
|
||||||
|
|
||||||
if ( BungeeCord.getInstance().config.isOnlineMode() )
|
if ( BungeeCord.getInstance().config.isOnlineMode() )
|
||||||
@ -316,14 +316,8 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
|||||||
public void run()
|
public void run()
|
||||||
{
|
{
|
||||||
unsafe().sendPacket( new PacketFCEncryptionResponse( new byte[ 0 ], new byte[ 0 ] ) );
|
unsafe().sendPacket( new PacketFCEncryptionResponse( new byte[ 0 ], new byte[ 0 ] ) );
|
||||||
try
|
BufferedBlockCipher encrypt = EncryptionUtil.getCipher( true, sharedKey );
|
||||||
{
|
|
||||||
Cipher encrypt = EncryptionUtil.getCipher( Cipher.ENCRYPT_MODE, sharedKey );
|
|
||||||
ch.addBefore( PipelineUtils.DECRYPT_HANDLER, PipelineUtils.ENCRYPT_HANDLER, new CipherEncoder( encrypt ) );
|
ch.addBefore( PipelineUtils.DECRYPT_HANDLER, PipelineUtils.ENCRYPT_HANDLER, new CipherEncoder( encrypt ) );
|
||||||
} catch ( GeneralSecurityException ex )
|
|
||||||
{
|
|
||||||
disconnect( "Cipher error: " + Util.exception( ex ) );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,11 @@ package net.md_5.bungee.netty;
|
|||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import javax.crypto.Cipher;
|
|
||||||
import javax.crypto.ShortBufferException;
|
import javax.crypto.ShortBufferException;
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.bouncycastle.crypto.BufferedBlockCipher;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to expose an
|
* Class to expose an
|
||||||
@ -18,7 +18,7 @@ public class CipherBase
|
|||||||
{
|
{
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private final Cipher cipher;
|
private final BufferedBlockCipher cipher;
|
||||||
private ThreadLocal<byte[]> heapInLocal = new EmptyByteThreadLocal();
|
private ThreadLocal<byte[]> heapInLocal = new EmptyByteThreadLocal();
|
||||||
private ThreadLocal<byte[]> heapOutLocal = new EmptyByteThreadLocal();
|
private ThreadLocal<byte[]> heapOutLocal = new EmptyByteThreadLocal();
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ public class CipherBase
|
|||||||
byte[] heapIn = bufToByte( in );
|
byte[] heapIn = bufToByte( in );
|
||||||
|
|
||||||
ByteBuf heapOut = ctx.alloc().heapBuffer( cipher.getOutputSize( readableBytes ) );
|
ByteBuf heapOut = ctx.alloc().heapBuffer( cipher.getOutputSize( readableBytes ) );
|
||||||
heapOut.writerIndex( cipher.update( heapIn, 0, readableBytes, heapOut.array(), heapOut.arrayOffset() ) );
|
heapOut.writerIndex( cipher.processBytes( heapIn, 0, readableBytes, heapOut.array(), heapOut.arrayOffset() ) );
|
||||||
|
|
||||||
return heapOut;
|
return heapOut;
|
||||||
}
|
}
|
||||||
@ -68,6 +68,6 @@ public class CipherBase
|
|||||||
heapOut = new byte[ outputSize ];
|
heapOut = new byte[ outputSize ];
|
||||||
heapOutLocal.set( heapOut );
|
heapOutLocal.set( heapOut );
|
||||||
}
|
}
|
||||||
out.writeBytes( heapOut, 0, cipher.update( heapIn, 0, readableBytes, heapOut ) );
|
out.writeBytes( heapOut, 0, cipher.processBytes( heapIn, 0, readableBytes, heapOut, 0 ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,14 +4,14 @@ import io.netty.buffer.ByteBuf;
|
|||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.MessageList;
|
import io.netty.channel.MessageList;
|
||||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||||
import javax.crypto.Cipher;
|
import org.bouncycastle.crypto.BufferedBlockCipher;
|
||||||
|
|
||||||
public class CipherDecoder extends MessageToMessageDecoder<ByteBuf>
|
public class CipherDecoder extends MessageToMessageDecoder<ByteBuf>
|
||||||
{
|
{
|
||||||
|
|
||||||
private final CipherBase cipher;
|
private final CipherBase cipher;
|
||||||
|
|
||||||
public CipherDecoder(Cipher cipher)
|
public CipherDecoder(BufferedBlockCipher cipher)
|
||||||
{
|
{
|
||||||
this.cipher = new CipherBase( cipher );
|
this.cipher = new CipherBase( cipher );
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,14 @@ package net.md_5.bungee.netty;
|
|||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.MessageToByteEncoder;
|
import io.netty.handler.codec.MessageToByteEncoder;
|
||||||
import javax.crypto.Cipher;
|
import org.bouncycastle.crypto.BufferedBlockCipher;
|
||||||
|
|
||||||
public class CipherEncoder extends MessageToByteEncoder<ByteBuf>
|
public class CipherEncoder extends MessageToByteEncoder<ByteBuf>
|
||||||
{
|
{
|
||||||
|
|
||||||
private final CipherBase cipher;
|
private final CipherBase cipher;
|
||||||
|
|
||||||
public CipherEncoder(Cipher cipher)
|
public CipherEncoder(BufferedBlockCipher cipher)
|
||||||
{
|
{
|
||||||
this.cipher = new CipherBase( cipher );
|
this.cipher = new CipherBase( cipher );
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user