What is GPG

Paraphrasing from the Arch Wiki, GPG is basically an implementation of PGP (Pretty Good Privacy)/ RFC 4880. You can use it to sign stuff, encrypt stuff, and authenticate yourself (eg over SSH or S/MIME).

Using GPG for SSH

  1. Generate Master Key

    • This is the key you’ll use to create subkeys. As such you’ll want to keep this safe somewhere

    • $ gpg --full-generate-key --expert
      gpg (GnuPG) 2.4.3; Copyright (C) 2023 g10 Code GmbH
      This is free software: you are free to change and redistribute it.
      There is NO WARRANTY, to the extent permitted by law.
      
      Please select what kind of key you want:
         (1) RSA and RSA
         (2) DSA and Elgamal
         (3) DSA (sign only)
         (4) RSA (sign only)
         (7) DSA (set your own capabilities)
         (8) RSA (set your own capabilities)
         (9) ECC (sign and encrypt) *default*
        (10) ECC (sign only)
        (11) ECC (set your own capabilities)
        (13) Existing key
        (14) Existing key from card
      Your selection? 11
      
      • We want to pick ECC, since that’s the more secure algorithm of these
    • Next, we want to disable signing, since we’ll only use this key to make more keys (i.e. we’ll be certifying other keys)

    • Possible actions for this ECC key: Sign Certify Authenticate
      Current allowed actions: Sign Certify
      
         (S) Toggle the sign capability
         (A) Toggle the authenticate capability
         (Q) Finished
      
      Your selection? S
      
      Possible actions for this ECC key: Sign Certify Authenticate
      Current allowed actions: Certify
      
         (S) Toggle the sign capability
         (A) Toggle the authenticate capability
         (Q) Finished
      
      Your selection? Q
      
    • Please select which elliptic curve you want:
         (1) Curve 25519 *default*
         (2) Curve 448
         (3) NIST P-256
         (4) NIST P-384
         (5) NIST P-521
         (6) Brainpool P-256
         (7) Brainpool P-384
         (8) Brainpool P-512
         (9) secp256k1
      Your selection?
      Please specify how long the key should be valid.
               0 = key does not expire
            <n>  = key expires in n days
            <n>w = key expires in n weeks
            <n>m = key expires in n months
            <n>y = key expires in n years
      Key is valid for? (0) 1y
      Key expires at Tue Sep 24 21:26:26 2024 UTC
      Is this correct? (y/N) y
      
      • Here we pick an elliptic curve, I just went with the default since I have no opinions about these
      • As for expiry date, I just put it at 1 year. You can change this later if you want
    • GnuPG needs to construct a user ID to identify your key.
      
      Real name: Mira Velturu
      Email address: [email protected]
      Comment: GPG Demo
      You selected this USER-ID:
          "Mira Velturu (GPG Demo) <[email protected]>"
      
      Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
      
      • The last step is linking your data to the key, and entering a password
    • After this, you’ll see something like:

      • gpg: revocation certificate stored as '/home/mira/.local/share/gnupg/openpgp-revocs.d/6AEDC0D9AD76A6DD613C884958C90C69DF7F1AF9.rev'
        public and secret key created and signed.
        
        pub   ed25519 2023-09-25 [C] [expires: 2024-09-24]
              6AEDC0D9AD76A6DD613C884958C90C69DF7F1AF9
        uid                      Mira Velturu (GPG Demo) <[email protected]>
        
      • The revocation cert lets you mark this key as invalid in case it gets leaked or something similar, keep this safe

      • Double check to make sure the output contains [C] and no other letters between the braces

  2. Alright now time to add subkeys so we can Sign/Authenticate/Encrypt stuff

    • First we’ll add a subkey for signing and authentication

    • $ gpg --expert --edit-key 6AEDC0D9AD76A6DD613C884958C90C69DF7F1AF9                         
      gpg (GnuPG) 2.4.3; Copyright (C) 2023 g10 Code GmbH
      This is free software: you are free to change and redistribute it.
      There is NO WARRANTY, to the extent permitted by law.
      
      Secret key is available.
      
      sec  ed25519/58C90C69DF7F1AF9
           created: 2023-09-25  expires: 2024-09-24  usage: C
           trust: ultimate      validity: ultimate
      [ultimate] (1). Mira Velturu (GPG Demo) <[email protected]>
      
      • that long string you see is from the command where we made the key
      • if you lost it, you can find it with gpg --list-keys
    • Now we add a subkey, the process is pretty similar to how we made the master key

    • gpg> addkey
      Please select what kind of key you want:
         (3) DSA (sign only)
         (4) RSA (sign only)
         (5) Elgamal (encrypt only)
         (6) RSA (encrypt only)
         (7) DSA (set your own capabilities)
         (8) RSA (set your own capabilities)
        (10) ECC (sign only)
        (11) ECC (set your own capabilities)
        (12) ECC (encrypt only)
        (13) Existing key
        (14) Existing key from card
      Your selection? 11
      
      Possible actions for this ECC key: Sign Authenticate
      Current allowed actions: Sign
      
         (S) Toggle the sign capability
         (A) Toggle the authenticate capability
         (Q) Finished
      
      Your selection? A
      
      Possible actions for this ECC key: Sign Authenticate
      Current allowed actions: Sign Authenticate
      
         (S) Toggle the sign capability
         (A) Toggle the authenticate capability
         (Q) Finished
      
      Your selection? Q
      Please select which elliptic curve you want:
         (1) Curve 25519 *default*
         (2) Curve 448
         (3) NIST P-256
         (4) NIST P-384
         (5) NIST P-521
         (6) Brainpool P-256
         (7) Brainpool P-384
         (8) Brainpool P-512
         (9) secp256k1
      Your selection?
      Please specify how long the key should be valid.
               0 = key does not expire
            <n>  = key expires in n days
            <n>w = key expires in n weeks
            <n>m = key expires in n months
            <n>y = key expires in n years
      Key is valid for? (0) 1y
      Key expires at Tue Sep 24 21:55:51 2024 UTC
      Is this correct? (y/N) y
      Really create? (y/N) y
      gpg> save
      
      • The main difference here is that we have both the Sign and Authenticate capabilities
    • Your output will look something like:

    • sec  ed25519/58C90C69DF7F1AF9
           created: 2023-09-25  expires: 2024-09-24  usage: C
           trust: ultimate      validity: ultimate
      ssb  ed25519/2A7D7227C6F75FF1
           created: 2023-09-25  expires: 2024-09-24  usage: SA
      [ultimate] (1). Mira Velturu (GPG Demo) <[email protected]>
      
    • We’ll need to do this process one more time to create an encryption subkey

    • $ gpg --expert --edit-key 6AEDC0D9AD76A6DD613C884958C90C69DF7F1AF9                                                                            36s686ms
      gpg (GnuPG) 2.4.3; Copyright (C) 2023 g10 Code GmbH
      This is free software: you are free to change and redistribute it.
      There is NO WARRANTY, to the extent permitted by law.
      
      Secret key is available.
      
      sec  ed25519/58C90C69DF7F1AF9
           created: 2023-09-25  expires: 2024-09-24  usage: C
           trust: ultimate      validity: ultimate
      ssb  ed25519/2A7D7227C6F75FF1
           created: 2023-09-25  expires: 2024-09-24  usage: SA
      [ultimate] (1). Mira Velturu (GPG Demo) <[email protected]>
      
    • gpg> addkey
      Please select what kind of key you want:
         (3) DSA (sign only)
         (4) RSA (sign only)
         (5) Elgamal (encrypt only)
         (6) RSA (encrypt only)
         (7) DSA (set your own capabilities)
         (8) RSA (set your own capabilities)
        (10) ECC (sign only)
        (11) ECC (set your own capabilities)
        (12) ECC (encrypt only)
        (13) Existing key
        (14) Existing key from card
      Your selection? 12
      Please select which elliptic curve you want:
         (1) Curve 25519 *default*
         (2) Curve 448
         (3) NIST P-256
         (4) NIST P-384
         (5) NIST P-521
         (6) Brainpool P-256
         (7) Brainpool P-384
         (8) Brainpool P-512
         (9) secp256k1
      Your selection?
      Please specify how long the key should be valid.
               0 = key does not expire
            <n>  = key expires in n days
            <n>w = key expires in n weeks
            <n>m = key expires in n months
            <n>y = key expires in n years
      Key is valid for? (0) 1y
      Key expires at Tue Sep 24 22:03:43 2024 UTC
      Is this correct? (y/N) y
      Really create? (y/N) y
      We need to generate a lot of random bytes. It is a good idea to perform
      some other action (type on the keyboard, move the mouse, utilize the
      disks) during the prime generation; this gives the random number
      generator a better chance to gain enough entropy.
      
      sec  ed25519/58C90C69DF7F1AF9
           created: 2023-09-25  expires: 2024-09-24  usage: C
           trust: ultimate      validity: ultimate
      ssb  ed25519/2A7D7227C6F75FF1
           created: 2023-09-25  expires: 2024-09-24  usage: SA
      ssb  cv25519/2AD22394690453C2
           created: 2023-09-25  expires: 2024-09-24  usage: E
      [ultimate] (1). Mira Velturu (GPG Demo) <[email protected]>
      gpg> save
      
  3. Okay now you have a key, lets make it work with SSH now

    • $ echo enable-ssh-support >> ~/.local/share/gnupg/gpg-agent.conf
      
    • Now you’re gonna need to set SSH_AUTH SOCK so that we use gpg-agent instead of ssh-agent for handling SSH credentials (don’t worry this won’t mess with your existing SSH credentials)

      • Add the following to your .bashprofile or .zshrc

      • unset SSH_AGENT_PID
        if [ "${gnupg_SSH_AUTH_SOCK_by:-0}" -ne $$ ]; then
          export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)"
        fi
        export GPG_TTY=$(tty)
        gpg-connect-agent updatestartuptty /bye >/dev/null
        
    • To use your keys for SSH Auth we’ll need to add it to the sshcontrol file

      • $ gpg --list-keys --with-keygrip
        /home/mira/.local/share/gnupg/pubring.kbx
        -----------------------------------------
        pub   ed25519 2023-09-25 [C] [expires: 2024-09-24]
              6AEDC0D9AD76A6DD613C884958C90C69DF7F1AF9
              Keygrip = 929E520FB577F34E064E670A6500B21D4835B226
        uid           [ultimate] Mira Velturu (GPG Demo) <[email protected]>
        sub   ed25519 2023-09-25 [SA] [expires: 2024-09-24]
              Keygrip = 25F5E8427F0F9338A00F98225D125C09EAEBFF24
        sub   cv25519 2023-09-25 [E] [expires: 2024-09-24]
              Keygrip = ED48EF4A2FDD7F03F779EC58B06B1AB0F4B75652
        
      • echo 25F5E8427F0F9338A00F98225D125C09EAEBFF24 >> ~/.local/share/gnupg/sshcontrol

      • run ssh-add -l to verify

        • I couldn’t actually get this part working but trust me bro :tm:
      • $ gpg --export-ssh-key 6AEDC0D9AD76A6DD613C884958C90C69DF7F1AF9
        ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGWaV6YjtxALsgpvSoBtyW1nFaTTifOQKQmmj9bQsrtJ openpgp:0xC6F75FF1
        
        • this’ll spit out your public SSH Key for the given Key ID
  4. Back up your keys and yeet the master key

    • $ gpg -a --export-secret-keys > master-secret-key.asc
      $ gpg -a --export-secret-subkeys > sub-secret-keys.asc
      $ gpg --delete-secret-key 6AEDC0D9AD76A6DD613C884958C90C69DF7F1AF9
      $ gpg --import sub-secret-keys.gpg
      
      • put these two files somewhere safe, like physical media

