Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package org.jframework.net.login;
- import java.io.FileInputStream;
- import java.io.ObjectInputStream;
- import java.math.BigInteger;
- import java.nio.ByteBuffer;
- import org.jframework.isaac.IsaacRandomPair;
- import org.jframework.model.Player;
- import org.jframework.net.handshake.HandshakeData;
- import org.jframework.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_modulus = (BigInteger) input_stream.readObject();
- rsa_exponent = (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;
- /*
- * (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);
- default:
- throw new Exception("Invalid state");
- }
- }
- /**
- * 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 true;
- }
- int login_opcode = buffer.get();
- if (login_opcode != LoginConstants.OPCODE_TYPE_NEW &&
- login_opcode != LoginConstants.OPCODE_TYPE_RECONNECTING) {
- throw new Exception("Invalid login opcode.");
- }
- reconnecting = login_opcode == LoginConstants.OPCODE_TYPE_RECONNECTING;
- request_length = buffer.get();
- state = State.DECODE_CLIENT_INFO;
- return true;
- }
- /**
- * 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 true;
- }
- if ((buffer.get() & 0xff) != 0xff) {
- throw new Exception("Invalid magic id.");
- }
- if (buffer.getShort() != 377) {
- System.out.println("mk");
- session.write(new LoginResponse.Unsuccessful(
- LoginConstants.STATUS_GAME_UPDATED), IoFuture.CLOSE);
- return false;
- }
- int low_mem_flag = buffer.get();
- if (low_mem_flag != 0 && low_mem_flag != 1) {
- throw new Exception("invalid value for low mem flag.");
- }
- buffer.get(new byte[36]);
- if (buffer.get() != (request_length - 41)) {
- throw new Exception("Player info portion size mismatch.");
- }
- state = State.DECODE_PLAYER_INFO;
- return true;
- }
- /**
- * 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 true;
- }
- ByteBuffer dec_buffer = decryptRsa(buffer, length);
- if (dec_buffer.get() != 10) {
- throw new Exception("Invalid player info portion opcode.");
- }
- long client_seed = dec_buffer.getLong();
- System.out.println(client_seed);
- 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();
- System.out.println(server_seed);
- long ess;
- System.out.println(ess = dec_buffer.getLong());
- if (ess /*dec_buffer.getLong()*/ != server_seed) {
- throw new Exception("Server seed mismatch");
- }
- int uid = dec_buffer.getInt();
- String username = ByteBufferUtils.readString(dec_buffer);
- String password = ByteBufferUtils.readString(dec_buffer);
- if (username.length() > 12 || password.length() > 20) {
- throw new Exception("Invalid length of either username or password");
- }
- 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, isaac_pair, credentials);
- return false;
- }
- /**
- * 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());
- //rsa disabled temporarily
- }
- /*
- * (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 {
- if (!(object instanceof LoginResponse)) {
- throw new Exception("LoginCodec : encode"); //TODO rewrite the message given in this exception and all others.
- }
- ByteBuffer buffer = ByteBuffer.allocate(object.getClass() == LoginResponse.Successful.class ? 3 : 1);
- LoginResponse response = (LoginResponse) object;
- buffer.put((byte) response.getStatus());
- if (object.getClass() == LoginResponse.Successful.class) {
- LoginResponse.Successful r = (LoginResponse.Successful) object;
- buffer.put((byte) r.getRights());
- buffer.put((byte) (r.isFlagged() ? 1 : 0));
- }
- return buffer;
- }
- }
Add Comment
Please, Sign In to add comment