PHPでGnuPGを使ってみる

こんにちは。橋本です。

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

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


<?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方式による暗号化を行うことが可能です。
暗号化が必要な状況は少ないかもしれませんが、もしよかったら試してみてはいかがでしょうか。