using System.Net.NetworkInformation; using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Text; namespace CertifiEd.Client; /// /// Computes a stable hardware fingerprint for the current machine — a SHA-256 hex /// digest over machine name, OS description, the first stable MAC address, and the /// platform machine id when available. /// public static class HwFingerprint { private static string? _cached; /// Returns the fingerprint, computed once per process. public static string Get() { if (_cached is not null) return _cached; var raw = new StringBuilder() .Append(Environment.MachineName).Append('|') .Append(RuntimeInformation.OSDescription).Append('|') .Append(GetStableMac() ?? "no-mac"); var platformId = GetPlatformMachineId(); if (platformId is not null) raw.Append('|').Append(platformId); var hash = SHA256.HashData(Encoding.UTF8.GetBytes(raw.ToString())); _cached = Convert.ToHexStringLower(hash); return _cached; } private static string? GetStableMac() { try { return NetworkInterface.GetAllNetworkInterfaces() .Where(n => n.NetworkInterfaceType != NetworkInterfaceType.Loopback && n.OperationalStatus == OperationalStatus.Up) .Select(n => n.GetPhysicalAddress().ToString()) .Where(mac => mac.Length > 0) .Order(StringComparer.Ordinal) .FirstOrDefault(); } catch (NetworkInformationException) { return null; } } private static string? GetPlatformMachineId() { if (OperatingSystem.IsWindows()) return GetWindowsMachineGuid(); if (OperatingSystem.IsLinux()) return TryReadFile("/etc/machine-id") ?? TryReadFile("/var/lib/dbus/machine-id"); if (OperatingSystem.IsMacOS()) return GetMacSerialNumber(); return null; } [System.Runtime.Versioning.SupportedOSPlatform("windows")] private static string? GetWindowsMachineGuid() { try { using var key = Microsoft.Win32.Registry.LocalMachine .OpenSubKey(@"SOFTWARE\Microsoft\Cryptography"); return key?.GetValue("MachineGuid")?.ToString(); } catch (Exception ex) when (ex is System.Security.SecurityException or UnauthorizedAccessException or IOException) { return null; } } private static string? TryReadFile(string path) { try { return File.Exists(path) ? File.ReadAllText(path).Trim() : null; } catch (IOException) { return null; } catch (UnauthorizedAccessException) { return null; } } private static string? GetMacSerialNumber() { try { var psi = new System.Diagnostics.ProcessStartInfo("ioreg", "-l") { RedirectStandardOutput = true, UseShellExecute = false, }; using var process = System.Diagnostics.Process.Start(psi); var output = process?.StandardOutput.ReadToEnd() ?? string.Empty; var line = output.Split('\n').FirstOrDefault(l => l.Contains("IOPlatformSerialNumber", StringComparison.Ordinal)); if (line is null) return null; var start = line.IndexOf('"', line.IndexOf('=', StringComparison.Ordinal) + 1); var end = start >= 0 ? line.IndexOf('"', start + 1) : -1; return start >= 0 && end > start ? line[(start + 1)..end] : null; } catch (Exception ex) when (ex is System.ComponentModel.Win32Exception or InvalidOperationException or IOException) { return null; } } }