开发者问题收集

如何返回在 bash 中不会退出的 gpg 命令的退出值来验证错误的密码?

2020-08-24
2440

在 GPG 中,没有适当的文档说明如何通过 bash 代码检查有效的密码,因此,这是一种黑客行为。根据以下示例代码,用于检查 gpg-agent 中缓存的 GPG 密码是否有效:

#!/bin/bash
KEY_ID=YOUR_KEY_ID
echo "1234" | gpg -q --batch --status-fd 1 --sign --local-user $KEY_ID --passphrase-fd 0 --output /dev/null
return_code=$?
if [ "$return_code" = 0 ]; then
 echo "Valid passphrase has been set in gpg-agent"
   else
 echo "Invalid passphrase or no passphrase is set in gpg-agent"
fi

如果设置了有效的密码,当我运行此 bash 脚本时,返回值为 0。这是正确的

但是

如果没有设置密码或设置了无效的密码,我可以看到命令正在等待一些未知的输入或进程,并且它不会退出(光标闪烁,直到我使用 CTRL+C 终止)。但这是表明提供的密码无效的良好信号。

我的问题是,如果提供的密码无效,我该如何强制命令退出并获取返回值 1,以便我可以正确使用 if else 条件?

注意和信息以从代码中重现问题(这不是问题):

设置 gpg 密码有两种方法:

  1. gpg --export-secret-keys -a <KEY_ID> (这可以验证密码)或
  2. 在 bash 中不带提示: /usr/libexec/gpg-preset-passphrase -c $KEY_GRIP <<< $PASSPHRASE (这不验证密码)。我需要使用 cron 命令。为什么?请阅读下文。

要清除密码,我执行以下操作: echo RELOADAGENT | gpg-connect-agent

KEY_ID - 您首次创建证书时获得的

KEY_GRIP - 可以使用以下命令获取: gpg --with-keygrip --list-secret-keys $KEY_ID

PASSPHRASE - 是您的证书在 gpg-agent 中缓存的密码。

请注意,如果您使用此方法在 gpg-agent 中缓存密码: /usr/libexec/gpg-preset-passphrase -c $KEY_GRIP <<< $PASSPHRASE ,它不会验证密码,因为错误的密码也可以缓存在 gpg-agent 中。此方法是以 cron 运行时跳过交互式输入的唯一方法,以防止由于没有用户输入而导致脚本错误。这就是我使用破解代码的原因。

3个回答

我找到了这个问题的答案。由于错误,返回代码无法正确输出。我只需要修改代码,这样它就不会使用默认的 pin-entry 密码提示。根据此相关错误 ( https://dev.gnupg.org/T5076 ),使用 pin-entry 密码可能会导致返回代码在随机时间卡住。简而言之,返回代码卡在随机时间,但可以使用此选项解决:

--pinentry-mode=loopback

因此,上述选项是禁用 pin-entry 密码提示,我们可以使用 gpg-preset-passphrase 实用程序在终端中设置密码。因此,使用此方法我可以获得正确的返回代码。

我发现这个线程讨论了如何在 gpg-agent 中禁用 PIN 输入,例如: 这里

因此,这是验证密码时具有正确返回代码的工作代码:

#!/bin/bash
gpg-agent --daemon
KEY_ID=ABC12321SS
GPG_PRESET_PASS="/usr/libexec/gpg-preset-passphrase" # This utility came with gpg
KEY_GRIP=$(gpg --with-keygrip --list-secret-keys "$KEY_ID" | grep -Pom1 '^ *Keygrip += +\K.*') # Get they key grip
# Ask passphrase
read -s -p "Enter a passphrase to cache into a running gpg-agent: " PASSPHRASE; echo
# Cache RAW passphrase here. RAW passphrase means un-validated passphrase. Passphrase can be valid or invalid cached in gpg-agent.
$GPG_PRESET_PASS -c $KEY_GRIP <<< $PASSPHRASE 
# AND NOW WE check if a RAW passphrase is cached:
RET_VAL=$?
if [ $RET_VAL = 0 ]; then
        echo "Un-validated (RAW) passphrase is cached"
        # This is the part that I must use --pinentry-mode=loopback, so I will get correct return code
        echo "Now validating a RAW cached passphrase from gpg-agent ..."
        test=$(echo "1234" | gpg -q --pinentry-mode=loopback --status-fd 1 --sign --local-user "$KEY_ID" --passphrase-fd 0 > /dev/null)
        RET_VAL=$?
        if [ $RET_VAL = 0 ]; then
                echo "Passphrase is valid"
        else
                echo "Passphrase is invalid"
                # Can clear the passphrase and ask again for RAW passphrase
        fi

else
        echo "Error when trying to cache RAW passphrase"
        exit 1
        # Run again the script to cache RAW passphrase
fi
MaXi32
2020-10-14

如果可以的话, 您可以启动另一个脚本来计时此脚本的执行时间。如果实际脚本退出,则输入正确的密码,否则,如果设置的时间到了,则终止脚本的 PID,然后脚本结束。

Muhammad Hasan
2020-08-24

您可以尝试类似的方法:

echo "1234" | gpg -q --batch --status-fd 1 --sign --local-user <KEY_ID> --passphrase-fd 0 --output /dev/null ||
{
    echo "Invalid passphrase or no passphrase is set in gpg-agent"
    exit
}
echo "Valid passphrase has been set in gpg-agent"

我不确定这是否可以处理看起来像等待输入的情况。

Snorik
2020-08-24