Minecraft-Console-Client/MinecraftClient/Protocol/PlayerInfo.cs

223 lines
7.8 KiB
C#
Raw Normal View History

using System;
using System.Linq;
2022-08-27 02:10:44 +08:00
using MinecraftClient.Protocol.Message;
using MinecraftClient.Protocol.ProfileKey;
namespace MinecraftClient.Protocol
{
public class PlayerInfo
{
2022-08-27 02:10:44 +08:00
public readonly Guid Uuid;
public readonly string Name;
// Tuple<Name, Value, Signature(empty if there is no signature)
2022-08-28 23:34:28 +08:00
public readonly Tuple<string, string, string?>[]? Property;
public int Gamemode;
public int Ping;
public string? DisplayName;
2023-01-13 16:12:10 +08:00
public bool Listed = true;
2022-09-09 16:13:25 +08:00
// Entity info
public Mapping.Entity? entity;
// For message signature
2023-01-14 02:41:03 +08:00
public int MessageIndex = -1;
2023-01-13 16:12:10 +08:00
public Guid ChatUuid = Guid.Empty;
private PublicKey? PublicKey;
2023-01-13 16:12:10 +08:00
private DateTime? KeyExpiresAt;
2022-08-27 02:10:44 +08:00
private bool lastMessageVerified;
private byte[]? precedingSignature;
2022-08-28 23:34:28 +08:00
public PlayerInfo(Guid uuid, string name, Tuple<string, string, string?>[]? property, int gamemode, int ping, string? displayName, long? timeStamp, byte[]? publicKey, byte[]? signature)
{
2022-08-27 02:10:44 +08:00
Uuid = uuid;
Name = name;
if (property != null)
Property = property;
Gamemode = gamemode;
Ping = ping;
DisplayName = displayName;
2022-09-12 19:02:08 +08:00
lastMessageVerified = false;
if (timeStamp != null && publicKey != null && signature != null)
{
DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds((long)timeStamp);
KeyExpiresAt = dateTimeOffset.UtcDateTime;
try
{
PublicKey = new PublicKey(publicKey, signature);
2022-09-12 19:02:08 +08:00
lastMessageVerified = true;
}
catch (System.Security.Cryptography.CryptographicException)
{
PublicKey = null;
}
}
2022-08-27 02:10:44 +08:00
precedingSignature = null;
}
public PlayerInfo(string name, Guid uuid)
{
Name = name;
2022-08-27 02:10:44 +08:00
Uuid = uuid;
Gamemode = -1;
Ping = 0;
2022-08-27 02:10:44 +08:00
lastMessageVerified = true;
precedingSignature = null;
}
2023-01-13 16:12:10 +08:00
public void ClearPublicKey()
{
ChatUuid = Guid.Empty;
PublicKey = null;
KeyExpiresAt = null;
}
public void SetPublicKey(Guid chatUuid, long publicKeyExpiryTime, byte[] encodedPublicKey, byte[] publicKeySignature)
{
ChatUuid = chatUuid;
KeyExpiresAt = DateTimeOffset.FromUnixTimeMilliseconds(publicKeyExpiryTime).UtcDateTime;
try
{
PublicKey = new PublicKey(encodedPublicKey, publicKeySignature);
lastMessageVerified = true;
}
catch (System.Security.Cryptography.CryptographicException)
{
PublicKey = null;
}
}
2022-08-27 02:10:44 +08:00
public bool IsMessageChainLegal()
{
return lastMessageVerified;
}
2022-08-27 02:10:44 +08:00
public bool IsKeyExpired()
{
return DateTime.Now.ToUniversalTime() > KeyExpiresAt;
2022-08-27 02:10:44 +08:00
}
/// <summary>
/// Verify message - 1.19
/// </summary>
/// <param name="message">Message content</param>
/// <param name="timestamp">Timestamp</param>
/// <param name="salt">Salt</param>
/// <param name="signature">Message signature</param>
/// <returns>Is this message vaild</returns>
public bool VerifyMessage(string message, long timestamp, long salt, ref byte[] signature)
{
if (PublicKey == null || IsKeyExpired())
return false;
else
{
DateTimeOffset timeOffset = DateTimeOffset.FromUnixTimeMilliseconds(timestamp);
byte[] saltByte = BitConverter.GetBytes(salt);
Array.Reverse(saltByte);
2022-08-27 02:10:44 +08:00
return PublicKey.VerifyMessage(message, Uuid, timeOffset, ref saltByte, ref signature);
}
}
2022-08-27 02:10:44 +08:00
/// <summary>
2023-01-14 02:41:03 +08:00
/// Verify message - 1.19.1 and 1.19.2
2022-08-27 02:10:44 +08:00
/// </summary>
/// <param name="message">Message content</param>
/// <param name="timestamp">Timestamp</param>
/// <param name="salt">Salt</param>
/// <param name="signature">Message signature</param>
/// <param name="precedingSignature">Preceding message signature</param>
/// <param name="lastSeenMessages">LastSeenMessages</param>
/// <returns>Is this message chain vaild</returns>
public bool VerifyMessage(string message, long timestamp, long salt, ref byte[] signature, ref byte[]? precedingSignature, LastSeenMessageList lastSeenMessages)
{
if (lastMessageVerified == false)
2022-08-27 02:10:44 +08:00
return false;
if (PublicKey == null || IsKeyExpired() || (this.precedingSignature != null && precedingSignature == null))
2022-09-12 19:02:08 +08:00
{
lastMessageVerified = false;
2022-08-27 02:10:44 +08:00
return false;
2022-09-12 19:02:08 +08:00
}
2022-08-27 02:10:44 +08:00
if (this.precedingSignature != null && !this.precedingSignature.SequenceEqual(precedingSignature!))
2022-09-12 19:02:08 +08:00
{
lastMessageVerified = false;
2022-08-27 02:10:44 +08:00
return false;
2022-09-12 19:02:08 +08:00
}
2022-08-27 02:10:44 +08:00
DateTimeOffset timeOffset = DateTimeOffset.FromUnixTimeMilliseconds(timestamp);
byte[] saltByte = BitConverter.GetBytes(salt);
Array.Reverse(saltByte);
bool res = PublicKey.VerifyMessage(message, Uuid, timeOffset, ref saltByte, ref signature, ref precedingSignature, lastSeenMessages);
lastMessageVerified = res;
2022-08-27 02:10:44 +08:00
this.precedingSignature = signature;
return res;
}
/// <summary>
2023-01-14 02:41:03 +08:00
/// Verify message head - 1.19.1 and 1.19.2
2022-08-27 02:10:44 +08:00
/// </summary>
/// <param name="precedingSignature">Preceding message signature</param>
/// <param name="headerSignature">Message signature</param>
/// <param name="bodyDigest">Message body hash</param>
/// <returns>Is this message chain vaild</returns>
public bool VerifyMessageHead(ref byte[]? precedingSignature, ref byte[] headerSignature, ref byte[] bodyDigest)
{
if (lastMessageVerified == false)
2022-08-27 02:10:44 +08:00
return false;
if (PublicKey == null || IsKeyExpired() || (this.precedingSignature != null && precedingSignature == null))
2022-09-12 19:02:08 +08:00
{
lastMessageVerified = false;
2022-08-27 02:10:44 +08:00
return false;
2022-09-12 19:02:08 +08:00
}
2022-08-27 02:10:44 +08:00
if (this.precedingSignature != null && !this.precedingSignature.SequenceEqual(precedingSignature!))
2022-09-12 19:02:08 +08:00
{
lastMessageVerified = false;
2022-08-27 02:10:44 +08:00
return false;
2022-09-12 19:02:08 +08:00
}
2022-08-27 02:10:44 +08:00
2022-09-04 17:34:12 +08:00
bool res = PublicKey.VerifyHeader(Uuid, ref bodyDigest, ref headerSignature, ref precedingSignature);
2022-08-27 02:10:44 +08:00
lastMessageVerified = res;
2022-08-27 02:10:44 +08:00
this.precedingSignature = headerSignature;
return res;
}
2023-01-14 02:41:03 +08:00
/// <summary>
/// Verify message - 1.19.3 and above
/// </summary>
/// <param name="message">Message content</param>
/// <param name="timestamp">Timestamp</param>
/// <param name="salt">Salt</param>
/// <param name="signature">Message signature</param>
/// <param name="precedingSignature">Preceding message signature</param>
/// <param name="lastSeenMessages">LastSeenMessages</param>
/// <returns>Is this message chain vaild</returns>
public bool VerifyMessage(string message, Guid playerUuid, Guid chatUuid, int messageIndex, long timestamp, long salt, ref byte[] signature, Tuple<int, byte[]?>[] previousMessageSignatures)
{
if (PublicKey == null || IsKeyExpired())
return false;
// net.minecraft.server.network.ServerPlayNetworkHandler#validateMessage
return true;
}
}
}