124

I am trying to automate backups with duplicity, but when I test the result, I get

gpg: public key decryption failed: bad passphrase

I want to check whether the passphrase I am using is actually the passphrase associated with the corresponding gpg secret-key, but I can't see anyway in the gpg command-line options to say "Don't encrypt or decrypt anything. Just confirm I am using the right passphrase."

This suggests that maybe I am (yet again) misunderstanding Gnu Privacy Guard. (It has a predilection for taunting me until I cry.)

Does it make sense to ask gpg to verify a passphrase? If so, how?

Oddthinking
  • 24,359
  • 19
  • 83
  • 121

4 Answers4

125

There is no in-built method for doing this, but it is simple enough to create a test that doesn't modify anything and allows you to just check your passphrase.

You didn't specify, so I will assume you are using GnuPG version less than v2 and are on Linux with Bash for your commandline interpreter.

I will give the command here and below I will explain what each part does - (note: the following is for GnuPG series version 1, see below for GnuPG series v2)

echo "1234" | gpg --no-use-agent -o /dev/null --local-user <KEYID> -as - && echo "The correct passphrase was entered for this key"

What that does is first, pipe some text to sign to GnuPG with echo "1234" | - because we don't really want to sign anything, this is just a test, so we will sign some useless text.

Next, we tell gpg to not use the key agent with --no-use-agent; this is important later because, depending on your key agent, it may not return "0" on success, and that is all we want to do - verify success of your passphrase.

Next, we tell gpg to put the signed data directly into the /dev/null file, meaning we discard it and not write the result to the terminal -- NOTE: if you are not using some variant of Linux/Unix, this file may not exist. On windows you may have to just allow it to write the signed data to the screen by just omitting the -o /dev/null part.

Next, we specify the key we want to do our test with by using --local-user 012345. You can use the KeyID for maximum specificity, or use a username, whichever best suites your needs.

Next we specify -as, which enables ascii output mode, and sets the context mode for signing. The - afterwards just tells GnuPG to get the data to be signed from standard-in, which is the very first part of the command we gave echo "1234" |.

And last, we have && echo "A message that indicates success" -- the "&&" means, if the previous command was successful, print this message. This is just added for clarity, because the success of the command above would otherwise be indicated by no output at all.

I hope that is clear enough for you to understand what is going on, and how you can use it do the testing you want to do. If any part is unclear or you do not understand, I will be glad to clarify.

[EDIT] - If you are using GnuPG v2, the above command will need to be modified slightly, like so:

echo "1234" | gpg2 --batch --passphrase-fd 1 --local-user <KEYID> -as - > /dev/null && echo "The correct passphrase was entered for this key"

The reason being, GnuPG v2 expects the passphrase to be retrieved via an agent, so we cannot disable the use of the agent with --no-use-agent and have the desired effect; instead we need to tell GnuPG v2 that we want to run a "batch" process, and retrieve the passphrase from STDIN (standard in) by using the option --passphrase-fd 1.

Note: Don't use -o /dev/null as it will delete character device and replace it with an empty file

Jari Turkia
  • 1,184
  • 1
  • 21
  • 37
kylehuff
  • 5,177
  • 2
  • 34
  • 35
  • 13
    This does not work with gpg2, as it always required an agent. Also the ncurses agent somehow gets confused by the piped input. So I just used `gpg --local-user -as`. This just lets the agent ask for the passphrase and tells you if it was correct (Then does nothing). – BubuIIC Jan 18 '13 at 01:42
  • 1
    You are correct BubullC, for the most part; with slight modification to the options passed you can have a similar result using gpg2. I modified my answer to support the differences between gpg and gpg2. – kylehuff Jan 21 '13 at 16:37
  • 5
    Try this for GnuPG 2.1: `gpg -o /dev/null --local-user -as <(echo 1234) && echo "The correct passphrase was entered for this key"` – starfry Oct 03 '16 at 20:43
  • @BubullC I tried your command `gpg --local-user -as` and it gave a rather strange result. It DOES prompt me for my passphrase, but then it displays a message starting with `You need a passphrase to unlock the secret key for`, prints out the basic key information, and then goes into input mode. And yes, I am on gpg2 on a Mac. – JESii Feb 22 '17 at 14:20
  • The given GnuPG v2 command didn't work for me using version 2.2 on Mac OS, but @starfry's variant did. Perhaps it could be added to the accepted answer as well? – fagerbua Dec 04 '17 at 13:23
  • 7
    For me on MacOS 10.12.6, none of the variations prompt for passphrase, and return a success message regardless. – Stan James Dec 28 '17 at 18:30
  • I experienced the same as @StanJames - described how to clear the cache for a specific key at https://superuser.com/questions/586969/force-gpg-agent-to-forget-password – Ben Creasy May 28 '18 at 21:26
  • 3
    `--passphrase-fd 1`? read from stdout? This works for me: `gpg2 -aso - <(echo 1234); echo $?`. Use `echo RELOADAGENT | gpg-connect-agent` to forget passphrases. – x-yuri Nov 22 '18 at 22:18
  • 1
    Last time I checked standard in is file descriptor 0, i.e. `--passphrase-fd 0` – Niklas Holm Sep 19 '19 at 06:29
  • 1
    Warning, command that you guys are suggesting that has /dev/null here causes the /dev/null permission to change / corrupted in CentOS 8. Whenever I recreate the new /dev/null , `Recreate rm -f /dev/null; mknod -m 666 /dev/null c 1 3` . and run the command, it will messed up the /dev/null file again and again. The same command posted by @kylehuff – MaXi32 Sep 02 '20 at 16:54
  • See my answer for bash implementation – MaXi32 Sep 06 '20 at 08:10
  • 1
    It returns `The correct passphrase was entered for this key` whatever I echo as passphrase – alper Dec 19 '21 at 15:29
  • This is a nice post for learning some gpg options, but I find this answer superior, as it is shorter and recommended in git manpage: https://stackoverflow.com/a/61803335/11239693 – pjboro Mar 29 '22 at 11:00
  • `gpg --local-user -aso /dev/null <(echo 1234) 2>/dev/null && echo "YUP" || echo "NOPE - Status: $?"` worked great for me after `echo RELOADAGENT | gpg-connect-agent` – JayRugMan Oct 18 '22 at 17:00
39

For me the simplistic way to check the passphrase is to use gpg --passwd shorthand. It tries to change the passphrase and the step is to confirm the old passphrase, and then you can click 'cancel' on the new passphrase prompt and this keeps the passphrase intact.

gpg --passwd <your-user-id>

As mentioned by ford04, for newer version of GPG, now the above command can be improved to

gpg --dry-run --passwd <your-user-id>

which is even better. See the commit.

