Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- @Override
- protected Object decode(ChannelHandlerContext ctx, Channel channel,
- ChannelBuffer buffer) throws Exception {
- switch (state) {
- /*
- * The login handshake
- */
- case LOGIN_HANDSHAKE:
- if (buffer.readableBytes() >= 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 = buffer.readByte() & 0xFF;
- /*
- * We generated the server session key using a SecureRandom
- * class for security.
- */
- serverKey = RANDOM.nextLong();
- /*
- * The initial response is just 0s which the client is set to
- * ignore (probably some sort of modification).
- */
- ChannelBuffer resp = ChannelBuffers.buffer(9);
- /*
- * This is the return code (just like the login return code 2
- * allows the session to login) This allows session keys to be
- * exchanged
- *
- * Warning, If this is skipped it makes a null pointer exception
- * and no ISAAC cipher is used
- */
- resp.writeByte(0);
- /*
- * This is sent so the ISAAC server and client side both use
- * that key.
- */
- resp.writeLong(serverKey);
- /*
- * We now write the data to the client
- */
- channel.write(resp);
- /*
- * Changes the state for the next part of the login
- */
- setLoginState(LoginState.LOGIN_HEADER);
- }
- break;
- /*
- * The login header
- */
- case LOGIN_HEADER:
- if (buffer.readableBytes() >= 3) {
- /*
- * We read the type of login.
- *
- * 16 = normal 18 = reconnection
- */
- int loginOpcode = buffer.readByte() & 0xff;
- if (loginOpcode != 16 && loginOpcode != 18) {
- channel.close();
- }
- /*
- * We read the size of the login packet.
- */
- loginSize = buffer.readShort() & 0xFFFF;
- setLoginState(LoginState.LOGIN_PAYLOAD);
- }
- break;
- /**
- * The login payload
- */
- case LOGIN_PAYLOAD:
- if (buffer.readableBytes() >= loginSize) {
- /*
- * Reads the client version as an Integer data type.
- */
- int version = buffer.readInt();
- if (version != CLIENT_VERSION) {
- channel.close();
- }
- /*
- * Maybe a flag?
- */
- buffer.readByte();
- /*
- * checks if the client is on low memory Most likely to tell the
- * server not to play sounds and such
- */
- boolean isLowMemory = (buffer.readByte() & 0xff) == 1 ? true
- : false;
- /*
- * checks if the client is HD
- */
- boolean isHD = (buffer.readByte() & 0xff) == 1 ? true : false;
- /*
- * There are different view points in HD
- *
- * 0 = Stand Detail
- * 1 = Fixed HD
- * 2 = Resizable HD Screen
- * 4 = Fixed Fullscreen
- */
- byte hdType = (byte) (buffer.readByte() & 0xff);
- /*
- * We now check what detail the client is and set it
- */
- GraphicDetail details = GraphicDetail.NORMAL;
- /*
- * The different hd types
- */
- switch (hdType) {
- case 0:
- /*
- * The standard detail.
- */
- details = GraphicDetail.NORMAL;
- break;
- case 1:
- /*
- * The fixed HD detail.
- */
- details = GraphicDetail.HD_FIXED;
- break;
- case 2:
- /*
- * The HD resizable detail.
- */
- details = GraphicDetail.HD_RESIZABLE;
- break;
- case 3:
- /*
- * The HD full screen detail.
- */
- details = GraphicDetail.HD_FULLSCREEN;
- break;
- }
- /*
- * We read the clientWidth, this is probably used to define something server side and to check
- * if the client doesn't exceed to a certain size client crashes when its resized to a certain smaller size
- * but it is probably also used to stop some types of Anti Cheating from the mouse click.
- */
- short clientWidth = (short) (buffer.readShort() & 0xffff);
- /*
- * We read the clientHeight, this is probably used to define something server side and to check
- * if the client doesn't exceed to a certain height size since the client crashes when its resized to a certain smaller size
- * but it is probably also used to stop some types of Anti Cheating from the mouse click.
- */
- short clientHeight = (short) (buffer.readShort() & 0xffff);
- /*
- * Maybe a flag?
- */
- buffer.readByte();
- /*
- * The client settings array
- */
- byte[] clientSettings = new byte[24];
- /*
- * In client sends as a 24 byte array of write bytes this is
- * probably some client setting sent on the players login.
- */
- for (int i = 0; i < 24; i++) {
- clientSettings[i] = buffer.readByte();
- }
- /*
- * A key from the client/loader
- * This key is just the "Settings" parameter from the loader, this is most likely used
- * to check if it matches the official setting key else it will report it back to jagex
- * and they will know you're using 3rd parter software.
- */
- ChannelBufferUtils.getRS2String(buffer);
- /*
- * maybe the random.dat value
- */
- buffer.readInt();
- /*
- * Not sure
- */
- buffer.readInt();
- /*
- * Not sure
- */
- buffer.readShort();
- /*
- * The cache index's CRC values (probably used to check the
- * local Cache CRC values are the same as the official Runescape
- * one)
- */
- for (int i = 0; i < 28; i++) {
- buffer.readInt();
- }
- /*
- * The amount of bytes
- */
- int rsaPayloadSize = buffer.readByte() & 0xFF;
- /*
- * The rsaPayload
- */
- byte[] rsaPayload = new byte[rsaPayloadSize];
- /*
- * The main buffer reads the bytes
- */
- buffer.readBytes(rsaPayload);
- /*
- * The encrypted buffer for RSA
- */
- ChannelBuffer rsaBuffer = ChannelBuffers
- .wrappedBuffer(new BigInteger(rsaPayload).modPow(
- RSA_PRIVATE, RSA_MODULE).toByteArray());
- /*
- * We now read the encrypted block opcode (although in most clients
- * and this server the RSA is disabled) and check it is equal to 10.
- */
- int blockOpcode = rsaBuffer.readByte() & 0xFF;
- if (blockOpcode != 10) {
- logger.info("Invalid login block opcode : " + blockOpcode);
- channel.close();
- }
- /*
- * We read the clients session key.
- */
- long clientKey = rsaBuffer.readLong();
- /*
- * We verify it has the correct server session key.
- */
- long reportedServerKey = rsaBuffer.readLong();
- if (reportedServerKey != serverKey) {
- logger.info("Server key mismatch (expected : " + serverKey
- + ", reported : " + reportedServerKey + ")");
- channel.close();
- }
- String username = StringUtils.longToName(rsaBuffer.readLong());
- String password = ChannelBufferUtils.getRS2String(rsaBuffer);
- logger.info("Login request : username=" + username
- + " password=" + password);
- /*
- * 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;
- ISAACCipher in = new ISAACCipher(sessionKey);
- for (int i = 0; i < sessionKey.length; i++) {
- sessionKey[i] += 50;
- }
- ISAACCipher out = new ISAACCipher(sessionKey);
- /*
- * We now return a new <code>PlayerDetails</code> which will
- * fire to the ChannelHandler.
- */
- return new PlayerDetails(username, password, isHD, details,
- clientWidth, clientHeight, isLowMemory, in, out, clientSettings);
- }
- }
- return null;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement