ハイスコアを含む小さな.txtファイルを保存するプログラムがあります。
// 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);
問題は、ユーザーがテキストエディターを使用して、できるだけ簡単にファイルを編集できることです。だから私はファイルを作りたい判読不能/編集不能または暗号化。
私は、データをリソースファイルに保存できると考えていましたが、リソースファイルに書き込むことはできますか?または、.dllとして保存、暗号化/復号化、またはMD5-sum/hashを探します。
ユーザーがファイルを変更するのを防ぐことはできません。それは彼らのコンピューターなので、彼らは何でもやりたいことができます(だから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();
}
}
}
}
}
比較的低いセキュリティを探しているように思えるので、実際にはチェックサムに行くことをお勧めします。いくつかの擬似コード:
string toWrite = score + "|" + md5(score+"myKey") + Environment.NewLine
スコアが100の場合、これは次のようになります。
100 | a6b6b0a8e56e42d8dac51a4812def434
ユーザーがファイルを気にしないようにするには、次を使用できます。
string[] split = readString().split("|");
if (split[1] != md5(split[0]+"myKey")){
alert("No messing with the scores!");
}else{
alert("Your score is "+split[0]);
}
もちろん、誰かがあなたの鍵を知るとすぐに、彼らは望むものをこれで台無しにすることができますが、私はそれをこの質問の範囲を超えて検討します。同じリスクは、暗号化/復号化メカニズムにも適用されます。
下のコメントで言及されている問題の1つは、誰かが(ブルートフォーシングによって)鍵を見つけたら、それを共有でき、誰もがファイルを非常に簡単に変更できることです。これを解決する方法は、コンピューター固有のものをキーに追加することです。たとえば、ログインしたユーザーの名前は、md5を実行しました。
string toWrite = score + "|" + md5(score+"myKey"+md5(System.username /**or so**/)) + Environment.NewLine
これにより、キーが「単純に共有される」ことを防ぎます。
おそらくあなたの最善の策は、標準のNTセキュリティを使用してファイル全体を保護し、プログラムでアクセス制御リストを変更して、ファイル全体が不要なユーザーによって編集されないようにすることです(もちろん、自分のアプリケーションになりすます人を除く)。
暗号化はここでは役に立ちません。ファイルは通常のテキストエディター(たとえば、notepad
)を使用して編集可能であり、エンドユーザーは余分な文字を追加するだけでファイルを破損する可能性があるためです。
テキストファイル全体を手動で編集すると、サポートが失われたことをユーザーに伝えます。結局のところ、このデータを保存しているのは、アプリケーションに必要なためです。破損したり、手動で編集するという危険なタスクを実行すると、アプリケーションでエラーが発生する可能性があります。
アプリケーションからファイルを変更するたびに、MD5またはSHAハッシュを計算して別のファイルに保存できます。もう一度読み書きしたい場合は、チェックします。ファイル全体が同じハッシュを生成してから再度書き込みます。
このように、ユーザーはファイルを手動で編集できますが、ユーザーがこのnexpected動作をいつ実行したかがわかります(ファイルが変更されるたびにユーザーが手動でハッシュを計算しない限り... )。
まだ言及していないことは、オンラインリーダーボードにハイスコアを保存することです。明らかにこのソリューションにはさらに多くの開発が必要ですが、ゲームについて話しているので、おそらくSteam、Origin、Uplayなどのサードパーティプロバイダーを利用できます。あなたのマシン。
Dllにデータを保存することはできません。また、リソースファイルとtxtファイルの両方が編集可能です。暗号化があなたにとって唯一の方法のようです。文字列を暗号化してから、txtファイルに保存できます。このスレッドを見てください: 文字列の暗号化と復号化
シンプルなソリューション:
。
別の解決策:
SQLite DBにデータを書き込みますか?
CryptoStream で暗号化してシリアル化および逆シリアル化できます:
ファイルのシリアル化:
ファイルのデシリアライズ:
ここで例と詳細情報を見つけることができます:
msdn.Microsoft.com/en-us/library/system.security.cryptography.cryptostream.aspx
http://www.codeproject.com/Articles/6465/Using-CryptoStream-in-C
例:
byte[] key = { 1, 2, 3, 4, 5, 6, 7, 8 }; // Where to store these keys is the tricky part,
byte[] iv = { 1, 2, 3, 4, 5, 6, 7, 8 };
string path = @"C:\path\to.file";
DESCryptoServiceProvider des = new DESCryptoServiceProvider();
// Encryption and serialization
using (var fStream = new FileStream(path, FileMode.Create, FileAccess.Write))
using (var cryptoStream = new CryptoStream(fStream , des.CreateEncryptor(key, iv), CryptoStreamMode.Write))
{
BinaryFormatter serializer = new BinaryFormatter();
// This is where you serialize your data
serializer.Serialize(cryptoStream, yourData);
}
// Decryption
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read))
using (var cryptoStream = new CryptoStream(fs, des.CreateDecryptor(key, iv), CryptoStreamMode.Read))
{
BinaryFormatter serializer = new BinaryFormatter();
// Deserialize your data from file
yourDataType yourData = (yourDataType)serializer.Deserialize(cryptoStream);
}
Resourcesに書き込むことはできません。詳細は this answer
実行時にリソース文字列を変更できない理由は、リソースが実行可能ファイルにコンパイルされるためです。コンパイル済みの* .exeまたは* .dllファイルをリバースエンジニアリングすると、実際にコード内の文字列を確認できます。既にコンパイルされた実行可能ファイルを編集することは決して良い考えではありません(ハックする場合を除きます)が、実行可能コードから実行しようとすると、実行中にファイルがロックされるため、まったく不可能です。
例:
File.SetAttributes(path, File.GetAttributes(path) | FileAttributes.Hidden);
ghf.ytr
(などの気まぐれは、今より気味の悪い気まぐれは考えられません!).dll
拡張子を持つテキストファイルを作成し、system32
などのWindowsフォルダーの1つに保存することをお勧めします。この方法では、ユーザーはスコア情報がどこに行くのかを見つけるのに非常に苦労します!ファイルにスコアテーブルが含まれていることを示唆しない名前(たとえば、YourApp.dat)としてファイルに名前を付けて、コンテンツを暗号化できます。
受け入れられる回答 here には、テキストの暗号化と復号化のコードが含まれています。
更新
暗号化のパスワードとしていくつかのGuid
を使用することもお勧めします。
テキストファイルを編集不可にするコードを次に示します。同様に、この手法を使用して読み取り不可能にするなど。
string pathfile = @"C:\Users\Public\Documents\Filepath.txt";
if (File.Exists(pathfile))
{
File.Delete(pathfile);
}
if (!File.Exists(pathfile))
{
using (FileStream fs = File.Create(pathfile))
{
Byte[] info = new UTF8Encoding(true).GetBytes("your text to be written to the file place here");
FileSecurity fsec = File.GetAccessControl(pathfile);
fsec.AddAccessRule(new FileSystemAccessRule("Everyone",
FileSystemRights.WriteData, AccessControlType.Deny));
File.SetAccessControl(pathfile, fsec);
}
}