public byte[] processHandleAuth_Request(byte[] data) { // RSA version check byte[] neededRSAV = { 0x04, 0x00, 0x00, 0x00 }; byte[] packetRSAV = new byte[4]; // In this packet, RSA starts at offset 3 ArrayUtils.copy(data, 3, packetRSAV, 0, 4); if (!ArrayUtils.equal(neededRSAV, packetRSAV)) { throw new AuthException("Invalid RSA version"); } // Get RSA encrypted blob from the data byte [] blob = new byte[128]; ArrayUtils.copy(data, 44, blob, 0, 128); Output.OptWriteLine("-> Encrypted blob received."); // Get RSA decrypted blob byte[] decryptedBlob = rsa.decryptWithPrivkey(blob); Output.OptWriteLine("-> Blob decoded."); // Copy the Auth TF key from decoded blob. byte [] tfKey = new byte[16]; ArrayUtils.copy(decryptedBlob, 7, tfKey, 0, 16); tf.setIV(blankIV); tf.setKey(tfKey); // Create the challenge challenge = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; byte[] criptedChallenge = new byte[16]; tf.encrypt(challenge, criptedChallenge); md5edChallenge = md5.digest(challenge); // Rajko said this Output.OptWriteLine(" --> Client TF key: " + StringUtils.bytesToString(tfKey)); Output.OptWriteLine(" --> MD5(challenge): " + StringUtils.bytesToString(md5edChallenge)); Output.OptWriteLine(" --> Twofished(challenge): " + StringUtils.bytesToString(criptedChallenge)); // Copy the encrypted thing to the global variable "Challenge" ArrayUtils.copy(criptedChallenge, 0, challenge, 0, 16); int nameLength = decryptedBlob.Length - 30; byte[] nameB = new byte[nameLength]; ArrayUtils.copy(decryptedBlob, 29, nameB, 0, nameLength); // Set WorldList username wl.setUsername(StringUtils.charBytesToString(nameB)); Output.OptWriteLine("-> User login: " + wl.getUsername()); byte[] a = new byte [18]; a[0] = 0x11; // Size a[1] = 0x09; // Answer opcode ArrayUtils.copy(criptedChallenge, 0, a, 2, 16); return(a); }