UnityのC#とPHPで暗号化・復号化してみる
Unite Japanみたいにソースをまるごと暗号化してメモリ内で復号化して使うみたいな暗号化はAndroidしか使えないし、やる気しないけど普通にUnityで暗号化したい時もあるのでちょっと試してみた。
PlayerPrefsだと暗号化されずにそのまま保存されるので、念のため暗号化しておくといいかもしれない。
このサイトだとVB.NETで書かれていたのでC#に直して、日本語も使いたいのでUTF8に変更してみた。
暗号方式的にはAES(ラインダール)というヤツ。
とりあえずC#とPHPで暗号化した結果が同じになるのか試してみた。
C#でAesCryptoServiceProviderも使えるけどRijndaelManagedと結果が違ってくるらしい。PHPと暗号・復号したいのでRijndaelManagedを使用。
_AES.cs
using UnityEngine;
using System;
using System.IO;
using System.Security.Cryptography;
class _AES
{
public void Action()
{
//'Shared 256 bit Key and IV here
string sKy = "lkirwf897+22#bbtrm8814z5qq=498j5"; //'32 chr shared ascii string (32 * 8 = 256 bit)
string sIV = "741952hheeyy66#cs!9hjv887mxx7@8y"; //'32 chr shared ascii string (32 * 8 = 256 bit)
string sTextVal = "暗号化するテキスト!!!";
string eText;
string dText;
eText = EncryptRJ256(sKy, sIV, sTextVal);
dText = DecryptRJ256(sKy, sIV, eText);
string msg = "";
msg += "元のテキスト=" + sTextVal;
msg += "\n";
msg += "暗号化=" + eText;
msg += "\n";
msg += "復号化=" + dText;
msg += "\n";
Debug.Log(msg);
}
//暗号化
public string EncryptRJ256(string prm_key, string prm_iv, string prm_text_to_encrypt)
{
string sToEncrypt = prm_text_to_encrypt;
RijndaelManaged myRijndael = new RijndaelManaged();
myRijndael.Padding = PaddingMode.Zeros;
myRijndael.Mode = CipherMode.CBC;
myRijndael.KeySize = 256;
myRijndael.BlockSize = 256;
byte encrypted;
byte toEncrypt;
byte key = new byte[0];
byte IV = new byte[0];
key = System.Text.Encoding.UTF8.GetBytes(prm_key);
IV = System.Text.Encoding.UTF8.GetBytes(prm_iv);
ICryptoTransform encryptor = myRijndael.CreateEncryptor(key, IV);
MemoryStream msEncrypt = new MemoryStream();
CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
toEncrypt = System.Text.Encoding.UTF8.GetBytes(sToEncrypt);
csEncrypt.Write(toEncrypt, 0, toEncrypt.Length);
csEncrypt.FlushFinalBlock();
encrypted = msEncrypt.ToArray();
return (Convert.ToBase64String(encrypted));
}
//復号化
public string DecryptRJ256(string prm_key, string prm_iv, string prm_text_to_decrypt)
{
string sEncryptedString = prm_text_to_decrypt;
RijndaelManaged myRijndael = new RijndaelManaged();
myRijndael.Padding = PaddingMode.Zeros;
myRijndael.Mode = CipherMode.CBC;
myRijndael.KeySize = 256;
myRijndael.BlockSize = 256;
byte key = new byte[0];
byte IV = new byte[0];
key = System.Text.Encoding.UTF8.GetBytes(prm_key);
IV = System.Text.Encoding.UTF8.GetBytes(prm_iv);
ICryptoTransform decryptor = myRijndael.CreateDecryptor(key, IV);
byte sEncrypted = Convert.FromBase64String(sEncryptedString);
byte fromEncrypt = new byte[sEncrypted.Length];
MemoryStream msDecrypt = new MemoryStream(sEncrypted);
CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);
return (System.Text.Encoding.UTF8.GetString(fromEncrypt));
}
}
実行結果(Mac)
元のテキスト=暗号化するテキスト!!! 暗号化=tMdcZye5uOVXvfZvkQ/yTvRgZpljXxBYNy0C/Wzavxo= 復号化=暗号化するテキスト!!!
実行結果(iPhone5)
元のテキスト=暗号化するテキスト!!! 暗号化=tMdcZye5uOVXvfZvkQ/yTvRgZpljXxBYNy0C/Wzavxo= 復号化=暗号化するテキスト!!!
PHP
<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);
$ky = 'lkirwf897+22#bbtrm8814z5qq=498j5'; // 32 * 8 = 256 bit key
$iv = '741952hheeyy66#cs!9hjv887mxx7@8y'; // 32 * 8 = 256 bit iv
$text = "暗号化するテキスト!!!";
$etext = encryptRJ256($ky, $iv, $text);
$dtext = decryptRJ256($ky, $iv, $etext);
echo "<HR>元のテキスト: $text";
echo "<HR>暗号化: $etext";
echo "<HR>復号化: $dtext";
function decryptRJ256($key,$iv,$string_to_decrypt)
{
$string_to_decrypt = base64_decode($string_to_decrypt);
$rtn = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $string_to_decrypt, MCRYPT_MODE_CBC, $iv);
$rtn = rtrim($rtn, "");
return($rtn);
}
function encryptRJ256($key,$iv,$string_to_encrypt)
{
$rtn = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $string_to_encrypt, MCRYPT_MODE_CBC, $iv);
$rtn = base64_encode($rtn);
return($rtn);
}
?>
実行結果(PHP)
元のテキスト: 暗号化するテキスト!!! 暗号化: tMdcZye5uOVXvfZvkQ/yTvRgZpljXxBYNy0C/Wzavxo= 復号化: 暗号化するテキスト!!!
どの環境でも暗号化の結果がおなじになった。Unityでも暗号化・復号化は難しいわけでは無いので、大事なモノは暗号化しとくといい。
今回は気にしなかったけど、ただの計算よりも暗号化・復号化の方がCPU使うと思うので大量のデータを処理する場合はパフォーマンスに注意が必要だろうな。
Updateで毎フレーム暗号化するような処理は避けた方が良い気がする。
ちなみにPlayerPrefsを暗号化してくれるAssetだと「ZDatabase - Unity Database」などがある。このアセットの注意点はGameObjectを生成してそれを使用しているらしくEditor拡張から使えないとこ。

使い方はこちらのサイトが参考になった
http://terasur.blog.fc2.com/blog-entry-370.html
参考