GUI for GPG within Windows WSL for passwords, pins, etc.
Optional persistence of passwords into Windows Credential Manager
(c) 2018 Dale Phurrough
Licensed under the Mozilla Public License 2.0
- Allows GnuPG to prompt and read passphrases by the pinentry protocol with a GUI when running within WSL (Windows Subsystem for Linux)
- Works for all keys managed by gpg-agent (GPG, SSH, etc)
- Drop-in replacement GUI to pinentry-curses, pinentry-gtk-2, etc.
- Works well with WSLgit. Enables your Git and GPG configuration/processing in WSL while access/using it from Windows apps like VS Code. Easy-breezy GPG signing of Git commits. 🙂📝
- Windows 10 Fall Creators Update (build 16299) or newer. You can check the version by
winver.exe
- WSL with Ubuntu 16.04 or newer. You can check the release version by
cat /etc/lsb-release
- GPG v2.1.11 or later. Earlier versions of 2.x (aka GPG2) or 1.x (aka GPG) have not been tested and are not recommended. You can check the version by
gpg2 --version
- Save the
pinentry-wsl-ps1.sh
script and set its permissions to be readable and executable, e.g.
chmod ug=rx pinentry-wsl-ps1.sh
- Configure gpg-agent to use this script for pinentry using
one of the following methods
- Set pinentry-program within ~/.gnupg/gpg-agent.conf to the script's path, e.g.
pinentry-program /mnt/c/repos/pinentry-wsl-ps1/pinentry-wsl-ps1.sh
- Or, set the path to this script when you launch gpg-agent, e.g.
gpg-agent --pinentry-program /mnt/c/repos/pinentry-wsl-ps1/pinentry-wsl-ps1.sh
- Set pinentry-program within ~/.gnupg/gpg-agent.conf to the script's path, e.g.
- Optionally enable persistence of passwords.
- Follow instructions https://github.com/davotronic5000/PowerShell_Credential_Manager to install the needed module from the Powershell Gallery or GitHub.
- Note security perspectives like https://security.stackexchange.com/questions/119765/how-secure-is-the-windows-credential-manager
- Edit the script and near the beginning of the file set
PERSISTENCE
to one of the values:""
no persistence"Session"
persists the password only for the current Windows login session"LocalMachine"
persists the password for the current Windows login on the local Windows computer"Enterprise"
persists the password for the current Windows login and requests Windows Credential Manager to synchronize it across Windows computers for that same Windows login
- Optionally disable toast notification of password retrieval from Credential Manager. By default, this code notifies you with a toast notification every time gpg-agent retrieves a password from the Windows Credential Manager. Gpg-agent caches passwords by default (see gpg-agent settings like
max-cache-ttl
) so you may not see the notification with every usage.- Disable: edit the script, near the top, set
NOTIFY
to the value"0"
- Enable: edit the script, near the top, set
NOTIFY
to the value"1"
- Disable: edit the script, near the top, set
- Run
gpg2 --version
andgpg-agent --version
. If you don't have version 2.1.11 or newer for both versions, you may have unknown problems. - I recommend you have a fully working GPG2 and GPG-agent setup using the default GPG2 configuration. Try two tests. If these both don't work, you first need to troubleshoot your install.
gpg2 --clearsign myfile.zip
. Your entire console window should clear and present you an isolated password entry field in a crudely drawn box. Type in your key's password and it should return to your normal console with no error. You should now have the newly signedmyfile.zip.asc
file.- If you are using the SSH-compatibility feature of GPG-agent, ensure you are not running
ssh-agent
. Tryssh-add ...
to add your SSH key for your favorite host. Then remove and stash in a protected location this ssh key file from your~/.ssh
directory to ensure ssh isn't using that file instead of the agent. Now try to ssh to this host. It should automatically retrieve the private host key from gpg-agent.
- I discovered that there are many ways for gpg-agent to be started silently. The options passed to it are inconsistent across the methods (and across gpg versions). On my computer, I explicitly start gpg-agent. Below is the method I use in my
.profile
. Please be aware that.profile
is not always run for all *nix shell scenarios and.bashrc
may be better for your setup. The details on this are written in the BASH man page in the INVOCATION section. - Configuration of GPG can become complicated if you diverge from what the GPG team considers a standard setup. You may need to read the official GPG documentation to configure it for your specific computer setup.
- GIT uses
gpg
by default. To instruct GIT to usegpg2
, you can easily configure it withgit config --global gpg.program gpg2
- Enable a gpg-agent log file. Edit your
~/.gnupg/gpg-agent.conf
file and insert the following lines. Your user must have permission to write to this file path. Restart gpg-agent after you save this configuration.debug 1024 debug-pinentry log-file /home/username/agent.log
- Enable a log file specific to this pinentry code. Edit the script, near the top, set
DEBUGLOG
to a file path, e.g."$HOME/pintrace.log"
. Your user must have permission to write to this file path. Restart gpg-agent after you save this configuration.
Below are some examples from my configuration files. If you have a working GPG2 and gpg-agent setup, the only config change likely needed is the pinentry-program
line from setup step 2.
if [ -z "$(pgrep gpg-agent)" ]; then
gpgconf --launch gpg-agent
# I use the above method because the following method
# doesn't set GPG_AGENT_INFO or GPG_TTY and has a bug
# setting SSH_AUTH_SOCK if you use socket redirection:
# eval $(gpg-agent --homedir $HOME/.gnupg --daemon)
fi
if [ -z "$(pgrep dirmngr)" ]; then
dirmngr --homedir $HOME/.gnupg --daemon >/dev/null 2>&1
# I use the above method to consistently set vars in .bashrc
# rather than the following:
# eval $(dirmngr --homedir $HOME/.gnupg --daemon)
fi
export GPGKEY=12345678 # set prefered gpg signing key
PIDFOUND=$(pgrep gpg-agent)
if [ -n "$PIDFOUND" ]; then
export GPG_AGENT_INFO="$HOME/.gnupg/S.gpg-agent:$PIDFOUND:1"
export GPG_TTY=$(tty)
export SSH_AUTH_SOCK="$HOME/.gnupg/S.gpg-agent.ssh"
unset SSH_AGENT_PID
fi
PIDFOUND=$(pgrep dirmngr)
if [ -n "$PIDFOUND" ]; then
export DIRMNGR_INFO="$HOME/.gnupg/S.dirmngr:$PIDFOUND:1"
fi
unset PIDFOUND
enable-ssh-support
disable-scdaemon
pinentry-program /mnt/c/repos/pinentry-wsl-ps1/pinentry-wsl-ps1.sh
- https://www.gnupg.org/software/pinentry/index.html
- https://www.gnupg.org/documentation/manuals/gnupg/Agent-Options.html
- https://github.com/GPGTools/pinentry/blob/master/doc/pinentry.texi
- https://gist.github.com/mdeguzis/05d1f284f931223624834788da045c65
- https://github.com/GPGTools/pinentry/blob/master/pinentry/pinentry.c