Skip to content

Instantly share code, notes, and snippets.

@jirutka
Last active August 9, 2022 09:39
Show Gist options
  • Save jirutka/8dc567ed4d7b4585111996242aa573a8 to your computer and use it in GitHub Desktop.
Save jirutka/8dc567ed4d7b4585111996242aa573a8 to your computer and use it in GitHub Desktop.
Generate a new GPG key pair in a temporary GPG Home and export it to a file. It can run completely unattended, without prompting for a passphrase.
#!/bin/sh
# Copyright 2018-2019 Jakub Jirutka <jakub@jirutka.cz>. All rights reserved.
# Licensed under the terms of the MIT license. See <https://opensource.org/licenses/MIT>.
#
#---help---
# Usage:
# gpg-keygen [options] SECKEY [PUBKEY]
# gpg-keygen [-h]
#
# Generate a new GPG key pair in a temporary GPG Home and export it to a file.
#
# Arguments:
# SECKEY Where to write the generated secret key. Use "-" for stdout.
# PUBKEY Where to write the generated public key. Use "-" for stdout.
#
# Options:
# -n --name NAME User name's real name. Defaults to a random string.
#
# -m --name-email EMAIL User name's email address. Defaults to none.
#
# -c --name-comment STRING User name's comment. Defaults to none.
#
# -e --expire-date EXPIRE When is the key going to expire. Defaults to 0 (no expire).
#
# -t --key-type ALGO Type of the primary key and subkey. The algorithm must be capable of
# signing. Defaults to RSA.
#
# -b --key-length NBITS The requested length of the generated key in bits. Defaults to 3072.
#
# -u --key-usage USAGE Space or comma delimited list of key usages. Allowed values are
# "encrypt", "sign", and "auth". Defaults to "encrypt,sign,auth".
#
# -p --passphrase PASS Passphrase to protect the key. If not provided and environment
# variable GPG_PASSPHRASE is empty, you'll be prompted to enter the
# passphrase.
#
# -v --verbose Be verbose.
#
# -V --version Print script's version and exit.
#
# -h --help Show this message and exit.
#
# Environment variables:
# GPG GPG command to run. Defaults to "gpg2".
# GPG_PASSPHRASE Passphrase to protect the key.
#
# Script's homepage: <https://gist.github.com/jirutka/8dc567ed4d7b4585111996242aa573a8>.
#
#---help---
set -eu
PROGNAME='gpg-keygen'
VERSION='0.1.0'
# Prompts user for a password in POSIX compatible way.
ask_pass() {
local prompt="$1"
local pass
printf '%s: ' "$prompt" >&2
stty -echo
read -r pass
stty echo
printf '\n' >&2
test -n "$pass" || return 1
printf '%s\n' "$pass"
}
outfile_arg() {
local arg="$1"
if [ "$arg" != '-' ]; then
mkdir -p "$(dirname "$arg")"
printf -- '--output %s\n' "$arg"
fi
}
die() {
printf '%s: %s\n' "$PROGNAME" "$@" >&2
exit 1
}
print_help() {
sed -En '/^#---help---/,/^#---help---/p' "$0" | sed -E 's/^# ?//; 1d;$d;'
}
#============================= M a i n ==============================#
: ${GPG:=gpg2}
expire_date='0'
key_length='3072'
key_type='RSA'
key_usage='encrypt,sign,auth'
name_comment=''
name_email=''
name_real=''
passphrase="${GPG_PASSPHRASE:-}"
verbosity='--quiet'
while [ $# -gt 0 ]; do
n=2
case "$1" in
-e | --expire-date) expire_date="$2";;
-b | --key-length) key_length="$2";;
-t | --key-type) key_type="$2";;
-u | --key-usage) key_usage="$2";;
-c | --name-comment) name_comment="$2";;
-m | --name-email) name_email="$2";;
-n | --name-real) name_real="$2";;
-p | --passphrase) passphrase="$2";;
-v | --verbose) verbosity='--verbose'; n=1;;
-V | --version) echo "$PROGNAME $VERSION"; exit 0;;
-h | --help) print_help; exit 0;;
- | --) break;;
-* | --*) die "unknown option: $1";;
*) break;;
esac
shift $n
done
if [ $# -lt 1 ]; then
print_help >&2
exit 1
fi
privkey_out="$1"
pubkey_out="${2:-}"
: ${name_real:="$(cat /dev/urandom | LC_CTYPE=C tr -cd 'A-Za-z0-9' | head -c 8)"}
if [ -z "$passphrase" ]; then
passphrase=$(ask_pass 'Enter passphrase')
fi
temp_dir=$(mktemp -d)
trap "rm -Rf '$temp_dir'" EXIT HUP INT TERM
export GNUPGHOME="$temp_dir"
cat > "$temp_dir/.input" <<-EOF
%echo Generating a basic GPG key
Key-Type: $key_type
Key-Length: $key_length
Key-Usage: $key_usage
Name-Real: $name_real
${name_email:+"Name-Email: $name_email"}
${name_comment:+"Name-Comment: $name_comment"}
Expire-Date: $expire_date
Passphrase: $passphrase
%commit
EOF
# Generate key.
$GPG $verbosity --batch --no-tty --gen-key "$temp_dir/.input"
# Find key's ID.
id=$($GPG --no-tty --list-secret-keys --with-colons 2>/dev/null \
| awk -F: '/^sec:/ { print $5 }')
echo "$id"
# List created keys.
if [ "$verbosity" = '--verbose' ]; then
$GPG --no-tty --list-keys >&2
fi
# Export public key.
if [ -n "$pubkey_out" ]; then
$GPG $verbosity $(outfile_arg "$pubkey_out") \
--batch --yes --no-tty --armor --export "$id"
fi
# Export secret key.
umask 0077
echo "$passphrase" | $GPG $verbosity $(outfile_arg "$privkey_out") \
--batch --yes --no-tty --pinentry-mode loopback --passphrase-fd 0 \
--armor --export-secret-keys "$id"
The MIT License
Copyright 2018-2019 Jakub Jirutka <jakub@jirutka.cz>.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
@Swedeniron
Copy link

Working until the last row's

gpg: invalid option "--pinentry-mode"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment