Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
203 views
in Technique[技术] by (71.8m points)

c# - Make .txt file unreadable / uneditable

I have a program which saves a little .txt file with a highscore in it:

 // Create a file to write to. 
string createHighscore = _higscore + Environment.NewLine;
File.WriteAllText(path, createText);

// Open the file to read from. 
string createHighscore = File.ReadAllText(path);

The problem is that the user can edit the file as simple as possible – with a texteditor. So I want to make the file unreadable / uneditable or encrypt it.

My thinking was that I could save the data in a resource file, but can I write in a resource file? Or save it as .dll, encrypt/decrypt it or look for a MD5-sum/hash.

question from:https://stackoverflow.com/questions/34262407/make-txt-file-unreadable-uneditable

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can't prevent the user from modifying the file. It's their computer, so they can do whatever they want (that's why the whole DRM issue is… difficult).

Since you said you're using the file to save an high-score, you have a couple of alternatives. Do note that as previously said no method will stop a really determined attacker from tampering with the value: since your application is running on the user computer he can simply decompile it, look at how you're protecting the value (gaining access to any secret used in the process) and act accordingly. But if you're willing to decompile an application, find out the protection scheme used and come up with a script/patch to get around it only to change a number only you can see, well, go for it?

Obfuscate the content

This will prevent the user from editing the file directly, but it won't stop them as soon as the obfuscation algorithm is known.

var plaintext = Encoding.UTF8.GetBytes("Hello, world.");
var encodedtext = Convert.ToBase64String(plaintext);

Save the ciphertext to the file, and reverse the process when reading the file.

Sign the content

This will not prevent the user from editing the file or seeing its content (but you don't care, an high-score is not secret) but you'll be able to detect if the user tampered with it.

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);
}

Save both the payload and the hash in the file, then when reading the file check if the saved hash matches a newly computed one. Your key must be kept secret.

Encrypt the content

Leverage .NET's cryptographic libraries to encrypt the content before saving it and decrypt it when reading the file.

Please take the following example with a grain of salt and spend due time to understand what everything does before implementing it (yes, you'll be using it for a trivial reason, but future you — or someone else — may not). Pay special attention on how you generate the IV and the key.

// 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();
                }
            }
        }
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...