Advertisement
Guest User

Untitled

a guest
Aug 1st, 2017
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 8.97 KB | None | 0 0
  1. package org.ex.ws.net.codec;
  2.  
  3. import java.security.SecureRandom;
  4. import java.util.logging.Logger;
  5.  
  6. import org.ex.constants.GlobalConstants;
  7. import org.ex.core.util.ChannelBufferUtils;
  8. import org.ex.ws.model.World;
  9. import org.ex.ws.model.player.PlayerDetails;
  10. import org.ex.ws.net.ISAACCipher;
  11. import org.ex.ws.net.codec.game.GamePacketBuilder;
  12. import org.ex.ws.net.ondemand.OnDemandPool;
  13. import org.ex.ws.net.ondemand.OnDemandRequest;
  14. import org.ex.ws.util.NameUtils;
  15. import org.jboss.netty.buffer.ChannelBuffer;
  16. import org.jboss.netty.channel.Channel;
  17. import org.jboss.netty.channel.ChannelHandlerContext;
  18. import org.jboss.netty.handler.codec.replay.ReplayingDecoder;
  19.  
  20. /**
  21.  * Login protocol decoding class.
  22.  *
  23.  * @author Mike
  24.  *
  25.  */
  26. public final class RS2LoginDecoder extends ReplayingDecoder<RS2LoginStage> {
  27.  
  28.     /**
  29.      * Logger instance.
  30.      */
  31.     private static final Logger logger = Logger.getLogger(RS2LoginDecoder.class
  32.             .getName());
  33.  
  34.     /**
  35.      * Packet opcode for game requests.
  36.      */
  37.     public static final int OPCODE_GAME = 14;
  38.  
  39.     /**
  40.      * Packet opcode for update requests.
  41.      */
  42.     public static final int OPCODE_UPDATE = 15;
  43.  
  44.     /**
  45.      * The secured random number generator.
  46.      */
  47.     private static final SecureRandom random = new SecureRandom();
  48.  
  49.     /**
  50.      * The initial login response data.
  51.      */
  52.     private static final byte[] INITIAL_RESPONSE = new byte[] { 0x0, 0x0, 0x0,
  53.             0x0, 0x0, 0x0, 0x0, 0x0 };
  54.  
  55.     @Override
  56.     protected Object decode(ChannelHandlerContext ctx, Channel channel,
  57.             ChannelBuffer buffer, RS2LoginStage stage) throws Exception {
  58.         switch (stage) {
  59.         case UPDATE:
  60.             /*
  61.              * Here we read the cache id (idx file), file id and priority.
  62.              */
  63.             int cacheId = buffer.readUnsignedByte();
  64.             int fileId = (buffer.readUnsignedByte() << 8)
  65.                     | buffer.readUnsignedByte();
  66.             int priority = buffer.readUnsignedByte();
  67.  
  68.             /*
  69.              * We push the request into the on-demand pool so it can be served.
  70.              */
  71.             OnDemandPool.getOnDemandPool().pushRequest(
  72.                     new OnDemandRequest(channel, cacheId, fileId, priority));
  73.  
  74.             break;
  75.         case OPCODE:
  76.             /*
  77.              * Here we read the first opcode which indicates the type of
  78.              * connection.
  79.              *
  80.              * 14 = game, 15 = update.
  81.              *
  82.              * Updating is disabled in the vast majority of 317 clients.
  83.              */
  84.             int opcode = buffer.readUnsignedByte();
  85.             switch (opcode) {
  86.             case OPCODE_GAME:
  87.                 checkpoint(RS2LoginStage.LOGIN);
  88.                 return null;
  89.             case OPCODE_UPDATE:
  90.                 checkpoint(RS2LoginStage.UPDATE);
  91.                 channel.write(new GamePacketBuilder().put(INITIAL_RESPONSE)
  92.                         .toGamePacket());
  93.                 return null;
  94.             }
  95.  
  96.             break;
  97.         case LOGIN:
  98.             /*
  99.              * The name hash is a simple hash of the name which is suspected to
  100.              * be used to select the appropiate login server.
  101.              */
  102.             @SuppressWarnings("unused")
  103.             int nameHash = buffer.readUnsignedByte();
  104.  
  105.             /*
  106.              * We generated the server session key using a SecureRandom class
  107.              * for security.
  108.              */
  109.             long serverKey = random.nextLong();
  110.  
  111.             /*
  112.              * The initial response is just 0s which the client is set to ignore
  113.              * (probably some sort of modification).
  114.              */
  115.             channel.write(new GamePacketBuilder().put(INITIAL_RESPONSE)
  116.                     .put((byte) 0).putLong(serverKey).toGamePacket());
  117.             checkpoint(RS2LoginStage.PRECRYPTED);
  118.             RS2ChannelAttributes.SERVER_KEY.set(channel, serverKey);
  119.             return null;
  120.  
  121.         case PRECRYPTED:
  122.             /*
  123.              * Read the type of login.
  124.              *
  125.              * 16 = normal, 18 = reconnection.
  126.              */
  127.             int loginOpcode = buffer.readUnsignedByte();
  128.             if (loginOpcode != 16 && loginOpcode != 18) {
  129.                 logger.info("Invalid login opcode : " + loginOpcode);
  130.                 channel.close();
  131.                 return null;
  132.             }
  133.  
  134.             /*
  135.              * Read the size of the login packet.
  136.              */
  137.             int loginSize = buffer.readUnsignedByte();
  138.  
  139.             /*
  140.              * And calculate how long the encrypted block will be.
  141.              */
  142.             int loginEncryptSize = loginSize - (36 + 1 + 1 + 2);
  143.  
  144.             /*
  145.              * This could be invalid, if so, ignore it.
  146.              */
  147.             if (loginEncryptSize <= 0) {
  148.                 logger.info("Encrypted packet size zero or negative : "
  149.                         + loginEncryptSize);
  150.                 channel.close();
  151.                 return null;
  152.             }
  153.             checkpoint(RS2LoginStage.CRYPTED);
  154.             RS2ChannelAttributes.LOGIN_SIZE.set(channel, loginSize);
  155.             RS2ChannelAttributes.LOGIN_SIZE_ENCRYPTED.set(channel,
  156.                     loginEncryptSize);
  157.             return null;
  158.         case CRYPTED:
  159.             int size = RS2ChannelAttributes.LOGIN_SIZE.get(channel);
  160.             int encryptSize = RS2ChannelAttributes.LOGIN_SIZE_ENCRYPTED
  161.                     .get(channel);
  162.             if (super.actualReadableBytes() >= size) {
  163.                 /*
  164.                  * Read the magic ID which is 255 (0xFF) which indicates this is
  165.                  * the real login packet.
  166.                  */
  167.                 final int magicId = buffer.readUnsignedByte();
  168.                 if (magicId != 255) {
  169.                     logger.info("Incorrect magic id : " + magicId);
  170.                     channel.close();
  171.                     return null;
  172.                 }
  173.  
  174.                 /*
  175.                  * Now read a short which is the client version and check if it
  176.                  * equals the server version.
  177.                  */
  178.                 final int version = buffer.readUnsignedShort();
  179.                 if (version != GlobalConstants.VERSION) {
  180.                     logger.info("Incorrect version : " + version);
  181.                     channel.close();
  182.                     return null;
  183.                 }
  184.  
  185.                 /*
  186.                  * The following byte indicates if the client is on low or high
  187.                  * memory.
  188.                  */
  189.                 @SuppressWarnings("unused")
  190.                 final boolean lowMemoryVersion = buffer.readUnsignedByte() == 1;
  191.  
  192.                 /*
  193.                  * Read the cache indices.
  194.                  */
  195.                 for (int i = 0; i < 9; i++) {
  196.                     buffer.readInt();
  197.                 }
  198.  
  199.                 /*
  200.                  * The encrypted size includes the size byte which is not
  201.                  * needed.
  202.                  */
  203.                 encryptSize--;
  204.  
  205.                 /*
  206.                  * Check if there is a mismatch in the sizing.
  207.                  */
  208.                 final int reportedSize = buffer.readUnsignedByte();
  209.                 if (reportedSize != encryptSize) {
  210.                     logger.info("Packet size mismatch (expected : "
  211.                             + encryptSize + ", reported : " + reportedSize
  212.                             + ")");
  213.                     channel.close();
  214.                     return null;
  215.                 }
  216.  
  217.                 /*
  218.                  * Now read the encrypted block opcode (although in most 317
  219.                  * clients and this server the RSA is disabled) and check if it
  220.                  * is equal to 10.
  221.                  */
  222.                 int blockOpcode = buffer.readUnsignedByte();
  223.                 if (blockOpcode != 10) {
  224.                     logger.info("Invalid login block opcode : " + blockOpcode);
  225.                     channel.close();
  226.                     return null;
  227.                 }
  228.  
  229.                 /*
  230.                  * Read the client's session key.
  231.                  */
  232.                 long clientKey = buffer.readLong();
  233.  
  234.                 /*
  235.                  * And verifiy it has the correct server session key.
  236.                  */
  237.                 long servKey = RS2ChannelAttributes.SERVER_KEY.get(channel);
  238.                 long reportedServerKey = buffer.readLong();
  239.                 if (reportedServerKey != servKey) {
  240.                     logger.info("Server key mismatch (expected : " + servKey
  241.                             + ", reported : " + reportedServerKey + ").");
  242.                     channel.close();
  243.                     return null;
  244.                 }
  245.  
  246.                 /*
  247.                  * The UID, found in random.dat in newer clients and uid.dat in
  248.                  * older clients, is a way of identifying a computer.
  249.                  *
  250.                  * However, some clients send a hardcoded or random UID, making
  251.                  * it useless in the private server scene.
  252.                  *
  253.                  * Excellia no longer uses any form of UID identification.
  254.                  * Instead, a specific long is used which must match the server
  255.                  * sided copy or the channel will close.
  256.                  */
  257.                 // int uid = buffer.readInt();
  258.                 final long verification = buffer.readLong();
  259.                 if (verification != 839527L) {
  260.                     logger.info("Invalid security verification (expected : 839527L, reported : "
  261.                             + verification + ").");
  262.                     channel.close();
  263.                     return null;
  264.                 }
  265.  
  266.                 /*
  267.                  * Read and format the name and password.
  268.                  */
  269.                 String name = NameUtils.formatName(ChannelBufferUtils
  270.                         .getRS2String(buffer));
  271.                 String pass = ChannelBufferUtils.getRS2String(buffer);
  272.                 logger.info("Login request : username=" + name + " password="
  273.                         + pass);
  274.  
  275.                 /*
  276.                  * Setup the ISAAC cipher which is used to encrypt and decrypt
  277.                  * opcodes.
  278.                  *
  279.                  * However, without RSA, this is rendered useless anyway.
  280.                  */
  281.                 int[] sessionKey = new int[4];
  282.                 sessionKey[0] = (int) (clientKey >> 32);
  283.                 sessionKey[1] = (int) clientKey;
  284.                 sessionKey[2] = (int) (servKey >> 32);
  285.                 sessionKey[3] = (int) servKey;
  286.  
  287.                 this.setState(null);
  288.                 RS2ChannelAttributes.SERVER_KEY.remove(channel);
  289.                 RS2ChannelAttributes.LOGIN_SIZE.remove(channel);
  290.                 RS2ChannelAttributes.LOGIN_SIZE_ENCRYPTED.remove(channel);
  291.  
  292.                 ISAACCipher inCipher = new ISAACCipher(sessionKey);
  293.                 for (int i = 0; i < 4; i++) {
  294.                     sessionKey[i] += 50;
  295.                 }
  296.                 ISAACCipher outCipher = new ISAACCipher(sessionKey);
  297.  
  298.                 /*
  299.                  * The login has successfully completed, do the appropiate
  300.                  * things to fire orr the chain of events which will load and
  301.                  * check saved games, etc.
  302.                  */
  303.                 channel.getPipeline().remove("protocol");
  304.                 channel.getPipeline()
  305.                         .addFirst("protocol", RS2CodecFactory.GAME);
  306.  
  307.                 PlayerDetails pd = new PlayerDetails(channel, name, pass,
  308.                         inCipher, outCipher);
  309.                 World.getWorld().load(pd);
  310.             }
  311.         }
  312.         return null;
  313.     }
  314.  
  315. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement