如何使用 gpg 命令行检查密码短语是否正确

我试图用 duplicity自动化备份,但是当我测试结果时,我得到

公钥解密失败: 密码错误

我想检查我正在使用的密码短语是否实际上是与相应的 gpg 密钥相关联的密码短语,但是我无论如何都不能在 gpg 命令行选项中看到“不要加密或解密任何东西。只要确认我用的是正确的密码就行了。”

This suggests that maybe I am (yet again) misunderstanding Gnu Privacy Guard. (它喜欢嘲笑我,直到我哭出来。)

要求 gpg 验证密码短语是否有意义? 如果有,如何验证?

78399 次浏览

没有内置的方法可以做到这一点,但是它很简单,可以创建一个不修改任何内容的测试,并允许您只检查您的密码短语。

您没有指定,因此我假设您使用的 GnuPG 版本小于 v2,并且在 Linux 上使用 Bash 作为命令行解释器。

我将在这里和下面给出命令,我将解释每个部分的作用-(注意: 下面是 GnuPG 系列的版本1,请参阅下面的 GnuPG 系列的版本2)

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

首先,使用 echo "1234" |将一些文本传送到 GnuPG 进行签名-因为我们实际上不想签名任何东西,这只是一个测试,所以我们将签名一些无用的文本。

接下来,我们告诉 gpg 不要在 --no-use-agent中使用密钥代理; 这在后面很重要,因为根据密钥代理的不同,成功时它可能不会返回“0”,这就是我们想要做的全部事情——验证密码短语的成功。

接下来,我们告诉 gpg 将签名数据直接放到 /dev/null文件中,这意味着我们丢弃它,而不是将结果写到终端——注意: 如果您没有使用 Linux/Unix 的某种变体,那么这个文件可能不存在。在 Windows 上,您可能只需要允许它通过省略 -o /dev/null部分将已签名的数据写到屏幕上。

接下来,我们使用 --local-user 012345指定要用来进行测试的键。您可以使用 KeyID 获得最大的特异性,或者使用用户名,以最适合您的需要的方式。

接下来,我们指定 -as,它启用 ascii 输出模式,并设置签名的上下文模式。之后,-只是告诉 GnuPG 从标准插入获取要签名的数据,标准插入是我们给 echo "1234" |的命令的第一部分。

最后,我们有 && echo "A message that indicates success"——“ & &”表示,如果前一个命令成功,打印此消息。这只是为了清晰起见而添加的,因为上面命令的成功在其他情况下根本不会显示任何输出。

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. Good luck!

[编辑]-如果您使用的是 GnuPG v2,上面的命令需要稍微修改一下,如下所示:

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

原因是,GnuPG v2期望通过代理检索密码短语,因此我们不能禁用使用 --no-use-agent的代理并获得期望的效果; 相反,我们需要告诉 GnuPG v2我们想运行一个“批处理”进程,并通过使用选项 --passphrase-fd 1从 STDIN (standard in)检索密码短语。

这是一个较短的命令行,用于检查密码短语是否正确:

gpg --export-secret-keys -a <KEYID> > /dev/null && echo OK

对我来说,检查密码短语最简单的方法就是使用 gpg --passwd速记法。它试图更改密码短语,步骤是确认旧的密码短语,然后您可以在新的密码短语提示符上单击“取消”,这将保持密码短语的完整性。

gpg --passwd <your-user-id>

正如 福特04所提到的,对于较新版本的 GPG,现在可以将上面的命令改进为

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

这个更好,看看 承诺

警告不要使用回声 gpg -o /dev/null,正如这里的顶级答案所建议的那样。这将导致/dev/null 拥有无效的权限并损坏 /dev/null文件。可以在运行此命令时验证/dev/null 文件的权限,以证明这一点。

你可以用这个:

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

我还为此创建了 bash 脚本(这个脚本使用 Centos 8)。这个脚本将要求输入密码短语,如果它无效,它将继续要求输入有效的密码短语。另外,如果输入错误或不存在的 KEY _ ID 作为参数,它也可以验证:

#!/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:

如果输入了无效的密码,样例输出(它会不断询问) :

[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:

如果输入有效密码,则输出示例:

[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

当缓存有效的密码短语时,下次运行此脚本时,它不会要求您输入密码短语。因此,这个脚本为您的问题提供了解决方案: “只需确认我使用了正确的密码短语”