Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package com.asteria.net.login;
- import io.netty.buffer.ByteBuf;
- import io.netty.buffer.Unpooled;
- import io.netty.channel.ChannelHandlerContext;
- import io.netty.handler.codec.ByteToMessageDecoder;
- import java.math.BigInteger;
- import java.util.List;
- import com.asteria.net.ISAACCipher;
- import com.asteria.net.NetworkConstants;
- import com.asteria.net.message.LoginDetailsMessage;
- import com.asteria.net.message.MessageBuilder;
- /**
- * The {@link ByteToMessageDecoder} implementation that will manage the
- * post-handshake section of the login protocol.
- *
- * @author lare96 <http://github.com/lare96>
- */
- public final class PostLoginHandshakeHandler extends ByteToMessageDecoder {
- @Override
- protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
- // Read the login type, validate it.
- if (in.readableBytes() < 2)
- return;
- int type = in.readByte();
- if (type != 16 && type != 18)
- throw new Exception("Invalid login type [" + type + "]");
- // Decode the block length, validate RSA block size.
- int blockLength = in.readUnsignedByte();
- int loginEncryptPacketSize = blockLength - (36 + 1 + 1 + 2);
- if (loginEncryptPacketSize <= 0)
- throw new Exception("Invalid RSA packet size [" + loginEncryptPacketSize + "]");
- if (in.readableBytes() < blockLength)
- return;
- // Read the client version, validate it.
- in.readByte();
- int version = in.readShort();
- if (version != 317)
- throw new Exception("Invalid client version [" + version + "]");
- // Read and ignore the data for CRC keys.
- in.readByte();
- for (int i = 0; i < 9; i++)
- in.readInt();
- // Either decode RSA, or proceed normally depending on the network
- // settings.
- loginEncryptPacketSize--;
- in.readByte();
- String username = null;
- String password = null;
- ISAACCipher encryptor = null;
- ISAACCipher decryptor = null;
- if (NetworkConstants.DECODE_RSA) {
- byte[] encryptionBytes = new byte[loginEncryptPacketSize];
- in.readBytes(encryptionBytes);
- ByteBuf rsaBuffer = Unpooled.wrappedBuffer(new BigInteger(encryptionBytes).modPow(NetworkConstants.RSA_EXPONENT,
- NetworkConstants.RSA_MODULUS).toByteArray());
- int rsaOpcode = rsaBuffer.readByte();
- if (rsaOpcode != 10)
- throw new Exception("Invalid RSA opcode [" + rsaOpcode + "]");
- long clientHalf = rsaBuffer.readLong();
- long serverHalf = rsaBuffer.readLong();
- int[] isaacSeed = { (int) (clientHalf >> 32), (int) clientHalf, (int) (serverHalf >> 32), (int) serverHalf };
- decryptor = new ISAACCipher(isaacSeed);
- for (int i = 0; i < isaacSeed.length; i++)
- isaacSeed[i] += 50;
- encryptor = new ISAACCipher(isaacSeed);
- rsaBuffer.readInt();
- MessageBuilder db = MessageBuilder.create(rsaBuffer);
- username = db.getString();
- password = db.getString();
- } else {
- in.readByte();
- long clientHalf = in.readLong();
- long serverHalf = in.readLong();
- int[] isaacSeed = { (int) (clientHalf >> 32), (int) clientHalf, (int) (serverHalf >> 32), (int) serverHalf };
- decryptor = new ISAACCipher(isaacSeed);
- for (int i = 0; i < isaacSeed.length; i++)
- isaacSeed[i] += 50;
- encryptor = new ISAACCipher(isaacSeed);
- in.readInt();
- MessageBuilder db = MessageBuilder.create(in);
- username = db.getString().toLowerCase().replaceAll("_", " ").trim();
- password = db.getString().toLowerCase();
- }
- // Finally, we've decoded all the data we need for the final response of
- // the login protocol. Here we send it as an upstream Netty message to
- // be handled in the PlayerIO class.
- out.add(new LoginDetailsMessage(ctx, username, password, encryptor, decryptor));
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement