ui基本完毕,修了一大把的bug

This commit is contained in:
FloatGaming
2026-07-13 02:28:39 +08:00
parent 1e20d73e90
commit fd22501f71
958 changed files with 378289 additions and 41038 deletions
+147 -46
View File
@@ -27,7 +27,7 @@ public static class SecureSaveVault
private static string VaultDirectoryPath
{
get { return Path.Combine(Application.persistentDataPath, VaultDirectoryName); }
get { return Path.Combine(SaveIdentityUtility.GetCanonicalPersistentRoot(), VaultDirectoryName); }
}
public static bool SaveJson<T>(string category, string key, T data, string legacyPlainPath = null)
@@ -121,20 +121,11 @@ public static class SecureSaveVault
return false;
}
string mainPath = GetFilePath(category, key, ".dat");
string backupPath = GetFilePath(category, key, ".bak");
if (TryReadEncryptedFile(category, key, mainPath, out json))
if (TryLoadFromCurrentOrLegacyEncryptedFiles(category, key, legacyPlainPath, out json))
{
return true;
}
if (TryReadEncryptedFile(category, key, backupPath, out json))
{
SaveRawJson(category, key, json, legacyPlainPath);
return true;
}
if (!string.IsNullOrEmpty(legacyPlainPath) && File.Exists(legacyPlainPath))
{
try
@@ -262,8 +253,7 @@ public static class SecureSaveVault
return false;
}
string expectedSignature = ComputeSignature(category, envelope.payload);
if (!string.Equals(expectedSignature, envelope.signature, StringComparison.Ordinal))
if (!TryValidateSignature(category, envelope.payload, envelope.signature))
{
Debug.LogWarning($"[SecureSaveVault] Signature mismatch ({category}/{key}). Possible tampering detected.");
return false;
@@ -329,7 +319,7 @@ public static class SecureSaveVault
private static string ComputeSignature(string category, string payloadBase64)
{
string signText = payloadBase64 + "|" + category + "|" + Application.identifier + "|" + SecretSeed + "|" + SystemInfo.deviceUniqueIdentifier;
string signText = payloadBase64 + "|" + category + "|" + SaveIdentityUtility.GetPrimaryApplicationIdentifier() + "|" + SecretSeed + "|" + SystemInfo.deviceUniqueIdentifier;
using (var sha = SHA256.Create())
{
byte[] hash = sha.ComputeHash(Encoding.UTF8.GetBytes(signText));
@@ -350,7 +340,7 @@ public static class SecureSaveVault
{
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.Key = BuildAesKey(category, key);
aes.Key = BuildAesKey(category, key, SaveIdentityUtility.GetPrimaryApplicationIdentifier());
aes.GenerateIV();
using (var encryptor = aes.CreateEncryptor())
{
@@ -374,28 +364,44 @@ public static class SecureSaveVault
return plainBytes != null;
}
#endif
using (var aes = Aes.Create())
IReadOnlyList<string> identifierVariants = SaveIdentityUtility.GetApplicationIdentifierVariants();
for (int i = 0; i < identifierVariants.Count; i++)
{
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.Key = BuildAesKey(category, key);
int ivLength = aes.BlockSize / 8;
if (protectedBytes == null || protectedBytes.Length <= ivLength)
using (var aes = Aes.Create())
{
return false;
}
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.Key = BuildAesKey(category, key, identifierVariants[i]);
int ivLength = aes.BlockSize / 8;
if (protectedBytes == null || protectedBytes.Length <= ivLength)
{
return false;
}
byte[] iv = new byte[ivLength];
byte[] cipher = new byte[protectedBytes.Length - ivLength];
Buffer.BlockCopy(protectedBytes, 0, iv, 0, ivLength);
Buffer.BlockCopy(protectedBytes, ivLength, cipher, 0, cipher.Length);
aes.IV = iv;
using (var decryptor = aes.CreateDecryptor())
{
plainBytes = decryptor.TransformFinalBlock(cipher, 0, cipher.Length);
return plainBytes != null;
byte[] iv = new byte[ivLength];
byte[] cipher = new byte[protectedBytes.Length - ivLength];
Buffer.BlockCopy(protectedBytes, 0, iv, 0, ivLength);
Buffer.BlockCopy(protectedBytes, ivLength, cipher, 0, cipher.Length);
aes.IV = iv;
try
{
using (var decryptor = aes.CreateDecryptor())
{
plainBytes = decryptor.TransformFinalBlock(cipher, 0, cipher.Length);
if (plainBytes != null)
{
return true;
}
}
}
catch
{
}
}
}
plainBytes = null;
return false;
}
catch (Exception ex)
{
@@ -416,7 +422,7 @@ public static class SecureSaveVault
try
{
protectedBytes = s_dpapiProtectMethod.Invoke(null, new object[] { plainBytes, BuildEntropy(category), s_dpapiCurrentUserScope }) as byte[];
protectedBytes = s_dpapiProtectMethod.Invoke(null, new object[] { plainBytes, BuildEntropy(category, SaveIdentityUtility.GetPrimaryApplicationIdentifier()), s_dpapiCurrentUserScope }) as byte[];
return protectedBytes != null && protectedBytes.Length > 0;
}
catch (Exception ex)
@@ -435,16 +441,24 @@ public static class SecureSaveVault
return false;
}
try
IReadOnlyList<string> identifierVariants = SaveIdentityUtility.GetApplicationIdentifierVariants();
for (int i = 0; i < identifierVariants.Count; i++)
{
plainBytes = s_dpapiUnprotectMethod.Invoke(null, new object[] { protectedBytes, BuildEntropy(category), s_dpapiCurrentUserScope }) as byte[];
return plainBytes != null && plainBytes.Length > 0;
}
catch
{
plainBytes = null;
return false;
try
{
plainBytes = s_dpapiUnprotectMethod.Invoke(null, new object[] { protectedBytes, BuildEntropy(category, identifierVariants[i]), s_dpapiCurrentUserScope }) as byte[];
if (plainBytes != null && plainBytes.Length > 0)
{
return true;
}
}
catch
{
}
}
plainBytes = null;
return false;
}
private static bool EnsureDpapi()
@@ -492,29 +506,116 @@ public static class SecureSaveVault
}
#endif
private static byte[] BuildEntropy(string category)
private static byte[] BuildEntropy(string category, string applicationIdentifier)
{
string seed = Application.identifier + "|" + SystemInfo.deviceUniqueIdentifier + "|" + SecretSeed + "|" + category;
string seed = applicationIdentifier + "|" + SystemInfo.deviceUniqueIdentifier + "|" + SecretSeed + "|" + category;
using (var sha = SHA256.Create())
{
return sha.ComputeHash(Encoding.UTF8.GetBytes(seed));
}
}
private static byte[] BuildAesKey(string category, string key)
private static byte[] BuildAesKey(string category, string key, string applicationIdentifier)
{
return BuildEntropy(category);
using (var sha = SHA256.Create())
{
string seed = applicationIdentifier + "|" + SystemInfo.deviceUniqueIdentifier + "|" + SecretSeed + "|" + category + "|" + key;
return sha.ComputeHash(Encoding.UTF8.GetBytes(seed));
}
}
private static string ShortHash(string value)
{
using (var sha = SHA256.Create())
{
byte[] hash = sha.ComputeHash(Encoding.UTF8.GetBytes(value + "|" + Application.identifier + "|" + SecretSeed));
byte[] hash = sha.ComputeHash(Encoding.UTF8.GetBytes(value + "|" + SaveIdentityUtility.GetPrimaryApplicationIdentifier() + "|" + SecretSeed));
return BitConverter.ToString(hash, 0, 12).Replace("-", string.Empty).ToLowerInvariant();
}
}
private static string ShortHash(string value, string applicationIdentifier)
{
using (var sha = SHA256.Create())
{
byte[] hash = sha.ComputeHash(Encoding.UTF8.GetBytes(value + "|" + applicationIdentifier + "|" + SecretSeed));
return BitConverter.ToString(hash, 0, 12).Replace("-", string.Empty).ToLowerInvariant();
}
}
private static bool TryLoadFromCurrentOrLegacyEncryptedFiles(string category, string key, string legacyPlainPath, out string json)
{
json = null;
IReadOnlyList<string> roots = SaveIdentityUtility.GetPersistentRootVariants(legacyPlainPath);
for (int i = 0; i < roots.Count; i++)
{
string root = roots[i];
if (string.IsNullOrWhiteSpace(root))
{
continue;
}
IReadOnlyList<string> identifierVariants = SaveIdentityUtility.GetApplicationIdentifierVariants();
for (int variantIndex = 0; variantIndex < identifierVariants.Count; variantIndex++)
{
string applicationIdentifier = identifierVariants[variantIndex];
string mainPath = GetFilePathForRoot(root, category, key, ".dat", applicationIdentifier);
if (TryReadEncryptedFile(category, key, mainPath, out json))
{
SaveRawJson(category, key, json, legacyPlainPath);
return true;
}
string backupPath = GetFilePathForRoot(root, category, key, ".bak", applicationIdentifier);
if (TryReadEncryptedFile(category, key, backupPath, out json))
{
SaveRawJson(category, key, json, legacyPlainPath);
return true;
}
}
}
return false;
}
private static bool TryValidateSignature(string category, string payloadBase64, string signature)
{
IReadOnlyList<string> identifierVariants = SaveIdentityUtility.GetApplicationIdentifierVariants();
for (int i = 0; i < identifierVariants.Count; i++)
{
string expectedSignature = ComputeSignature(category, payloadBase64, identifierVariants[i]);
if (string.Equals(expectedSignature, signature, StringComparison.Ordinal))
{
return true;
}
}
return false;
}
private static string ComputeSignature(string category, string payloadBase64, string applicationIdentifier)
{
string signText = payloadBase64 + "|" + category + "|" + applicationIdentifier + "|" + SecretSeed + "|" + SystemInfo.deviceUniqueIdentifier;
using (var sha = SHA256.Create())
{
byte[] hash = sha.ComputeHash(Encoding.UTF8.GetBytes(signText));
return Convert.ToBase64String(hash);
}
}
private static string GetCategoryDirectoryForRoot(string rootPath, string category, string applicationIdentifier)
{
string safeCategory = ShortHash("cat|" + category, applicationIdentifier);
return Path.Combine(rootPath, VaultDirectoryName, "." + safeCategory);
}
private static string GetFilePathForRoot(string rootPath, string category, string key, string extension, string applicationIdentifier)
{
string categoryDirectory = GetCategoryDirectoryForRoot(rootPath, category, applicationIdentifier);
string safeKey = ShortHash("key|" + key, applicationIdentifier);
return Path.Combine(categoryDirectory, "." + safeKey + extension);
}
private static void DeleteLegacyPlainFile(string legacyPlainPath)
{
if (string.IsNullOrEmpty(legacyPlainPath) || !File.Exists(legacyPlainPath))