using System; using System.IO; using System.Runtime.InteropServices; using System.Security; using System.Security.Cryptography; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EFCDesk.Classes { public static class SecureDataHandler { private const string SettingKey = "IdUsuario"; // Genera entropía dinámica a partir de datos de hardware y usuario private static byte[] GetEntropy() { string machineName = Environment.MachineName; string userName = Environment.UserName; string cpu = Environment.GetEnvironmentVariable("PROCESSOR_IDENTIFIER") ?? ""; string sysDrive = Environment.GetEnvironmentVariable("SystemDrive") ?? ""; //string exeHash = GetExecutableHash(); string mac = GetMacAddress() ?? ""; string combo = $"MiAppSalt|{machineName}|{userName}|{cpu}|{sysDrive}|{mac}"; return Encoding.UTF8.GetBytes(combo); } // Calcula hash SHA256 del ejecutable para validar que no ha sido copiado o modificado private static string GetExecutableHash() { string exePath = Application.ExecutablePath; using (var sha = SHA256.Create()) using (var stream = File.OpenRead(exePath)) { byte[] hash = sha.ComputeHash(stream); return Convert.ToBase64String(hash); } } private static string? GetMacAddress() { var nic = System.Net.NetworkInformation.NetworkInterface .GetAllNetworkInterfaces() .FirstOrDefault(n => n.OperationalStatus == System.Net.NetworkInformation.OperationalStatus.Up && n.NetworkInterfaceType != System.Net.NetworkInformation.NetworkInterfaceType.Loopback && n.GetPhysicalAddress().GetAddressBytes().Length > 0); if (nic == null) return null; // Sin ":" return string.Concat(nic.GetPhysicalAddress() .GetAddressBytes() .Select(b => b.ToString("X2"))); } public static void SaveData(string data) { if (data == null) throw new ArgumentNullException(nameof(data)); byte[] bytes = Encoding.UTF8.GetBytes(data); byte[] encrypted = ProtectedData.Protect(bytes, GetEntropy(), DataProtectionScope.CurrentUser); string encryptedBase64 = Convert.ToBase64String(encrypted); Properties.Settings.Default[SettingKey] = encryptedBase64; Properties.Settings.Default.Save(); ClearBytes(bytes); ClearBytes(encrypted); } public static SecureString? ReadDataAsSecureString() { string? encryptedBase64 = Properties.Settings.Default[SettingKey] as string; if (string.IsNullOrEmpty(encryptedBase64)) return null; byte[] encrypted = Convert.FromBase64String(encryptedBase64); byte[]? decrypted = null; try { decrypted = ProtectedData.Unprotect(encrypted, GetEntropy(), DataProtectionScope.CurrentUser); string? data = Encoding.UTF8.GetString(decrypted); var secure = new SecureString(); if (data != null) { foreach (char c in data) secure.AppendChar(c); ClearString(ref data); } secure.MakeReadOnly(); return secure; } catch (CryptographicException) { // Los datos no se pueden desencriptar → devolver null en vez de corromper return null; } finally { if (decrypted != null) ClearBytes(decrypted); ClearBytes(encrypted); } } public static string? ReadDataAsPlainText() { SecureString? ss = ReadDataAsSecureString(); if (ss == null) return null; try { return SecureStringToString(ss); } finally { ss.Dispose(); } } public static void DeleteData() { Properties.Settings.Default[SettingKey] = null; Properties.Settings.Default.Save(); } public static bool IsDataValid() { string? encryptedBase64 = Properties.Settings.Default[SettingKey] as string; if (string.IsNullOrEmpty(encryptedBase64)) return false; byte[] encrypted = Convert.FromBase64String(encryptedBase64); try { byte[] decrypted = ProtectedData.Unprotect(encrypted, GetEntropy(), DataProtectionScope.CurrentUser); ClearBytes(decrypted); return true; } catch { return false; } } private static string? SecureStringToString(SecureString secure) { if (secure == null) return null; IntPtr ptr = IntPtr.Zero; try { ptr = Marshal.SecureStringToGlobalAllocUnicode(secure); return Marshal.PtrToStringUni(ptr); } finally { if (ptr != IntPtr.Zero) Marshal.ZeroFreeGlobalAllocUnicode(ptr); } } private static void ClearBytes(byte[] buf) { if (buf == null) return; for (int i = 0; i < buf.Length; i++) buf[i] = 0; } private static unsafe void ClearString(ref string? s) { if (s == null) return; fixed (char* p = s) { for (int i = 0; i < s.Length; i++) p[i] = '\0'; } s = null; } } }