Pinentry: Difference between revisions
| Line 355: | Line 355: | ||
echo "Password: $password" | echo "Password: $password" | ||
</pre> | |||
== reliable option gpg-agent == | |||
<pre> | |||
#!/bin/bash | |||
# Ensure gpg-agent knows which terminal to use | |||
export GPG_TTY=$(tty) | |||
gpg-connect-agent updatestartuptty /bye >/dev/null | |||
response=$( | |||
gpg-connect-agent <<'EOF' | |||
GET_PASSPHRASE mytest X X "Enter Password" | |||
/bye | |||
EOF | |||
) | |||
echo "Raw response:" | |||
echo "$response" | |||
# Your system appears to return: | |||
# OK <hex-encoded-password> | |||
hex=$(echo "$response" | awk '/^OK / {print $2}') | |||
if [[ -z "$hex" ]]; then | |||
echo "Cancelled or no password entered" | |||
exit 1 | |||
fi | |||
password=$(printf '%s' "$hex" | xxd -r -p) | |||
echo "Password length: ${#password}" | |||
# Use password here | |||
# ... | |||
unset password | |||
</pre> | </pre> | ||
== keywords == | == keywords == | ||
Revision as of 21:55, 26 August 2026
echo -e 'SETTITLE YUBI\nSETDESC YUBI\nSETPROMPT YUBI\nSETERROR YUBI\nGETPIN\n' | /usr/bin/pinentry | grep '^D'
sample-pinentry.sh ::
#!/bin/bash
# Ensure pinentry is installed
command -v pinentry >/dev/null 2>&1 || {
echo "ERROR: pinentry not found"
exit 1
}
# Talk to pinentry using its text protocol
response=$(
{
echo "SETTITLE Credential Prompt"
echo "SETPROMPT Passphrase:"
echo "SETDESC Please enter your passphrase."
echo "GETPIN"
} | pinentry
)
# Extract the entered PIN/password
pin=$(echo "$response" | awk '/^D / {print substr($0,3)}')
if [[ -n "$pin" ]]; then
echo "Passphrase was entered."
echo "Length: ${#pin}"
# Do something with $pin here
else
echo "No passphrase entered or dialog cancelled."
fi
secure-sample-pinentry.sh ::
#!/bin/bash
pin=$(
{
echo "SETTITLE Secure Prompt"
echo "SETPROMPT Password:"
echo "GETPIN"
} | pinentry | sed -n 's/^D //p'
)
if [[ -z "$pin" ]]; then
echo "Cancelled"
exit 1
fi
# Use the secret
echo "Received secret"
# Clear the variable when done
unset pin
Info
When the user enters a value, pinentry returns lines similar to:
OK Pleased to meet you D MySecretPassword OK
The line beginning with D contains the entered secret, which is why the script extracts it.
gpg-agent version
Example 1: Ask for a passphrase via gpg-agent
#!/bin/bash
# Establish a connection to gpg-agent
GPG_CONNECT=$(gpg-connect-agent /bye 2>/dev/null)
if [[ $? -ne 0 ]]; then
echo "gpg-agent is not running"
exit 1
fi
# Request a passphrase
response=$(
gpg-connect-agent <<EOF
GET_PASSPHRASE --data mycacheid X X "Enter your password"
/bye
EOF
)
password=$(echo "$response" | sed -n 's/^D //p')
if [[ -z "$password" ]]; then
echo "User cancelled"
exit 1
fi
echo "Password received"
unset password
This caches the password, so if you call it again, it will have it stored.
--
Example 2: Trigger the user's configured pinentry
This example lets gpg-agent display the configured Pinentry GUI:
#!/bin/bash
result=$(
gpg-connect-agent <<'EOF'
GET_PASSPHRASE myapp-login X X "Please enter your password"
/bye
EOF
)
secret=$(echo "$result" | sed -n 's/^D //p')
if [[ -n "$secret" ]]; then
echo "Success"
else
echo "Cancelled"
fi
--
Example 3: Cache the secret
A nice feature of gpg-agent is passphrase caching:
#!/bin/bash CACHE_ID="my-company-tool" secret=$( gpg-connect-agent <<EOF | GET_PASSPHRASE $CACHE_ID X X "Authentication Required" /bye EOF sed -n 's/^D //p' ) echo "Secret obtained"
This one didn't seem to work for me?
--- Setup --
export GPG_TTY=$(tty) gpg-connect-agent updatestartuptty /bye
Reload agent:
gpg-connect-agent reloadagent /bye
Configure ~/.gnupg/gpg-agent.conf
pinentry-program /usr/bin/pinentry-tty pinentry-program /usr/bin/pinentry-curses
--- manually test --
gpg-connect-agent <<EOF GET_PASSPHRASE mytest X X "Enter Password" EOF
Direct Pin Entry Example
#!/bin/bash
output=$(
{
echo "SETTITLE Login"
echo "SETPROMPT Password:"
echo "SETDESC Please enter your password."
echo "GETPIN"
} | pinentry
)
secret=$(sed -n 's/^D //p' <<< "$output")
if [[ -z "$secret" ]]; then
echo "Cancelled"
exit 1
fi
echo "Got password (${#secret} chars)"
Normal Usage
echo "hello" > test.txt gpg -c test.txt
will trigger:
gpg
-> gpg-agent
-> pinentry
reusable password prompt via gpg-agent
gpg-preset-passphrase # or gpg-agent --daemon
Quick and dirty
{
echo "SETTITLE Login"
echo "SETPROMPT Password:"
echo "GETPIN"
} | pinentry
#!/bin/bash
output=$(
{
echo "SETTITLE Test"
echo "SETPROMPT Password:"
echo "GETPIN"
} | pinentry
)
echo "----- RAW OUTPUT -----"
printf '%s\n' "$output"
echo "----------------------"
if "D secret", then:
secret=$(printf '%s\n' "$output" | sed -n 's/^D //p')
If it contains percent-encoding: "D abc%20def", then you will need to decode before use
Another Try
export GPG_TTY=$(tty) gpg-connect-agent updatestartuptty /bye gpg-connect-agent <<EOF GET_PASSPHRASE mytest X X "Enter Password" EOF
Decode with:
xxd -r -p
{
gpg-connect-agent <<EOF
GET_PASSPHRASE mytest X X "Enter Password"
EOF
} | xxd -r -p
# echo "pinentry-program /usr/bin/pinentry-tty" >> ~/.gnupg/gpg-agent.conf echo "pinentry-program /usr/bin/pinentry-gtk" >> ~/.gnupg/gpg-agent.conf gpgconf --kill gpg-agent
---
~/.gnupg/gpg-agent.conf
# pinentry-tty renders cleanly in the Copilot CLI terminal (no curses/mouse junk) pinentry-program /usr/bin/pinentry-tty # Allow non-interactive passphrase paths allow-loopback-pinentry allow-preset-passphrase # Keep the passphrase cached for a full workday so signing is silent after one unlock default-cache-ttl 34200 max-cache-ttl 34200
another try
Fix #3: Use a dedicated TTY
A trick for scripts is to communicate over stdin/stdout while pinentry accesses /dev/tty:
#!/bin/bash
exec 3<> /dev/tty
output=$(
{
echo "SETTITLE Login"
echo "SETPROMPT Password:"
echo "GETPIN"
} | pinentry 2>&1
)
echo "$output"
---
gpg-connect-agent <<EOF GET_PASSPHRASE mytest X X "Test" EOF
---
{
echo "GETPIN"
} | pinentry
---
export GPG_TTY=$(tty) pinentry-curses <<EOF SETTITLE Login SETPROMPT Password: GETPIN EOF
decode version
#!/bin/bash
response=$(
gpg-connect-agent <<EOF
GET_PASSPHRASE mytest X X "Enter Password"
EOF
)
hex=$(awk '/^OK / {print $2}' <<< "$response")
password=$(printf '%s' "$hex" | xxd -r -p)
echo "Password: $password"
reliable option gpg-agent
#!/bin/bash
# Ensure gpg-agent knows which terminal to use
export GPG_TTY=$(tty)
gpg-connect-agent updatestartuptty /bye >/dev/null
response=$(
gpg-connect-agent <<'EOF'
GET_PASSPHRASE mytest X X "Enter Password"
/bye
EOF
)
echo "Raw response:"
echo "$response"
# Your system appears to return:
# OK <hex-encoded-password>
hex=$(echo "$response" | awk '/^OK / {print $2}')
if [[ -z "$hex" ]]; then
echo "Cancelled or no password entered"
exit 1
fi
password=$(printf '%s' "$hex" | xxd -r -p)
echo "Password length: ${#password}"
# Use password here
# ...
unset password