/************************************************************************* * ModernUO * * Copyright 2019-2025 - ModernUO Development Team * * Email: hi@modernuo.com * * File: LoginKeys.cs * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * *************************************************************************/ using System.Collections.Generic; using System.Runtime.CompilerServices; namespace Server.Network; /// /// Represents encryption keys derived from a client version. /// Used for login packet encryption/decryption. /// public readonly struct LoginKeys { public static readonly LoginKeys Empty = new(0, 0); private static readonly Dictionary _cache = []; public uint Key1 { get; } public uint Key2 { get; } private LoginKeys(uint key1, uint key2) { Key1 = key1; Key2 = key2; } /// /// Gets or computes encryption keys for the specified client version. /// Results are cached for performance. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static LoginKeys GetKeys(ClientVersion version) { if (version == null) { return Empty; } if (_cache.TryGetValue(version, out var keys)) { return keys; } keys = ComputeKeys(version); _cache[version] = keys; return keys; } /// /// Computes encryption keys from client version using the UO key derivation algorithm. /// private static LoginKeys ComputeKeys(ClientVersion version) { uint major = (uint)version.Major; uint minor = (uint)version.Minor; uint revision = (uint)version.Revision; // Key1 derivation uint key1 = (major << 23) | (minor << 14) | (revision << 4); key1 ^= (revision * revision) << 9; key1 ^= minor * minor; key1 ^= (minor * 11) << 24; key1 ^= (revision * 7) << 19; key1 ^= 0x2C13A5FD; // Key2 derivation uint key2 = (major << 22) | (revision << 13) | (minor << 3); key2 ^= (revision * revision * 3) << 10; key2 ^= minor * minor; key2 ^= (minor * 13) << 23; key2 ^= (revision * 7) << 18; key2 ^= 0xA31D527F; return new LoginKeys(key1, key2); } }