Encryption

Asymmetric

  • Okay this one’s pretty simple:

  • $ gpg --recipient user-ids --encrypt doc
    
    • this will encrypt doc using your private key and the public keys of your recipients
  • $ gpg --output doc --decrypt doc.gpg
    
    • this will decrypt doc.gpg if you have a matching private key

Symmetric

  • Even easier, no keys required

  • $ gpg -c doc
    
    • this will encrypt and decrypt doc using a pre-shared key

Signing

  • Don’t @ me I know this isn’t actually encryption, but being able to provide signatures is important since it’ll show a) the file comes from you, and b) the file hasn’t been tampered with or corrupted

  •   $ gpg --output doc.sig --sign doc
    
    • this’ll attach the signature to your file and output a compressed version
    • I don’t really recommend this since doc.sig will be a binary blob
    • if you want to not compress this and leave the contents of doc readable in doc.sig use --clearsign instead of --sign
  •   $ gpg --output doc.sig --detach-sig doc
    
    • This will put just the signature into doc.sig which you can send to someone alongside doc
  • As for verifying signatures, just do

    •   $ gpg --verify doc.sig
      
    • If this is a detached signature, make sure doc is in the same folder


ETC

  • By convention, encrypted files end in .gpg if they are binary data, or .asc if stored with ASCII Armor (which is basically just base64)
  • $ gpg --list-keys: list pubkeys in your keyring
  • $ gpg --list-secret-keys: list private keys in your keyring
  • $ gpg --export --armor --output public-key.asc [email or key ID]: output your pubkey
  • $ gpg --import public-key.asc: import a pubkey
  • $ gpg --gen-revoke --armor --output revcert.asc [email or key ID]: output your revocation key
  • $ gpg --keyserver keyserver.ubuntu.com --send-keys [key ID]: to send your public key to the ubuntu keyserver
    • this seems to be the most popular one, keybase.io also exists among others

Troubleshooting

  • if you run into issues with it not prompting for a password or see no pinentry
    • try adding --pinentry=loopback as a flag for gpg
    • for a permanent fix, look into adding a config option in gpg-agent.conf
    • honestly this should really be a TODO cause pinentry is its own mess

References