Automatically Encrypt my Org Journal Diary while Syncing

1. Motivation

I’ve long been keeping a private diary/journal with Org Journal in Emacs. For long, I’ve been writing on a single PC at home with no online syncing or real-time backup out of privacy concerns. This is inconvenient, because I’m not always home, and unsafe, because the disk may break down.

Fortunately, Org Journal supports automatic GnuPG (GPG) encryption, so each Journal file will be automatically encrypted each time we save the file. Thus, it is safe to sync my encrypted files with Dropbox. In this blog post, I’ll describe:

  • how I set up GnuPG and Org Journal to enable encryption;
  • how I migrate (archive) old journal files to this new system.

2. Setting up GPG

GPG is a nice tool for asymmetric encryption. Asymmetric encryption, in short, uses a public key to encrypt the secret and a private key to decrypt the secret (in this case my diary). The private key must be kept private and safe — if it is disclosed, somebody else can decrypt my secret; if it is lost, I won’t be able to decrypt my own journal (until the era of quantum computing:-)).

GPG should ship with most Linux distributions and Mac OS. Windows users will need to install GPG4win. The first step is to generate a GPG key pair, see Steps 1–12 in this Github tutorial.

I would like to edit my journal on multiple machines, and it’s therefore necessary to export this key pair to my other machines. First, to list all keys:

gpg -k

To export the public key:

gpg --armor --output pub.key --export example@email.com

where pub.key is the file name, and the email address is corresponds to the key to be exported. To export the private key, use 1:

gpg --armor --export-secret-keys example@email.com | gpg --armor --symmetric --output mykey.sec.asc

This will prompt for a passphrase to (symmetrically) encrypt my private key.

After sending the keys to another machine, I import the keys. For the public key:

gpg --import pub.key

and the encrypted private key:

gpg -d mykey.sec.asc | gpg --allow-secret-key-import --import

and I’ll be prompted for passphrase twice, the first one being the symmetric decryption during export, and the second one being the one I entered during key pair generation.

The keys must be trusted after import, otherwise I’ll be warned when using that key. To trust the key, type:

gpg --edit-key example@email.com

and I enter an interactive prompt which looks like this:

gpg>

type trust and then hit ENTER and choose 5 (ultimate) and then type quit. That’s it!

3. Org journal settings

Setting Org journal is simple — just set

(setq org-journal-encrypt-journal t)

in my config file. It is also possible to encrypt certain entries with Org Crypt. See the Org Journal readme page.

I used to keep separate journal files for each day (i.e. org-journal-file-type is 'daily), but I realised that to search over older journal files with org-journal-search-forever is rather slow because all files must be decrypted one by one. Thus, now I use a single file for each year:

(setq org-journal-file-type 'yearly
      org-journal-file-format "%Y.org")

4. Archiving old journal files

So now what to do is my old, daily journal files? I would like them to be encrypted, synced and searchable.

My first attempt was to encrypt them one by one with the same key and then delete the original .org files. However, this again makes it rather slow to search over all files with org-journal-search-forever. So my solution is to merge them into one big .org file and then encrypt it. This won’t enable me to search with org-journal-search-forever but I can search within the buffer with swiper.

The Elisp code for merging is:

(with-current-buffer (get-buffer-create "old-journal.org")
  (let ((filelist (with-temp-buffer
                    (insert-directory (concat (file-name-as-directory org-journal-dir) "*.org") nil t t)
                    (split-string (buffer-string)))))
    (dolist (file filelist nil)
      (let ((file-string (with-current-buffer (find-file-noselect (concat (file-name-as-directory org-journal-dir) file))
                           (buffer-string))))
        (insert file-string))))
  ;(display-buffer (current-buffer))
  (write-file (concat (file-name-as-directory org-journal-dir) "old-journal.org")))

in which org-journal-dir is the path to my journal files. To preview the output first, I use the display-buffer line and annotate the write-file line. Then I encrypt the output file with gpg (either in command line or with epa-encrypt-file in Emacs) and delete the .org file.

5. Avoiding entering passphrase each time I open my journal

The last issue I encountered (on one of my machine) is that I have to enter my passpharase each time I open my journal. I would like it to be cached for, say, an hour. The way to do it is to configure the GPG Agent, which ships with GPG. First is to see if any config already exists:

cd ~/.gnupg
touch gpg-agent.conf
cat gpg-agent.conf

Second, modify or type in these lines in the config file:

default-cache-ttl 3600
max-cache-ttl 86400

This will allow GPG Agent to cache my passphrase for 3600 seconds (one hour).

That’s it! Happy new year!

Footnotes: