Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package server.refactor.net.codec.login;
- import java.math.BigInteger;
- import java.security.SecureRandom;
- import java.util.logging.Logger;
- import org.apache.mina.common.ByteBuffer;
- import org.jboss.netty.buffer.ChannelBuffer;
- import org.jboss.netty.buffer.ChannelBuffers;
- import org.jboss.netty.channel.Channel;
- import org.jboss.netty.channel.ChannelHandlerContext;
- import server.RS2Server;
- import server.net.ChannelBufferUtils;
- import server.refactor.net.NetworkConstants;
- import server.refactor.net.codec.StatefulFrameDecoder;
- import server.refactor.security.ISAACRandomGenPair;
- import server.refactor.security.PlayerCredentials;
- import server.util.ISAACRandomGen;
- import server.util.Misc;
- /**
- * A {@link StatefulFrameDecoder} which decodes the login request frames.
- */
- public final class LoginDecoder extends StatefulFrameDecoder<LoginDecoderState> {
- private final Logger logger = Logger.getLogger(LoginDecoder.class.getName());
- /**
- * The secure random number generator.
- */
- private static final SecureRandom random = new SecureRandom();
- /**
- * The username hash.
- */
- private int usernameHash;
- /**
- * The server-side session key.
- */
- private long serverSeed;
- /**
- * The reconnecting flag.
- */
- private boolean reconnecting;
- /**
- * The login packet length.
- */
- private int loginLength;
- /**
- * The modifier for encrypted strings
- */
- private int stringModifier;
- /**
- * Creates the login decoder with the default initial state.
- */
- public LoginDecoder() {
- super(LoginDecoderState.LOGIN_HANDSHAKE, true);
- }
- @Override
- protected Object decode(final ChannelHandlerContext ctx, final Channel channel, final ChannelBuffer buffer, final LoginDecoderState state) throws Exception {
- switch (state) {
- case LOGIN_HANDSHAKE:
- return decodeHandshake(ctx, channel, buffer);
- case LOGIN_HEADER:
- return decodeHeader(ctx, channel, buffer);
- case LOGIN_PAYLOAD:
- return decodePayload(ctx, channel, buffer);
- default:
- throw new Exception("Invalid login decoder state");
- }
- }
- /**
- * Decodes in the handshake state.
- *
- * @param ctx
- * The channel handler context.
- * @param channel
- * The channel.
- * @param buffer
- * The buffer.
- * @return The frame, or {@code null}.
- * @throws Exception
- * if an error occurs.
- */
- private Object decodeHandshake(final ChannelHandlerContext ctx, final Channel channel, final ChannelBuffer buffer) throws Exception {
- if (buffer.readable()) {
- usernameHash = buffer.readUnsignedByte();
- // Delay login process in case server startup is not finished.
- if (!RS2Server.engineStarted) {
- final ChannelBuffer resp = ChannelBuffers.buffer(9);
- resp.writeLong(0);
- resp.writeByte(LoginConstants.STATUS_DELAY);
- channel.write(resp);
- channel.close();
- } else {
- serverSeed = random.nextLong();
- final ChannelBuffer resp = ChannelBuffers.buffer(19);
- resp.writeLong(0);
- resp.writeByte(LoginConstants.STATUS_EXCHANGE_DATA);
- // TODO: Send input order
- resp.writeLong(serverSeed);
- stringModifier = (0xFF + Misc.random(0xFFFF - 0xFF));
- // System.out.println("Sending modifier: " + stringModifier);
- resp.writeShort(stringModifier);
- channel.write(resp);
- setState(LoginDecoderState.LOGIN_HEADER);
- }
- }
- return null;
- }
- /**
- * Decodes in the header state.
- *
- * @param ctx
- * The channel handler context.
- * @param channel
- * The channel.
- * @param buffer
- * The buffer.
- * @return The frame, or {@code null}.
- * @throws Exception
- * if an error occurs.
- */
- private Object decodeHeader(final ChannelHandlerContext ctx, final Channel channel, final ChannelBuffer buffer) throws Exception {
- if (buffer.readableBytes() >= 2) {
- final int loginType = buffer.readByte();
- if (loginType != LoginConstants.TYPE_STANDARD && loginType != LoginConstants.TYPE_RECONNECTION)
- throw new Exception("Invalid login type");
- reconnecting = loginType == LoginConstants.TYPE_RECONNECTION;
- loginLength = buffer.readUnsignedByte();
- setState(LoginDecoderState.LOGIN_PAYLOAD);
- }
- return null;
- }
- /**
- * Decodes in the payload state.
- *
- * @param ctx
- * The channel handler context.
- * @param channel
- * The channel.
- * @param buffer
- * The buffer.
- * @return The frame, or {@code null}.
- * @throws Exception
- * if an error occurs.
- */
- private Object decodePayload(final ChannelHandlerContext ctx, final Channel channel, final ChannelBuffer buffer) throws Exception {
- if (buffer.readableBytes() >= loginLength) {
- final ChannelBuffer payload = buffer.readBytes(loginLength);
- if (payload.readUnsignedByte() != 0xFF) {
- channel.close();
- throw new Exception("Invalid magic id");
- }
- int release = payload.readUnsignedShort();
- int memoryStatus = payload.readUnsignedByte();
- final int[] archiveCrcs = new int[9];
- for (int i = 0; i < 9; i++)
- archiveCrcs[i] = payload.readInt();
- int length = payload.readUnsignedByte();
- if (length != loginLength - 41) {
- channel.close();
- logger.warning("FAIL PAYLOAD length " + length + " " + " login length " + loginLength );
- throw new Exception("Secure payload length mismatch");
- }
- ChannelBuffer rsaBuffer = payload.readBytes(length);
- BigInteger bigInteger = new BigInteger(rsaBuffer.array());
- bigInteger = bigInteger.modPow(NetworkConstants.RSA_EXPONENT, NetworkConstants.RSA_MODULUS);
- rsaBuffer = ChannelBuffers.wrappedBuffer(bigInteger.toByteArray());
- final int securityID = rsaBuffer.readUnsignedByte();
- if (securityID != 10) {
- channel.close();
- logger.warning("FAIL PAYLOAD ID " + securityID);
- throw new Exception("Invalid secure payload id");
- }
- final long clientSeed = rsaBuffer.readLong();
- final long reportedServerSeed = rsaBuffer.readLong();
- if (reportedServerSeed != serverSeed) {
- channel.close();
- throw new Exception("Server seed mismatch");
- }
- int uid = rsaBuffer.readInt(); // The SignLink uid
- final String playerMacAddress = "";
- final String clientSerial = "";
- final String regSerial = "";
- String username = readString(rsaBuffer);
- String password = readString(rsaBuffer);
- final int[] seed = new int[4];
- seed[0] = (int) (clientSeed >> 32);
- seed[1] = (int) clientSeed;
- seed[2] = (int) (serverSeed >> 32);
- seed[3] = (int) serverSeed;
- final ISAACRandomGen decodingRandom = new ISAACRandomGen(seed);
- for (int i = 0; i < seed.length; i++)
- seed[i] += 50;
- final ISAACRandomGen encodingRandom = new ISAACRandomGen(seed);
- final ISAACRandomGenPair randomPair = new ISAACRandomGenPair(encodingRandom, decodingRandom);
- final PlayerCredentials credentials = new PlayerCredentials(username, password, usernameHash, reconnecting, uid, release, playerMacAddress, clientSerial, regSerial, randomPair, ctx.getChannel(), false);
- final LoginRequest req = new LoginRequest(credentials, randomPair, reconnecting, false, release, null);
- //return new Object[] { req, buffer.readBytes(buffer.readableBytes()) };
- if (buffer.readable())
- return new Object[] { req, buffer.readBytes(buffer.readableBytes()) };
- else {
- logger.warning("req");
- return req;
- }
- }
- return null;
- }
- private String decryptString(byte[] buffer, int multiplier) {
- byte[] decrypted = new byte[buffer.length];
- for (int i = 0, modifier = 1; i < buffer.length; i++) {
- decrypted[i] = (byte) ((buffer[i] ^ (modifier * multiplier) & 0xFF));
- modifier *= (i * 2);
- }
- return new String(decrypted);
- }
- /**
- * Reads a string from the specified {@link ByteBuffer}.
- *
- * @param buffer The buffer.
- * @return The string.
- */
- public static String readString(ByteBuffer buffer) {
- StringBuilder bldr = new StringBuilder();
- char character;
- while ((character = (char) buffer.get()) != STRING_TERMINATOR) {
- bldr.append(character);
- }
- return bldr.toString();
- }
- /**
- * Reads a string from the specified {@link ByteBuf}.
- *
- * @param buffer The buffer.
- * @return The string.
- */
- public static String readString(ChannelBuffer buffer) {
- StringBuilder builder = new StringBuilder();
- int character;
- while (buffer.readable() && (character = buffer.readUnsignedByte()) != STRING_TERMINATOR) {
- builder.append((char) character);
- }
- return builder.toString();
- }
- /**
- * The terminator of a string.
- */
- public static final int STRING_TERMINATOR = 10;
- }
Add Comment
Please, Sign In to add comment