Example #1
0
        private static EncryptionKeyRequestPacket CreateEncryptionRequest(RemoteClient client, MinecraftServer server)
        {
            var verifyToken = new byte[4];
            var csp = new RNGCryptoServiceProvider();
            csp.GetBytes(verifyToken);
            client.VerificationToken = verifyToken;

            var encodedKey = AsnKeyBuilder.PublicKeyToX509(server.ServerKey);
            var request = new EncryptionKeyRequestPacket(client.ServerId,
                encodedKey.GetBytes(), verifyToken);
            return request;
        }
Example #2
0
        private void InitializeEncryption(EncryptionKeyRequestPacket packet)
        {
            // We have to hijack the encryption here to be able to sniff the
            // connection. What we do is set up two unrelated crypto streams,
            // one for the server, one for the client. We actually act a bit
            // more like a real client or a real server in this particular
            // stage of the connection, because we generate a shared secret
            // as a client and a public key as a server, and liase with each
            // end of the connection without tipping them off to this. After
            // this is done, we wrap the connection in an AesStream and
            // everything works fine.

            // Interact with the server (acting as a client)

            // Generate our shared secret
            var secureRandom = RandomNumberGenerator.Create();
            ServerSharedKey = new byte[16];
            secureRandom.GetBytes(ServerSharedKey);

            // Parse the server public key
            var parser = new AsnKeyParser(packet.PublicKey);
            var key = parser.ParseRSAPublicKey();

            // Encrypt shared secret and verification token
            var crypto = new RSACryptoServiceProvider();
            crypto.ImportParameters(key);
            byte[] encryptedSharedSecret = crypto.Encrypt(ServerSharedKey, false);
            byte[] encryptedVerification = crypto.Encrypt(packet.VerificationToken, false);

            // Create an 0xFC response to give the server
            ServerEncryptionResponse = new EncryptionKeyResponsePacket
            {
                SharedSecret = encryptedSharedSecret,
                VerificationToken = encryptedVerification
            };

            // Authenticate with minecraft.net if need be
            if (packet.ServerId != "-")
            {
                try
                {
                    var session = Session.DoLogin(Settings.Username, Settings.Password);
                    // Generate session hash
                    byte[] hashData = Encoding.ASCII.GetBytes(packet.ServerId)
                        .Concat(ServerSharedKey)
                        .Concat(packet.PublicKey).ToArray();
                    var hash = Cryptography.JavaHexDigest(hashData);
                    var webClient = new WebClient();
                    string result = webClient.DownloadString("http://session.minecraft.net/game/joinserver.jsp?user=" +
                        Uri.EscapeUriString(session.UserName) +
                        "&sessionId=" + Uri.EscapeUriString(session.SessionId) +
                        "&serverId=" + Uri.EscapeUriString(hash));
                    if (result != "OK")
                        Console.WriteLine("Warning: Unable to login as user " + Settings.Username + ": " + result);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Warning: Unable to login as user " + Settings.Username + ": " + e.Message);
                }
            }

            // Interact with the client (acting as a server)

            // Generate verification token
            ClientVerificationToken = new byte[4];
            secureRandom.GetBytes(ClientVerificationToken);
            // Encode public key as an ASN X509 certificate
            var encodedKey = AsnKeyBuilder.PublicKeyToX509(ServerKey);

            if (Settings.AuthenticateClients)
                ClientAuthenticationHash = CreateHash();
            else
                ClientAuthenticationHash = "-";

            ClientEncryptionRequest = new EncryptionKeyRequestPacket
            {
                VerificationToken = ClientVerificationToken,
                ServerId = ClientAuthenticationHash,
                PublicKey = encodedKey.GetBytes()
            };
            // Send the client our encryption details and await its response
            ClientEncryptionRequest.WritePacket(ClientStream);
            ClientStream.Flush();
        }