如何在Windows平台下的网络服务器上通过PHP进行gpg加密?

时间:2011-02-22 01:24:30

标签: php windows encryption xampp gnupg

我正在尝试在运行XAMPP的PHP平台上进行GPG加密。

网络服务器是Apache,运行的是PHP 5.2.9。 我正在使用GPG4Win 2.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()将允许我不打扰生成唯一文件,然后不得不清理它们。

1 个答案:

答案 0 :(得分:2)

我最终还是妥协了,让解决方案最初“正常工作”,尽管我对它的完成方式并不是很满意。

问题似乎分为两部分。

第一部分是尝试签名时进程会挂起,并使用--passwd-fd选项。如果我退出这个选项,我会得到一个提示,通过网络服务器的交互性,手动输入,一切都会好的。对于无人值守的应用程序,解决方法是简单地没有密码。我已经在各种GnuPG论坛中看到过这样的建议,即如果你的密码短语将作为纯文本存储在与私钥相同的机器上,那么你也可以免除伪装而没有伪装。暂时没有密码短语。

第二部分是输入太大。神奇的数字似乎是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的经验,我会非常欢迎听到一些消息,即使它已经过了几年。