読者です 読者をやめる 読者になる 読者になる

WonderPlanet DEVELOPER BLOG

ワンダープラネットの開発者ブログです。モバイルゲーム開発情報を発信。

【Unity】AESでデータを暗号化

リニューアル後、2エントリー目、担当の大橋です。
リニューアルに伴った特別なネタを持っているわけでもないので、いつものピンポイントなネタでお送りします。

Unityでデータを暗号化

Unityでなんらかのデータを保存するとき、PlayerPrefsを利用したり、 ファイルに書き込んだりすると思いますが、
ある程度の知識があるユーザーであれば、これらの保存したデータを 比較的簡単に見ることができてしまいます。

そのため、アプリを利用するユーザーには知られたくないデータを保存する場合、
そのデータを暗号化する必要があります。

ということで、今回はAESという暗号化方式でデータを暗号化する方法を取り上げようかと思います。

AESはアメリカ国立標準技術研究所(NIST)が新しい標準暗号として暗号方式を公募し、
Rijndaelという暗号方式がAESとして採用されました。
そういうこともあり、UnityでAESを実装するときは「RijndaelManaged」というクラスを使います。

暗号化のコード

using System.Security.Cryptography;
using System.Text;
RijndaelManaged rijndael = new RijndaelManaged ();
rijndael.KeySize = 128;
rijndael.BlockSize = 128;

// パスワードから共有キーと初期化ベクターを作成
string pw = “passward”;
string salt = “salt”;

byte[] bSalt = Encoding.UTF8.GetBytes (salt);
Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes (pw, bSalt);
deriveBytes.IterationCount = 1000;        // 反復回数

rijndael.Key = deriveBytes.GetBytes (rijndael.KeySize / 8);
rijndael.IV = deriveBytes.GetBytes (rijndael.BlockSize / 8);

// 暗号化
ICryptoTransform encryptor = rijndael.CreateEncryptor ();
byte[] encrypted = encryptor.TransformFinalBlock (src, 0, src.Length);

encryptor.Dispose ();

暗号化コードを順に説明していきます

RijndaelManaged rijndael = new RijndaelManaged ();
rijndael.KeySize = 128;
rijndael.BlockSize = 128;

AESでの暗号化は、RijndaelManagedというクラスを使います。
ですので、何はともあれRijndaelManagedのインスタンスを作成します。

そして、暗号化の鍵長とブロック長を設定します。
AESはブロック長が128ビット固定で、鍵長が128ビット、192ビット、256ビットの中から選べますが、
今回はどちらも128ビットにしておきます。

string pw = “passward”;
string salt = “salt”;

パスワードとサルトの文字列です。
この二つの文字列を元に、暗号化のキーと初期化ベクトル(IV)を作ります。

初期化ベクトルとは
AESはブロック暗号方式で、ブロック暗号方式では、暗号化対象をブロックごとに区切って暗号化します。
このとき(CBCモードのとき)、一つ前のブロックの暗号化結果を次のブロックの暗号化に利用します。
ただし、一番最初のブロックを暗号化するときは、一つ前のブロックがありません。
そこで、一つ前のブロックの暗号化結果の代わりとして使われるのが初期化ベクトルです。

byte[] bSalt = Encoding.UTF8.GetBytes (salt);
Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes (pw, bSalt);
deriveBytes.IterationCount = 1000;        // 反復回数

rijndael.Key = deriveBytes.GetBytes (rijndael.KeySize / 8);
rijndael.IV = deriveBytes.GetBytes (rijndael.BlockSize / 8);

パスワードとサルトから暗号化キーと初期化ベクトルを作成し、
それらをRijndaelManagedに指定します。

ICryptoTransform encryptor = rijndael.CreateEncryptor ();
byte[] encrypted = encryptor.TransformFinalBlock (src, 0, src.Length);

暗号化対象のバイト配列(byte[] src)を暗号化します。
暗号化されたバイト配列がencryptedに入ります。
文字や数値を暗号化する場合は、あらかじめバイト配列に変換しておく必要があります。

encryptor.Dispose ();

最後にRijndaelManagedをDisposeして、暗号化完了です。

復号化

暗号化したデータを利用するときは復号化しなければいけません。
復号化は次のようなコードになります。

RijndaelManaged rijndael = new RijndaelManaged ();
rijndael.KeySize = 128;
rijndael.BlockSize = 128;

// パスワードから共有キーと初期化ベクターを作成
string pw = “passward”;
string salt = “salt”;

byte[] bSalt = Encoding.UTF8.GetBytes (salt);
Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes (pw, bSalt);
deriveBytes.IterationCount = 1000;        // 反復回数

rijndael.Key = deriveBytes.GetBytes (rijndael.KeySize / 8);
rijndael.IV = deriveBytes.GetBytes (rijndael.BlockSize / 8);

// 復号化
ICryptoTransform decryptor = rijndael.CreateDecryptor ();
byte[] plain = decryptor.TransformFinalBlock (src, 0, src.Length);

decryptor.Dispose ();

ほとんど暗号化時と同じようなコードになります。
というより、暗号化したときと同じ鍵長、ブロック長、パスワード、サルトを指定しないと ちゃんと復号化されません。

ICryptoTransform decryptor = rijndael.CreateDecryptor ();
byte[] plain = decryptor.TransformFinalBlock (src, 0, src.Length);

暗号化と違うのはこの部分だけです。
暗号化ではCreateEncryptor ()でしたが、復号化ではCreateDecryptor ()になります。
srcは暗号化したバイト列(byte[])です。
復号化されたバイト列がplainに入ります。
文字列や数値を暗号化している場合は、復号化されたバイト列から文字列や数値に戻す必要があります。

以上が、AESでの暗号化、復号化になります。
難しいことはRijndaelManagedなどがやってくれるので、意外と簡単!