// System using System; // Unity using UnityEngine; // GUPS - AntiCheat - Core using GUPS.AntiCheat.Core.Protected; // GUPS - AntiCheat using GUPS.AntiCheat.Detector; using GUPS.AntiCheat.Settings; namespace GUPS.AntiCheat.Protected { /// /// Represents a protected DateTime, designed to enhance integrity and security by obfuscating its value and incorporating anti-cheat measures. /// In most cases, this protected DateTime can be used as a drop-in replacement for the default DateTime type. /// [Serializable] public struct ProtectedDateTime : IProtected, IDisposable, ISerializationCallbackReceiver { /// /// A struct does not have a default constructor that is called when the structure is created. Therefore, the protected primitive must return /// a default value if it does not have an assigned value. /// private bool isInitialized; /// /// Gets a value indicating whether the protected value has integrity, i.e., whether it has maintained its original state. /// private bool hasIntegrity; /// /// Gets a value indicating whether the protected value has integrity, i.e., whether it has maintained its original state. /// public bool HasIntegrity { get => hasIntegrity || !isInitialized; private set => hasIntegrity = value; } /// /// The encrypted true value represented by a ProtectedInt64. /// private ProtectedInt64 obfuscatedInt64; /// /// A honeypot pretending to be the original value. If a user attempts to change this value via a cheat/hack engine, you will be notified. /// The protected value will retain its true value. /// [SerializeField] private Int64 fakeValue; /// /// Unity serialization hook. Ensures the correct values are serialized. /// public void OnBeforeSerialize() { this.fakeValue = Value.Ticks; } /// /// Unity deserialization hook. Ensures the correct values are deserialized. /// public void OnAfterDeserialize() { this = new DateTime(this.fakeValue); } /// /// Creates a new protected DateTime with the specified initial value. /// /// The initial value of the protected DateTime. public ProtectedDateTime(DateTime _Value) { // Initialization this.isInitialized = true; this.obfuscatedInt64 = 0; this.fakeValue = 0; this.hasIntegrity = true; // Obfuscate the value. this.Obfuscate(_Value); } /// /// Gets and sets the true unencrypted field value. /// public DateTime Value { get { if (!this.isInitialized) { return new DateTime(); } if (!this.CheckIntegrity()) { AntiCheatMonitor.Instance.GetDetector()?.OnNext(this); } return this.UnObfuscate(); } set { this.Obfuscate(value); } } /// /// Gets the true unencrypted field value. /// object IProtected.Value => this.Value; /// /// Obfuscates the specified value, encrypting it with the secret key. /// private void Obfuscate(DateTime _Value) { // Obfuscate the value. this.obfuscatedInt64.Value = _Value.Ticks; // Assign the fake value. this.fakeValue = _Value.Ticks; } /// /// Unobfuscates the secured value and returns the true unencrypted value. /// /// The true unencrypted value. private DateTime UnObfuscate() { // Get the unobfuscated value. return new DateTime(this.obfuscatedInt64.Value); } /// /// Obfuscates the current value, generating a new random secret key. /// public void Obfuscate() { // Obfuscate the value. this.obfuscatedInt64.Obfuscate(); } /// /// Checks the integrity of the protected DateTime, detecting if an attacher changed the honeypot fake value. /// /// True if the protected DateTime has integrity; otherwise, false. public bool CheckIntegrity() { // Unobfuscate the secured value. DateTime var_UnobfuscatedValue = this.UnObfuscate(); // Check if an attacher changed the honeypot fake value. if (this.fakeValue != var_UnobfuscatedValue.Ticks) { this.HasIntegrity = false; } // Return the integrity status. return this.HasIntegrity; } /// /// Disposes of the secure and secret values. /// public void Dispose() { this.obfuscatedInt64.Dispose(); } /// /// Converts the protected DateTime to its string representation. /// /// The string representation of the true value. public override string ToString() { return this.Value.ToString(); } /// /// Gets the hash code of the protected DateTime's true value. /// /// The hash code of the true value. public override int GetHashCode() { return this.Value.GetHashCode(); } #region Implicit operator /// /// Implicitly converts a DateTime value to a protected DateTime. /// /// The DateTime value to convert. /// The corresponding protected DateTime. public static implicit operator ProtectedDateTime(DateTime _Value) { return new ProtectedDateTime(_Value); } /// /// Implicitly converts a protected DateTime to its DateTime value. /// /// The protected DateTime to convert. /// The DateTime value of the protected DateTime. public static implicit operator DateTime(ProtectedDateTime _Value) { return _Value.Value; } #endregion #region Equality operator /// /// Checks if two protected DateTimes are equal based on their true values. /// /// The first protected DateTime. /// The second protected DateTime. /// True if the true values are equal; otherwise, false. public static bool operator ==(ProtectedDateTime v1, ProtectedDateTime v2) { return v1.Value == v2.Value; } /// /// Checks if two protected DateTimes are not equal based on their true values. /// /// The first protected DateTime. /// The second protected DateTime. /// True if the true values are not equal; otherwise, false. public static bool operator !=(ProtectedDateTime v1, ProtectedDateTime v2) { return v1.Value != v2.Value; } /// /// Checks if the protected DateTime is equal to another object based on their true values. /// /// The object to compare with the protected DateTime. /// True if the true values are equal; otherwise, false. public override bool Equals(object obj) { if (obj is ProtectedDateTime) { return this.Value == ((ProtectedDateTime)obj).Value; } return this.Value.Equals(obj); } #endregion } }