mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2025-10-14 21:22:49 +00:00
Rewrote AES stream & Perform "SessionCheck" in advance
This commit is contained in:
parent
a3971f9097
commit
13d1a9856a
28 changed files with 306 additions and 2807 deletions
|
|
@ -235,13 +235,13 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
{
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int k = 0;
|
||||
byte b;
|
||||
while (true)
|
||||
{
|
||||
k = socket.ReadDataRAW(1)[0];
|
||||
i |= (k & 0x7F) << j++ * 7;
|
||||
b = socket.ReadDataRAW(1)[0];
|
||||
i |= (b & 0x7F) << j++ * 7;
|
||||
if (j > 5) throw new OverflowException("VarInt too big");
|
||||
if ((k & 0x80) != 128) break;
|
||||
if ((b & 0x80) != 128) break;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
|
@ -259,9 +259,9 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
do
|
||||
{
|
||||
b = cache.Dequeue();
|
||||
i |= (b & 127) << j++ * 7;
|
||||
i |= (b & 0x7F) << j++ * 7;
|
||||
if (j > 5) throw new OverflowException("VarInt too big");
|
||||
} while ((b & 128) == 128);
|
||||
} while ((b & 0x80) == 128);
|
||||
return i;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ using System.Security.Cryptography;
|
|||
using MinecraftClient.Mapping;
|
||||
using MinecraftClient.Inventory;
|
||||
using MinecraftClient.Protocol.Keys;
|
||||
using MinecraftClient.Protocol.Session;
|
||||
|
||||
namespace MinecraftClient.Protocol.Handlers
|
||||
{
|
||||
|
|
@ -439,7 +440,7 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
else c.Client.Send(buffer);
|
||||
}
|
||||
|
||||
private bool Handshake(string uuid, string username, string sessionID, string host, int port)
|
||||
private bool Handshake(string uuid, string username, string sessionID, string host, int port, SessionToken session)
|
||||
{
|
||||
//array
|
||||
byte[] data = new byte[10 + (username.Length + host.Length) * 2];
|
||||
|
|
@ -493,7 +494,7 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
else if (Settings.DebugMessages)
|
||||
ConsoleIO.WriteLineFormatted(Translations.Get("mcc.handshake", serverID));
|
||||
|
||||
return StartEncryption(uuid, username, sessionID, token, serverID, PublicServerkey);
|
||||
return StartEncryption(uuid, username, sessionID, token, serverID, PublicServerkey, session);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -502,10 +503,10 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
}
|
||||
}
|
||||
|
||||
private bool StartEncryption(string uuid, string username, string sessionID, byte[] token, string serverIDhash, byte[] serverKey)
|
||||
private bool StartEncryption(string uuid, string username, string sessionID, byte[] token, string serverIDhash, byte[] serverPublicKey, SessionToken session)
|
||||
{
|
||||
System.Security.Cryptography.RSACryptoServiceProvider RSAService = CryptoHandler.DecodeRSAPublicKey(serverKey);
|
||||
byte[] secretKey = CryptoHandler.GenerateAESPrivateKey();
|
||||
RSACryptoServiceProvider RSAService = CryptoHandler.DecodeRSAPublicKey(serverPublicKey);
|
||||
byte[] secretKey = CryptoHandler.ClientAESPrivateKey ?? CryptoHandler.GenerateAESPrivateKey();
|
||||
|
||||
if (Settings.DebugMessages)
|
||||
Translations.WriteLineFormatted("debug.crypto");
|
||||
|
|
@ -513,13 +514,34 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
if (serverIDhash != "-")
|
||||
{
|
||||
Translations.WriteLine("mcc.session");
|
||||
if (!ProtocolHandler.SessionCheck(uuid, sessionID, CryptoHandler.getServerHash(serverIDhash, serverKey, secretKey)))
|
||||
string serverHash = CryptoHandler.getServerHash(serverIDhash, serverPublicKey, secretKey);
|
||||
|
||||
bool needCheckSession = true;
|
||||
if (session.ServerPublicKey != null && session.SessionPreCheckTask != null
|
||||
&& serverIDhash == session.ServerIDhash && Enumerable.SequenceEqual(serverPublicKey, session.ServerPublicKey))
|
||||
{
|
||||
handler.OnConnectionLost(ChatBot.DisconnectReason.LoginRejected, Translations.Get("mcc.session_fail"));
|
||||
return false;
|
||||
session.SessionPreCheckTask.Wait();
|
||||
if (session.SessionPreCheckTask.Result) // PreCheck Successed
|
||||
needCheckSession = false;
|
||||
}
|
||||
|
||||
if (needCheckSession)
|
||||
{
|
||||
if (ProtocolHandler.SessionCheck(uuid, sessionID, serverHash))
|
||||
{
|
||||
session.ServerIDhash = serverIDhash;
|
||||
session.ServerPublicKey = serverPublicKey;
|
||||
SessionCache.Store(Settings.Login.ToLower(), session);
|
||||
}
|
||||
else
|
||||
{
|
||||
handler.OnConnectionLost(ChatBot.DisconnectReason.LoginRejected, Translations.Get("mcc.session_fail"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Encrypt the data
|
||||
byte[] key_enc = RSAService.Encrypt(secretKey, false);
|
||||
byte[] token_enc = RSAService.Encrypt(token, false);
|
||||
|
|
@ -557,9 +579,9 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
}
|
||||
}
|
||||
|
||||
public bool Login(PlayerKeyPair playerKeyPair)
|
||||
public bool Login(PlayerKeyPair? playerKeyPair, SessionToken session)
|
||||
{
|
||||
if (Handshake(handler.GetUserUUID(), handler.GetUsername(), handler.GetSessionID(), handler.GetServerHost(), handler.GetServerPort()))
|
||||
if (Handshake(handler.GetUserUUID(), handler.GetUsername(), handler.GetSessionID(), handler.GetServerHost(), handler.GetServerPort(), session))
|
||||
{
|
||||
Send(new byte[] { 0xCD, 0 });
|
||||
try
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ using MinecraftClient.Logger;
|
|||
using System.Threading.Tasks;
|
||||
using MinecraftClient.Protocol.Keys;
|
||||
using System.Text.RegularExpressions;
|
||||
using MinecraftClient.Protocol.Session;
|
||||
|
||||
namespace MinecraftClient.Protocol.Handlers
|
||||
{
|
||||
|
|
@ -1534,7 +1535,7 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
/// Do the Minecraft login.
|
||||
/// </summary>
|
||||
/// <returns>True if login successful</returns>
|
||||
public bool Login(PlayerKeyPair? playerKeyPair)
|
||||
public bool Login(PlayerKeyPair? playerKeyPair, SessionToken session)
|
||||
{
|
||||
byte[] protocol_version = dataTypes.GetVarInt(protocolversion);
|
||||
string server_address = pForge.GetServerAddress(handler.GetServerHost());
|
||||
|
|
@ -1574,7 +1575,7 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
string serverID = dataTypes.ReadNextString(packetData);
|
||||
byte[] serverPublicKey = dataTypes.ReadNextByteArray(packetData);
|
||||
byte[] token = dataTypes.ReadNextByteArray(packetData);
|
||||
return StartEncryption(handler.GetUserUUID(), handler.GetSessionID(), token, serverID, serverPublicKey, playerKeyPair);
|
||||
return StartEncryption(handler.GetUserUUID(), handler.GetSessionID(), token, serverID, serverPublicKey, playerKeyPair, session);
|
||||
}
|
||||
else if (packetID == 0x02) //Login successful
|
||||
{
|
||||
|
|
@ -1598,24 +1599,43 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
/// Start network encryption. Automatically called by Login() if the server requests encryption.
|
||||
/// </summary>
|
||||
/// <returns>True if encryption was successful</returns>
|
||||
private bool StartEncryption(string uuid, string sessionID, byte[] token, string serverIDhash, byte[] serverPublicKey, PlayerKeyPair? playerKeyPair)
|
||||
private bool StartEncryption(string uuid, string sessionID, byte[] token, string serverIDhash, byte[] serverPublicKey, PlayerKeyPair? playerKeyPair, SessionToken session)
|
||||
{
|
||||
System.Security.Cryptography.RSACryptoServiceProvider RSAService = CryptoHandler.DecodeRSAPublicKey(serverPublicKey);
|
||||
byte[] secretKey = CryptoHandler.GenerateAESPrivateKey();
|
||||
RSACryptoServiceProvider RSAService = CryptoHandler.DecodeRSAPublicKey(serverPublicKey);
|
||||
byte[] secretKey = CryptoHandler.ClientAESPrivateKey ?? CryptoHandler.GenerateAESPrivateKey();
|
||||
|
||||
log.Debug(Translations.Get("debug.crypto"));
|
||||
|
||||
if (serverIDhash != "-")
|
||||
{
|
||||
log.Info(Translations.Get("mcc.session"));
|
||||
if (!ProtocolHandler.SessionCheck(uuid, sessionID, CryptoHandler.getServerHash(serverIDhash, serverPublicKey, secretKey)))
|
||||
string serverHash = CryptoHandler.getServerHash(serverIDhash, serverPublicKey, secretKey);
|
||||
|
||||
bool needCheckSession = true;
|
||||
if (session.ServerPublicKey != null && session.SessionPreCheckTask != null
|
||||
&& serverIDhash == session.ServerIDhash && Enumerable.SequenceEqual(serverPublicKey, session.ServerPublicKey))
|
||||
{
|
||||
handler.OnConnectionLost(ChatBot.DisconnectReason.LoginRejected, Translations.Get("mcc.session_fail"));
|
||||
return false;
|
||||
session.SessionPreCheckTask.Wait();
|
||||
if (session.SessionPreCheckTask.Result) // PreCheck Successed
|
||||
needCheckSession = false;
|
||||
}
|
||||
|
||||
if (needCheckSession)
|
||||
{
|
||||
if (ProtocolHandler.SessionCheck(uuid, sessionID, serverHash))
|
||||
{
|
||||
session.ServerIDhash = serverIDhash;
|
||||
session.ServerPublicKey = serverPublicKey;
|
||||
SessionCache.Store(Settings.Login.ToLower(), session);
|
||||
}
|
||||
else
|
||||
{
|
||||
handler.OnConnectionLost(ChatBot.DisconnectReason.LoginRejected, Translations.Get("mcc.session_fail"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Encryption Response packet
|
||||
List<byte> encryptionResponse = new();
|
||||
encryptionResponse.AddRange(dataTypes.GetArray(RSAService.Encrypt(secretKey, false))); // Shared Secret
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace MinecraftClient.Protocol
|
|||
/// Start the login procedure once connected to the server
|
||||
/// </summary>
|
||||
/// <returns>True if login was successful</returns>
|
||||
bool Login(PlayerKeyPair playerKeyPair);
|
||||
bool Login(PlayerKeyPair? playerKeyPair, Session.SessionToken session);
|
||||
|
||||
/// <summary>
|
||||
/// Disconnect from the server
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ namespace MinecraftClient.Protocol.Keys
|
|||
{
|
||||
private static string certificates = "https://api.minecraftservices.com/player/certificates";
|
||||
|
||||
public static PlayerKeyPair? GetKeys(string accessToken)
|
||||
public static PlayerKeyPair? GetNewProfileKeys(string accessToken)
|
||||
{
|
||||
ProxiedWebRequest.Response? response = null;
|
||||
try
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ namespace MinecraftClient.Protocol.Session
|
|||
|
||||
List<string> sessionCacheLines = new List<string>();
|
||||
sessionCacheLines.Add("# Generated by MCC v" + Program.Version + " - Keep it secret & Edit at own risk!");
|
||||
sessionCacheLines.Add("# Login=SessionID,PlayerName,UUID,ClientID");
|
||||
sessionCacheLines.Add("# Login=SessionID,PlayerName,UUID,ClientID,RefreshToken,ServerIDhash,ServerPublicKey");
|
||||
foreach (KeyValuePair<string, SessionToken> entry in sessions)
|
||||
sessionCacheLines.Add(entry.Key + '=' + entry.Value.ToString());
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MinecraftClient.Protocol.Session
|
||||
{
|
||||
|
|
@ -15,6 +16,10 @@ namespace MinecraftClient.Protocol.Session
|
|||
public string PlayerID { get; set; }
|
||||
public string ClientID { get; set; }
|
||||
public string RefreshToken { get; set; }
|
||||
public string ServerIDhash { get; set; }
|
||||
public byte[]? ServerPublicKey { get; set; }
|
||||
|
||||
public Task<bool>? SessionPreCheckTask = null;
|
||||
|
||||
public SessionToken()
|
||||
{
|
||||
|
|
@ -23,11 +28,26 @@ namespace MinecraftClient.Protocol.Session
|
|||
PlayerID = String.Empty;
|
||||
ClientID = String.Empty;
|
||||
RefreshToken = String.Empty;
|
||||
ServerIDhash = String.Empty;
|
||||
ServerPublicKey = null;
|
||||
}
|
||||
|
||||
public bool SessionPreCheck()
|
||||
{
|
||||
if (this.ID == string.Empty || this.PlayerID == String.Empty || this.ServerPublicKey == null)
|
||||
return false;
|
||||
if (Crypto.CryptoHandler.ClientAESPrivateKey == null)
|
||||
Crypto.CryptoHandler.ClientAESPrivateKey = Crypto.CryptoHandler.GenerateAESPrivateKey();
|
||||
string serverHash = Crypto.CryptoHandler.getServerHash(ServerIDhash, ServerPublicKey, Crypto.CryptoHandler.ClientAESPrivateKey);
|
||||
if (ProtocolHandler.SessionCheck(PlayerID, ID, serverHash))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Join(",", ID, PlayerName, PlayerID, ClientID, RefreshToken);
|
||||
return String.Join(",", ID, PlayerName, PlayerID, ClientID, RefreshToken, ServerIDhash,
|
||||
(ServerPublicKey == null) ? String.Empty : Convert.ToBase64String(ServerPublicKey));
|
||||
}
|
||||
|
||||
public static SessionToken FromString(string tokenString)
|
||||
|
|
@ -46,6 +66,23 @@ namespace MinecraftClient.Protocol.Session
|
|||
session.RefreshToken = fields[4];
|
||||
else
|
||||
session.RefreshToken = String.Empty;
|
||||
if (fields.Length > 5)
|
||||
session.ServerIDhash = fields[5];
|
||||
else
|
||||
session.ServerIDhash = String.Empty;
|
||||
if (fields.Length > 6)
|
||||
{
|
||||
try
|
||||
{
|
||||
session.ServerPublicKey = Convert.FromBase64String(fields[6]);
|
||||
}
|
||||
catch
|
||||
{
|
||||
session.ServerPublicKey = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
session.ServerPublicKey = null;
|
||||
|
||||
Guid temp;
|
||||
if (!JwtRegex.IsMatch(session.ID))
|
||||
|
|
@ -60,5 +97,7 @@ namespace MinecraftClient.Protocol.Session
|
|||
|
||||
return session;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue