I'm trying to remote control gpg through a python program via POpen
.
I have a file that contains encrypted data which I want to decrypt, modify and write back to disk re-encrypted.
Currently I am storing the decrypted information in a temporary file (which I shred
when the program ends). Then I perform my modifications to that file and then re-encrypt it using a function, which pipes the passphrase through stdin
.
The code for this is as follows:
def encrypt(source, dest, passphrase, cipher=None):
"""Encrypts the source file.
@param source Source file, that should be encrypted.
@param dest Destination file.
@param passphrase Passphrase to be used.
@param cipher Cipher to use. If None or empty string gpg's default cipher is
used.
"""
phraseecho = Popen(("echo", passphrase), stdout=subprocess.PIPE)
gpgargs = [
"gpg",
"-c",
"--passphrase-fd", "0", # read passphrase from stdin
"--output", dest,
"--batch",
"--force-mdc"]
if not cipher is None and len(cipher) > 0:
gpgargs.extend(("--cipher-algo", cipher))
gpgargs.append(source)
encrypter = Popen(
gpgargs,
stdin=phraseecho.stdout,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout, stderr = encrypter.communicate()
rc = encrypter.returncode
if not rc == 0:
raise RuntimeError(
"Calling gpg failed with return code %d: %s" % (rc, stderr))
This works perfectly well, but I'm fairly sure that storing potentionally sensitive, decrypted data in a temporary file is a rather big security flaw.
So I want to rewrite my encryption/decryption functions in a way, that enables them to work completely in memory without storing sensitive data on disk.
Decryption works straight forward by also piping the passphrase via stdin
and capturing stdout
for the decrypted data.
Encryption on the other hand drives me mad, since I can't just pipe the passphrase AND the message to `stdin'...at least
encrypter.stdin.write("%s\n%s" % (passphrase, message))
didn't work.
My next best guess is to supply the file-descriptor of some kind of in-memory file/pipe/socket or whatever as --passphrase-fd
argument. The thing is: I don't know if there even is a thing such as in-memory files or if sockets would apply, since I never used them.
Can anybody help out or point me to a better solution for my problem?
The solution does not have to be portable - I'm totally fine with Linux only approaches.
Thanks in advance...
Edit:
Thanks a lot to both of you, Lars and ryran. Both solutions work perfectly! Unfortunately I can only accept one