Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package org.jscape.net.login;
- import java.io.FileInputStream;
- import java.io.ObjectInputStream;
- import java.math.BigInteger;
- import java.nio.ByteBuffer;
- import org.jscape.isaac.IsaacRandomPair;
- import org.jscape.model.Player;
- import org.jscape.net.handshake.HandshakeData;
- import org.jscape.net.util.ByteBufferUtils;
- import rsnio.IOListener;
- import rsnio.channel.ChannelSession;
- import rsnio.codec.BufferDecoder;
- import rsnio.codec.ObjectEncoder;
- import rsnio.util.IoFuture;
- /**
- * An implementation of {@link BufferDecoder} and {@link ObjectEncoder}
- * which handles all codec for the runescape player login protocol.
- * @author Jimmy Frix
- */
- public final class LoginCodec implements BufferDecoder, ObjectEncoder {
- /**
- * A state in which a {@link LoginCodec} object may be in.
- * @author Jimmy Frix
- */
- private enum State {
- /**
- * Represents a state where incoming data is decoded as if it's
- * the header of a login packet.
- */
- DECODE_HEADER,
- /**
- * Represents a state where incoming data is decoded as if it's
- * the portion of the login packet followed by the header which
- * contains data pertaining to the client it's self.
- */
- DECODE_CLIENT_INFO,
- /**
- * Represents a state where incoming data is decoded as if it's
- * the portion of the login packet, followed by the portion which
- * contains information on the client it's self, which contains
- * encrypted data on the player's login information.
- */
- DECODE_PLAYER_INFO;
- }
- /**
- * The exponent used in decrypting information encrypted
- * with rsa.
- */
- private static BigInteger rsa_exponent;
- /**
- * The modulus used in decrypting information encrypted
- * with rsa.
- */
- private static BigInteger rsa_modulus;
- /*
- * Loads the private rsa keys when the class is loaded.
- */
- static {
- try (ObjectInputStream input_stream = new ObjectInputStream(
- new FileInputStream("./data/crypto/jscape_rsa.priv"))) {
- rsa_exponent = (BigInteger) input_stream.readObject();
- rsa_modulus = (BigInteger) input_stream.readObject();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- /**
- * The current state.
- */
- private State state = State.DECODE_HEADER;
- /**
- * A flag indicating whether or not the client is reconnecting from
- * a pre-existing session which lost connection.
- */
- private boolean reconnecting;
- /**
- * The length of the login packet being decoded.
- */
- private int request_length;
- /**
- * A flag indicating whether or not the client has a low-memory setting.
- */
- private boolean low_mem;
- /**
- * The archive crcs.
- */
- private int[] archive_crcs = new int[9];
- /*
- * (non-Javadoc)
- * @see rsnio.codec.BufferDecoder#decode(
- * java.nio.ByteBuffer,
- * rsnio.channel.ChannelSession,
- * rsnio.IOListener)
- */
- @Override
- public boolean decode(ByteBuffer buffer, ChannelSession session,
- IOListener listener) throws Exception {
- switch (state) {
- case DECODE_HEADER:
- return decodeHeader(buffer, session, listener);
- case DECODE_CLIENT_INFO:
- return decodeClientInfo(buffer, session, listener);
- case DECODE_PLAYER_INFO:
- return decodePlayerInfo(buffer, session, listener);
- }
- return false;
- }
- /**
- * Decodes in the {@link State#DECODE_HEADER} state.
- * @param buffer The buffer to decode from.
- * @param session The session the data come from.
- * @param listener The server's {@link IOListener} implementation.
- * @return <code>true</code> if there was enough bytes to decode,
- * <code>false</code> if not.
- */
- private boolean decodeHeader(ByteBuffer buffer, ChannelSession session,
- IOListener listener) throws Exception {
- if (buffer.remaining() < (1 + 1)) {
- return false;
- }
- int login_opcode = buffer.get();
- if (login_opcode != LoginConstants.OPCODE_TYPE_NEW &&
- login_opcode != LoginConstants.OPCODE_TYPE_RECONNECTING) {
- session.write(new LoginResponse.Unsuccessful(
- LoginConstants.STATUS_BAD_SESSION_ID), IoFuture.CLOSE);
- return true;
- }
- reconnecting = login_opcode == LoginConstants.OPCODE_TYPE_RECONNECTING;
- request_length = buffer.get();
- state = State.DECODE_CLIENT_INFO;
- return false;
- }
- /**
- * Decodes in the {@link State#DECODE_CLIENT_INFO} state.
- * @param buffer The buffer to decode from.
- * @param session The session the data come from.
- * @param listener The server's {@link IOListener} implementation.
- * @return <code>true</code> if there was enough bytes to decode,
- * <code>false</code> if not.
- */
- private boolean decodeClientInfo(ByteBuffer buffer, ChannelSession session,
- IOListener listener) throws Exception {
- if (buffer.remaining() < 41) {
- return false;
- }
- if (buffer.get() != 0xff) {
- session.write(new LoginResponse.Unsuccessful(
- LoginConstants.STATUS_BAD_SESSION_ID), IoFuture.CLOSE);
- return true;
- }
- if (buffer.getShort() != 377) {
- session.write(new LoginResponse.Unsuccessful(
- LoginConstants.STATUS_GAME_UPDATED), IoFuture.CLOSE);
- }
- int low_mem_flag = buffer.get();
- if (low_mem_flag != 0 && low_mem_flag != 1) {
- session.write(new LoginResponse.Unsuccessful(
- LoginConstants.STATUS_BAD_SESSION_ID), IoFuture.CLOSE);
- return true;
- }
- low_mem = low_mem_flag == 1;
- for (int i = 0; i < archive_crcs.length; i++) {
- archive_crcs[i] = buffer.getInt();
- }
- if (buffer.get() != (request_length - 41)) {
- session.write(new LoginResponse.Unsuccessful(
- LoginConstants.STATUS_BAD_SESSION_ID), IoFuture.CLOSE);
- return true;
- }
- state = State.DECODE_PLAYER_INFO;
- return false;
- }
- /**
- * Decodes in the {@link State#DECODE_PLAYER_INFO} state.
- * @param buffer The buffer to decode from.
- * @param session The session the data come from.
- * @param listener The server's {@link IOListener} implementation.
- * @return <code>true</code> if there was enough bytes to decode,
- * <code>false</code> if not.
- */
- private boolean decodePlayerInfo(ByteBuffer buffer, ChannelSession session,
- IOListener listener) throws Exception {
- int length = request_length - 41;
- if (buffer.remaining() < length) {
- return false;
- }
- ByteBuffer dec_buffer = decryptRsa(buffer, length);
- if (dec_buffer.get() != 10) {
- session.write(new LoginResponse.Unsuccessful(
- LoginConstants.STATUS_BAD_SESSION_ID), IoFuture.CLOSE);
- return true;
- }
- long client_seed = dec_buffer.getLong();
- HandshakeData handshake_data = (HandshakeData) session.getAttachment();
- if (handshake_data == null) {
- throw new NullPointerException("Session contains no data from" +
- " the handshake.");
- }
- long server_seed = handshake_data.getServerSeed();
- if (dec_buffer.getLong() != server_seed) {
- session.write(new LoginResponse.Unsuccessful(
- LoginConstants.STATUS_BAD_SESSION_ID), IoFuture.CLOSE);
- return true;
- }
- int uid = dec_buffer.getInt();
- String username = ByteBufferUtils.readString(dec_buffer);
- String password = ByteBufferUtils.readString(dec_buffer);
- if (username.length() > 12 || password.length() > 20) {
- session.write(new LoginResponse.Unsuccessful(
- LoginConstants.STATUS_BAD_SESSION_ID), IoFuture.CLOSE);
- return true;
- }
- IsaacRandomPair isaac_pair = IsaacRandomPair.create(
- server_seed, client_seed);
- Player.Credentials credentials = new Player.Credentials(
- username, password, handshake_data.getUsernameHash(), uid);
- LoginRequest request = new LoginRequest(
- reconnecting, low_mem, archive_crcs, isaac_pair, credentials);
- LoginService.getInstance().submitLoadRequest(session, request);
- return true;
- }
- /**
- * Decrypts the specified amount of bytes from the specified buffer and
- * decrypts them as if they were encrypted with rsa.
- * @param buffer The buffer the bytes are in.
- * @param length The amount of bytes to read and decrypt.
- * @return A new {@link ByteBuffer} containing the decrypted bytes.
- */
- private ByteBuffer decryptRsa(ByteBuffer buffer, int length) {
- byte[] array = new byte[length];
- buffer.get(array);
- return ByteBuffer.wrap(new BigInteger(array).
- modPow(rsa_exponent, rsa_modulus).toByteArray());
- }
- /*
- * (non-Javadoc)
- * @see rsnio.codec.ObjectEncoder#encode(
- * java.lang.Object,
- * rsnio.channel.ChannelSession,
- * rsnio.IOListener)
- */
- @Override
- public ByteBuffer encode(Object object, ChannelSession session,
- IOListener listener) throws Exception {
- //TODO encode if login response
- return null;
- }
- }
Add Comment
Please, Sign In to add comment