Guest User

Untitled

a guest
Jun 12th, 2018
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 8.48 KB | None | 0 0
  1. package org.jscape.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.jscape.isaac.IsaacRandomPair;
  9. import org.jscape.model.Player;
  10. import org.jscape.net.handshake.HandshakeData;
  11. import org.jscape.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_exponent = (BigInteger) input_stream.readObject();
  74.             rsa_modulus = (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.      * A flag indicating whether or not the client has a low-memory setting.
  98.      */
  99.     private boolean low_mem;
  100.  
  101.     /**
  102.      * The archive crcs.
  103.      */
  104.     private int[] archive_crcs = new int[9];
  105.  
  106.     /*
  107.      * (non-Javadoc)
  108.      * @see rsnio.codec.BufferDecoder#decode(
  109.      *  java.nio.ByteBuffer,
  110.      *  rsnio.channel.ChannelSession,
  111.      *  rsnio.IOListener)
  112.      */
  113.     @Override
  114.     public boolean decode(ByteBuffer buffer, ChannelSession session,
  115.             IOListener listener) throws Exception {
  116.  
  117.         switch (state) {
  118.         case DECODE_HEADER:
  119.             return decodeHeader(buffer, session, listener);
  120.         case DECODE_CLIENT_INFO:
  121.             return decodeClientInfo(buffer, session, listener);
  122.         case DECODE_PLAYER_INFO:
  123.             return decodePlayerInfo(buffer, session, listener);
  124.         }
  125.         return false;
  126.     }
  127.  
  128.     /**
  129.      * Decodes in the {@link State#DECODE_HEADER} state.
  130.      * @param buffer The buffer to decode from.
  131.      * @param session The session the data come from.
  132.      * @param listener The server's {@link IOListener} implementation.
  133.      * @return <code>true</code> if there was enough bytes to decode,
  134.      * <code>false</code> if not.
  135.      */
  136.     private boolean decodeHeader(ByteBuffer buffer, ChannelSession session,
  137.             IOListener listener) throws Exception {
  138.  
  139.         if (buffer.remaining() < (1 + 1)) {
  140.             return false;
  141.         }
  142.  
  143.         int login_opcode = buffer.get();
  144.  
  145.         if (login_opcode != LoginConstants.OPCODE_TYPE_NEW &&
  146.                 login_opcode != LoginConstants.OPCODE_TYPE_RECONNECTING) {
  147.             session.write(new LoginResponse.Unsuccessful(
  148.                     LoginConstants.STATUS_BAD_SESSION_ID), IoFuture.CLOSE);
  149.             return true;
  150.         }
  151.  
  152.         reconnecting = login_opcode == LoginConstants.OPCODE_TYPE_RECONNECTING;
  153.         request_length = buffer.get();
  154.         state = State.DECODE_CLIENT_INFO;
  155.         return false;
  156.     }
  157.  
  158.     /**
  159.      * Decodes in the {@link State#DECODE_CLIENT_INFO} state.
  160.      * @param buffer The buffer to decode from.
  161.      * @param session The session the data come from.
  162.      * @param listener The server's {@link IOListener} implementation.
  163.      * @return <code>true</code> if there was enough bytes to decode,
  164.      * <code>false</code> if not.
  165.      */
  166.     private boolean decodeClientInfo(ByteBuffer buffer, ChannelSession session,
  167.             IOListener listener) throws Exception {
  168.  
  169.         if (buffer.remaining() < 41) {
  170.             return false;
  171.         }
  172.  
  173.         if (buffer.get() != 0xff) {
  174.             session.write(new LoginResponse.Unsuccessful(
  175.                     LoginConstants.STATUS_BAD_SESSION_ID), IoFuture.CLOSE);
  176.             return true;
  177.         }
  178.  
  179.         if (buffer.getShort() != 377) {
  180.             session.write(new LoginResponse.Unsuccessful(
  181.                     LoginConstants.STATUS_GAME_UPDATED), IoFuture.CLOSE);
  182.         }
  183.  
  184.         int low_mem_flag = buffer.get();
  185.  
  186.         if (low_mem_flag != 0 && low_mem_flag != 1) {
  187.             session.write(new LoginResponse.Unsuccessful(
  188.                     LoginConstants.STATUS_BAD_SESSION_ID), IoFuture.CLOSE);
  189.             return true;
  190.         }
  191.  
  192.         low_mem = low_mem_flag == 1;
  193.  
  194.         for (int i = 0; i < archive_crcs.length; i++) {
  195.             archive_crcs[i] = buffer.getInt();
  196.         }
  197.  
  198.         if (buffer.get() != (request_length - 41)) {
  199.             session.write(new LoginResponse.Unsuccessful(
  200.                     LoginConstants.STATUS_BAD_SESSION_ID), IoFuture.CLOSE);
  201.             return true;
  202.         }
  203.  
  204.         state = State.DECODE_PLAYER_INFO;
  205.  
  206.         return false;
  207.     }
  208.  
  209.     /**
  210.      * Decodes in the {@link State#DECODE_PLAYER_INFO} state.
  211.      * @param buffer The buffer to decode from.
  212.      * @param session The session the data come from.
  213.      * @param listener The server's {@link IOListener} implementation.
  214.      * @return <code>true</code> if there was enough bytes to decode,
  215.      * <code>false</code> if not.
  216.      */
  217.     private boolean decodePlayerInfo(ByteBuffer buffer, ChannelSession session,
  218.             IOListener listener) throws Exception {
  219.  
  220.         int length = request_length - 41;
  221.  
  222.         if (buffer.remaining() < length) {
  223.             return false;
  224.         }
  225.  
  226.         ByteBuffer dec_buffer = decryptRsa(buffer, length);
  227.  
  228.         if (dec_buffer.get() != 10) {
  229.             session.write(new LoginResponse.Unsuccessful(
  230.                     LoginConstants.STATUS_BAD_SESSION_ID), IoFuture.CLOSE);
  231.             return true;
  232.         }
  233.  
  234.         long client_seed = dec_buffer.getLong();
  235.  
  236.         HandshakeData handshake_data = (HandshakeData) session.getAttachment();
  237.  
  238.         if (handshake_data == null) {
  239.             throw new NullPointerException("Session contains no data from" +
  240.                     " the handshake.");
  241.         }
  242.  
  243.         long server_seed = handshake_data.getServerSeed();
  244.  
  245.         if (dec_buffer.getLong() != server_seed) {
  246.             session.write(new LoginResponse.Unsuccessful(
  247.                     LoginConstants.STATUS_BAD_SESSION_ID), IoFuture.CLOSE);
  248.             return true;
  249.         }
  250.  
  251.         int uid = dec_buffer.getInt();
  252.  
  253.         String username = ByteBufferUtils.readString(dec_buffer);
  254.         String password = ByteBufferUtils.readString(dec_buffer);
  255.  
  256.         if (username.length() > 12 || password.length() > 20) {
  257.             session.write(new LoginResponse.Unsuccessful(
  258.                     LoginConstants.STATUS_BAD_SESSION_ID), IoFuture.CLOSE);
  259.             return true;
  260.         }
  261.  
  262.         IsaacRandomPair isaac_pair = IsaacRandomPair.create(
  263.                 server_seed, client_seed);
  264.  
  265.         Player.Credentials credentials = new Player.Credentials(
  266.                 username, password, handshake_data.getUsernameHash(), uid);
  267.  
  268.         LoginRequest request = new LoginRequest(
  269.                 reconnecting, low_mem, archive_crcs, isaac_pair, credentials);
  270.  
  271.         LoginService.getInstance().submitLoadRequest(session, request);
  272.  
  273.         return true;
  274.     }
  275.  
  276.     /**
  277.      * Decrypts the specified amount of bytes from the specified buffer and
  278.      * decrypts them as if they were encrypted with rsa.
  279.      * @param buffer The buffer the bytes are in.
  280.      * @param length The amount of bytes to read and decrypt.
  281.      * @return A new {@link ByteBuffer} containing the decrypted bytes.
  282.      */
  283.     private ByteBuffer decryptRsa(ByteBuffer buffer, int length) {
  284.         byte[] array = new byte[length];
  285.         buffer.get(array);
  286.         return ByteBuffer.wrap(new BigInteger(array).
  287.                 modPow(rsa_exponent, rsa_modulus).toByteArray());
  288.     }
  289.  
  290.     /*
  291.      * (non-Javadoc)
  292.      * @see rsnio.codec.ObjectEncoder#encode(
  293.      *  java.lang.Object,
  294.      *  rsnio.channel.ChannelSession,
  295.      *  rsnio.IOListener)
  296.      */
  297.     @Override
  298.     public ByteBuffer encode(Object object, ChannelSession session,
  299.             IOListener listener) throws Exception {
  300.         //TODO encode if login response
  301.         return null;
  302.     }
  303.  
  304. }
Add Comment
Please, Sign In to add comment