1

XAMPPを実行しているPHPのWindowsプラットフォームでGPG暗号化を実行しようとしています。

WebサーバーはApacheであり、PHP5.2.9を実行しています。GPG4Win2.0.4を使用しています。

コマンドラインからencryptコマンドを実行することに成功しました。受信者とホスト名を変更しました。

C:\>C:\PROGRA~1\GNU\GnuPG\pub\gpg.exe --encrypt --homedir C:\DOCUME~1\reubenh.AD\APPLIC~1\gnupg --recipient name@host.com --armor < test.txt > test.enc.txt

PHPでは、proc_open()を使用しているため、暗号化するコンテンツをプロセスに直接パイプし、stdoutパイプを使用して出力を取得できます。

以下は、コードのスニペットです。

    $cmd = Configure::read('Legacy.GPG.gpg_bin').' --encrypt '.
        '--homedir '.Configure::read('Legacy.GPG.gpg_home').' '.
        '--recipient '.Configure::read('Legacy.MO.gnugp_keyname').' '.
        '--local-user '.'me@host.com'.' '.
        '--armor --no-tty --batch --debug-all';

    error_log('Encrypting Command line is '.$cmd);

    $descriptors = array(
        0 => array('pipe', 'r'),
        1 => array('pipe', 'w'),
        2 => array('file', LOGS.'gpg.log', 'a')
    );

    $process = proc_open($cmd, $descriptors, $pipes);
    if (is_resource($process)) {
        error_log(print_r($pipes, true));
        list($stdin, $stdout) = $pipes;

        error_log('Have pipes');

        error_log('body length is '.strlen($this->request['body']));
        $ret = fwrite($stdin, $this->request['body'], strlen($this->request['body']));
        error_log($ret.' written');         

        error_log('before fclose()');                       
        fclose($stdin);

        error_log('Done with input');

        $encryptedData = '';
        while(!feof($stdout)) {
            $line = fgets($stdout);
            error_log('Line read:'.error_log(print_r($line, true)));
            $encryptedData .= $line; 
        }
        fclose($stdout);

        $return = proc_close($process);

        error_log('Encryption process returned '.print_r($return, true));

        if ($return == '0') { // ... next step is to sign

最初のerror_log()ステートメントから生成されたコマンドは次のとおりです。

C:\PROGRA~1\GNU\GnuPG\pub\gpg.exe --encrypt --homedir C:\DOCUME~1\reubenh.AD\APPLIC~1\gnupg --recipient name@host.com --local-user me@host.com --armor --no-tty --batch --debug-all

実際の走行は「パイプを持っている」までのようです。その後、停止します。

また、Process Explorerで、gpg.exeがgpg2.exeも生成することを確認できます。私がハンドルを持っていないのはこのgpg2.exeであり、私が呼び出した元のgpg.exeではなく、入力を待っているのではないかと思います。

gpg2.exeを直接呼び出しようとしましたが、子gpg2.exeがまだ生成されています。

proc_open()を使用し、ディスクI / Oを使用してコンテンツを提供し、出力を取得することは避けたいと思います。これはWebサーバーで実行されるため、proc_open()を使用すると、わざわざ一意のファイルを生成できなくなります。それらをクリーンアップする必要があります。

4

1 に答える 1

2

解決策を最初に「機能させる」ために妥協しましたが、その方法にはあまり満足していません。

問題は 2 つの部分にあるように見えました。

最初の部分は、署名しようとするとプロセスがハングし、 --passwd-fd オプションを使用することでした。このオプションを省略した場合、Web サーバーのインタラクティブな性質によってプロンプトが表示され、手動で入力すればすべて問題ありません。無人アプリケーションの回避策は、単純にパスフレーズを持たないことです。さまざまな GnuPG フォーラムで、パスフレーズを秘密鍵と同じマシンにプレーン テキストとして保存する場合は、ふりをやめて、持っていなくてもよいという推奨事項を見てきました。現在、パスフレーズは機能していません。

2 番目の部分は、入力が大きすぎるということでした。マジックナンバーは72kbらしい。proc_open と標準パイプを使用して、それよりも大きなペイロードを暗号化するのはうまくいかないようでした。その結果、ペイロードを一時的にファイルに書き込み、proc_open によって読み取られるようにすることにしました。次のように参照してください。

$tmpfile = tmpfile();
fwrite($tmpfile, $this->request['body']);
fseek($tmpfile, 0);

$cmd = '...'; // similar to question command, but with --sign --encrypt and no --passphrase-fd

$descriptors = array(
    0 => $tmpfile,
    1 => array('pipe', 'w'),
    2 => array('file', LOGS.'gpg.log', 'a')
);

$options = array('bypass_shell' => true);

$process = proc_open($cmd, $descriptors, $pipes, null, null, $options);
if (is_resource($process)) {
    stream_set_blocking($pipes[1], 0);

    fclose($tmpfile);

    $encryptedData = '';
    $line = fgets($pipes[1]);
    while (!feof($pipes[1])) {
        $encryptedData .= $line;
        $line =fgets($pipes[1]);
    }

    fclose($pipes[1]);

    $return = proc_close($process);

    if ($return = '0') { 
        // success processing
    }        
}

list() = $pipes を使用しないことを選択しました。これは、stdout パイプのみが実際に配列で返されるためです。

Windows 環境で GPG と PHP を使用した経験のある方がいらっしゃいましたら、何年も先のことであっても、何かお聞かせいただければ幸いです。

于 2011-02-23T05:10:31.893 に答える