@Override public void handle(NetworkContext context, MessageForgeHandshakeInOutAck message) { Session session = context.getSession(); Attribute<ForgeServerHandshakePhase> phase = context.getChannel().attr(ForgeHandshakePhase.PHASE); switch (phase.get()) { case WAITING_ACK: if (!message.getPhase().equals(ForgeClientHandshakePhase.WAITING_SERVER_DATA)) { session.disconnect( "Retrieved unexpected forge handshake ack message. (Got " + message.getPhase() + ", expected " + ForgeClientHandshakePhase.WAITING_SERVER_DATA + ")"); } else { List<MessageForgeHandshakeOutRegistryData.Entry> entries = Lists.newArrayList(); entries.add( new MessageForgeHandshakeOutRegistryData.Entry( "fml:items", Maps.newHashMap(), Lists.newArrayList())); entries.add( new MessageForgeHandshakeOutRegistryData.Entry( "fml:blocks", Maps.newHashMap(), Lists.newArrayList())); session.send(new MessageForgeHandshakeOutRegistryData(entries)); session.send(new MessageForgeHandshakeInOutAck(ForgeServerHandshakePhase.WAITING_ACK)); phase.set(ForgeServerHandshakePhase.COMPLETE); } LanternGame.log() .info( "{}: Forge handshake -> Received ack (waitingServerData) message.", session.getGameProfile().getName()); break; case COMPLETE: if (!message.getPhase().equals(ForgeClientHandshakePhase.WAITING_SERVER_COMPLETE)) { session.disconnect( "Retrieved unexpected forge handshake ack message. (Got " + message.getPhase() + ", expected " + ForgeClientHandshakePhase.WAITING_SERVER_COMPLETE + ")"); } else { session.send(new MessageForgeHandshakeInOutAck(ForgeServerHandshakePhase.COMPLETE)); phase.set(ForgeServerHandshakePhase.DONE); } LanternGame.log() .info( "{}: Forge handshake -> Received ack (waitingServerComplete) message.", session.getGameProfile().getName()); break; case DONE: if (!message.getPhase().equals(ForgeClientHandshakePhase.PENDING_COMPLETE) && !message.getPhase().equals(ForgeClientHandshakePhase.COMPLETE)) { session.disconnect( "Retrieved unexpected forge handshake ack message. (Got " + message.getPhase() + ", expected " + ForgeClientHandshakePhase.PENDING_COMPLETE + " or " + ForgeClientHandshakePhase.COMPLETE + ")"); } else { if (message.getPhase().equals(ForgeClientHandshakePhase.PENDING_COMPLETE)) { session.send(new MessageForgeHandshakeInOutAck(ForgeServerHandshakePhase.DONE)); LanternGame.log() .info( "{}: Forge handshake -> Received ack (pendingComplete) message.", session.getGameProfile().getName()); } else { session.setProtocolState(ProtocolState.PLAY); session.spawnPlayer(); LanternGame.log() .info( "{}: Forge handshake -> Received ack (complete) message.", session.getGameProfile().getName()); } } break; case ERROR: break; default: session.disconnect( "Retrieved unexpected forge handshake ack message. (Got " + message.getPhase() + ")"); } }
@Override public void handle(NetworkContext context, MessageLoginInEncryptionResponse message) { Session session = context.getSession(); PrivateKey privateKey = session.getServer().getKeyPair().getPrivate(); // Create rsaCipher Cipher rsaCipher; try { rsaCipher = Cipher.getInstance("RSA"); } catch (GeneralSecurityException e) { LanternGame.log().error("Could not initialize RSA cipher", e); session.disconnect("Unable to initialize RSA cipher."); return; } // Decrypt shared secret SecretKey sharedSecret; try { rsaCipher.init(Cipher.DECRYPT_MODE, privateKey); sharedSecret = new SecretKeySpec(rsaCipher.doFinal(message.getSharedSecret()), "AES"); } catch (Exception e) { LanternGame.log().warn("Could not decrypt shared secret", e); session.disconnect("Unable to decrypt shared secret."); return; } // Decrypt verify token byte[] verifyToken; try { rsaCipher.init(Cipher.DECRYPT_MODE, privateKey); verifyToken = rsaCipher.doFinal(message.getVerifyToken()); } catch (Exception e) { LanternGame.log().warn("Could not decrypt verify token", e); session.disconnect("Unable to decrypt verify token."); return; } // Check verify token if (!Arrays.equals(verifyToken, session.getVerifyToken())) { session.disconnect("Invalid verify token."); return; } // Initialize stream encryption session.setEncryption(sharedSecret); // Create hash for auth String hash; try { MessageDigest digest = MessageDigest.getInstance("SHA-1"); String sessionId = context.getChannel().attr(HandlerLoginStart.SESSION_ID).getAndRemove(); digest.update(sessionId.getBytes()); digest.update(sharedSecret.getEncoded()); digest.update(session.getServer().getKeyPair().getPublic().getEncoded()); // BigInteger takes care of sign and leading zeroes hash = new BigInteger(digest.digest()).toString(16); } catch (NoSuchAlgorithmException e) { LanternGame.log().error("Unable to generate SHA-1 digest", e); session.disconnect("Failed to hash login data."); return; } // Start auth thread Thread clientAuthThread = new Thread(new ClientAuthRunnable(session, session.getVerifyUsername(), hash)); clientAuthThread.setName("ClientAuth{" + session.getVerifyUsername() + "}"); clientAuthThread.start(); }