日記

cocos2d-xでリソースの暗号化をしてみる。

こんにちは。三点リーダが大好き過ぎて多様しちゃうマン、korcsだよ!
本気出すとか言いつつ、また更新滞ってたけどいつものことですね……。
何だかんだで東京へ引っ越してきて、色々やってました。(という言い訳)
引っ越しついでに同人誌の整理してたら、ダブって買ってるのが予想以上にたくさんあってびっくりしました……。
そんなこんなのどうでも良い日常。


ということで、今回は

「cocos2d-x v3.0でリソースの暗号化」

です。
ぶっちゃけ、暗号化なんて自前でやったことなかったので、なんか変なとこあったらメールフォームとかからツッコんでください。(予防線)

暗号化しよう – ゲームプログラミングWiki
暗号化については↑を参考にさせてもらいました。
エンコード用のexeは上記のものをほぼそのまま使わせてもらってます。
そして、cocos2d-xでデコードするにはFileUtilsを修正します。
ファイルの場所は「プロジェクトの場所\cocos2d\cocos\2d\platform」です。
注意が必要なのが、これ、プラットフォーム毎に継承して違うクラスを使ってるので、対応プラットフォーム全部の修正する必要があります。
Windowsの場合は「プロジェクトの場所\cocos2d\cocos\2d\platform\win32\CCFileUtilsWin32.cpp」です。
AndroidとLinuxもそれぞれのフォルダにあります。MacとiOSは「Apple」フォルダにあります。
ここでは、とりあえず、継承元のCCFileUtils.cppで解説します。

static Data getData(const std::string& filename, bool forString)
{
    CCASSERT(!filename.empty(), "Invalid filename!");
    
    Data ret;
    unsigned char* buffer = nullptr;
    ssize_t size = 0;
    const char* mode = nullptr;
    if (forString)
        mode = "rt";
    else
        mode = "rb";
    
    do
    {
        // Read the file from hardware
        std::string fullPath = FileUtils::getInstance()->fullPathForFilename(filename);
        FILE *fp = fopen(fullPath.c_str(), mode);
        CC_BREAK_IF(!fp);
        fseek(fp,0,SEEK_END);
        size = ftell(fp);
        fseek(fp,0,SEEK_SET);
        
        if (forString)
        {
            buffer = (unsigned char*)malloc(sizeof(unsigned char) * (size + 1));
            buffer[size] = '\0';
        }
        else
        {
            buffer = (unsigned char*)malloc(sizeof(unsigned char) * size);
        }
        
        size = fread(buffer, sizeof(unsigned char), size, fp);
        fclose(fp);
    } while (0);
    
    if (nullptr == buffer || 0 == size)
    {
        std::string msg = "Get data from file(";
        msg.append(filename).append(") failed!");
        CCLOG("%s", msg.c_str());
    }
    else
    {
		//-----------------------------------------------------------------------------
		// ファイル暗号化対応
		//-----------------------------------------------------------------------------
		if (filename.find(".dat") != string::npos){
			for(int i = 0; i < size; i++){
				buffer[i] = ~buffer[i];
			}
		}
		//-----------------------------------------------------------------------------
        ret.fastSet(buffer, size);
    }
    
    return ret;
}

getData()内の
ret.fastSet(buffer, size); の直前にデコードの処理を追加します。
私の場合は暗号化したファイルの拡張子を.datに統一して、

if (filename.find(".dat") != string::npos)

で暗号化したファイルか判別してます。
んでもって、データのビットを全部反転しちゃってます。
こんだけで暗号化できます。ね、簡単でしょ?
ちなみに、Androidの場合は変数名がちょっと違ってて、「buffer」->「data」になるので注意。
自分は今のところ、WindowsとAndroidでしか確認してませんが、たぶん他も同じで大丈夫(だといいな)

ただビットを反転させるだけだと、簡単に解読できちゃうんで、実際は文字列のkeyを元に暗号化して使ってます。DXライブラリのDXArchiveはソースが同梱されてるので、それ参考にさせてもらってます。
DXライブラリ置き場 ダウンロードページで、VisualC++用に同梱されてます。

最後に

@echo off
for /d %%d in (*) do (
	for %%f in (%%d\*.png) do ResourceEncoder.exe %%f
)

こんな感じでリソースをエンコードするバッチを作っとくと便利です。

あと、TexturePackerとか使ってる場合は、画像の拡張子変更したら.plist内のファイル名も変更しないといけないので注意。
この辺もバッチで自動化してます。

はい、そんな感じで次回はたぶんマウスの座標取得とかその辺の話。

2014/02/20



CAPTCHA