Guest User

Untitled

a guest
Jun 13th, 2018
98
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 8.45 KB | None | 0 0
  1. package org.jframework.net.login;
  2.  
  3. import java.io.FileInputStream;
  4. import java.io.ObjectInputStream;
  5. import java.math.BigInteger;
  6. import java.nio.ByteBuffer;
  7.  
  8. import org.jframework.isaac.IsaacRandomPair;
  9. import org.jframework.model.Player;
  10. import org.jframework.net.handshake.HandshakeData;
  11. import org.jframework.net.util.ByteBufferUtils;
  12.  
  13. import rsnio.IOListener;
  14. import rsnio.channel.ChannelSession;
  15. import rsnio.codec.BufferDecoder;
  16. import rsnio.codec.ObjectEncoder;
  17. import rsnio.util.IoFuture;
  18.  
  19. /**
  20.  * An implementation of {@link BufferDecoder} and {@link ObjectEncoder}
  21.  * which handles all codec for the runescape player login protocol.
  22.  * @author Jimmy Frix
  23.  */
  24. public final class LoginCodec implements BufferDecoder, ObjectEncoder {
  25.  
  26.     /**
  27.      * A state in which a {@link LoginCodec} object may be in.
  28.      * @author Jimmy Frix
  29.      */
  30.     private enum State {
  31.  
  32.         /**
  33.          * Represents a state where incoming data is decoded as if it's
  34.          * the header of a login packet.
  35.          */
  36.         DECODE_HEADER,
  37.  
  38.         /**
  39.          * Represents a state where incoming data is decoded as if it's
  40.          * the portion of the login packet followed by the header which
  41.          * contains data pertaining to the client it's self.
  42.          */
  43.         DECODE_CLIENT_INFO,
  44.  
  45.         /**
  46.          * Represents a state where incoming data is decoded as if it's
  47.          * the portion of the login packet, followed by the portion which
  48.          * contains information on the client it's self, which contains
  49.          * encrypted data on the player's login information.
  50.          */
  51.         DECODE_PLAYER_INFO;
  52.  
  53.     }
  54.  
  55.     /**
  56.      * The exponent used in decrypting information encrypted
  57.      * with rsa.
  58.      */
  59.     private static BigInteger rsa_exponent;
  60.  
  61.     /**
  62.      * The modulus used in decrypting information encrypted
  63.      * with rsa.
  64.      */
  65.     private static BigInteger rsa_modulus;
  66.  
  67.     /*
  68.      * Loads the private rsa keys when the class is loaded.
  69.      */
  70.     static {
  71.         try (ObjectInputStream input_stream = new ObjectInputStream(
  72.                 new FileInputStream("./data/crypto/jscape_rsa.priv"))) {
  73.             rsa_modulus = (BigInteger) input_stream.readObject();
  74.             rsa_exponent = (BigInteger) input_stream.readObject();
  75.         } catch (Exception e) {
  76.             e.printStackTrace();
  77.         }
  78.     }
  79.  
  80.     /**
  81.      * The current state.
  82.      */
  83.     private State state = State.DECODE_HEADER;
  84.  
  85.     /**
  86.      * A flag indicating whether or not the client is reconnecting from
  87.      * a pre-existing session which lost connection.
  88.      */
  89.     private boolean reconnecting;
  90.  
  91.     /**
  92.      * The length of the login packet being decoded.
  93.      */
  94.     private int request_length;
  95.  
  96.     /*
  97.      * (non-Javadoc)
  98.      * @see rsnio.codec.BufferDecoder#decode(
  99.      *  java.nio.ByteBuffer,
  100.      *  rsnio.channel.ChannelSession,
  101.      *  rsnio.IOListener)
  102.      */
  103.     @Override
  104.     public boolean decode(ByteBuffer buffer, ChannelSession session,
  105.             IOListener listener) throws Exception {
  106.         switch (state) {
  107.         case DECODE_HEADER:
  108.             return decodeHeader(buffer, session, listener);
  109.         case DECODE_CLIENT_INFO:
  110.             return decodeClientInfo(buffer, session, listener);
  111.         case DECODE_PLAYER_INFO:
  112.             return decodePlayerInfo(buffer, session, listener);
  113.         default:
  114.             throw new Exception("Invalid state");
  115.         }
  116.     }
  117.  
  118.     /**
  119.      * Decodes in the {@link State#DECODE_HEADER} state.
  120.      * @param buffer The buffer to decode from.
  121.      * @param session The session the data come from.
  122.      * @param listener The server's {@link IOListener} implementation.
  123.      * @return <code>true</code> if there was enough bytes to decode,
  124.      * <code>false</code> if not.
  125.      */
  126.     private boolean decodeHeader(ByteBuffer buffer, ChannelSession session,
  127.             IOListener listener) throws Exception {
  128.  
  129.         if (buffer.remaining() < (1 + 1)) {
  130.             return true;
  131.         }
  132.  
  133.         int login_opcode = buffer.get();
  134.  
  135.         if (login_opcode != LoginConstants.OPCODE_TYPE_NEW &&
  136.                 login_opcode != LoginConstants.OPCODE_TYPE_RECONNECTING) {
  137.             throw new Exception("Invalid login opcode.");
  138.         }
  139.  
  140.         reconnecting = login_opcode == LoginConstants.OPCODE_TYPE_RECONNECTING;
  141.         request_length = buffer.get();
  142.         state = State.DECODE_CLIENT_INFO;
  143.         return true;
  144.     }
  145.  
  146.     /**
  147.      * Decodes in the {@link State#DECODE_CLIENT_INFO} state.
  148.      * @param buffer The buffer to decode from.
  149.      * @param session The session the data come from.
  150.      * @param listener The server's {@link IOListener} implementation.
  151.      * @return <code>true</code> if there was enough bytes to decode,
  152.      * <code>false</code> if not.
  153.      */
  154.     private boolean decodeClientInfo(ByteBuffer buffer, ChannelSession session,
  155.             IOListener listener) throws Exception {
  156.  
  157.         if (buffer.remaining() < 41) {
  158.             return true;
  159.         }
  160.  
  161.         if ((buffer.get() & 0xff) != 0xff) {
  162.             throw new Exception("Invalid magic id.");
  163.         }
  164.  
  165.         if (buffer.getShort() != 377) {
  166.             System.out.println("mk");
  167.             session.write(new LoginResponse.Unsuccessful(
  168.                     LoginConstants.STATUS_GAME_UPDATED), IoFuture.CLOSE);
  169.             return false;
  170.         }
  171.  
  172.         int low_mem_flag = buffer.get();
  173.  
  174.         if (low_mem_flag != 0 && low_mem_flag != 1) {
  175.             throw new Exception("invalid value for low mem flag.");
  176.         }
  177.  
  178.         buffer.get(new byte[36]);
  179.  
  180.         if (buffer.get() != (request_length - 41)) {
  181.             throw new Exception("Player info portion size mismatch.");
  182.         }
  183.  
  184.         state = State.DECODE_PLAYER_INFO;
  185.  
  186.         return true;
  187.     }
  188.  
  189.     /**
  190.      * Decodes in the {@link State#DECODE_PLAYER_INFO} state.
  191.      * @param buffer The buffer to decode from.
  192.      * @param session The session the data come from.
  193.      * @param listener The server's {@link IOListener} implementation.
  194.      * @return <code>true</code> if there was enough bytes to decode,
  195.      * <code>false</code> if not.
  196.      */
  197.     private boolean decodePlayerInfo(ByteBuffer buffer, ChannelSession session,
  198.             IOListener listener) throws Exception {
  199.  
  200.         int length = request_length - 41;
  201.  
  202.         if (buffer.remaining() < length) {
  203.             return true;
  204.         }
  205.  
  206.         ByteBuffer dec_buffer = decryptRsa(buffer, length);
  207.  
  208.         if (dec_buffer.get() != 10) {
  209.             throw new Exception("Invalid player info portion opcode.");
  210.         }
  211.  
  212.         long client_seed = dec_buffer.getLong();
  213.         System.out.println(client_seed);
  214.  
  215.         HandshakeData handshake_data = (HandshakeData) session.getAttachment();
  216.  
  217.         if (handshake_data == null) {
  218.             throw new NullPointerException("Session contains no data from" +
  219.                     " the handshake.");
  220.         }
  221.  
  222.         long server_seed = handshake_data.getServerSeed();
  223.         System.out.println(server_seed);
  224.         long ess;
  225.         System.out.println(ess = dec_buffer.getLong());
  226.         if (ess /*dec_buffer.getLong()*/ != server_seed) {
  227.             throw new Exception("Server seed mismatch");
  228.         }
  229.  
  230.         int uid = dec_buffer.getInt();
  231.  
  232.         String username = ByteBufferUtils.readString(dec_buffer);
  233.         String password = ByteBufferUtils.readString(dec_buffer);
  234.  
  235.         if (username.length() > 12 || password.length() > 20) {
  236.             throw new Exception("Invalid length of either username or password");
  237.         }
  238.  
  239.         IsaacRandomPair isaac_pair = IsaacRandomPair.create(
  240.                 server_seed, client_seed);
  241.  
  242.         Player.Credentials credentials = new Player.Credentials(
  243.                 username, password, handshake_data.getUsernameHash(), uid);
  244.  
  245.         LoginRequest request = new LoginRequest(
  246.                 reconnecting, isaac_pair, credentials);
  247.         return false;
  248.     }
  249.  
  250.     /**
  251.      * Decrypts the specified amount of bytes from the specified buffer and
  252.      * decrypts them as if they were encrypted with rsa.
  253.      * @param buffer The buffer the bytes are in.
  254.      * @param length The amount of bytes to read and decrypt.
  255.      * @return A new {@link ByteBuffer} containing the decrypted bytes.
  256.      */
  257.     private ByteBuffer decryptRsa(ByteBuffer buffer, int length) {
  258.         byte[] array = new byte[length];
  259.         buffer.get(array);
  260.         return ByteBuffer.wrap(new BigInteger(array)./*
  261.                 modPow(rsa_exponent, rsa_modulus).*/toByteArray());
  262.         //rsa disabled temporarily
  263.     }
  264.  
  265.     /*
  266.      * (non-Javadoc)
  267.      * @see rsnio.codec.ObjectEncoder#encode(
  268.      *  java.lang.Object,
  269.      *  rsnio.channel.ChannelSession,
  270.      *  rsnio.IOListener)
  271.      */
  272.     @Override
  273.     public ByteBuffer encode(Object object, ChannelSession session,
  274.             IOListener listener) throws Exception {
  275.  
  276.         if (!(object instanceof LoginResponse)) {
  277.             throw new Exception("LoginCodec : encode"); //TODO rewrite the message given in this exception and all others.
  278.         }
  279.  
  280.         ByteBuffer buffer = ByteBuffer.allocate(object.getClass() == LoginResponse.Successful.class ? 3 : 1);
  281.  
  282.         LoginResponse response = (LoginResponse) object;
  283.  
  284.         buffer.put((byte) response.getStatus());
  285.  
  286.         if (object.getClass() == LoginResponse.Successful.class) {
  287.             LoginResponse.Successful r = (LoginResponse.Successful) object;
  288.             buffer.put((byte) r.getRights());
  289.             buffer.put((byte) (r.isFlagged() ? 1 : 0));
  290.         }
  291.  
  292.         return buffer;
  293.     }
  294.  
  295. }
Add Comment
Please, Sign In to add comment