decrypt.sh 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. #!/usr/bin/env bash
  2. #
  3. # decrypt.sh — Decrypt a PGP-encrypted attachment using the private key in this
  4. # folder. The private key is passphrase-protected; the passphrase is read from a
  5. # separate file (default: passphrase.txt).
  6. #
  7. # Usage:
  8. # ./decrypt.sh [ENCRYPTED_FILE] [OUTPUT_FILE]
  9. #
  10. # ENCRYPTED_FILE Path to the .pgp/.gpg/.asc file to decrypt.
  11. # Defaults to the single *.pgp file in this folder.
  12. # OUTPUT_FILE Where to write the decrypted result.
  13. # Defaults to ENCRYPTED_FILE with its .pgp/.gpg suffix removed.
  14. #
  15. # The script imports the key into a throwaway, isolated GnuPG home so it never
  16. # touches your real ~/.gnupg keyring, then removes it on exit.
  17. set -euo pipefail
  18. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  19. KEY_FILE="${KEY_FILE:-$SCRIPT_DIR/pgp-secret-keys.asc}"
  20. PASSPHRASE_FILE="${PASSPHRASE_FILE:-$SCRIPT_DIR/passphrase.txt}"
  21. die() { echo "Error: $*" >&2; exit 1; }
  22. command -v gpg >/dev/null 2>&1 || die "gpg is not installed (try: brew install gnupg)"
  23. [ -f "$KEY_FILE" ] || die "private key not found: $KEY_FILE"
  24. [ -f "$PASSPHRASE_FILE" ] || die "passphrase file not found: $PASSPHRASE_FILE (create it and put the key passphrase inside)"
  25. # --- Resolve the encrypted input file ---------------------------------------
  26. ENC_FILE="${1:-}"
  27. if [ -z "$ENC_FILE" ]; then
  28. # Auto-pick the single *.pgp in this folder.
  29. shopt -s nullglob
  30. candidates=("$SCRIPT_DIR"/*.pgp)
  31. shopt -u nullglob
  32. case "${#candidates[@]}" in
  33. 0) die "no *.pgp file found in $SCRIPT_DIR — pass the file as the first argument" ;;
  34. 1) ENC_FILE="${candidates[0]}" ;;
  35. *) die "multiple *.pgp files found — pass the one to decrypt as the first argument" ;;
  36. esac
  37. fi
  38. [ -f "$ENC_FILE" ] || die "encrypted file not found: $ENC_FILE"
  39. # --- Resolve the output file -------------------------------------------------
  40. OUT_FILE="${2:-}"
  41. if [ -z "$OUT_FILE" ]; then
  42. case "$ENC_FILE" in
  43. *.pgp) OUT_FILE="${ENC_FILE%.pgp}" ;;
  44. *.gpg) OUT_FILE="${ENC_FILE%.gpg}" ;;
  45. *.asc) OUT_FILE="${ENC_FILE%.asc}" ;;
  46. *) OUT_FILE="${ENC_FILE}.decrypted" ;;
  47. esac
  48. fi
  49. # Read passphrase from the separate file (strip a single trailing newline).
  50. PASSPHRASE="$(cat "$PASSPHRASE_FILE")"
  51. [ -n "$PASSPHRASE" ] || die "passphrase file is empty: $PASSPHRASE_FILE"
  52. # --- Isolated, throwaway keyring --------------------------------------------
  53. GNUPGHOME="$(mktemp -d)"
  54. export GNUPGHOME
  55. chmod 700 "$GNUPGHOME"
  56. cleanup() { rm -rf "$GNUPGHOME"; }
  57. trap cleanup EXIT
  58. echo "Importing private key ..." >&2
  59. gpg --batch --quiet --import "$KEY_FILE"
  60. echo "Decrypting: $(basename "$ENC_FILE")" >&2
  61. gpg --batch --yes --quiet \
  62. --pinentry-mode loopback \
  63. --passphrase-fd 3 \
  64. --output "$OUT_FILE" \
  65. --decrypt "$ENC_FILE" 3<<<"$PASSPHRASE"
  66. echo "Decrypted -> $OUT_FILE" >&2