Advertisement
Guest User

Untitled

a guest
May 17th, 2017
107
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 10.06 KB | None | 0 0
  1. package org.hyperion.rs2.net;
  2.  
  3. import java.security.SecureRandom;
  4. import java.util.logging.Logger;
  5.  
  6. import org.apache.mina.core.buffer.IoBuffer;
  7. import org.apache.mina.core.future.IoFuture;
  8. import org.apache.mina.core.future.IoFutureListener;
  9. import org.apache.mina.core.session.IoSession;
  10. import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
  11. import org.apache.mina.filter.codec.ProtocolCodecFilter;
  12. import org.apache.mina.filter.codec.ProtocolDecoderOutput;
  13. import org.hyperion.Server;
  14. import org.hyperion.rs2.Constants;
  15. import org.hyperion.rs2.model.PlayerDetails;
  16. import org.hyperion.rs2.model.World;
  17. import org.hyperion.rs2.net.ondemand.OnDemandPool;
  18. import org.hyperion.rs2.net.ondemand.OnDemandRequest;
  19. import org.hyperion.rs2.util.IoBufferUtils;
  20. import org.hyperion.rs2.util.NameUtils;
  21.  
  22. /**
  23.  * Login protocol decoding class.
  24.  * @author Graham Edgecombe
  25.  *
  26.  */
  27. public class RS2LoginDecoder extends CumulativeProtocolDecoder {
  28.  
  29.     /**
  30.      * Logger instance.
  31.      */
  32.     private static final Logger logger = Logger.getLogger(RS2LoginDecoder.class.getName());
  33.    
  34.     /**
  35.      * Opcode stage.
  36.      */
  37.     public static final int STATE_OPCODE = 0;
  38.    
  39.     /**
  40.      * Login stage.
  41.      */
  42.     public static final int STATE_LOGIN = 1;
  43.    
  44.     /**
  45.      * Precrypted stage.
  46.      */
  47.     public static final int STATE_PRECRYPTED = 2;
  48.    
  49.     /**
  50.      * Crypted stage.
  51.      */
  52.     public static final int STATE_CRYPTED = 3;
  53.    
  54.     public static final int STATE_CRC = 4;
  55.    
  56.     /**
  57.      * Update stage.
  58.      */
  59.     public static final int STATE_UPDATE = -1;
  60.    
  61.     /**
  62.      * Game opcode.
  63.      */
  64.     public static final int OPCODE_GAME = 14;
  65.    
  66.     /**
  67.      * Update opcode.
  68.      */
  69.     public static final int OPCODE_UPDATE = 15;
  70.    
  71.     /**
  72.      * Secure random number generator.
  73.      */
  74.     private static final SecureRandom RANDOM = new SecureRandom();
  75.    
  76.     @Override
  77.     protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
  78.         int state = (Integer) session.getAttribute("state", STATE_OPCODE);
  79.         logger.info("state: " + state);
  80.         switch(state) {
  81.         case STATE_UPDATE:
  82.             if(in.remaining() >= 4) {
  83.                 /*
  84.                  * Here we read the cache id (idx file), file id and priority.
  85.                  */
  86.                 int priority = in.get() & 0xFF;
  87.                 int cacheId = in.get() & 0xFF;
  88.                 int fileId = ((in.get() & 0xFF) << 8) | (in.get() & 0xFF);
  89.  
  90.                 /*
  91.                  * We push the request into the ondemand pool so it can be served.
  92.                  */
  93.                 if (priority >= 0 && priority <= 2) {
  94.                     OnDemandPool.getOnDemandPool().pushRequest(new OnDemandRequest(session, cacheId, fileId, priority));
  95.                 }
  96.                 return true;
  97.             } else {
  98.                 in.rewind();
  99.                 return false;
  100.             }
  101.         case STATE_OPCODE:
  102.             if(in.remaining() >= 2) {
  103.                 /*
  104.                  * Here we read the first opcode which indicates the type
  105.                  * of connection.
  106.                  *
  107.                  * 14 = game
  108.                  * 15 = update
  109.                  *
  110.                  * Updating is disabled in the vast majority of 317
  111.                  * clients.
  112.                  */
  113.                 int opcode = in.get() & 0xFF;
  114.                 int nameHash = in.get() & 0xFF;
  115.                 switch(opcode) {
  116.                 case OPCODE_GAME:
  117.                     final long SERVER_SESSION_KEY = ((long) (java.lang.Math.random() * 99999999D) << 32) + (long) (java.lang.Math.random() * 99999999D);
  118.                     session.write(new PacketBuilder().put((byte) 0).putLong(SERVER_SESSION_KEY).toPacket());
  119.                     session.setAttribute("serverSessionKey", SERVER_SESSION_KEY);
  120.                     session.setAttribute("state", STATE_LOGIN);
  121.                     return true;
  122.                 case OPCODE_UPDATE:
  123.                     if (in.remaining() >= 4) {
  124.                         if(in.getInt() != 408) {
  125.                             session.write(new PacketBuilder().put((byte) 6).toPacket());
  126.                             session.close(false);
  127.                             break;
  128.                         }
  129.                         session.setAttribute("state", STATE_UPDATE);
  130.                         session.write(new PacketBuilder().put((byte)0).toPacket());
  131.                     } else {
  132.                         in.rewind();
  133.                         return false;
  134.                     }
  135.                     return true;
  136.                 default:
  137.                     logger.info("Invalid opcode : " + opcode);
  138.                     session.close(false);
  139.                     break;
  140.                 }
  141.             } else {
  142.                 in.rewind();
  143.                 return false;
  144.             }
  145.             break;
  146.         case STATE_LOGIN:
  147.             if(in.remaining() >= 1) {
  148.                 /*
  149.                  * The name hash is a simple hash of the name which is
  150.                  * suspected to be used to select the appropriate login
  151.                  * server.
  152.                  */
  153.                 @SuppressWarnings("unused")
  154.                 int nameHash = in.get() & 0xFF;
  155.                
  156.                 /*
  157.                  * We generated the server session key using a SecureRandom
  158.                  * class for security.
  159.                  */
  160.                 long serverKey = RANDOM.nextLong();
  161.                
  162.                 /*
  163.                  * The initial response is just 0s which the client is set
  164.                  * to ignore (probably some sort of modification).
  165.                  */
  166.                 //session.write(new PacketBuilder().put(INITIAL_RESPONSE).put((byte) 0).putLong(serverKey).toPacket());
  167.                 session.setAttribute("state", STATE_PRECRYPTED);
  168.                 session.setAttribute("serverKey", serverKey);
  169.                 return true;
  170.             }
  171.             break;
  172.         case STATE_PRECRYPTED:
  173.             if(in.remaining() >= 2) {
  174.                 /*
  175.                  * We read the type of login.
  176.                  *
  177.                  * 16 = normal
  178.                  * 18 = reconnection
  179.                  */
  180.                 int loginOpcode = in.get() & 0xFF;
  181.                 if(loginOpcode != 16 && loginOpcode != 18) {
  182.                     logger.info("Invalid login opcode : " + loginOpcode);
  183.                     session.close(false);
  184.                     in.rewind();
  185.                     return false;
  186.                 }
  187.                
  188.                 /*
  189.                  * We read the size of the login packet.
  190.                  */
  191.                 int loginSize = in.get() & 0xFF;
  192.                
  193.                 /*
  194.                  * And calculated how long the encrypted block will be.
  195.                  */
  196.                 int loginEncryptSize = loginSize - (36 + 1 + 1 + 2);
  197.                
  198.                 /*
  199.                  * This could be invalid so if it is we ignore it.
  200.                  */
  201.                 if(loginEncryptSize <= 0) {
  202.                     logger.info("Encrypted packet size zero or negative : " + loginEncryptSize);
  203.                     session.close(false);
  204.                     in.rewind();
  205.                     return false;
  206.                 }
  207.                 session.setAttribute("state", STATE_CRYPTED);
  208.                 session.setAttribute("size", loginSize);
  209.                 session.setAttribute("encryptSize", loginEncryptSize);
  210.                 return true;
  211.             }
  212.             break;
  213.         case STATE_CRYPTED:
  214.             int size = (Integer) session.getAttribute("size");
  215.             int encryptSize = (Integer) session.getAttribute("encryptSize");
  216.             if(in.remaining() >= size) {
  217.                 /*
  218.                  * We read the magic ID which is 255 (0xFF) which indicates
  219.                  * this is the real login packet.
  220.                  */
  221.                 int magicId = in.get() & 0xFF;
  222.                 if(magicId != 255) {
  223.                     logger.info("Incorrect magic id : " + magicId);
  224.                     session.close(false);
  225.                     in.rewind();
  226.                     return false;
  227.                 }
  228.                
  229.                 /*
  230.                  * We now read a short which is the client version and
  231.                  * check if it equals 317.
  232.                  */
  233.                 int version = in.getShort() & 0xFFFF;
  234.                 if(version != Server.VERSION) {
  235.                     logger.info("Incorrect version : " + version);
  236.                     session.close(false);
  237.                     in.rewind();
  238.                     return false;
  239.                 }
  240.                
  241.                 /*
  242.                  * The following byte indicates if we are using a low
  243.                  * memory version.
  244.                  */
  245.                 @SuppressWarnings("unused")
  246.                 boolean lowMemoryVersion = (in.get() & 0xFF) == 1;
  247.                
  248.                 /*
  249.                  * We know read the cache indices.
  250.                  */
  251.                 for(int i = 0; i < 9; i++) {
  252.                     in.getInt();
  253.                 }
  254.                
  255.                 /*
  256.                  * The encrypted size includes the size byte which we don't
  257.                  * need.
  258.                  */
  259.                 encryptSize--;
  260.                
  261.                 /*
  262.                  * We check if there is a mismatch in the sizing.
  263.                  */
  264.                 int reportedSize = in.get() & 0xFF;
  265.                 if(reportedSize != encryptSize) {
  266.                     logger.info("Packet size mismatch (expected : " + encryptSize + ", reported : " + reportedSize + ")");
  267.                     session.close(false);
  268.                     in.rewind();
  269.                     return false;
  270.                 }
  271.                
  272.                 /*
  273.                  * We now read the encrypted block opcode (although in most
  274.                  * 317 clients and this server the RSA is disabled) and
  275.                  * check it is equal to 10.
  276.                  */
  277.                 int blockOpcode = in.get() & 0xFF;
  278.                 if(blockOpcode != 10) {
  279.                     logger.info("Invalid login block opcode : " + blockOpcode);
  280.                     session.close(false);
  281.                     in.rewind();
  282.                     return false;
  283.                 }
  284.  
  285.                 /*
  286.                  * We read the client's session key.
  287.                  */
  288.                 long clientKey = in.getLong();
  289.                
  290.                 /*
  291.                  * And verify it has the correct server session key.
  292.                  */
  293.                 long serverKey = (Long) session.getAttribute("serverKey");
  294.                 long reportedServerKey = in.getLong();
  295.                 if(reportedServerKey != serverKey) {
  296.                     logger.info("Server key mismatch (expected : " + serverKey + ", reported : " + reportedServerKey + ")");
  297.                     session.close(false);
  298.                     in.rewind();
  299.                     return false;
  300.                 }
  301.                
  302.                 /*
  303.                  * The UID, found in random.dat in newer clients and
  304.                  * uid.dat in older clients is a way of identifying a
  305.                  * computer.
  306.                  *
  307.                  * However, some clients send a hardcoded or random UID,
  308.                  * making it useless in the private server scene.
  309.                  */
  310.                 int uid = in.getInt();
  311.                
  312.                 /*
  313.                  * We read and format the name and passwords.
  314.                  */
  315.                 String name = NameUtils.formatName(IoBufferUtils.getRS2String(in));
  316.                 String pass = IoBufferUtils.getRS2String(in);
  317.                 logger.info("Login request : username=" + name + " password=" + pass);
  318.                
  319.                 /*
  320.                  * And setup the ISAAC cipher which is used to encrypt and
  321.                  * decrypt opcodes.
  322.                  *
  323.                  * However, without RSA, this is rendered useless anyway.
  324.                  */
  325.                 int[] sessionKey = new int[4];
  326.                 sessionKey[0] = (int) (clientKey >> 32);
  327.                 sessionKey[1] = (int) clientKey;
  328.                 sessionKey[2] = (int) (serverKey >> 32);
  329.                 sessionKey[3] = (int) serverKey;
  330.                
  331.                 session.removeAttribute("state");
  332.                 session.removeAttribute("serverKey");
  333.                 session.removeAttribute("size");
  334.                 session.removeAttribute("encryptSize");
  335.                
  336.                 ISAACCipher inCipher = new ISAACCipher(sessionKey);
  337.                 for(int i = 0; i < 4; i++) {
  338.                     sessionKey[i] += 50;
  339.                 }
  340.                 ISAACCipher outCipher = new ISAACCipher(sessionKey);
  341.                
  342.                 /*
  343.                  * Now, the login has completed, and we do the appropriate
  344.                  * things to fire off the chain of events which will load
  345.                  * and check the saved games etc.
  346.                  */
  347.                 session.getFilterChain().remove("protocol");
  348.                 session.getFilterChain().addFirst("protocol", new ProtocolCodecFilter(RS2CodecFactory.GAME));
  349.                
  350.                 PlayerDetails pd = new PlayerDetails(session, name, pass, uid, inCipher, outCipher);
  351.                 World.getWorld().load(pd);
  352.             }
  353.             break;
  354.         }
  355.         in.rewind();
  356.         return false;
  357.     }
  358.  
  359. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement