您无法阻止用户修改文件。这是他们的电脑,所以他们可以做任何他们想做的事(这就是为什么整个 DRM 问题……很困难)。
既然您说您正在使用该文件来保存高分,那么您有几个选择。请注意,如前所述,没有任何方法可以阻止真正坚定的攻击者篡改该值:由于您的应用程序在用户计算机上运行,他可以简单地反编译它,看看您是如何保护该值的(获得对任何秘密的访问权限)过程中使用)并采取相应措施。但如果你愿意反编译一个应用程序,找出使用的保护方案并想出一个脚本/补丁来绕过它,只是为了改变一个只有你能看到的数字,好吧,去吧?
混淆内容
这将阻止用户直接编辑文件,但不会在混淆算法已知后立即阻止他们。
var plaintext = Encoding.UTF8.GetBytes("Hello, world.");
var encodedtext = Convert.ToBase64String(plaintext);
将密文保存到文件中,读取文件时反向处理。
签署内容
这不会阻止用户编辑文件或查看其内容(但您不在乎,高分不是秘密),但您将能够检测到用户是否篡改了文件。
var key = Encoding.UTF8.GetBytes("My secret key");
using (var algorithm = new HMACSHA512(key))
{
var payload = Encoding.UTF8.GetBytes("Hello, world.");
var binaryHash = algorithm.ComputeHash(payload);
var stringHash = Convert.ToBase64String(binaryHash);
}
将有效负载和哈希值都保存在文件中,然后在读取文件时检查保存的哈希值是否与新计算的哈希值匹配。您的密钥必须保密。
加密内容
利用 .NET 的加密库在保存内容之前对其进行加密,并在读取文件时对其进行解密。
请对以下示例持保留态度,并在实施之前花适当的时间了解所有内容的作用(是的,您将出于微不足道的原因使用它,但未来您 - 或其他人 - 可能不会) .请特别注意如何生成 IV 和密钥。
// The initialization vector MUST be changed every time a plaintext is encrypted.
// The initialization vector MUST NOT be reused a second time.
// The initialization vector CAN be saved along the ciphertext.
// See https://en.wikipedia.org/wiki/Initialization_vector for more information.
var iv = Convert.FromBase64String("9iAwvNddQvAAfLSJb+JG1A==");
// The encryption key CAN be the same for every encryption.
// The encryption key MUST NOT be saved along the ciphertext.
var key = Convert.FromBase64String("UN8/gxM+6fGD7CdAGLhgnrF0S35qQ88p+Sr9k1tzKpM=");
using (var algorithm = new AesManaged())
{
algorithm.IV = iv;
algorithm.Key = key;
byte[] ciphertext;
using (var memoryStream = new MemoryStream())
{
using (var encryptor = algorithm.CreateEncryptor())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
{
using (var streamWriter = new StreamWriter(cryptoStream))
{
streamWriter.Write("MySuperSecretHighScore");
}
}
}
ciphertext = memoryStream.ToArray();
}
// Now you can serialize the ciphertext however you like.
// Do remember to tag along the initialization vector,
// otherwise you'll never be able to decrypt it.
// In a real world implementation you should set algorithm.IV,
// algorithm.Key and ciphertext, since this is an example we're
// re-using the existing variables.
using (var memoryStream = new MemoryStream(ciphertext))
{
using (var decryptor = algorithm.CreateDecryptor())
{
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
using (var streamReader = new StreamReader(cryptoStream))
{
// You have your "MySuperSecretHighScore" back.
var plaintext = streamReader.ReadToEnd();
}
}
}
}
}