Lei Zhao
  • 986
  • 10
  • 11
  • 2
    This indeed is the most straightforward method that works regardless of whether you have the `gpg-agent` active or not. – foki Dec 22 '20 at 17:54
  • 4
    Or even better: `gpg --passwd --dry-run `. From man pages `--passwd`: "When using together with the option `--dry-run` this will not actually change the passphrase but check that the current passphrase is correct." – ford04 Feb 25 '21 at 11:26
  • 1
    @ford04 I believe that when I answered the question, the man page on my computer did not include such sentence. It was an older version of gpg. See this [commit](https://dev.gnupg.org/rG165bc38cefbc03515403b60b704cabf4dc0b71f4). – Lei Zhao Feb 26 '21 at 11:44
  • can passphase echoed into the command instead of manually writing it? – alper Dec 19 '21 at 15:34
  • works flawlessly! – Gaurav Apr 24 '22 at 12:16
24

This is a shorter command line to check if passphrase is OK:

gpg --export-secret-keys -a <KEYID> > /dev/null && echo OK
Allan Lewis
  • 308
  • 3
  • 13
Guest
  • 265
  • 3
  • 2
  • 1
    No, if you have a `gpg-agent` active (which most people do have) and you're properly logged in, this will not ask for the passphrase. – foki Dec 22 '20 at 17:51
  • This just freezes and does not return anything – alper Dec 19 '21 at 15:30
5

Warning do not use echo gpg -o /dev/null as suggested by top answer here. This will cause /dev/null to have invalid permission and corrupting the /dev/null file. You can verify the /dev/null file's permission when running this command to prove this.

You can use this:

echo "1234" | gpg -q --batch --status-fd 1 --sign --local-user $KEY_ID --passphrase-fd 0 > /dev/null

I also created bash script for this (This one is working with Centos 8). This script will ask for passphrase, if it's invalid, it will keep asking to input valid passphrase. Also if you input wrong or non-existing KEY_ID as an argument it can validate that as well:

#!/bin/bash
# usage ./gpgcron KEYID   | ./gpgcron 2B705B8B6FA943B1
script_path=$(dirname $(realpath -s $0))
script_name=$(basename -- "$0")
GPG_CACHE_BIN="/usr/libexec/gpg-preset-passphrase"
KEY_ID=$1
KEY_GRIP=$(gpg --with-keygrip --list-secret-keys $KEY_ID | grep -Pom1 '^ *Keygrip += +\K.*')
RETVAL=$?
if [[ $RETVAL -ne 0 || -z $KEY_ID ]]; then
    echo "Please provide correct KEY_ID. Example ./$script_name KEY_ID"
    exit 1
fi

export GPG_TTY=$(tty)

function set_gpg_cachepass {
    read -s -p "[$script_name | input]: Enter passphrase to cache into gpg-agent: " PASSPHRASE; echo
    $GPG_CACHE_BIN -c $KEY_GRIP <<< $PASSPHRASE
    RETVAL=$?
    echo "[$script_name | info ]: gpg-preset-passphrase return code: [$RETVAL]"
    if [ $RETVAL = 0 ]; then
        echo "[$script_name | info ]: A passphrase has been set and cached in gpg-agent"
        echo "[$script_name | info ]: Paraphrase set return code: [$RETVAL]"
        gpg_validatepass
    else
        echo "[$script_name | info ]: Unsuccessful error occured: [$RETVAL]"
        set_gpg_cachepass
    fi
}

function gpg_validatepass {
    echo "[$script_name | info ]: Validating passphrase cached in gpg-agent ..."
    echo "1234" | gpg -q --batch --status-fd 1 --sign --local-user $KEY_ID --passphrase-fd 0 > /dev/null
    RETVAL=$?
    if [ $RETVAL = 0 ]; then
        echo "[$script_name | info ]: OK, valid passphrase has been cached in gpg-agent"
    else
        echo "[$script_name | info ]: Warning, invalid passphrase or no passphrase is cached in gpg-agent"
        set_gpg_cachepass
    fi
}

RES=$(echo "KEYINFO --no-ask $KEY_GRIP Err Pmt Des" | gpg-connect-agent | awk '{ print $7 }')
if [ "$RES" == "1" ]; then
    echo "[$script_name | info ]: OK, passphrase is already cached in gpg agent for KEY_ID of [$KEY_ID]"
    gpg_validatepass
else
    echo "[$script_name | info ]: Warning, no passphrase is cached in gpg agent for KEY_ID of [$KEY_ID]"
    set_gpg_cachepass
fi

Sample output if no password is cached in gpg-agent:

[root@earth gpg]# ./gpgcron 2B705B8B6FA943B2
[gpgcron | info ]: Warning, no passphrase is cached in gpg agent for KEY_ID of [2B705B8B6FA943B2]
[gpgcron | input]: Enter passphrase to cache into gpg-agent:

Sample output if invalid passphrase is entered (it will keep asking):

[root@earth gpg]# ./gpgcron 2B705B8B6FA943B2
[gpgcron | info ]: OK, passphrase is already cached in gpg agent for KEY_ID of [2B705B8B6FA943B2]
[gpgcron | info ]: Validating passphrase cached in gpg-agent ...
gpg: signing failed: Bad passphrase
gpg: signing failed: Bad passphrase
[gpgcron | info ]: Warning, invalid passphrase or no passphrase is cached in gpg-agent
[gpgcron | input]: Enter passphrase to cache into gpg-agent:

Sample output if valid passphrase is entered:

[gpgcron | input]: Enter passphrase to cache into gpg-agent:
[gpgcron | info ]: gpg-preset-passphrase return code: [0]
[gpgcron | info ]: A passphrase has been set and cached in gpg-agent
[gpgcron | info ]: Paraphrase set return code: [0]
[gpgcron | info ]: Validating passphrase cached in gpg-agent ...
[gpgcron | info ]: OK, valid passphrase has been cached in gpg-agent

When valid passphrase is cached, the next time you run this script, it will not ask you to enter passphrase. So this script give the solution to your question; "Just confirm I am using the right passphrase"

MaXi32
  • 632
  • 9
  • 26