ECBモードでFlashとPHPとの可逆暗号の連携に挑戦してみました。
暗号化の目的
Flashゲームなんかで、Flashからゲームの結果の値をシステムに渡すときに、そのPOSTしたパラメータが丸見えになってしまうときがあります。
たとえば、Firefoxのアドオンの Live HTTP headers とかを使われたときなど。
ここら辺の値をなるべく隠しておく方法として、Flashで暗号化してPHPで受け取った値を復元させてみました。
暗号化方式はいろいろあるのだけど何だか良くわかんないので、とりあえず今回はECBモードを使っています。
Flashで暗号化と復元(ECBモード)
Flashの暗号化については as3Crypto というライブラリを使います。
MD5、 SHA-1、SHA-224, SHA-256、RSA、AES、DES、3DES、BlowFish などの暗号化方式を備えた優れものだそうです。
とはいっても、違いがあんまり良くわかってない…。
Flashの記述
package { import com.hurlant.crypto.Crypto; import com.hurlant.crypto.symmetric.ICipher; import com.hurlant.crypto.symmetric.IPad; import com.hurlant.crypto.symmetric.PKCS5; import com.hurlant.util.Base64; import com.hurlant.util.Hex; import flash.display.Sprite; import flash.events.Event; import flash.utils.ByteArray; public class Crypt { public var key:String = ''; /** * constructorz * @param key 暗号鍵 */ public function Crypt(key:String = '') { this.key = key; } /** * ECBを利用して平文を暗号化させます。 * @param txt 平文 * @return 暗号化された文字 */ public function encrypt(txt:String):String { var type:String = 'blowfish-ecb'; var key_:ByteArray = Hex.toArray(Hex.fromString(key)); var data:ByteArray = Hex.toArray(Hex.fromString(txt)); var pad:IPad = new PKCS5; var cipher:ICipher = Crypto.getCipher(type, key_, pad); pad.setBlockSize(cipher.getBlockSize()); try { cipher.encrypt(data); return Base64.encodeByteArray(data); } catch(error:Error) { trace(error); } return null; } /** * ECBを利用して暗号化された文字を復元させます。 * @param txt 暗号化された文字 * @return 平文 */ public function decrypt(txt:String):String { var type:String = 'blowfish-ecb'; var key_:ByteArray = Hex.toArray(Hex.fromString(key)); var data:ByteArray = Base64.decodeToByteArray(txt); var pad:IPad = new PKCS5; var cipher:ICipher = Crypto.getCipher(type, key_, pad); pad.setBlockSize(cipher.getBlockSize()); try { cipher.decrypt(data); return Hex.toString(Hex.fromArray(data)); } catch(error:Error) { trace(error); } return null; } } }
サンプル
ソースコードはFlashエリア上を右クリックで [View Source] からどうぞ。
- Example:Flashで暗号化と復元
PHPで暗号化と復元(ECBモード)
PHPの暗号化については、Mcrypt関数を使いたかったんだけど、自分が今利用している さくらインターネットのサーバーだと使えなかったので、Crypt::Blowfish というpearライブラリをサーバーにインストールして使いました。
pearライブラリのインストール方法はGo-PEARを使えばインストールできるよ。
PHP側の記述
<?php require_once('Crypt/Blowfish.php'); ## パラメーター $key = (isset($_REQUEST['key'])) ? $_REQUEST['key'] : 'key'; $value = (isset($_REQUEST['value'])) ? $_REQUEST['value'] : ''; ## 処理 $blowfish = new Crypt_Blowfish($key); $result = $blowfish->encrypt($value); $result = base64_encode($result); echo $result; ?>
<?php require_once('Crypt/Blowfish.php'); ## パラメーター $key = (isset($_REQUEST['key'])) ? $_REQUEST['key'] : 'key'; $value = (isset($_REQUEST['value'])) ? $_REQUEST['value'] : ''; ## 処理 $blowfish = new Crypt_Blowfish($key); $value = base64_decode($value); $result = rtrim($blowfish->decrypt($value),"\x00..\x1F"); echo $result; ?>
HTML側の記述
jQueryを使ってPHPとフォームの送受信をしてますが、あまり気にせず…。
<!DOCTYPE HTML> <html lang="ja"> <head> <style type="text/css"> body { font-family:Arial,Helvetica,sans-serif; background:#FFF; line-height:1.4; color:#4D4E53; font-size:80%; margin:0px; } fieldset {border: solid #7A4A39 1px;} fieldset p {margin: 0.5em 0;} input[type="text"]{font-size:1em;} legend {font-weight: bold;} #encrypt_box {padding-bottom: 20px;margin-bottom: 20px;border-bottom: dotted #999 1px;} div.result_box {padding-top: 10px;} div.result_box .empty {color: #03F;} </style> <script type="text/javascript" src="/js/jquery-1.5.2.js"></script> <script type="text/javascript"> (function($){ $(function(){ $('#encrypt_box,#decrypt_box').each(function(){ var result_box=$('div.result_box',this); result_box.hide(); $('form',this).submit(function(){ var type=$(this).attr("method"); var url=$(this).attr("action"); var data={}; $('input',this).each(function(){ var name=$(this).attr('name'); var val=$(this).val(); var type=$(this).attr('type'); if(type=='text'){ if(val!=''){ data[name]=val; } }else if(type=='radio'){ if($(this).attr('checked')){ data[name]=val; } } }); $.ajax({type:type,url:url,data:data, success:function(msg){ result_box.hide(); result_box[0].innerHTML=(msg!="")?msg:'<span class="empty">(empty)</span>'; result_box.fadeIn("slow"); }, error:function(msg){ alert("Error status="+msg["status"]); } }); return false; }); }); }); })(jQuery); </script> </head> <body> <div id="encrypt_box"> <form id="eform" action="encrypt.php" method="post"> <fieldset> <legend>ECBモードで暗号化する</legend> <p><label for="ekey">暗号キー : </label><input type="text" value="key" id="ekey" name="key" /></p> <p><label for="evalue"> 平文 : </label><input type="text" value="hoge" id="evalue" name="value" /></p> <p><input type="submit" value="暗号化" /></p> </fieldset> </form> <div class="result_box"></div> </div><!-- END #encrypt_box --> <div id="decrypt_box"> <form id="dform" action="decrypt.php" method="post"> <fieldset> <legend>ECBモードで復元する</legend> <p><label for="dkey">暗号キー : </label><input type="text" value="key" id="dkey" name="key" /></p> <p><label for="dvalue"> 暗号 : </label><input type="text" value="" id="dvalue" name="value" /></p> <p><input type="submit" value="復元" /></p> </fieldset> </form> <div class="result_box"></div> </div><!-- END #decrypt_box --> </body>
サンプル
- Example:PHPで暗号化と復元
最後に
暗号キーはあらかじめ決めておけば、FlashとPHPにそれぞれ合鍵を持たせて暗号化された文字のみをやりとりできます。