Advertisement
Guest User

Untitled

a guest
Aug 31st, 2017
133
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 9.41 KB | None | 0 0
  1. package com.rs2.server.network.login;
  2.  
  3. import java.math.BigInteger;
  4. import java.util.List;
  5.  
  6. import com.rs2.RSLoader;
  7. import com.rs2.server.game.node.animable.player.Player;
  8. import com.rs2.server.game.node.animable.player.PlayerDefinition;
  9. import com.rs2.server.game.node.animable.player.display.Display;
  10. import com.rs2.server.network.buffer.impl.PacketReader;
  11. import com.rs2.server.network.login.msg.LoginMessage;
  12. import com.rs2.server.network.login.msg.LoginType;
  13. import com.rs2.util.Utilities;
  14. import com.rs2.util.buffer.Base37Utils;
  15. import com.rs2.util.buffer.BufferUtils;
  16. import com.rs2.util.security.isaac.IsaacRandom;
  17. import com.rs2.util.security.isaac.IsaacRandomPair;
  18. import com.rs2.util.security.xtea.XTEACipher;
  19.  
  20. import io.netty.buffer.ByteBuf;
  21. import io.netty.buffer.Unpooled;
  22. import io.netty.channel.ChannelHandlerContext;
  23. import io.netty.handler.codec.ByteToMessageDecoder;
  24.  
  25. /**
  26.  * A class that represents a {@link ByteToMessageDecoder} responsible for decoding of the login block given by the client.
  27.  *
  28.  * @author Waterfiend | Aug 30, 2017 : 1:11:58 PM
  29.  */
  30. public class LoginDecoder extends ByteToMessageDecoder {
  31.  
  32.     /**
  33.      * The type of login used.
  34.      */
  35.     private LoginType loginType;
  36.  
  37.     /*
  38.      * (non-Javadoc)
  39.      *
  40.      * @see io.netty.handler.codec.ByteToMessageDecoder#decode(io.netty.channel.ChannelHandlerContext, io.netty.buffer.ByteBuf, java.util.List)
  41.      */
  42.     @Override
  43.     protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception {
  44.         if (buffer.isReadable()) {
  45.             /** The type of login requested */
  46.             setLoginType(buffer.readUnsignedByte() == 19 ? LoginType.LOBBY_LOGIN : LoginType.WORLD_LOGIN);
  47.            
  48.             /** The amount of bytes required by the buffer */
  49.             int size = buffer.readUnsignedShort();
  50.            
  51.             /** A check for the appropriate byte amount of the client */
  52.             if (buffer.readableBytes() != size) {
  53.                 System.err.println("Decode Login Buffer -> Insufficient amount of readable bytes from the buffer!");
  54.                 ctx.channel().close(); 
  55.                 return;
  56.             }
  57.             /** A check for the match of the protocol builds. */
  58.             if (buffer.readInt() != RSLoader.getProtocol().getMajorBuild() || buffer.readInt() != RSLoader.getProtocol().getMinorBuild()) {
  59.                 System.err.println("Decode Login -> Incompatible build!");
  60.                 ctx.channel().close();
  61.                 return;
  62.             }
  63.            
  64.             /** Start of the Login block using a local buffer */
  65.             byte[] data = new byte[size - 8];
  66.             buffer.readBytes(data);
  67.            
  68.             /** A creation of a new buffer using the previous data */
  69.             PacketReader reader = new PacketReader(data);
  70.            
  71.             switch (getLoginType()) {
  72.             case LOBBY_LOGIN:
  73.                 decodeLobbyLogin(ctx, reader, out);
  74.                 break;
  75.             case WORLD_LOGIN:
  76.             case WORLD_RECONNECTION:
  77.                 decodeWorldLogin(ctx, reader, out);
  78.                 break;
  79.             }
  80.         }
  81.     }
  82.  
  83.     /**
  84.      * Decodes the Lobby Login Buffer.
  85.      * @param ctx
  86.      * @param buffer
  87.      * @param out
  88.      */
  89.     public void decodeLobbyLogin(ChannelHandlerContext ctx, PacketReader buffer, List<Object> out) {
  90.  
  91.     }
  92.    
  93.     /**
  94.      * Decodes the world login request procedure.
  95.      *
  96.      * @param ctx The connected {@link ChannelHandlerContext}.
  97.      *
  98.      * @param buffer The used {@link PacketReader}.
  99.      *
  100.      * @param out The used output {@link Object}.
  101.      */
  102.     public void decodeWorldLogin(ChannelHandlerContext ctx, PacketReader buffer, List<Object> out) {
  103.         /** Reads this boolean to clarify whether or not to reconnect */
  104.         buffer.readBoolean();
  105.        
  106.         /** The size of the secure buffer */
  107.         int secureBufferSize = buffer.readUnsignedShort();
  108.  
  109.         /** A check for the appropriate byte amount of the client */
  110.         if (secureBufferSize > buffer.getRemaining()) {
  111.             ctx.channel().close();
  112.             System.err.println("Decode Login -> Insufficient amount of readable bytes from the buffer! (2) Size: " + secureBufferSize + ", Remaining: " + buffer.getRemaining() + ".");
  113.             return;
  114.         }
  115.  
  116.         /** Start of the RSA block using an RSA buffer */
  117.         byte[] secureBytes = new byte[secureBufferSize];
  118.         buffer.read(secureBytes);
  119.        
  120.         /** A creation of a new buffer using RSA */
  121.         PacketReader secureBuffer = new PacketReader(new BigInteger(secureBytes).modPow(RSLoader.getProtocol().getLoginExponent(), RSLoader.getProtocol().getLoginModulus()).toByteArray());
  122.        
  123.         /** The magic number known as a block opcode */
  124.         int blockOpcode = secureBuffer.readUnsignedByte();
  125.        
  126.         /** Checks if the block opcode is valid or not */
  127.         if (blockOpcode != 10) {
  128.             System.err.println("Decode World -> Wrong Block Opcode!");
  129.             ctx.channel().close();
  130.             return;
  131.         }
  132.  
  133.         /** Creates an array of 4 integers and reads these seeds from the client */
  134.         int[] xteaKeys = new int[4];
  135.         for (int idx = 0; idx < xteaKeys.length; idx++) {
  136.             xteaKeys[idx] = secureBuffer.readInt();
  137.         }
  138.  
  139.         /** The rsa login hash to be read */
  140.         long rsaHash = secureBuffer.readLong();
  141.  
  142.         /** Checks if the rsa login hash is 0L, otherwise the channel is closed */
  143.         if (rsaHash != 0L) {
  144.             System.err.println("Decode World -> Wrong RSA login hash " + rsaHash + "!");
  145.             ctx.channel().close();
  146.             return;
  147.         }
  148.        
  149.         /** The game password requested upon login */
  150.         String password = secureBuffer.readString();
  151.  
  152.         /** A representation of 2 longs of the login seeds */
  153.         long[] loginSeeds = new long[2];
  154.         for (int index = 0; index < loginSeeds.length; index++) {
  155.             loginSeeds[index] = secureBuffer.readLong();
  156.         }
  157.  
  158.         /* End of the RSA block -> start of the XTEA block */
  159.  
  160.         /** Start of the XTEA block using an XTEA buffer */
  161.         byte[] xteaBlock = new byte[buffer.getRemaining()];
  162.         buffer.read(xteaBlock);
  163.        
  164.         /** Declaration of the xtea cipher and it's decryption for the xtea block */
  165.          XTEACipher xteaCipher = new XTEACipher(xteaKeys);
  166.          xteaCipher.decrypt(xteaBlock, 0, xteaBlock.length);
  167.          
  168.          /** Creation of a new buffer using XTEA */
  169.          ByteBuf xteaBuffer = Unpooled.wrappedBuffer(xteaBlock);
  170.        
  171.         /** Presents the requested user-name either decoded as a string or a long */
  172.         String username = Utilities.protocolFormat(xteaBuffer.readBoolean() ? BufferUtils.readString(xteaBuffer) : Base37Utils.decodeBase37(xteaBuffer.readLong())).trim();
  173.        
  174.         /** The width and height of the screen displayed respectively. */
  175.         Display display = new Display(xteaBuffer.readUnsignedByte(), xteaBuffer.readUnsignedShort(), xteaBuffer.readUnsignedShort());
  176.    
  177.         /** Reads the byte for the anti-aliasing feature. */
  178.         xteaBuffer.readUnsignedByte();
  179.        
  180.         /** Skips the 24 bytes of the uuid (#192) since they are unneeded */
  181.         xteaBuffer.skipBytes(24);
  182.        
  183.         /** The login token in the client that must be read & matched correctly */
  184.         String loginToken = BufferUtils.readString(xteaBuffer);
  185.        
  186.         /** Checks whether or not the login token matches the client protocol's or not */
  187.         if (!loginToken.equals(RSLoader.getProtocol().getLoginToken())) {
  188.             System.err.println("Decode World -> Wrong login token : " + loginToken + " .");
  189.             ctx.channel().close();
  190.             return;
  191.         }
  192.        
  193.         /** Reads the integer of the affiliation id. */
  194.         xteaBuffer.readInt();
  195.        
  196.         /** Skips 2 Bytes */
  197.         xteaBuffer.skipBytes(2);
  198.        
  199.         /** Reads the count of UI actions */
  200.         xteaBuffer.readInt();
  201.        
  202.         /** Reads the user flow long. */
  203.         xteaBuffer.readLong();
  204.        
  205.         /** The state of having additional info. */
  206.         boolean hasAdditionalInformation = xteaBuffer.readBoolean();
  207.        
  208.         /** Checks whether or not the request has additional info. */
  209.         if (hasAdditionalInformation) {
  210.             BufferUtils.readString(xteaBuffer);
  211.         }
  212.        
  213.         /** If the request has jagtheora or not. */
  214.         xteaBuffer.readBoolean();
  215.        
  216.         /** If the request is using javascript; or is using Google Chrome */
  217.         xteaBuffer.readBoolean(); xteaBuffer.readBoolean();
  218.        
  219.         /** Reads an unknown byte, integer, string, and boolean. */
  220.         xteaBuffer.readByte(); xteaBuffer.readInt(); BufferUtils.readString(xteaBuffer); xteaBuffer.readBoolean();
  221.        
  222.         /** An array of the indexes within the cache which ends up reading its integer data */
  223.         for (int index = 0; index < 36; index++) {
  224.             xteaBuffer.readInt();
  225.         }
  226.        
  227.         /** Creates an input instance of the {@link IsaacRandom} xtea keys. */
  228.         IsaacRandom input = new IsaacRandom(xteaKeys);
  229.        
  230.         /** An array of the xtea keys being read. */
  231.         for (int xteaKey = 0; xteaKey < 4; xteaKey++) {
  232.             xteaKeys[xteaKey] += 50;
  233.         }
  234.        
  235.         /** Creates an output instance of the {@link IsaacRandom} xtea keys. */
  236.         IsaacRandom output = new IsaacRandom(xteaKeys);
  237.        
  238.         /** Creates a 'merge' instance of the random pairs with the input & output */
  239.         IsaacRandomPair isaacRandomPair = new IsaacRandomPair(input, output);
  240.    
  241.         /** A list is added for a login request containing the player information. */
  242.         out.add(new LoginMessage(new Player(new PlayerDefinition(username, password), ctx.channel()), display, isaacRandomPair, LoginType.WORLD_LOGIN));
  243.     }
  244.  
  245.     /**
  246.      * Gets the type of login.
  247.      *
  248.      * @return the loginType
  249.      */
  250.     public LoginType getLoginType() {
  251.         return loginType;
  252.     }
  253.  
  254.     /**
  255.      * Sets the type of login.
  256.      *
  257.      * @param loginType The loginType to set.
  258.      */
  259.     public void setLoginType(LoginType loginType) {
  260.         this.loginType = loginType;
  261.     }
  262.  
  263. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement