Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package com.rs2.server.network.login;
- import java.math.BigInteger;
- import java.util.List;
- import com.rs2.RSLoader;
- import com.rs2.server.game.node.animable.player.Player;
- import com.rs2.server.game.node.animable.player.PlayerDefinition;
- import com.rs2.server.game.node.animable.player.display.Display;
- import com.rs2.server.network.buffer.impl.PacketReader;
- import com.rs2.server.network.login.msg.LoginMessage;
- import com.rs2.server.network.login.msg.LoginType;
- import com.rs2.util.Utilities;
- import com.rs2.util.buffer.Base37Utils;
- import com.rs2.util.buffer.BufferUtils;
- import com.rs2.util.security.isaac.IsaacRandom;
- import com.rs2.util.security.isaac.IsaacRandomPair;
- import com.rs2.util.security.xtea.XTEACipher;
- import io.netty.buffer.ByteBuf;
- import io.netty.buffer.Unpooled;
- import io.netty.channel.ChannelHandlerContext;
- import io.netty.handler.codec.ByteToMessageDecoder;
- /**
- * A class that represents a {@link ByteToMessageDecoder} responsible for decoding of the login block given by the client.
- *
- * @author Waterfiend | Aug 30, 2017 : 1:11:58 PM
- */
- public class LoginDecoder extends ByteToMessageDecoder {
- /**
- * The type of login used.
- */
- private LoginType loginType;
- /*
- * (non-Javadoc)
- *
- * @see io.netty.handler.codec.ByteToMessageDecoder#decode(io.netty.channel.ChannelHandlerContext, io.netty.buffer.ByteBuf, java.util.List)
- */
- @Override
- protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception {
- if (buffer.isReadable()) {
- /** The type of login requested */
- setLoginType(buffer.readUnsignedByte() == 19 ? LoginType.LOBBY_LOGIN : LoginType.WORLD_LOGIN);
- /** The amount of bytes required by the buffer */
- int size = buffer.readUnsignedShort();
- /** A check for the appropriate byte amount of the client */
- if (buffer.readableBytes() != size) {
- System.err.println("Decode Login Buffer -> Insufficient amount of readable bytes from the buffer!");
- ctx.channel().close();
- return;
- }
- /** A check for the match of the protocol builds. */
- if (buffer.readInt() != RSLoader.getProtocol().getMajorBuild() || buffer.readInt() != RSLoader.getProtocol().getMinorBuild()) {
- System.err.println("Decode Login -> Incompatible build!");
- ctx.channel().close();
- return;
- }
- /** Start of the Login block using a local buffer */
- byte[] data = new byte[size - 8];
- buffer.readBytes(data);
- /** A creation of a new buffer using the previous data */
- PacketReader reader = new PacketReader(data);
- switch (getLoginType()) {
- case LOBBY_LOGIN:
- decodeLobbyLogin(ctx, reader, out);
- break;
- case WORLD_LOGIN:
- case WORLD_RECONNECTION:
- decodeWorldLogin(ctx, reader, out);
- break;
- }
- }
- }
- /**
- * Decodes the Lobby Login Buffer.
- * @param ctx
- * @param buffer
- * @param out
- */
- public void decodeLobbyLogin(ChannelHandlerContext ctx, PacketReader buffer, List<Object> out) {
- }
- /**
- * Decodes the world login request procedure.
- *
- * @param ctx The connected {@link ChannelHandlerContext}.
- *
- * @param buffer The used {@link PacketReader}.
- *
- * @param out The used output {@link Object}.
- */
- public void decodeWorldLogin(ChannelHandlerContext ctx, PacketReader buffer, List<Object> out) {
- /** Reads this boolean to clarify whether or not to reconnect */
- buffer.readBoolean();
- /** The size of the secure buffer */
- int secureBufferSize = buffer.readUnsignedShort();
- /** A check for the appropriate byte amount of the client */
- if (secureBufferSize > buffer.getRemaining()) {
- ctx.channel().close();
- System.err.println("Decode Login -> Insufficient amount of readable bytes from the buffer! (2) Size: " + secureBufferSize + ", Remaining: " + buffer.getRemaining() + ".");
- return;
- }
- /** Start of the RSA block using an RSA buffer */
- byte[] secureBytes = new byte[secureBufferSize];
- buffer.read(secureBytes);
- /** A creation of a new buffer using RSA */
- PacketReader secureBuffer = new PacketReader(new BigInteger(secureBytes).modPow(RSLoader.getProtocol().getLoginExponent(), RSLoader.getProtocol().getLoginModulus()).toByteArray());
- /** The magic number known as a block opcode */
- int blockOpcode = secureBuffer.readUnsignedByte();
- /** Checks if the block opcode is valid or not */
- if (blockOpcode != 10) {
- System.err.println("Decode World -> Wrong Block Opcode!");
- ctx.channel().close();
- return;
- }
- /** Creates an array of 4 integers and reads these seeds from the client */
- int[] xteaKeys = new int[4];
- for (int idx = 0; idx < xteaKeys.length; idx++) {
- xteaKeys[idx] = secureBuffer.readInt();
- }
- /** The rsa login hash to be read */
- long rsaHash = secureBuffer.readLong();
- /** Checks if the rsa login hash is 0L, otherwise the channel is closed */
- if (rsaHash != 0L) {
- System.err.println("Decode World -> Wrong RSA login hash " + rsaHash + "!");
- ctx.channel().close();
- return;
- }
- /** The game password requested upon login */
- String password = secureBuffer.readString();
- /** A representation of 2 longs of the login seeds */
- long[] loginSeeds = new long[2];
- for (int index = 0; index < loginSeeds.length; index++) {
- loginSeeds[index] = secureBuffer.readLong();
- }
- /* End of the RSA block -> start of the XTEA block */
- /** Start of the XTEA block using an XTEA buffer */
- byte[] xteaBlock = new byte[buffer.getRemaining()];
- buffer.read(xteaBlock);
- /** Declaration of the xtea cipher and it's decryption for the xtea block */
- XTEACipher xteaCipher = new XTEACipher(xteaKeys);
- xteaCipher.decrypt(xteaBlock, 0, xteaBlock.length);
- /** Creation of a new buffer using XTEA */
- ByteBuf xteaBuffer = Unpooled.wrappedBuffer(xteaBlock);
- /** Presents the requested user-name either decoded as a string or a long */
- String username = Utilities.protocolFormat(xteaBuffer.readBoolean() ? BufferUtils.readString(xteaBuffer) : Base37Utils.decodeBase37(xteaBuffer.readLong())).trim();
- /** The width and height of the screen displayed respectively. */
- Display display = new Display(xteaBuffer.readUnsignedByte(), xteaBuffer.readUnsignedShort(), xteaBuffer.readUnsignedShort());
- /** Reads the byte for the anti-aliasing feature. */
- xteaBuffer.readUnsignedByte();
- /** Skips the 24 bytes of the uuid (#192) since they are unneeded */
- xteaBuffer.skipBytes(24);
- /** The login token in the client that must be read & matched correctly */
- String loginToken = BufferUtils.readString(xteaBuffer);
- /** Checks whether or not the login token matches the client protocol's or not */
- if (!loginToken.equals(RSLoader.getProtocol().getLoginToken())) {
- System.err.println("Decode World -> Wrong login token : " + loginToken + " .");
- ctx.channel().close();
- return;
- }
- /** Reads the integer of the affiliation id. */
- xteaBuffer.readInt();
- /** Skips 2 Bytes */
- xteaBuffer.skipBytes(2);
- /** Reads the count of UI actions */
- xteaBuffer.readInt();
- /** Reads the user flow long. */
- xteaBuffer.readLong();
- /** The state of having additional info. */
- boolean hasAdditionalInformation = xteaBuffer.readBoolean();
- /** Checks whether or not the request has additional info. */
- if (hasAdditionalInformation) {
- BufferUtils.readString(xteaBuffer);
- }
- /** If the request has jagtheora or not. */
- xteaBuffer.readBoolean();
- /** If the request is using javascript; or is using Google Chrome */
- xteaBuffer.readBoolean(); xteaBuffer.readBoolean();
- /** Reads an unknown byte, integer, string, and boolean. */
- xteaBuffer.readByte(); xteaBuffer.readInt(); BufferUtils.readString(xteaBuffer); xteaBuffer.readBoolean();
- /** An array of the indexes within the cache which ends up reading its integer data */
- for (int index = 0; index < 36; index++) {
- xteaBuffer.readInt();
- }
- /** Creates an input instance of the {@link IsaacRandom} xtea keys. */
- IsaacRandom input = new IsaacRandom(xteaKeys);
- /** An array of the xtea keys being read. */
- for (int xteaKey = 0; xteaKey < 4; xteaKey++) {
- xteaKeys[xteaKey] += 50;
- }
- /** Creates an output instance of the {@link IsaacRandom} xtea keys. */
- IsaacRandom output = new IsaacRandom(xteaKeys);
- /** Creates a 'merge' instance of the random pairs with the input & output */
- IsaacRandomPair isaacRandomPair = new IsaacRandomPair(input, output);
- /** A list is added for a login request containing the player information. */
- out.add(new LoginMessage(new Player(new PlayerDefinition(username, password), ctx.channel()), display, isaacRandomPair, LoginType.WORLD_LOGIN));
- }
- /**
- * Gets the type of login.
- *
- * @return the loginType
- */
- public LoginType getLoginType() {
- return loginType;
- }
- /**
- * Sets the type of login.
- *
- * @param loginType The loginType to set.
- */
- public void setLoginType(LoginType loginType) {
- this.loginType = loginType;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement