Esempio n. 1
0
        public static void EncryptionKeyRequest(MinecraftClient client, IPacket _packet)
        {
            var packet = (EncryptionKeyRequestPacket)_packet;
            var random = RandomNumberGenerator.Create();
            client.SharedSecret = new byte[16];
            random.GetBytes(client.SharedSecret); // Generate a secure AES key

            if (packet.ServerId != "-") // Online mode
            {
                // Authenticate with minecraft.net
                if (!client.Session.OnlineMode)
                    throw new AuthenticationException("Server is in online mode, but client is in offline mode.");
                var data = Encoding.ASCII.GetBytes(packet.ServerId)
                    .Concat(client.SharedSecret)
                    .Concat(packet.PublicKey).ToArray();
                var hash = Cryptography.JavaHexDigest(data);
                var webClient = new WebClient();
                string result = webClient.DownloadString("http://session.minecraft.net/game/joinserver.jsp?user="******"&sessionId=" + Uri.EscapeUriString(client.Session.SessionId) +
                    "&serverId=" + Uri.EscapeUriString(hash));
                if (result != "OK")
                {
                    // TODO
                }
            }

            var parser = new AsnKeyParser(packet.PublicKey);
            var key = parser.ParseRSAPublicKey();

            // Encrypt shared secret and verification token
            var crypto = new RSACryptoServiceProvider();
            crypto.ImportParameters(key);
            var encryptedSharedSecret = crypto.Encrypt(client.SharedSecret, false);
            var encryptedVerification = crypto.Encrypt(packet.VerificationToken, false);
            var response = new EncryptionKeyResponsePacket(encryptedSharedSecret, encryptedVerification);
            client.SendPacket(response);
            client.FlushPackets();
            client.NetworkManager.BaseStream = new AesStream(client.NetworkStream, client.SharedSecret);
        }
Esempio n. 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="******"&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();
        }
Esempio n. 3
0
        private void FinializeServerEncryption(EncryptionKeyResponsePacket encryptionKeyResponsePacket)
        {
            // Here, we have all the details we need to initialize our
            // proxy<->server crypto stream. This happens *after* we have
            // already completed the crypto handshake with the client.

            // Wrap the server stream in a crypto stream
            ServerStream = new MinecraftStream(new BufferedStream(new AesStream(Server, ServerSharedKey)));
            Log.Write("Encrypted server connection established.");

            // Write the response. This is the first encrypted packet
            // sent to the client. The correct response is to send
            // an 0xFC EncryptionKeyResponse with both fields as empty
            // arrays.
            var response = new EncryptionKeyResponsePacket
            {
                SharedSecret = new byte[0],
                VerificationToken = new byte[0]
            };
            response.WritePacket(ClientStream);
            ClientStream.Flush();

            // Wrap the client stream in a crypto stream
            ClientStream = new MinecraftStream(new BufferedStream(new AesStream(Client, ClientSharedKey)));
            Log.Write("Encrypted client connection established.");

            // And now we're done with encryption and everything can
            // continue normally.
        }
Esempio n. 4
0
        private bool FinializeClientEncryption(EncryptionKeyResponsePacket encryptionKeyResponsePacket)
        {
            // Here, we need to prepare everything to enable client<->proxy
            // encryption, but we can't turn it on quite yet.

            // Decrypt shared secret
            ClientSharedKey = CryptoServiceProvider.Decrypt(encryptionKeyResponsePacket.SharedSecret, false);
            var verificationToken = CryptoServiceProvider.Decrypt(encryptionKeyResponsePacket.VerificationToken, false);
            // Check verification token
            for (int i = 0; i < verificationToken.Length; i++)
            {
                if (verificationToken[i] != ClientVerificationToken[i])
                    Log.Write("WARNING: Client verification token does not match!");
            }
            if (Settings.AuthenticateClients)
            {
                // Do authentication
                // Create a hash for session verification
                AsnKeyBuilder.AsnMessage encodedKey = AsnKeyBuilder.PublicKeyToX509(ServerKey);
                byte[] shaData = Encoding.UTF8.GetBytes(ClientAuthenticationHash)
                    .Concat(ClientSharedKey)
                    .Concat(encodedKey.GetBytes()).ToArray();
                string hash = Cryptography.JavaHexDigest(shaData);

                var client = new WebClient();
                var result = client.DownloadString(string.Format("http://session.minecraft.net/game/checkserver.jsp?user={0}&serverId={1}",
                    PlayerName, hash));
                if (result != "YES")
                {
                    Log.Write("Failed to authenticate " + PlayerName + "!");
                    new DisconnectPacket("Failed to authenticate!").WritePacket(ServerStream);
                    new DisconnectPacket("Failed to authenticate!").WritePacket(ClientStream);
                    ServerStream.Flush();
                    ClientStream.Flush();
                    return false;
                }
            }

            // Send unencrypted response
            ServerEncryptionResponse.WritePacket(ServerStream);
            ServerStream.Flush();

            // We wait for the server to respond, then set up encryption
            // for both sides of the connection.
            return true;
        }
Esempio n. 5
0
        private bool FinializeClientEncryption(EncryptionKeyResponsePacket encryptionKeyResponsePacket)
        {
            // Here, we need to prepare everything to enable client<->proxy
            // encryption, but we can't turn it on quite yet.

            if (Settings.AuthenticateClients)
            {
                // Do authentication
                // Create a hash for session verification
                AsnKeyBuilder.AsnMessage encodedKey = AsnKeyBuilder.PublicKeyToX509(ServerKey);
                byte[] shaData = Encoding.UTF8.GetBytes(ClientAuthenticationHash)
                    .Concat(ClientSharedKey)
                    .Concat(encodedKey.GetBytes()).ToArray();
                string hash = Cryptography.JavaHexDigest(shaData);

                var client = new WebClient();
                var result = client.DownloadString(string.Format("http://session.minecraft.net/game/checkserver.jsp?user={0}&serverId={1}",
                    PlayerName, hash));
                if (result != "YES")
                {
                    Log.Write("Failed to authenticate " + PlayerName + "!");
                    ServerStream.WritePacket(new DisconnectPacket("Failed to authenticate!"), Craft.Net.PacketDirection.Serverbound);
                    ClientStream.WritePacket(new DisconnectPacket("Failed to authenticate!"), Craft.Net.PacketDirection.Clientbound);
                    Server.Flush();
                    Client.Flush();
                    return false;
                }
            }

            // Send unencrypted response
            ServerStream.WritePacket(ServerEncryptionResponse, Craft.Net.PacketDirection.Serverbound);
            Server.Flush();

            // We wait for the server to respond, then set up encryption
            // for both sides of the connection.
            ServerStream.BaseStream = new AesStream(Server, ServerSharedKey);
            return true;
        }