#!/usr/bin/env bash # a script to generate backups for my GPG keys # Literally all of active keys I use for different purposes. For things like shared keys, # I override them via PUBLIC_KEYS AND PRIVATE_KEYS variables at runtime. DEFAULT_PRIVATE_KEYS="0527234A430387EA5695D824A30EBE40AD856D88 4D5E631758CB9CC45941B1CE67BFC91B3DA12BE8 EA957E7086E934F8DB9CAD21940047813E9D641C 5D69E717C5BC95731C2AD8BD120C218ED2291996 2CFF8721393487AEEF2C38987067DB4C7768552F 18C97CF46F06176E7EC43BDC7E4E0EF8B968A952 51D2F9710A20AAE56DC9A9AB77D63E4A0C267204" DEFAULT_PUBLIC_KEYS="0527234A430387EA5695D824A30EBE40AD856D88 4D5E631758CB9CC45941B1CE67BFC91B3DA12BE8 EA957E7086E934F8DB9CAD21940047813E9D641C 5D69E717C5BC95731C2AD8BD120C218ED2291996" # allow anybody to automate this via envvars PRIVATE_KEYS="${PRIVATE_KEYS:-"$DEFAULT_PRIVATE_KEYS"}" PUBLIC_KEYS="${PUBLIC_KEYS:-"$DEFAULT_PUBLIC_KEYS"}" # Command snippet taken from OpenKeychain FAQs # https://www.openkeychain.org/faq/#what-is-the-best-way-to-transfer-my-own-key-to-openkeychain BACKUP_FILE_PASSWORD=$(gpg --armor --gen-random 1 20) TIMESTAMP=$(date +%s) generate_pubkey_bak() { echo "[Stage 1]: Export all public keys per PUBLIC_KEYS to '$EXPORT_DIR/pubkeys-$TIMESTAMP.asc'" echo sleep 3 if [[ $_arg_secretkeys_only == "true" ]]; then echo "warning: Skipping because --only-secret flag is used" return fi for key in $PUBLIC_KEYS; do echo "Exporting keyid $key's public key" if [[ $_arg_dryrun == "true" ]]; then echo "+ gpg --armor --export \"$key\" >> \"$EXPORT_DIR/pubkeys-$TIMESTAMP.asc\"" else gpg --armor --export "$key" >> "$EXPORT_DIR/pubkeys-$TIMESTAMP.asc" fi sleep 3 done echo } generate_privkey_bak() { echo "[Stage 2]: Export all private keys per PRIVATE_KEYS to '$EXPORT_DIR/gpg-keys-backup-$TIMESTAMP.asc'" echo sleep 3 if [[ $_arg_pubkeys_only == "true" ]]; then echo "warning: Skipping because --only-public flag is used" return fi if [[ $_arg_dryrun == "true" ]]; then for key in $PRIVATE_KEYS; do echo "Exporting keyid $key with private key" echo "+ gpg --armor --export-secret-keys $key >> $EXPORT_DIR/gpg-keys-backup-$TIMESTAMP.asc" sleep 5 done echo "+ gpg --armor --batch --passphrase ${BACKUP_FILE_PASSWORD} --symmetric --output ${EXPORT_DIR}/gpg-keys-encrypted-backup-${TIMESTAMP} < ${EXPORT_DIR}/gpg-keys-backup-${TIMESTAMP}.asc" return fi for key in $PRIVATE_KEYS; do echo "Exporting keyid $key with private key" gpg --armor --export-secret-keys "$key" >> "${EXPORT_DIR}/gpg-keys-backup-${TIMESTAMP}.asc" sleep 5 done echo "[private-keys-backup] Here's the encrypted passphrase for ${BACKUP_FILE_PASSWORD}" sleep 10 gpg --armor --batch --passphrase "${BACKUP_FILE_PASSWORD}" --symmetric --output "${EXPORT_DIR}/gpg-keys-encrypted-backup-${TIMESTAMP}" < "${EXPORT_DIR}/gpg-keys-backup-${TIMESTAMP}.asc" echo } check_export_dir() { echo "[Stage 0]: Check if the \$EXPORT_DIR exists and create if necessary" echo sleep 3 # dry-run if [[ $_arg_dryrun == "true" ]]; then echo "+ mkdir $EXPORT_DIR" return fi if [[ ! -d "$EXPORT_DIR" ]]; then echo "warning: Directory $EXPORT_DIR doesn't exist, attempting to create dir..." if mkdir "$EXPORT_DIR"; then true else error_code=$? echo "error: Something gone horribly wrong while creating export directory." echo "error: Check the logs, fix perms with chmod/chown/sudo and try again." exit $error_code fi else echo "info: export directory exists, contiuning..." fi } usage() { echo "Usage: $0 [--only-public | --only-secret | --dry-run]" echo echo "Available params:" echo " --dry-run, -d Run a simultation of commands" echo " --help Show this help page" echo " --only-secret, -s Only export secret keys" echo " --only-public, -p Only export public keys" echo echo "Supported variables to override defaults:" echo " DEBUG Set to any value to enable debug logging (via 'set -x')" echo " EXPORT_DIR Directory for storing exports" echo " PUBLIC_KEYS List of GPG keys for exporting public keys, seperated by spaces" echo " PRIVATE_KEYS List of GPG keys for exporting private keys, seperated by spaces" } main() { if [[ $DEBUG != "" ]]; then set -x fi _arg_pubkeys_only=false _arg_secretkeys_only=false _arg_dryrun=false EXPORT_DIR=${EXPORT_DIR:-"$HOME/.export-toolkit"} # arg parser goes here for _arg in "${@}"; do { if test "$_arg" != "--" && [[ "$_arg" == -* ]]; then { case "$_arg" in --help | -h) usage; exit 0 ;; --pubkeys | --only-public | -p) _arg_pubkeys_only=true ;; --secretkeys | --only-secret | -s) _arg_secretkeys_only=true ;; --dryrun | --dry-run | -d) _arg_dryrun=true ;; esac shift; } fi } done check_export_dir generate_pubkey_bak generate_privkey_bak } main "$@"