GPG on MacOS

    Setting up GPG

    Recently I had to setup GPG on Mac to be able to encrypt/decrypt certain files. I'd used GPG tools a long time ago but never liked the way it works. For example it automatically imports some default keys on install, which seems unnecessary to me.

    Turns out it's not that difficult to install GPG using brew and get it working.

    Keep in mind

    Set an expiry date

    Make sure that keys are always expirable. They can be renewed later on. Or if you lose it then you don't have to worry about it for long.

    Keep master key separate

    This is the main key that has SC permission/usages when you run gpg --list-secret-keys. The C part means that it can issue/certify new subkeys.

    This key should be kept in a secure location and should only be used to issue new subkeys or revoke/renew old ones.

    Use subkeys

    Instead of using your master key for encryption and signing, it's better to use the subkeys so that you can revoke them easily if you lose them.

    Encrypting vs signing keys

    Encrypting keys have E permission and signing have S. You use the former for encryption and the latter for singing exclusively.

    Steps

    Generating key pairs

    Returns an interactive prompt that guides you through creating a key pair.

    gpg --full-gen-key
    

    There's a question of whether to chose RSA or ed25519. The latter is selected by default.

    Generating Subkeys for regular usage

    This allows us to easily to issue/revoke certain keys if they're compromised without throwing away the master key.

    Get the key ID

    gpg --list-secret-keys
    

    The line beginning with sec is the master key. It has [SC] which is Signing and Certification. For the line ssb, the [E] indicates that it's an encryption subkey. However, we're going to create a seprate signing subkey. Start by editing the key.

    gpg --edit-key <key-id-long-very-long>
    

    In the interactive gpg shell, enter addkey command.

    addkey
    

    You'll see:

    Please select what kind of key you want:
       (3) DSA (sign only)
       (4) RSA (sign only)
       (5) Elgamal (encrypt only)
       (6) RSA (encrypt only)
      (10) ECC (sign only)
      (12) ECC (encrypt only)
      (14) Existing key from card
    Your selection?
    

    Select option 10 and follow from there.

    Exportng keys to backup

    We export the keys and make a backup. Then we delete the master key from the keyring and import the subkeys.

    gpg --output keshab.rsa4096.public.gpg --export <KEY-ID>
    gpg --output keshab.rsa4096.secret.gpg --export-secret-key <KEY-ID>
    gpg --output keshab.rsa4096.secretsubkeys.gpg --export-secret-subkeys <KEY-ID>
    

    Now backup those files in a secure location.

    Deleting exported keys from the GPG keyring

    To delete the keys, run:

    gpg --delete-secret-keys <KEY-ID>
    

    And follow the instructions. Run gpg --list-secret-keys to confirm the deletion.

    Import only the subkeys

    Finally, import only the subkeys:

    gpg --import keshab.rsa4096.secretsubkeys.gpg
    

    and follow the instructions. Run gpg --list-secret-keys again to confirm the import worked.

    gpg --list-secret-keys
    

    The suffix hash on sec# suggests that only subkeys are available.

    Trust a key

    This is not needed for most cases, esp. if the key was generated in this computer. An imported key can be "trusted" by doing the following.

    gpg --edit-key <email/key-id>
    

    Then in the interactive shell, type trust command.

    Command> trust
    

    You'll be prompted to select how far you want to trust the key.

    Using Emacs to edit .gpg files

    Add following in ~/.gnupg/gpg-agent.conf to use Emacs for pinentry and not the external dialogue.

    allow-emacs-pinentry
    allow-loopback-pinentry
    

    Kill the GPG agent by running

    gpgconf --kill gpg-agent
    

    Then add this to the init file to select the default encrypting key and recipent.

    (setq epa-pinentry-mode 'loopback  ;; use emacs
          epa-file-encrypt-to "self@keshab.net" ;; encryption recipent
          epa-file-select-keys "self@keshab.net" ;; encryption key
          )
    

    Using signing keys to sign git commits

    Get long key ID

    gpg -K --keyid-format=long
    

    Configure git to use this for signing, go to the git repo and run.

    git config user.signingkey <LONG-KEY-ID>
    

    The long key ID is of the signing subkey. Remember to not use your master key.

    Use --global flag to make this apply to all repos.

    Let zsh know about GPG

    if [ -r ~/.zshrc ]; then echo 'export GPG_TTY=$(tty)' >> ~/.zshrc; \
    else echo 'export GPG_TTY=$(tty)' >> ~/.zprofile; fi
    

    Install pinentry-mac for password inputs

    This doesn't seem necessary when using Emacs for pin entry but is needed if creating signed commits from the command line.

    brew install pinentry-mac
    echo "pinentry-program $(which pinentry-mac)" >> ~/.gnupg/gpg-agent.conf
    killall gpg-agent
    

    :results: nil:END:

    Sign commits

    git commit -S -m "something"
    

    and to autosign all future commits, run:

    git config commit.gpgsign true
    

    Add it to github/gitlab

    Export the key as ASCII armor format

    gpg --armor --export <KEY-ID>
    

    Troubleshooting

    2023-04-03 I received this error when trying to do a git commit. My key wasn't expired though, which I verified by running the key listing command.

    error: gpg failed to sign the data
    fatal: failed to write commit object
    

    I tried committing with GIT_TRACE=1 environment variable.

    GIT_TRACE=1 git commit
    

    Which printed the failing gpg command.

    gpg --status-fd=2 -bsau <key-id>
    

    Running this command didn't throw any error though.

    I'd just logged out and logged in onto the machine, maybe that broke something? I then killed gpg-agent on a whim.

    gpgconf --kill gpg-agent
    

    Now it's working. Not sure what was up.

    2023-11-24 Saving .gpg files would hang in Emacs. Found this question in stackoverflow that suggests downgrading the gpg package.

    brew uninstall --ignore-dependencies gpg
    

    and then

    brew install gnupg@2.2