2022-08-15 23:55:44 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
using MinecraftClient.Protocol.Keys;
|
2022-08-27 02:10:44 +08:00
|
|
|
|
using MinecraftClient.Protocol.Message;
|
2022-08-15 23:55:44 +08:00
|
|
|
|
|
|
|
|
|
|
namespace MinecraftClient.Protocol
|
|
|
|
|
|
{
|
|
|
|
|
|
public class PlayerInfo
|
|
|
|
|
|
{
|
2022-08-27 02:10:44 +08:00
|
|
|
|
public readonly Guid Uuid;
|
2022-08-15 23:55:44 +08:00
|
|
|
|
|
|
|
|
|
|
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;
|
2022-08-15 23:55:44 +08:00
|
|
|
|
|
|
|
|
|
|
public int Gamemode;
|
|
|
|
|
|
|
|
|
|
|
|
public int Ping;
|
|
|
|
|
|
|
|
|
|
|
|
public string? DisplayName;
|
|
|
|
|
|
|
2022-09-09 16:13:25 +08:00
|
|
|
|
// Entity info
|
|
|
|
|
|
|
|
|
|
|
|
public Mapping.Entity? entity;
|
|
|
|
|
|
|
|
|
|
|
|
// For message signature
|
|
|
|
|
|
|
2022-08-15 23:55:44 +08:00
|
|
|
|
private readonly PublicKey? PublicKey;
|
|
|
|
|
|
|
|
|
|
|
|
private readonly 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-15 23:55:44 +08:00
|
|
|
|
{
|
2022-08-27 02:10:44 +08:00
|
|
|
|
Uuid = uuid;
|
2022-08-15 23:55:44 +08:00
|
|
|
|
Name = name;
|
|
|
|
|
|
if (property != null)
|
|
|
|
|
|
Property = property;
|
|
|
|
|
|
Gamemode = gamemode;
|
|
|
|
|
|
Ping = ping;
|
|
|
|
|
|
DisplayName = displayName;
|
|
|
|
|
|
if (timeStamp != null && publicKey != null && signature != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds((long)timeStamp);
|
|
|
|
|
|
KeyExpiresAt = dateTimeOffset.UtcDateTime;
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
PublicKey = new PublicKey(publicKey, signature);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (System.Security.Cryptography.CryptographicException)
|
|
|
|
|
|
{
|
|
|
|
|
|
PublicKey = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-08-27 02:10:44 +08:00
|
|
|
|
lastMessageVerified = true;
|
|
|
|
|
|
precedingSignature = null;
|
2022-08-15 23:55:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public PlayerInfo(string name, Guid uuid)
|
|
|
|
|
|
{
|
|
|
|
|
|
Name = name;
|
2022-08-27 02:10:44 +08:00
|
|
|
|
Uuid = uuid;
|
2022-08-15 23:55:44 +08:00
|
|
|
|
Gamemode = -1;
|
|
|
|
|
|
Ping = 0;
|
2022-08-27 02:10:44 +08:00
|
|
|
|
lastMessageVerified = true;
|
|
|
|
|
|
precedingSignature = null;
|
2022-08-15 23:55:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-08-27 02:10:44 +08:00
|
|
|
|
public bool IsMessageChainLegal()
|
2022-08-15 23:55:44 +08:00
|
|
|
|
{
|
2022-08-27 02:10:44 +08:00
|
|
|
|
return this.lastMessageVerified;
|
2022-08-15 23:55:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-08-27 02:10:44 +08:00
|
|
|
|
public bool IsKeyExpired()
|
2022-08-15 23:55:44 +08:00
|
|
|
|
{
|
2022-08-27 02:10:44 +08:00
|
|
|
|
return DateTime.Now.ToUniversalTime() > this.KeyExpiresAt;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <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())
|
2022-08-15 23:55:44 +08:00
|
|
|
|
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-15 23:55:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-08-27 02:10:44 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Verify message - 1.19.1 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, long timestamp, long salt, ref byte[] signature, ref byte[]? precedingSignature, LastSeenMessageList lastSeenMessages)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (this.lastMessageVerified == false)
|
|
|
|
|
|
return false;
|
|
|
|
|
|
if (PublicKey == null || IsKeyExpired() || (this.precedingSignature != null && precedingSignature == null))
|
|
|
|
|
|
return false;
|
|
|
|
|
|
if (this.precedingSignature != null && !this.precedingSignature.SequenceEqual(precedingSignature!))
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
|
|
this.lastMessageVerified = res;
|
|
|
|
|
|
this.precedingSignature = signature;
|
|
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Verify message head - 1.19.1 and above
|
|
|
|
|
|
/// </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 (this.lastMessageVerified == false)
|
|
|
|
|
|
return false;
|
|
|
|
|
|
if (PublicKey == null || IsKeyExpired() || (this.precedingSignature != null && precedingSignature == null))
|
|
|
|
|
|
return false;
|
|
|
|
|
|
if (this.precedingSignature != null && !this.precedingSignature.SequenceEqual(precedingSignature!))
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
this.lastMessageVerified = res;
|
|
|
|
|
|
this.precedingSignature = headerSignature;
|
|
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
|
}
|
2022-08-15 23:55:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|