我正在尝试在运行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()将允许我不打扰生成唯一文件,然后不得不清理它们。
答案 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的经验,我会非常欢迎听到一些消息,即使它已经过了几年。