UnityでAES暗号化を導入する: ローカルデータを「少しでも」安全に扱うコツ
UnityでAES暗号化を導入する: ローカルデータを「少しでも」安全に扱うコツ
なぜAES暗号化が必要か?
ゲーム開発やアプリ開発をしていると、APIキーやユーザー名、スコアなどのデータをローカルに保存しなくてはならない場面があります。単に「PlayerPrefsに文字列として保存」するだけでは、ファイルやレジストリを直接覗かれたときに まる見え になってしまう可能性が高いわけです。
そこで登場するのがAES暗号化。C#標準のライブラリ(System.Security.Cryptography
)で提供されているため、自前で複雑な暗号ロジックを書く必要がない点がメリットです。もちろん、キーやIVをローカルに置いている限り、本格的なセキュリティとしては万全ではありませんが、「ちょっと隠しておきたい」程度の対策には十分役立ちます。
どんな問題を解決できるのか?
- APIキーが平文で書かれていると、改変や盗用リスクがある
- ゲーム内のステータスやセーブデータを改ざんされたくない(数値を勝手にいじられるなど)
- ユーザー情報や課金関連の一部を、完全オフラインで少しでも安全に保持したい
AES暗号化を導入すれば、最低限のハードルを設けられます。何も対策しないよりは、改ざんや盗用のコストを上げられるわけです。
AES暗号化の基礎: C#のサンプルコード
以下は、C#でAES暗号化する最小限の例です。Unityプロジェクトでも同じように使用できます。
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
public static class AESTool
{
// 実際には、キーとIVは安全に管理する必要があります
private static readonly byte[] key = Encoding.UTF8.GetBytes("1234567890ABCDEF1234567890ABCDEF");
private static readonly byte[] iv = Encoding.UTF8.GetBytes("ABCDEF1234567890");
public static string Encrypt(string plainText)
{
using(Aes aes = Aes.Create())
{
aes.Key = key;
aes.IV = iv;
using(var ms = new MemoryStream())
{
using(var cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
{
byte[] bytes = Encoding.UTF8.GetBytes(plainText);
cs.Write(bytes, 0, bytes.Length);
}
// 暗号化した結果をBase64で返す
return Convert.ToBase64String(ms.ToArray());
}
}
}
public static string Decrypt(string cipherText)
{
using(Aes aes = Aes.Create())
{
aes.Key = key;
aes.IV = iv;
using(var ms = new MemoryStream())
{
using(var cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
byte[] bytes = Convert.FromBase64String(cipherText);
cs.Write(bytes, 0, bytes.Length);
}
// 復号化したデータをUTF8文字列へ
return Encoding.UTF8.GetString(ms.ToArray());
}
}
}
}
- Encryptメソッド: 平文(プレーンテキスト)をAESで暗号化し、Base64文字列に変換
- Decryptメソッド: Base64文字列をバイト列に戻し、AESで復号化してUTF8文字列へ
どう使う?Unityでの実装例
手順1: ランタイムで暗号化して保存
たとえば、APIキーやユーザーのトークンをPlayerPrefs
に保存したい場合、以下のように暗号化してSetStringする方法があります。
public void SaveEncryptedData(string key, string plainValue)
{
string encrypted = AESTool.Encrypt(plainValue);
PlayerPrefs.SetString(key, encrypted);
PlayerPrefs.Save();
}
手順2: 読み込み時に復号化
public string LoadEncryptedData(string key)
{
string encrypted = PlayerPrefs.GetString(key, "");
if (string.IsNullOrEmpty(encrypted))
{
return null; // データがない
}
return AESTool.Decrypt(encrypted);
}
こうすることで、PlayerPrefsをレジストリやファイルシステムで直接覗いても、すぐには分からない形にできます。
メリットと限界を整理しよう
メリット
- XORなどの簡易方式に比べ、より安全性が高い
- .NET標準APIが整備されているため、導入が容易
- ちょっとした改ざん・流出対策としては有効
デメリット
- ローカルにキーとIVを置く以上、完全防御にはならない
- コードやアセットを解析されれば、キーを取り出されるリスクは残る
- 暗号化処理自体はXORに比べてやや重い(とはいえ、頻繁に呼ばなければ問題なし)
気を付けたいポイント
- キーとIVの管理: ベタ書きすると、逆コンパイルされれば丸見え。難読化ツールなどと組み合わせて、より解析を難しくするアプローチが有効
- 書き込み回数: どんなに高速とはいえ、暗号化処理をゲームループ中に乱発するとパフォーマンスに影響が出る場合も。セーブやロードの頻度を考慮する
- オンライン検証との併用: 本格的に不正防止したいなら、最終的にはサーバー検証が理想。ローカルの暗号化だけでは「時間をかければ解読可能」という大前提は覆せません
暗号化の更新を減らす工夫
- ユーザーが設定を変更したときだけ暗号化 → 保存
- 大きな連続セーブが必要な場合は、パラメータだけ暗号化し、細部は平文で持つ…など
まとめ: 「やらないよりは、やったほうがいい」暗号化
AES暗号化を導入すれば、ただの文字列保存よりは高いハードルを設定できます。APIキーや重要設定が丸見えになるリスクを少しでも減らしたいなら、XORよりはAESが無難です。もちろん、完璧な安全策とは言い難いですが、コードを読まれても即座に値を特定できないという点で、一定の改ざん対策にはなります。
ローカルで「どうしてもキーを持たざるを得ない」ケースは多いので、その際に難読化やIL2CPPビルドなどと組み合わせると、さらに解析の難易度を上げられます。
最終的には、セキュリティレベルと開発コストをバランスすることが大事。オンライン検証やサーバー側の管理ができるなら、そちらを活用するのがベストです。しかしローカルオンリーでどうにかしたいなら、AES暗号化を試してみてはいかがでしょうか。
この記事を読んでもっと実践したいと感じたあなたへ
Unity開発を効率よく進めるためには、実践的なスキルと仲間との交流が欠かせません。
そんな方におすすめのステップが、下記の3つです。
1. 有料教材「どこでもUnity教室」でゲーム制作を短期マスター
- 5日でシンプルなFPS完成:初心者向けに要点を押さえたカリキュラム
- C#や最新のInputSystem、FPS実装まで網羅:つまずきやすいポイントを先回りで解説
- 購入特典:Discord招待+サンプルプロジェクトDLで、疑問や実装例を即確認
Unity初心者でも最短5日で3D FPSが完成!今すぐ始める入門チュートリアルはこちら
2. 無料コミュニティで、疑問をすぐに解消&モチベーションUP
- 初心者~中級者までOK:学習進度に合わせて質問や情報共有
- 質問サポートが充実:わからないことを仲間や講師に即相談
- 学習仲間と切磋琢磨:一緒に学ぶから続けやすい
Discordサーバー参加はこちら
3. 実績豊富な“ゲーム開発所RYURYU”があなたをトータルサポート
- コナラ総販売200件超:さまざまなUnity開発の依頼を対応
- VR/AR/AIなど最新技術にも精通:幅広いノウハウを活かして開発支援
- ゲームクリエイター甲子園や東京ゲームショウなど出展実績多数
ご相談・お問い合わせはこちら
ローカルデータのAES暗号化は、完璧ではないにせよ「何も対策しないより確実に安心感が増す」やり方です。自分のプロジェクトにあわせて、必要なレベルの保護を実装してみましょう。どうしても迷ったら、コミュニティや専門家に相談するのも手です。ゲーム開発で大事なのは「リスクを完全ゼロにする」ことではなく、実現したい機能と安全性を両立する柔軟な姿勢かもしれません。
Discussion