Home / Alt manpages / pinentry-curses(1)

  • pinentry-curses(1)
  • User command
  • linux

Make GnuPG Use pinentry-curses in a Text Terminal

You will finish with GnuPG configured to present its pass-phrase dialog through pinentry-curses in a text terminal, with checks for the terminal environment and the agent process. Allow about fifteen minutes. You need the installed pinentry-curses package, GnuPG, a usable terminal, and a private key whose pass phrase you are willing to enter. The examples do not create, revoke or delete keys.

1. Check the installed program

Start with read-only checks. They do not need elevated privileges:

$ command -v pinentry-curses
/usr/bin/pinentry-curses
$ dpkg-query -W -f='${Package} ${Version}\n' pinentry-curses
pinentry-curses 1.2.1-3ubuntu5
$ pinentry-curses --version
pinentry-curses (pinentry) 1.2.1

The local package reports version 1.2.1. Its manual describes a curses-based PIN or pass-phrase dialog, normally called by gpg-agent rather than launched by a user. The program is intended for text mode, including sessions without the X Window System.

Checkpoint: if command -v prints nothing, stop here and repair the package installation through your normal package-management process. Do not guess a path in the agent configuration.

2. Tell gpg-agent which pinentry to use

The agent option pinentry-program selects the full path of the PIN entry program. Put this line in ~/.gnupg/gpg-agent.conf:

pinentry-program /usr/bin/pinentry-curses

This changes a per-user configuration file, so keep a copy of its current contents before editing it. If the file already contains a pinentry-program line, replace that line rather than adding competing entries. Do not use sudo: the file belongs to the account running your GnuPG agent.

There is no need to restart a system service for this per-user setting. Ask the running agent to reload its configuration:

$ gpg-connect-agent reloadagent /bye
OK

If the command reports an error, inspect the exact file and path. A reload does not make an invalid executable valid.

3. Give the agent the right terminal

A background agent does not automatically know which terminal should receive a curses dialog. In the shell where you will run GnuPG, set GPG_TTY to the current terminal:

$ export GPG_TTY=$(tty)
$ printf '%s\n' "$GPG_TTY"
/dev/pts/4

The device name will differ. Add the export to ~/.bashrc if this is a Bash login workflow and you want it in future interactive shells. For another shell, use that shell's normal startup file. If you are connected through a multiplexer or SSH, run the check in the same session that will invoke GnuPG.

Checkpoint: tty must print a terminal device, not an error such as "not a tty". A redirected command, cron job or service usually has no interactive terminal for pinentry-curses to draw on.

4. Confirm the agent sees the selected program

Ask the agent for its effective configuration:

$ gpg-connect-agent 'GETINFO cmd_has_option GETINFO pinentry-program' /bye
OK

That query only checks an agent protocol capability, not the selected path, so the most useful verification is a real, harmless GnuPG operation that is expected to require your key. List your secret keys first:

$ gpg --list-secret-keys --keyid-format=long
/home/you/.gnupg/pubring.kbx
------------------------
sec   ed25519/0123456789ABCDEF 2024-01-01 [SC]
      0123456789ABCDEF0123456789ABCDEF01234567
uid                 [ unknown] Example User <[email protected]>

Use a key you recognise. The key ID above is illustrative, so do not paste it as though it were yours. If no secret key is listed, this guide cannot produce a pass-phrase prompt on this account yet.

5. Trigger and verify the curses prompt

Use a temporary text file and sign it. This reads data but changes no key material:

$ printf '%s\n' 'pinentry-curses smoke test' > /tmp/pinentry-curses-test.txt
$ gpg --armor --local-user 0123456789ABCDEF --clearsign /tmp/pinentry-curses-test.txt

GnuPG should open a text pass-phrase dialog. Enter the pass phrase only into that dialog. A successful command creates /tmp/pinentry-curses-test.txt.asc and returns to the shell. Verify the signature, then remove both temporary files:

$ gpg --verify /tmp/pinentry-curses-test.txt.asc
gpg: Good signature from "Example User <[email protected]>" [unknown]
$ rm -f /tmp/pinentry-curses-test.txt /tmp/pinentry-curses-test.txt.asc

The identity and trust text vary. "Good signature" is the useful result here. The rm command is destructive, but its targets are the two disposable files created by this test. If you need to inspect them first, postpone removal instead of deleting a similarly named real file.

6. Fix the common failure modes

If no dialog appears, check the terminal before changing configuration. Confirm that GPG_TTY is exported in the shell running GnuPG and reload the agent again. A new terminal can have a different /dev/pts/N path.

If GnuPG says it cannot start the PIN entry program, check the executable directly:

$ test -x /usr/bin/pinentry-curses && echo executable
executable
$ /usr/bin/pinentry-curses --help | head -12
Usage: pinentry-curses [options] (-h for help)

If the path is executable but the prompt is still wrong, look for a second pinentry-program line in ~/.gnupg/gpg-agent.conf, reload the agent, and retry. Do not enable --debug casually: the local manual warns that debugging may reveal the entered pass phrase. Never include debug output in a ticket or log without checking it for secrets.

The curses dialog is not a general replacement for a graphical or service-safe pinentry. A non-interactive process needs an explicitly designed integration, and a command launched by cron will not acquire your terminal merely because GPG_TTY is set in an interactive shell.

Done means

  • pinentry-curses is installed and its version is known.
  • ~/.gnupg/gpg-agent.conf names /usr/bin/pinentry-curses once.
  • GPG_TTY points to the terminal running GnuPG.
  • The agent was reloaded after the configuration change.
  • A test signature prompted for the pass phrase and verified as a good signature.
  • The temporary test files were removed, and no key or agent service was disrupted.