Implement BouncyCastle as the cipher engine.

This commit is contained in:
md_5 2013-07-04 09:57:27 +10:00
parent 927a295add
commit 66de4c95ef
7 changed files with 32 additions and 25 deletions

View File

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

View File

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

View File

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

View File

@ -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 );
{ ch.addBefore( PipelineUtils.DECRYPT_HANDLER, PipelineUtils.ENCRYPT_HANDLER, new CipherEncoder( encrypt ) );
Cipher encrypt = EncryptionUtil.getCipher( Cipher.ENCRYPT_MODE, sharedKey );
ch.addBefore( PipelineUtils.DECRYPT_HANDLER, PipelineUtils.ENCRYPT_HANDLER, new CipherEncoder( encrypt ) );
} catch ( GeneralSecurityException ex )
{
disconnect( "Cipher error: " + Util.exception( ex ) );
}
} }
} ); } );
} }

View File

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

View File

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

View File

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