[Tutor] GPG password entry automation help

rmlibre at riseup.net rmlibre at riseup.net
Tue Dec 10 09:14:08 EST 2019


No one responded to the request I put out, so I ducked into the codebase
of some other projects that also talk with GPG to learn their tricks. It
was rough trying to find exactly what I was missing. But after narrowing
down the possibilities and cross-referencing with the GPG documentation,
I got it!!

It's a big lesson for me in how to find answers: read the docs, other
people's code, and other people's questions. I'll post the working code
below.


folder/
----tiny_gnupg.py
----gpghome/
--------gpg2
         

># tiny_gnupg.py
>
>from pathlib import Path
>from subprocess import check_output
>
>
>class GnuPG:
>    def __init__(self, username="", email="", passphrase=""):
>        self.set_homedir()
>        self.email = email
>        self.username = username
>        self.passphrase = passphrase
>        self.fingerprint = ""
>
>    def set_homedir(self, path="gpghome"):
>        self.home = self.format_homedir(path)
>        self.executable = self.home + "/gpg2"
>
>    def format_homedir(self, path="gpghome"):
>        return Path(path).absolute().as_uri().replace("file://", "")
>
>    def encode_inputs(self, *inputs):
>        return ("\n".join(inputs) + "\n").encode()
>
>    def read_output(self, command=None, inputs=b"", shell=False):
>        return check_output(command, input=inputs, shell=shell).decode()
>
>    def gen_key(self):
>        command = [
>            self.executable,  # path to gpg2 executable
>            "--homedir",  # this creates a non-system keyring
>            self.home,  # path to keyring storage folder
>            "--pinentry-mode",  # dunno exactly what this does, but it works
>            "loopback",
>            "--expert",
>            "--full-gen-key",
>            "--with-colons",
>            "--command-fd",
>            "0",
>            "--status-fd",
>            "1",
>            "--passphrase-fd",  # tells GPG to expect the pw as the first input
>            "0",
>        ]
>        inputs = self.encode_inputs(
>            self.passphrase,
>            "9",
>            "1",
>            "0",
>            "y",
>            self.username,
>            self.email,
>            "There's safety in numbers.",
>            "O",
>        )
>        output = self.read_output(command, inputs)
>        self.fingerprint = output.strip().split("\n")[-1][-40:]
>
>
>username = "username"
>email = "username at user.net"
>passphrase = "test_user_passphrase"
>gpg = GnuPG(username, email, passphrase)
>
># This will generate a new combined encryption ed25519 ECC key and
># signing/certifying ed25519 ECC key.
>gpg.gen_key()


This was really difficult to figure out, and from searching the web,
lot's of folks have trouble figuring out the GPG interface. I turned my
solution into a package with the other encrypt, decrypt, keyserver
upload and download functions coded as well, for anyone who stumbles
across this problem in the future: https://pypi.org/project/tiny-gnupg/.
It's all gplv3 licensed.


Also, thanks, Joe, for the initial insight and guidance for me to find
the right direction to explore! :)


More information about the Tutor mailing list