diff --git a/data/rsa.xml b/data/rsa.xml
new file mode 100644
index 00000000..abe68a05
--- /dev/null
+++ b/data/rsa.xml
@@ -0,0 +1,4 @@
+
+ 143690958001225849100503496893758066948984921380482659564113596152800934352119496873386875214251264258425208995167316497331786595942754290983849878549630226741961610780416197036711585670124061149988186026407785250364328460839202438651793652051153157765358767514800252431284681765433239888090564804146588087023
+ 124425314960550024206991065332877157931472210939505789558012215720454903710618146200843877022273818555405810618059191162604008259757866640421952188957253368398733319663236323097864278319463888334484786055755767881706264786840339899269810859874287402892848784247637729987603089254067178011764721326471352835473
+
\ No newline at end of file
diff --git a/src/org/apollo/game/GameService.java b/src/org/apollo/game/GameService.java
index 23540626..1da9d1e3 100644
--- a/src/org/apollo/game/GameService.java
+++ b/src/org/apollo/game/GameService.java
@@ -15,6 +15,7 @@ import org.apollo.game.model.World;
import org.apollo.game.model.World.RegistrationStatus;
import org.apollo.game.sync.ClientSynchronizer;
import org.apollo.io.EventHandlerChainParser;
+import org.apollo.io.RsaKeyParser;
import org.apollo.login.LoginService;
import org.apollo.net.session.GameSession;
import org.apollo.util.NamedThreadFactory;
@@ -117,6 +118,14 @@ public final class GameService extends Service {
} finally {
is.close();
}
+
+ is = new FileInputStream("data/rsa.xml");
+ try {
+ RsaKeyParser parser = new RsaKeyParser(is);
+ parser.parse();
+ } finally {
+ is.close();
+ }
}
/**
diff --git a/src/org/apollo/io/RsaKeyParser.java b/src/org/apollo/io/RsaKeyParser.java
new file mode 100644
index 00000000..d23e36ee
--- /dev/null
+++ b/src/org/apollo/io/RsaKeyParser.java
@@ -0,0 +1,66 @@
+package org.apollo.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+
+import org.apollo.net.NetworkConstants;
+import org.apollo.util.xml.XmlNode;
+import org.apollo.util.xml.XmlParser;
+import org.xml.sax.SAXException;
+
+/**
+ * A class that parses the {@code rsa.xml} file.
+ *
+ * @author Major
+ */
+public class RsaKeyParser {
+
+ /**
+ * The source {@link InputStream}.
+ */
+ private final InputStream is;
+
+ /**
+ * The {@link XmlParser} instance.
+ */
+ private final XmlParser parser;
+
+ /**
+ * Creates the RSA specification parser.
+ *
+ * @param is The source {@link InputStream}.
+ * @throws SAXException If a SAX error occurs.
+ */
+ public RsaKeyParser(InputStream is) throws SAXException {
+ parser = new XmlParser();
+ this.is = is;
+ }
+
+ /**
+ * Parses the {@code rsa.xml} file.
+ *
+ * @throws SAXException If a SAX error occurs.
+ * @throws IOException
+ */
+ public void parse() throws SAXException, IOException {
+ XmlNode rootNode = parser.parse(is);
+ if (!rootNode.getName().equals("rsa")) {
+ throw new IOException("root node name is not 'rsa'");
+ }
+
+ XmlNode modulusNode = rootNode.getChild("modulus");
+ if (modulusNode == null) {
+ throw new IOException("no node named 'modulus' beneath root node");
+ }
+
+ XmlNode exponentNode = rootNode.getChild("private-exponent");
+ if (exponentNode == null) {
+ throw new IOException("no node named 'private-exponent' beneath root node");
+ }
+
+ NetworkConstants.RSA_MODULUS = new BigInteger(modulusNode.getValue());
+ NetworkConstants.RSA_EXPONENT = new BigInteger(exponentNode.getValue());
+ }
+
+}
\ No newline at end of file
diff --git a/src/org/apollo/net/NetworkConstants.java b/src/org/apollo/net/NetworkConstants.java
index 6f32e758..9c111feb 100644
--- a/src/org/apollo/net/NetworkConstants.java
+++ b/src/org/apollo/net/NetworkConstants.java
@@ -1,5 +1,7 @@
package org.apollo.net;
+import java.math.BigInteger;
+
/**
* Holds various network-related constants such as port numbers.
*
@@ -22,6 +24,16 @@ public final class NetworkConstants {
*/
public static final int JAGGRAB_PORT = 43595;
+ /**
+ * The exponent used when decrypting the RSA block.
+ */
+ public static BigInteger RSA_EXPONENT;
+
+ /**
+ * The modulus used when decrypting the RSA block.
+ */
+ public static BigInteger RSA_MODULUS;
+
/**
* The service port.
*/
@@ -39,4 +51,4 @@ public final class NetworkConstants {
}
-}
+}
\ No newline at end of file
diff --git a/src/org/apollo/net/codec/login/LoginDecoder.java b/src/org/apollo/net/codec/login/LoginDecoder.java
index fd4068d2..79c1d844 100644
--- a/src/org/apollo/net/codec/login/LoginDecoder.java
+++ b/src/org/apollo/net/codec/login/LoginDecoder.java
@@ -1,10 +1,12 @@
package org.apollo.net.codec.login;
+import java.math.BigInteger;
import java.security.SecureRandom;
import net.burtleburtle.bob.rand.IsaacRandom;
import org.apollo.fs.FileSystemConstants;
+import org.apollo.net.NetworkConstants;
import org.apollo.security.IsaacRandomPair;
import org.apollo.security.PlayerCredentials;
import org.apollo.util.ChannelBufferUtil;
@@ -64,7 +66,7 @@ public final class LoginDecoder extends StatefulFrameDecoder
case LOGIN_PAYLOAD:
return decodePayload(ctx, channel, buffer);
default:
- throw new Exception("Invalid login decoder state");
+ throw new IllegalArgumentException("Invalid login decoder state");
}
}
@@ -156,6 +158,11 @@ public final class LoginDecoder extends StatefulFrameDecoder
ChannelBuffer securePayload = payload.readBytes(securePayloadLength);
+ BigInteger bigInteger = new BigInteger(securePayload.array());
+ bigInteger = bigInteger.modPow(NetworkConstants.RSA_EXPONENT, NetworkConstants.RSA_MODULUS);
+
+ securePayload = ChannelBuffers.wrappedBuffer(bigInteger.toByteArray());
+
int secureId = securePayload.readUnsignedByte();
if (secureId != 10) {
throw new Exception("Invalid secure payload id");
@@ -173,7 +180,7 @@ public final class LoginDecoder extends StatefulFrameDecoder
String password = ChannelBufferUtil.readString(securePayload);
if (username.length() > 12 || password.length() > 20) {
- throw new Exception("Username or password too long");
+ throw new Exception("Username or password too long.");
}
int[] seed = new int[4];
@@ -196,11 +203,10 @@ public final class LoginDecoder extends StatefulFrameDecoder
if (buffer.readable()) {
return new Object[] { req, buffer.readBytes(buffer.readableBytes()) };
- } else {
- return req;
}
+ return req;
}
return null;
}
-}
+}
\ No newline at end of file