アシアルブログ

アシアルの中の人が技術と想いのたけをつづるブログです

symfony + PHPスクリプト暗号化(ionCube)

こんにちは井川です。今回は、symfonyに組み込んだPHPスクリプトを暗号化した際に。アプリケーションを正常に動作させる簡単な方法をご紹介します。この方法を使うことで、実際にionCubeでPHPスクリプトを暗号化しても正常に動作します(その他のエンコーダでも同様だと思います)。

symfonyは、libディレクトリ、apps/アプリ/libディレクトリ、apps/アプリ/module/*/lib以下のPHPファイルとクラスの対応関係を自動的に生成し、cacheディレクトリ以下にキャッシュファイルとして保存します(cache/アプリ/環境/config_autoload.yml.php)。そして次回からは、そのキャッシュファイルを用いてautoloadを実行します。このキャッシュファイル生成方法はいたって簡単です。上記libディレクトリ内の全PHPスクリプト(lib/vendor/symfonyなどは除く)を文字列として読み込み、その文字列からクラス名を抽出します。デフォルトでは、sfAutoloadConfigHandlerクラスがこの役割を担っており、parse()メソッド内部で上記の処理を行います。

PHPスクリプトの暗号化を使うと、キャッシュファイル生成時に各PHPファイルを文字列として読み込んでも、クラス名を抽出できません。このため、symfony実行時にエラーが発生します。

そこで今回はアプリケーションが正常に動作するように、上記キャッシュファイルを生成するクラスを新たに作ります。そして、symfonyで使われるように設定します。方法はとても簡単です。

まず、PHPファイルへのクラス定義時に以下の2つの制約を設けます。

①1ファイルに1クラス
PHPファイル名は「クラス名.class.php

そして、新しいクラスでは、ファイル名からそのファイル内に記述されているクラス名を取得し、クラス名とPHPファイルの絶対パスの関係を取り出します(config_autoload.yml.phpに記述)。

実際に、デフォルトでクラス名とファイルパスの関係を抽出しているのは、sfAutoloadConfigHandlerクラスの113~115行目です。



<?php
  ...
  foreach ($finder->in($matches) as $file)
  {
    $mapping = array_merge($mapping, $this->parseFile($path, $file, isset($entry['prefix']) ? $entry['prefix'] : ''));
  }
  ...


そこで、sfAutoloadConfigHandlerクラスを継承したTestAutoloadConfigHandlerクラスを次のように実装します。



<?php
class TestAutoloadConfigHandler extends  sfAutoloadConfigHandler
{
  protected function parse(array $configFiles)
  {
    ...
      foreach ($finder->in($matches) as $file)
      {
        $file_name = basename($file);
        
        if (preg_match('/^(.+)\.class\.php$/i', $file_name, $m))
        {
          $mapping[strtolower($m[1])] = $file;
        }
      }
    ...
  }
}


このクラスを使用するために、configディレクトリにconfig_handlers.ymlを設置します。内容は以下の通りです。



config/autoload.yml:
  class:    TestAutoloadConfigHandler


さらに、config/ProjectConfiguration.class.phpの先頭部分で、先のハンドラクラスを読み込みます。



<?php
require_once dirname(__FILE__).'/../lib/vendor/symfony/lib/autoload/sfCoreAutoload.class.php';
sfCoreAutoload::register();
require_once dirname(__FILE__) . '/../lib/config/TestAutoloadConfigHandler.class.php';

....


後は、暗号化を行い、暗号化スクリプトを使用する環境でsymfony ccを実行します。これで暗号化スクリプトsymfonyを使用できます。

ここでご紹介した方法は簡易的なものです。他のライブラリで、1つのファイルに複数のクラスを記述しているものや、ファイル名とクラス名が一致しないものを使う場合には、TestAutoloadConfigHandlerクラスを適切に書き直さなければなりません。必要に応じて試してみて下さい。

PHPでGnuPGを使ってみる

こんにちは。橋本です。

今日はPHPGnuPGを使って、OpenPGP方式による暗号化を行う方法を紹介します。
PHPGnuPGを扱うためには、PECLgnupg拡張モジュールを使います。


まずはプレーンテキストに対して暗号化と署名を行う方法です。
どちらも専用のメソッドを使うことで簡単に行うことができます。
以下が使用例です。



<?php
  // 暗号化用フィンガープリント(相手の鍵)、署名用のフィンガープリント(自分の鍵)、パスフレーズ
  $crypt_fp = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
  $sign_fp = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
  $passphrase = 'fugafuga';
  
  $plain_text = 'hogehoge';
  
  $gnupg = new gnupg();
  // 暗号化用の鍵を追加
  $gnupg->addencryptkey($crypt_fp);
  $gnupg->addsignkey($sign_fp, $passphrase);

  // 暗号化のみ行う場合
  $ecrypted_text = $gnupg->encrypt($plain_text);
  // 署名を行う場合
  $signed_text = $gnupg->sign($plain_text);
  // 署名と暗号化を同時に行う場合
  $encryptsigned_text = $gnupg->encryptsign($plain_text);
?>


暗号化を行うために相手の公開鍵が必要になるため、addencryptkey()関数を用いて、公開鍵を追加しています。
キーリングから相手の鍵の情報を取得するための情報としてフィンガープリントを引数として渡します。

また、署名を行う際には署名を行う人の秘密鍵が必要になるため、addsignkey()関数を用いて秘密鍵を追加しています。
秘密鍵の取得には、公開鍵の取得で用いたフィンガープリントの他に、パスフレーズを設定している場合にはパスフレーズが必要になります。

ちなみに、署名の形式は、setsignmode関数を用いて変更することが可能です。

署名と暗号化の両方を行う場合には、encryptsign()関数を使用します。
署名と暗号化を行うため、addsignkey()関数とaddencryptkey()関数で公開鍵、秘密鍵の追加が必要です。


今度は、暗号化や署名がされたテキストを復号する方法です。
こちらもまずは例を見てください。


<?php
  // フィンガープリント、パスフレーズ(自分の秘密鍵)
  $decrypt_fp = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
  $passphrase = 'fugafuga';
  $verified_text = '';
  $decryptverified_text = '';
  
  $encrypted_text = file_get_contents('/hoge/encrypted.txt');
  $signed_text = file_get_contents('/hoge/signed.txt');
  $encryptsigned_text = file_get_contents('/hoge/encryptsigned.txt');
  
  $gnupg = new gnupg();
  $gnupg->adddecryptkey($decrypt_fp, $passphrase);

  // 暗号化された文章を復号
  $decrypted_text = $gnupg->decrypt($encrypted_text);
  // 署名された文章の検証
  $sign_info = $gnupg->verify($signed_text, false, $verified_text);
  // 暗号化と署名がされた文章の復号と検証
  $sign_info2 = $gnupg->decryptverify($encryptsigned_text, $decryptverified_text);
  
?>


まずは暗号化された文章の復号ですが、復号には、decrypt()関数を用います。自分の秘密鍵が必要となりますので、引数には、フィンガープリントとパスフレーズが必要です。復号に成功した場合には戻り値として、復号済みのテキストが返ってきます。

次に署名の検証ですが、署名は、署名単体での検証と、署名付き文章の検証を行うことができます。
上記の例では、署名付きの文章を検証しています。署名付きの文章を検証する際には、第一引数に署名済みのテキスト、第二引数にはfalse、第三引数には検証済みの文章を格納したい変数を指定します。
署名の検証がうまくいった場合には、戻り値として署名の情報が戻ってくる他、第三引数として渡した変数に、検証済みのテキストが格納されます。
ちなみに、署名を単体で検証したい場合には、18行目を以下のように書き換えます。



<?php
  //$signは、単体の署名
 $sign_info = $gnupg->verify($signed_text, $sign);
?>

最後に、暗号化と署名が両方されたテキストの復号と検証については、decrptverify()関数を使用します。
復号と検証がうまくいった場合には、戻り値として、署名に関する情報が戻ってくるほか、第三引数として渡した変数に復号と検証済みのテキストが格納されます。

ちなみに、各鍵の情報は、keyinfo()関数を使用することで取得することができます。鍵情報の中には、フィンガープリントや鍵IDなどの情報が含まれていますので、上記の例で指定したフィンガープリントをメールアドレスから取得したいときには以下のようにすると取得することができます。



<?php
  $email = 'akifumi@hoge.co.jp';
  
  $gnupg = new gnupg();
  $key_info = $gnupg->keyinfo($email);
  
  $fingerprint = $keyinfo[0]['subkeys'][0]['fingerprint'];

  /*
  $key_infoは以下のような配列形式になっています。
  $keyinfo Array
      (
        [0] => Array
          (
            [disabled] =>
            [expired] =>
            [revoked] =>
            [is_secret] =>
            [can_sign] => 1
            [can_encrypt] => 1
            [uids] => Array
              (
                [0] => Array
                  (
                    [name] => Akifumi Hashismoto
                    [comment] =>
                    [email] => akifumi@hoge.co.jp
                    [uid] => Akifumi Hashimoto <akifumi@hoge.co.jp>
                    [revoked] =>
                    [invalid] =>
                  )

              )

            [subkeys] => Array
              (
                [0] => Array
                  (
                    [fingerprint] => xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
                    [keyid] => xxxxxxxxxxxxxxxx
                    [timestamp] => xxxxxxxxxx
                    [expires] => xxxxxxxxxx
                    [is_secret] =>
                    [invalid] =>
                    [can_encrypt] =>
                    [can_sign] => 1
                    [disabled] =>
                    [expired] =>
                    [revoked] =>
                  )
               )
            )
        )
     )  
*/
?>

同じ要領で鍵IDを取得することも可能です。

以上のようにPECL::gnupg拡張モジュールを使用することによって簡単にOpenPGP方式による暗号化を行うことが可能です。
暗号化が必要な状況は少ないかもしれませんが、もしよかったら試してみてはいかがでしょうか。