4

I am trying to incorporate GPG clear-signing of text in a string in a PHP script. I can cause GPG to encrypt text in a string like this:

$encrypted = shell_exec("echo '$text' | gpg -e -a -r foo@bar.com --trust-model always");

and that works perfectly, with the encrypted text being sent to the $encrypted variable. This proves GNUPGHOME and GNUPG are set up correctly.

However, when I try to produce a clear-signed message in the same way with this:

$text = "googar";

$signature = exec("echo $passphrase | gpg -v --clearsign --no-tty --passphrase-fd 0 '$text' 2>&1 1> /dev/null", $output);

I am returned this error:

... string(51) "gpg: can't open `googar': No such file or directory"
[3]=>
string(46) "gpg: googar: clearsign failed: file open error"
}

This error is returned with or without the single quotes around the $text variable.

How can I force GPG or shell_exec to treat $text as a pipe instead of it looking for a file?

I need to echo the passphrase in this way (I know, its 'horribly insecure' because GPG has no way to pass in a passphrase as a variable on the command line.

Axinar
  • 43
  • 1
  • 3

2 Answers2

5

You could use proc_open and create a separate file descriptor for your password:

$descriptorspec = array(
    0 => array("pipe", "r"),
    1 => array("pipe", "w"),
    2 => array("pipe", "w"),
    3 => array("pipe", "r"),
);

$pipes = false;
$process = proc_open("gpg -v --clearsign --no-tty --passphrase-fd 3", $descriptorspec, $pipes);

if(is_resource($process)) {
    fwrite($pipes[3], $passphrase);
    fclose($pipes[3]);

    fwrite($pipes[0], $text);
    fclose($pipes[0]);

    $output = stream_get_contents($pipes[1]);
    $stderr = stream_get_contents($pipes[2]);

    fclose($pipes[1]);
    fclose($pipes[2]);

    $retval = proc_close($process);

    echo "retval = $retval\n";
    echo "output= $output\n";
    echo "err= $stderr\n";
}
vstm
  • 11,709
  • 1
  • 44
  • 45
  • Thank you so much for this, problem solved. I dropped in your code, and it just works. I will study its parts to learn something new. Once again, thanks! – Axinar Aug 08 '11 at 14:12
2

You could use process substitution:

echo $passphrase | gpg -v --clearsign --no-tty --passphrase-fd 0 <(printf '$text') 2>&1 1> /dev/null
                                                                 ^^              ^

This will make gpg thinks it is reading data from a file, but the file will be a temporary named pipe which input will be printf '$text'.

jfg956
  • 14,312
  • 3
  • 22
  • 33
  • Thanks for your answer. It now returns no error, but also does not display the GPG signed output. – Axinar Aug 08 '11 at 13:29
  • True, no output, because stdout and stderr are piped to /dev/null. Try without `2>&1 1> /dev/null`at the end, and if the result is ok, I will update the answer (I am too lazy to build the test case myself). – jfg956 Aug 08 '11 at 15:27