GPG and TextMate

Note: see update at bottom.

Several years ago, when it became clear that I was going to have far more login names and passwords than I could comfortably keep in my head, I created a password file in my home directory, put in all the logins and passwords I had at the time, and encrypted the file with GPG. Thus, one passphrase gave me access to all my other secret information, and I could add new logins and passwords as the need arose. This simple “password locker” was hardly an original idea, but because it was simple I was able to carry it with me when I switched from Linux to Mac a few years ago—same password file, same GPG passphrase and keyring.

I even carried along a transparent way of encrypting and decrypting the password file: a vim configuration file that would ask me for my passphrase when I opened the file, show and allow editing of the plaintext, then re-encrypt the file when I saved it. Vim was never my editor of choice, but this file was more read than edited, and the editing that was done to it was pretty rudimentary. So the convenience of transparency outweighed the inconvenience of using a less-than-favorite editor. So for three years I’ve been using the very unMaclike vim to view and edit my password file, because I didn’t know of a simple way to do it in (initially) BBEdit or (now) TextMate.

But yesterday I saw the “AES Encrypt Document/Selection With Password…” and “AES Decrypt Document/Selection With Password…” commands in TextMate’s Text Bundle and decided to adapt them to GPG. Here’s my encryption command, called “Encrypt GPG” and given a Key Equivalent of Control-Option-Command-G (⌃⌥⌘G):

 1:  get_r () {
 2:    res=$(CocoaDialog 2>/dev/null inputbox --float --no-newline \
 3:      --title 'Encrypt with GPG' \
 4:      --informative-text "$1" \
 5:      --text "$2" \
 6:      --button1 "$3" --button2 Cancel)
 7:    [[ ${res:0:1} == 1 ]] && echo -n "${res:2}"
 8:  }
 9:  
10:  r=$(get_r 'Who is this going to?' drang OK)
11:  [[ -z "$r" ]] && exit_discard
12:  
13:  if ! gpg -qear "$r" --no-tty; then
14:     exit_show_tool_tip
15:  fi

It uses the very nice CocoaDialog application to ask the user for the recipient of the encrypted file (the idea of public key encryption, like GPG, is to encrypt the file so that only the recipient can decrypt it). Because I usually encrypt things for my own use, the default recipient is me, but the command is general enough that I can encrypt the file for anyone in my GPG keyring. The encryption itself is done on line 13: the -qea options tell GPG to be relatively quiet in what it prints out, encrypt the file, and ASCII-armor it. ASCII-armoring makes the encrypted file come out in printable characters, which is helpful when working in a text editor. The -r option is for the recipient, which has been saved in the $r variable. Finally, the --no-tty option tells GPG that it’s not working through a terminal.

The decryption command is called “Decrypt GPG” and is given the same Key Equivalent, ⌃⌥⌘G.

 1:  get_pw () {
 2:    res=$(CocoaDialog 2>/dev/null secure-inputbox --float --no-newline \
 3:      --title 'Decrypt with GPG' \
 4:      --informative-text "$1" \
 5:      --button1 "$2" --button2 Cancel)
 6:    [[ ${res:0:1} == 1 ]] && echo -n "${res:2}"
 7:  }
 8:  
 9:  pw=$(get_pw 'GPG passphrase?' Decrypt)
10:  [[ -z "$pw" ]] && exit_discard
11:  
12:  if ! gpg -qd --passphrase "$pw" --no-tty; then
13:     exit_show_tool_tip
14:  fi

It gets the passphrase using CocoaDialog and decrypts the file with the GPG command on line 12. The -d option is for decryption, the passphrase is saved in the $pw variable, and the other options are as before.

Both commands get their input from either the selected text or the entire document and their output replaces the input.

So now I can open my encrypted password file in TextMate, which looks like this:

-----BEGIN PGP MESSAGE-----
Version: GnuPG v1.4.6 (Darwin)

hQIOA7gA+xUvP1efEAgAiFrp4J95LeBzgnHfv6J+A9pGIUE4g0nL1V/fG93FOUw0
YoAABdV8TnlR6P5CLVdNdx9b30WtpaOinX9WNLAiP8Sy1cGmS+OSL/QJu1oaIIi2
    .
  [snip]
    .
WFZ6WBmm/dbt+aO97qCcZKEgZehU2ONe5YCrTq/8JvkPorIFnxqP73wy
=x4Cj
-----END PGP MESSAGE-----

I then hit ⌃⌥⌘G, select the “Decrypt GPG” choice from the little popup menu, enter my passphrase in the CocoaDialog box, and the plaintext file appears. If I’m just looking up a password, I can just close the file when I’m done and decline to save the changes. If I add or change a password, I re-encrypt the file by hitting ⌃⌥⌘G, selecting the “Encrypt GPG” choice, and hitting Return to accept the default recipient. The file is now encrypted and ASCII-armored, ready for saving.

This is not as transparent as the automatic encrypting and decrypting available with vim, but it keeps me from having to open a Terminal window and typing in vim seekret.asc. And I can navigate and edit in a more comfortable editor.

Update
If you’re interested in my old Vim setup, I’ve posted the configuration file here.

Tags: