Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package org.hyperion.rs2.net;
- import java.security.SecureRandom;
- import java.util.logging.Logger;
- import org.apache.mina.core.buffer.IoBuffer;
- import org.apache.mina.core.session.IoSession;
- import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
- import org.apache.mina.filter.codec.ProtocolCodecFilter;
- import org.apache.mina.filter.codec.ProtocolDecoderOutput;
- import org.hyperion.Server;
- import org.hyperion.rs2.model.PlayerDetails;
- import org.hyperion.rs2.model.World;
- import org.hyperion.rs2.Constants;
- import org.hyperion.rs2.net.ondemand.OnDemandPool;
- import org.hyperion.rs2.net.ondemand.OnDemandRequest;
- import org.hyperion.rs2.util.IoBufferUtils;
- import org.hyperion.rs2.util.NameUtils;
- import org.hyperion.rs2.util.TextUtils;
- /**
- * Login protocol decoding class.
- * @author Graham Edgecombe
- *
- */
- public class RS2LoginDecoder extends CumulativeProtocolDecoder {
- /**
- * Logger instance.
- */
- private static final Logger logger = Logger.getLogger(RS2LoginDecoder.class.getName());
- /**
- * The world list opcode.
- */
- public static final int OPCODE_WORLD_LIST = 131;
- /**
- * Update opcode.
- */
- public static final int OPCODE_UPDATE = 15;
- /**
- * Game opcode.
- */
- public static final int OPCODE_GAME = 14;
- /**
- * The JS5 stage.
- */
- private static final int STATE_JS5 = -1;
- /**
- * Update stage.
- */
- public static final int STATE_UPDATE = -2;
- /**
- * World stage.
- */
- public static final int STATE_WORLD = -3;
- /**
- * Opcode stage.
- */
- public static final int STATE_OPCODE = 0;
- /**
- * Precrypted stage.
- */
- public static final int STATE_PRECRYPTED = 1;
- /**
- * Crypted stage.
- */
- public static final int STATE_CRYPTED = 2;
- /**
- * Login stage.
- */
- public static final int STATE_LOGIN = 3;
- /**
- * Secure random number generator.
- */
- private static final SecureRandom RANDOM = new SecureRandom();
- /**
- * Initial login response.
- */
- private static final byte[] INITIAL_RESPONSE = new byte[] {
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
- };
- @Override
- protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
- synchronized(session) {
- int state = (Integer) session.getAttribute("state", STATE_OPCODE);
- switch(state) {
- case STATE_WORLD:
- if(in.remaining() >= 2) {
- int worldOpcode = in.getShort();
- PacketBuilder worldList = new PacketBuilder();
- for(int data : Constants.WORLD_LIST_DATA) {
- worldList.put((byte) data);
- }
- session.write(worldList.toPacket());
- session.close(false);
- }
- return true;
- case STATE_UPDATE:
- if(in.remaining() >= 4) {
- for(int i = 0; i < 4; i++) {
- in.get();
- }
- PacketBuilder uKeys = new PacketBuilder();
- for(int key : Constants.UPDATE_KEYS) {
- uKeys.put((byte) key);
- System.out.println("uKey sent");
- }
- session.write(uKeys.toPacket());
- session.close(false);
- return true;
- } else {
- in.rewind();
- return false;
- }
- case STATE_JS5:
- if(in.remaining() >= 4) {
- in.get();
- int clientVersion = in.getShort();
- if(clientVersion == 525) {
- PacketBuilder u1Response = new PacketBuilder();
- u1Response.put((byte) 0);
- session.write(u1Response.toPacket());
- session.setAttribute("state", STATE_UPDATE);
- }
- }
- in.rewind();
- return false;
- case STATE_OPCODE:
- int opcode = in.get() & 0xFF;
- switch(opcode) {
- case OPCODE_GAME:
- session.setAttribute("state", STATE_LOGIN);
- return true;
- case OPCODE_UPDATE:
- session.setAttribute("state", STATE_JS5);
- return true;
- case OPCODE_WORLD_LIST:
- session.setAttribute("state", STATE_WORLD);
- return true;
- default:
- logger.info("Invalid opcode : " + opcode);
- session.close(false);
- break;
- }
- break;
- case STATE_LOGIN:
- if(in.remaining() >= 1) {
- /*
- * The name hash is a simple hash of the name which is
- * suspected to be used to select the appropriate login
- * server.
- */
- @SuppressWarnings("unused")
- int nameHash = in.get() & 0xFF;
- /*
- * We generated the server session key using a SecureRandom
- * class for security.
- */
- long serverKey = RANDOM.nextLong();
- /*
- * The initial response is just 0s which the client is set
- * to ignore (probably some sort of modification).
- */
- session.write(new PacketBuilder().put((byte) 0).putLong(serverKey).toPacket());
- session.setAttribute("state", STATE_PRECRYPTED);
- session.setAttribute("serverKey", serverKey);
- return true;
- }
- break;
- case STATE_PRECRYPTED:
- if(in.remaining() >= 2) {
- /*
- * We read the type of login.
- *
- * 16 = normal
- * 18 = reconnection
- */
- int loginOpcode = in.get() & 0xFF;
- if(loginOpcode != 16 && loginOpcode != 18) {
- logger.info("Invalid login opcode : " + loginOpcode);
- session.close(false);
- in.rewind();
- return false;
- }
- /*
- * We read the size of the login packet.
- */
- int loginSize = in.get() & 0xFF;
- /*
- * And calculated how long the encrypted block will be.
- */
- int loginEncryptSize = loginSize - (36 + 1 + 1 + 2);
- session.setAttribute("state", STATE_CRYPTED);
- session.setAttribute("size", loginSize);
- session.setAttribute("encryptSize", loginEncryptSize);
- return true;
- }
- break;
- case STATE_CRYPTED:
- int size = (Integer) session.getAttribute("size");
- int encryptSize = (Integer) session.getAttribute("encryptSize");
- if(in.remaining() >= size) {
- /*
- * We now read a short which is the client version and
- * check if it equals 317.
- */
- int version = in.getInt();
- if(version != Server.VERSION) {
- logger.info("Incorrect version : " + version);
- session.close(false);
- in.rewind();
- return false;
- }
- for (int byteIdx = 0;byteIdx < 4;byteIdx++) {
- in.get();
- }
- in.getShort();
- in.getShort();
- in.get();
- for (int byteIdx = 0;byteIdx < 24;byteIdx++)
- in.get();
- IoBufferUtils.getRS2String(in);
- for (int byteIdx = 0;byteIdx < 3;byteIdx++)
- in.get();
- for (int it = 0;it < 2;it++)
- in.getInt();
- in.getShort();
- for (int i = 0; i < 26; i++) {
- in.getInt();
- }
- int junk29 = in.getShort();
- int junk30 = in.get();
- int junk31 = in.getShort();
- int junk32 = in.get();
- /*
- * The encrypted size includes the size byte which we don't
- * need.
- */
- encryptSize--;
- /*
- * We check if there is a mismatch in the sizing.
- */
- int reportedSize = in.get() & 0xFF;
- if(reportedSize != 10) {
- in.get();
- }
- /*
- * We read the client's session key.
- */
- long clientKey = in.getLong();
- /*
- * And verify it has the correct server session key.
- */
- long serverKey = (Long) session.getAttribute("serverKey");
- long reportedServerKey = in.getLong();
- if(reportedServerKey != serverKey) {
- //logger.info("Server key mismatch (expected : " + serverKey + ", reported : " + reportedServerKey + ")");
- //session.close(false);
- //in.rewind();
- //return false;
- }
- /*
- * We read and format the name and passwords.
- */
- String name = NameUtils.formatName(TextUtils.longToPlayerName(in.getLong()));
- String pass = IoBufferUtils.getRS2String(in);
- logger.info("Login request : username=" + name + " password=" + pass);
- /*
- * And setup the ISAAC cipher which is used to encrypt and
- * decrypt opcodes.
- *
- * However, without RSA, this is rendered useless anyway.
- */
- int[] sessionKey = new int[4];
- sessionKey[0] = (int) (clientKey >> 32);
- sessionKey[1] = (int) clientKey;
- sessionKey[2] = (int) (serverKey >> 32);
- sessionKey[3] = (int) serverKey;
- session.removeAttribute("state");
- session.removeAttribute("serverKey");
- session.removeAttribute("size");
- session.removeAttribute("encryptSize");
- ISAACCipher inCipher = null;// new ISAACCipher(sessionKey);
- for(int i = 0; i < 4; i++) {
- sessionKey[i] += 50;
- }
- ISAACCipher outCipher = null;// new ISAACCipher(sessionKey);
- /*
- * Now, the login has completed, and we do the appropriate
- * things to fire off the chain of events which will load
- * and check the saved games etc.
- */
- session.getFilterChain().remove("protocol");
- session.getFilterChain().addFirst("protocol", new ProtocolCodecFilter(RS2CodecFactory.GAME));
- PlayerDetails pd = new PlayerDetails(session, name, pass, 0, inCipher, outCipher);
- World.getWorld().load(pd);
- }
- break;
- }
- in.rewind();
- return false;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement