@SuppressWarnings("null")
public synchronized void login(String username, String password, String seed)
throws InvalidVersionException, TimeoutException, LoginFailedException,
BannedAddressException {
int received = 0;
RSAPublicKey key = null;
byte[] clientNonce = null;
byte[] serverNonce = null;
/* Send to server a login request and indicate the game name and version */
netMan.addMessage(new MessageC2SLoginRequestKey(null, getGameName(), getVersionNumber()));
int timeout = TIMEOUT;
while (received < 3) {
Message msg = getMessage(timeout);
// Okay, now we know that there is a marauroa server responding to the handshake.
// We can give it more time for the next steps in case the database is slow.
// Loging heavily depends on the database because number of failed logins for both
// ip-address and username, banstatus, username&password have to be checked. And
// the list of characters needs to be loaded from the database.
timeout = TIMEOUT_EXTENDED;
switch (msg.getType()) {
case S2C_INVALIDMESSAGE: {
throw new LoginFailedException(((MessageS2CInvalidMessage) msg).getReason());
}
/* Server sends its public RSA key */
case S2C_LOGIN_SENDKEY: {
logger.debug("Received Key");
key = ((MessageS2CLoginSendKey) msg).getKey();
clientNonce = Hash.random(Hash.hashLength());
netMan.addMessage(new MessageC2SLoginSendPromise(null, Hash.hash(clientNonce)));
break;
}
/* Server sends a random big integer */
case S2C_LOGIN_SENDNONCE: {
logger.debug("Received Server Nonce");
if (serverNonce != null) {
throw new LoginFailedException("Already received a serverNonce");
}
serverNonce = ((MessageS2CLoginSendNonce) msg).getHash();
byte[] b1 = Hash.xor(clientNonce, serverNonce);
if (b1 == null) {
throw new LoginFailedException("Incorrect hash b1");
}
byte[] b2 = Hash.xor(b1, Hash.hash(password));
if (b2 == null) {
throw new LoginFailedException("Incorrect hash b2");
}
byte[] cryptedPassword = key.encodeByteArray(b2);
if (seed != null) {
byte[] bs = null;
try {
bs = seed.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
logger.error(e, e);
}
if (bs.length != 16) {
throw new LoginFailedException("Seed has not the correct length.");
}
byte[] b3 = null;
b3 = Hash.xor(b1, bs);
if (b3 == null) {
throw new LoginFailedException("Incorrect hash seed");
}
byte[] cryptedSeed = key.encodeByteArray(b3);
netMan.addMessage(new MessageC2SLoginSendNonceNamePasswordAndSeed(null,
clientNonce, username, cryptedPassword, cryptedSeed));
} else {
netMan.addMessage(new MessageC2SLoginSendNonceNameAndPassword(null,
clientNonce, username, cryptedPassword));