如何返回在 bash 中不会退出的 gpg 命令的退出值来验证错误的密码?
在 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 密码有两种方法:
-
gpg --export-secret-keys -a <KEY_ID>
(这可以验证密码)或 -
在 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 运行时跳过交互式输入的唯一方法,以防止由于没有用户输入而导致脚本错误。这就是我使用破解代码的原因。
我找到了这个问题的答案。由于错误,返回代码无法正确输出。我只需要修改代码,这样它就不会使用默认的 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
如果可以的话, 您可以启动另一个脚本来计时此脚本的执行时间。如果实际脚本退出,则输入正确的密码,否则,如果设置的时间到了,则终止脚本的 PID,然后脚本结束。
您可以尝试类似的方法:
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"
我不确定这是否可以处理看起来像等待输入的情况。