Search code examples
phpbashlampgnupgpassphrase

How can I force GPG to accept input from STDIN instead of trying to open a file?


I am trying to incorporate GPG's 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 [email protected] --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 get 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, it's 'horribly insecure' because GPG has no way to pass in a passphrase as a variable on the command line.


Solution

  • 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";
    }