Jérôme Belleman
Home  •  Tools  •  Posts  •  Talks  •  Travels  •  Graphics  •  About Me

Python, Subprocess, GPG and Standard Input

25 Apr 2015

A discussion around having the gpg command tell the passphrase from data when both are expected to be supplied on stdin, and ways to achieve this in Python.

1 Both the Passphrase and Data Through Standard Input

As the gpg command can take both data and a passphrase from stdin, one might be wondering how to make both available to it. While it turns out writing first the passphrase, then the data to stdin seems to work I've never seen this method advertised. So I decided that only writing data to stdin and providing the passphrase by giving the gpg command a file descriptor might be more desirable.

2 Using Pipes

But what's a safe way to write a passphrase to file? Even if you use encrypted filesystems, using the tempfile module to write a temporary file and having it deleted immediately after you're done isn't really satisfying.

Thankfully, there's a better way, still: pipes. A discussion on Stack Overflow entitled Python/POpen/gpg: Supply passphrase and encryption text both through stdin or file descriptor explains how a snippet similar to this one will work like a charm:

rpipe, wpipe = os.pipe()
os.write(wpipe, passphrase)
os.close(wpipe)

tarproc = subprocess.Popen(tarcmd, stdout=subprocess.PIPE)
gpgproc = subprocess.Popen(gpgcmd + [str(rpipe)], stdin=tarproc.stdout)
gpgproc.communicate()
tarproc.communicate()
os.close(rpipe)

I found it interesting to see that str(rpipe) is usually a relatively low number. You'll also notice in that Stack Overflow discussion referred to below that one example suggests adding a newline at the end of the passphrase: I didn't find that necessary in practice.

3 References