using System; using System.Security.Cryptography; using System.Text; public static class BoardAuthentication { private const int _blockSizeBytes = 16; private const int _hexBlockLength = _blockSizeBytes * 2; private static readonly byte[] _aesObfuscatedKey = { 0x69, 0x40, 0xC7, 0x0E, 0xF2, 0xC7, 0x45, 0x70, 0x72, 0xCD, 0x28, 0x58, 0x99, 0x8F, 0x73, 0xA8, 0x5F, 0x5F, 0xED, 0xB4, 0xC1, 0x62, 0xB4, 0x24, 0xAC, 0xD7, 0xA3, 0xD6, 0xD8, 0x0B, 0x50, 0x37 }; public static string CreateChallengeHex() { byte[] challenge = new byte[_blockSizeBytes]; using RandomNumberGenerator generator = RandomNumberGenerator.Create(); generator.GetBytes(challenge); return ToHex(challenge); } public static string EncryptHexBlock(string plainHex) { byte[] plain = ParseHexBlock(plainHex); using Aes aes = Aes.Create(); aes.KeySize = 256; aes.BlockSize = 128; aes.Mode = CipherMode.ECB; aes.Padding = PaddingMode.None; aes.Key = (byte[])_aesObfuscatedKey.Clone(); using ICryptoTransform encryptor = aes.CreateEncryptor(); byte[] encrypted = encryptor.TransformFinalBlock(plain, 0, plain.Length); return ToHex(encrypted); } public static bool TryExtractHexPayload(string line, string prefix, out string payload) { payload = null; if (string.IsNullOrEmpty(line) || string.IsNullOrEmpty(prefix) || line.Length != prefix.Length + _hexBlockLength || !line.StartsWith(prefix, StringComparison.Ordinal)) return false; string candidate = line.Substring(prefix.Length); for (int i = 0; i < candidate.Length; i++) { if (!IsHexCharacter(candidate[i])) return false; } payload = candidate.ToUpperInvariant(); return true; } public static bool ValidateEncryptedResponse(string challengeHex, string responseHex) { if (!TryNormalizeHexBlock(responseHex, out string normalizedResponse)) return false; string expectedResponse = EncryptHexBlock(challengeHex); int difference = 0; for (int i = 0; i < expectedResponse.Length; i++) difference |= expectedResponse[i] ^ normalizedResponse[i]; return difference == 0; } private static byte[] ParseHexBlock(string value) { if (!TryNormalizeHexBlock(value, out string normalized)) throw new ArgumentException($"Ожидался HEX-блок длиной {_hexBlockLength} символа.", nameof(value)); byte[] bytes = new byte[_blockSizeBytes]; for (int i = 0; i < bytes.Length; i++) bytes[i] = Convert.ToByte(normalized.Substring(i * 2, 2), 16); return bytes; } private static bool TryNormalizeHexBlock(string value, out string normalized) { normalized = null; if (string.IsNullOrEmpty(value) || value.Length != _hexBlockLength) return false; for (int i = 0; i < value.Length; i++) { if (!IsHexCharacter(value[i])) return false; } normalized = value.ToUpperInvariant(); return true; } private static bool IsHexCharacter(char value) => value >= '0' && value <= '9' || value >= 'A' && value <= 'F' || value >= 'a' && value <= 'f'; private static string ToHex(byte[] bytes) { StringBuilder builder = new(bytes.Length * 2); for (int i = 0; i < bytes.Length; i++) builder.Append(bytes[i].ToString("X2")); return builder.ToString(); } }