@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();
  }