例えば、ゲームのセーブデータをサーバで保存していて
「アイテム1個持ってます」という情報をSWFで受け取る場合、
SWFに届く前に「アイテム100個持ってます」に改竄されるとまずいということで暗号化することにしました。
RSA暗号は「暗号」と「署名」の2つの使い方ができます。
▼暗号
公開鍵を使って誰でも暗号化できるが、復号できるのは秘密鍵を持っている人だけ。
SWFからサーバに送るデータを途中で読み取られないようにする場合などに使うと思います。
SWFに埋め込んだ公開鍵で暗号化して送り、サーバ側にある秘密鍵で解読というような使い方。
こちらが参考になります:suz-lab - blog: AS3で暗号/復号化(RSA版)
▼署名
秘密鍵を使って暗号化したデータを、公開鍵で復号する。
暗号文を復号した結果が平文と同じなら、正しい送り主からのデータであり改竄されていないということになる。
今回はこちらを使います。
サーバ側で秘密鍵を使って暗号化し、SWF側で公開鍵を使って復号するという流れ。
暗号化ライブラリはas3cryptoを使います。
下記がサンプルソースですが、
実際には【2】の処理はサーバ側で行い、SWF側では【1】と【3】を実装することになります。
import flash.utils.ByteArray; import com.hurlant.crypto.rsa.RSAKey; import com.hurlant.util.Base64; import com.hurlant.util.Hex; public function CryptTest() { // 暗号化の対象となる文字列 var original_str:String = "アイテム1個持ってます"; //------------------------ //【1】復号用の公開鍵 var public_modulus:String= "f0bc13f68e0c02397af4aeaf2edc94f92e94945eea1f745235ff05ff16e9b6490267b9" +"82b22c6aff4b6887fc89e7d92d8a2254c7f4c2fb7a116478f875dc8da5"; var public_exponent:String = "10001"; //------------------------ //【2】↓ここからは、サーバ側でやる処理ですがサンプルということで載せてます。 //暗号化用の秘密鍵 var private_exponent:String= "de6f3a16e7bb4ad6e7b86c2bec25def4bb48882b8732971d5b4d0fb25aee8a00f2fd" +"6987d1ca990846b50e70be386867be09b64840157c0d7d451d91ccc92e21"; var rsa_sign:RSAKey = RSAKey.parsePrivateKey(public_modulus, public_exponent, private_exponent); //ByteArrayに var srcEncryptBA:ByteArray = Base64.decodeToByteArray(Base64.encode(original_str)); //暗号化したデータを格納するためのByteArray var dstEncryptBA:ByteArray = new ByteArray(); //暗号化実行 rsa_sign.sign(srcEncryptBA, dstEncryptBA, srcEncryptBA.length); //暗号化されたデータをBase64エンコード var encrypted_str:String = Base64.encodeByteArray(dstEncryptBA); trace("暗号化済み文字列。これをSWFに返す。" + encrypted_str); //↑ここまで、サーバ側でやる処理 //------------------------ //【3】復号 var rsa_verify : RSAKey= RSAKey.parsePublicKey(public_modulus, public_exponent); var srcDecryptBA:ByteArray = Base64.decodeToByteArray(encrypted_str); //復号したデータを格納するためのByteArray var dstDecryptBA:ByteArray = new ByteArray(); //復号実行 try{ rsa_verify.verify(srcDecryptBA, dstDecryptBA, srcDecryptBA.length); trace("復号した文字列:" + dstDecryptBA.toString()); if(dstDecryptBA.toString()==original_str){ trace("改竄なし"); }else{ trace("改竄あり"); } }catch (e) { trace("verify失敗。不正なデータ。"); } rsa_verify.dispose(); }
鍵の生成はAS3 Crypto Demo pageでやると簡単。
余談:「暗号化」の対義語は「復号化」ではなく「復号」なんだって。
追記:(09/06/15 02:50)
もっと厳しくやるには、タイムスタンプを含めておいてサーバ時間と比較しないといけないかも。
「アイテム1個持ってます」というサーバレスポンスを解析保存され
アイテム0個の時にそのデータを送り込まれる、ということを防ぐために。
素直にSSL使えば何も考えなくていいのかな。
コメント