Как зашифровать gpg через PHP на платформе Windows, под веб-сервером? - PullRequest
1 голос
/ 22 февраля 2011

Я пытаюсь выполнить шифрование GPG на платформе Windows, в PHP, используя XAMPP.

Веб-сервер 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 () и избегать использования дискового ввода-вывода для предоставления содержимого и получения выходных данных, поскольку это будет выполняться на веб-сервере, а proc_open () позволит мне не беспокоиться о создании уникальных файлов и затем нужно их почистить.

1 Ответ

2 голосов
/ 23 февраля 2011

В итоге я пошел на компромисс, чтобы получить решение, которое изначально «работало», хотя я не очень доволен тем, как оно было сделано.

Проблема, казалось, была в двух частях.

Первая часть заключалась в том, что процесс зависал при попытке подписать и использовать опцию --passwd-fd.Если бы я пропустил эту опцию, я бы получил подсказку через интерактивную природу веб-сервера, ввел бы ее вручную, и все было бы в порядке.Обходной путь для необслуживаемого приложения - просто не иметь парольную фразу.Я видел рекомендации на различных форумах GnuPG о том, что если ваша парольная фраза будет храниться в виде обычного текста на той же машине, что и закрытый ключ, то вы также можете обойтись без притворства и не иметь его.На данный момент парольная фраза не работает.

Вторая часть заключалась в том, что ввод был слишком большим.Магическое число, казалось, было 72 КБ.Любая полезная нагрузка, которая должна быть зашифрована больше, чем при использовании 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 () = $ pipe, потому что только массив stdout фактически вернется в массив.

Если у кого-то есть опыт работы с GPGи PHP в среде Windows, я бы с радостью что-то услышал, даже если бы это было лет спустя.

...