Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- @Override
- protected boolean doDecode(IoSession session, IoBuffer in,
- ProtocolDecoderOutput out) throws Exception {
- int state = (Integer) session.getAttribute("state", STATE_OPCODE);
- switch (state) {
- case STATE_OPCODE:
- if (in.remaining() >= 1) {
- /*
- * Here we read the first opcode which indicates the type of
- * connection.
- *
- * 14 = game 15 = update 131: world list
- *
- * Updating is done by sending keys in many 525 servers
- */
- int opcode = in.get() & 0xFF;
- System.out.println(opcode);
- switch (opcode) {
- case OPCODE_WORLD_LIST:
- session.setAttribute("state", STATE_WORLD_LIST);
- break;
- case OPCODE_GAME:
- session.setAttribute("state", STATE_LOGIN);
- break;
- case OPCODE_UPDATE:
- session.setAttribute("state", CHECK_UPDATE_VERSION);
- break;
- }
- return true;
- }
- in.rewind();
- break;
- /*
- * Checks the client version for updating
- */
- case CHECK_UPDATE_VERSION:
- if (in.remaining() >= 4) {
- int version = in.getInt();
- System.out.println(version);
- if (version != Server.VERSION) {
- logger.info("Incorrect version : " + version);
- session.write(new PacketBuilder().put((byte) 6).toPacket());
- session.close(false);
- in.rewind();
- return false;
- }
- session.write(new PacketBuilder().put((byte) 0).toPacket());
- session.setAttribute("state", STATE_UPDATE);
- return true;
- }
- in.rewind();
- break;
- /*
- * WorldList writing
- */
- case STATE_WORLD_LIST:
- if (in.remaining() >= 4) {
- int loginOpcode = in.getInt();
- System.out.println(loginOpcode);
- if (loginOpcode == 0) {
- session.write(WorldList.getData(true, true));
- session.close(false);
- } else {
- session.write(WorldList.getData(false, true));
- session.close(false);
- }
- return true;
- }
- in.rewind();
- break;
- /*
- * Sends the update keys (as i dont have an cache updater implemented
- */
- case STATE_UPDATE:
- if (4 <= in.remaining()) {
- in.skip(4);
- PacketBuilder ukeys = new PacketBuilder();
- for (int key : Constants.UPDATE_KEYS) {
- ukeys.put((byte) key);
- }
- session.write(ukeys.toPacket());
- session.close(false);
- return true;
- }
- in.rewind();
- 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;
- }
- in.rewind();
- break;
- /*
- * Checks if the login opcodes are correct
- */
- case STATE_PRECRYPTED:
- if (3 <= in.remaining()) {
- /*
- * 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.getUnsignedShort();
- session.setAttribute("state", STATE_CRYPTED);
- session.setAttribute("size", loginSize);
- return true;
- }
- in.rewind();
- break;
- /*
- * Main login information here
- */
- case STATE_CRYPTED:
- int size = (Integer) session.getAttribute("size");
- if (in.remaining() >= size) {
- /*
- * Reads the client version as an <code>in.getInt()</code>
- */
- int version = in.getInt();
- if (version != Server.VERSION) {
- logger.info("Incorrect version : " + version);
- session.close(false);
- in.rewind();
- return false;
- }
- /*
- * Maybe a flag?
- */
- in.get();
- /*
- * checks if the client is on low memory
- * Most likely to tell the server not to play sounds
- * and such
- */
- @SuppressWarnings("unused")
- boolean lowMemory = (in.get() & 0xff) == 1 ? true : false;
- /*
- * checks if the client is HD
- */
- boolean isHD = (in.get() & 0xff) == 1 ? true : false;
- /*
- * The hd type,
- */
- byte hdType = (byte) (in.get() & 0xff);
- /*
- * The client width
- */
- @SuppressWarnings("unused")
- short clientWidth = (short) (in.getShort() & 0xffff);
- /*
- * The client height
- */
- @SuppressWarnings("unused")
- short clientHeight = (short) (in.getShort() & 0xffff);
- /*
- * Maybe a flag?
- */
- in.get();
- /*
- * In client sends as a 24 byte array of write bytes
- * Not actually sure what it is for but most likely to
- * piss us off
- */
- for(int i = 0; i < 24; i++) {
- in.get();
- }
- /*
- * A key from the client
- */
- IoBufferUtils.getRS2String(in);
- /*
- * maybe the random.dat value
- */
- in.getInt();
- /*
- * Not sure
- */
- in.getInt();
- /*
- * Not sure
- */
- in.getShort();
- /*
- * The cache index
- */
- for(int i = 0; i < 28; i++) {
- in.getInt();
- }
- /*
- * Something to do with RSA as its only sent when its enabled
- */
- int encryption = in.get() & 0xFF;
- /*
- * An byte array set to the value of the encryption
- */
- byte[] encryptionBytes = new byte[encryption];
- /*
- * Adds the byte array to the in IoBuffer
- */
- in.get(encryptionBytes);
- /*
- * The encrypted buffer for RSA
- */
- IoBuffer rsaBuffer = IoBuffer.wrap(new BigInteger(
- encryptionBytes).modPow(RSA_PRIVATE, RSA_MODULE)
- .toByteArray());
- /*
- * We now read the encrypted block opcode (although in most 317
- * clients and this server the RSA is disabled) and check it is
- * equal to 10.
- */
- int blockOpcode = rsaBuffer.get() & 0xFF;
- if (blockOpcode != 10) {
- logger.info("Invalid login block opcode : " + blockOpcode);
- session.close(false);
- in.rewind();
- return false;
- }
- /*
- * We read the client's session key.
- */
- long clientKey = rsaBuffer.getLong();
- /*
- * And verify it has the correct server session key.
- */
- long serverKey = (Long) session.getAttribute("serverKey");
- long reportedServerKey = rsaBuffer.getLong();
- if (reportedServerKey != serverKey) {
- logger.info("Server key mismatch (expected : " + serverKey
- + ", reported : " + reportedServerKey + ")");
- session.close(false);
- in.rewind();
- return false;
- }
- String name = NameUtils.longToName(rsaBuffer.getLong());
- String pass = IoBufferUtils.getRS2String(rsaBuffer);
- logger.info("Login request : username=" + name + " password="
- + pass);
- /*
- * And setup the ISAAC cipher which is used to encrypt and
- * decrypt opcodes.
- */
- 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 = new ISAACCipher(sessionKey);
- for (int i = 0; i < 4; i++) {
- sessionKey[i] += 50;
- }
- ISAACCipher outCipher = 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));
- World.getWorld().load(
- new PlayerDetails(session, NameUtils.formatName(name), pass, 0, isHD, hdType,
- inCipher, outCipher));
- }
- break;
- }
- in.rewind();
- return false;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement