For all the reasons listed in the previous chapter I decided to implement Cabal’s mitigation in R.I.S.K.S. and to store the GPG primary key inside a tomb-file that can be opened only in the cases listed in the Debian wiki. Unfortunately the configuration process is quite long and delicate.

Ramdisk setup

I use a ramdisk to store the GPG and pass configuration directly in ram so that nothing is written on the hard drive and therefore nothing can be recovered by an attacker in possession of the hard drive.

Before creating the ramdisk I need to know how much free space I have in ram:

free -h
            total        used        free      shared  buff/cache   available
Mem:           465M        203M         36M        6.2M        225M        243M
Swap:            0B          0B          0B

I have 36 MB free. The size of the ramdisk must be smaller than the free space but 10MB are more than enough.

Warning: my ~/.gnupg directory is empty so I can safely remove it. Be sure that yours is empty too otherwise you end up deleting your valuable GPG account.

I create the ramdisk:

RAMDISK="${HOME}/.gnupg"
rm -fR ${RAMDISK}
mkdir ${RAMDISK}
sudo mount -t tmpfs -o size=10m ramdisk ${RAMDISK}
sudo chown ${USER} ${RAMDISK}
sudo chmod 0700 ${RAMDISK}

Test:

mount | grep ramdisk

Output:

ramdisk on /home/user/ramdisk type tmpfs (rw,relatime,size=10240k) ramdisk on /rw/home/user/ramdisk type tmpfs (rw,relatime,size=10240k)

Test: I create and delte a file in ramdisk

touch ${RAMDISK}/delme
rm ${RAMDISK}/delme

Warning:

  • the space used by the ramdisk won’t be freed until reboot
  • whatever stored in the ~/ramdisk will be lost in case the ramdisk is umounted
  • whatever stored in the ~/ramdisk will be lost in case of vault is turned off or rebooted

GPG configuration

I create the skeleton for GPG’s home directory ~/.gnupg so that it won’t throw errors or warnings at the first run:

dd if=/dev/random of=~/.gnupg/delme
rm ~/.gnupg/delme
mkdir -p ~/.gnupg/{openpgp-revocs.d,private-keys-v1.d}

This is the final content of the directory:

tree ~/.gnupg
.gnupg
├── openpgp-revocs.d
└── private-keys-v1.d

2 directories, 0 files

I create a customized configuration file for GPG which improves a little GPG’s common behavior.

cat >${RAMDISK}/gpg.conf <<EOF
# Avoid information leaked
no-emit-version
no-comments
export-options export-minimal

# Options for keys listing
keyid-format 0xlong
with-fingerprint
with-keygrip
with-subkey-fingerprint

# Displays the validity of the keys
list-options show-uid-validity
verify-options show-uid-validity

# Limits preferred algorithms
personal-cipher-preferences AES256
personal-digest-preferences SHA512
default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed

# Options for asymmetric encryption
cipher-algo AES256
digest-algo SHA512
cert-digest-algo SHA512
compress-algo ZLIB
disable-cipher-algo 3DES
weak-digest SHA1

# Options for symmetric encryption
s2k-cipher-algo AES256
s2k-digest-algo SHA512
s2k-mode 3
s2k-count 65011712
EOF

I find particularly useful the “listing options”, especially the “with-keygrip” and “with-subkey-fingerprint” options which force GPG to show the name of the file where each key is stored.

GPG keys and subkeys creation

Primary key-pair creation

I create a batch file for GPG so that the keys can be created without interaction.

Warning:

  • modify these fields: Name-Real, Name-Email and Passphrase
  • make sure that each identity has its own different passphrase. The risk is to end up sending messages with the wrong identity and you will break the isolation.
  • the passphrase must be a diceware passphrase
  • write down on paper the passphrase

Eventually I can add a comment (maybe a password hint?) to the primary key by adding this line to the batch file:

Name-Comment: -comment goes here-
cat >${RAMDISK}/primary_key_unattended <<EOF
%echo Generating a standard key
Key-Type: RSA
Key-Usage: sign
Key-Length: 4096
Name-Real: Joe Tester
Name-Email: joe@foo.bar
Expire-Date: 0
Passphrase: knapp tiber fist lush hatred we're
%commit
%echo done
EOF

I’m ready to create the GPG primary key-pair:

gpg --batch --gen-key ${RAMDISK}/primary_key_unattended

Output:

gpg: keybox '/home/user/.gnupg/pubring.kbx' created
gpg: Generating a standard key
gpg: /home/user/.gnupg/trustdb.gpg: trustdb created
gpg: key 0x6596C5FA775EB9AB marked as ultimately trusted
gpg: revocation certificate stored as '/home/user/.gnupg/openpgp-revocs.d/72052A26269F7552DDED36626596C5FA775EB9AB.rev'
gpg: done

I wipe away the primary_key_unattended file:

wipe ${RAMDISK}/primary_key_unattended

I ask GPG to display the keys available in my key-ring at this stage:

gpg -K

gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
/home/user/.gnupg/pubring.kbx
-----------------------------
pub   rsa4096/0x6596C5FA775EB9AB 2018-10-08 [SC]
    Key fingerprint = 7205 2A26 269F 7552 DDED  3662 6596 C5FA 775E B9AB
    Keygrip = 50123401D7AA3CBF514F23D5FA98D3D485075B2E
uid                   [ultimate] Joe Tester <joe@foo.bar>

The signing key-pair (also called primary key-pair) has been created and this is the current content of ~/.gnupg

tree .gnupg

.gnupg
├── gpg.conf
├── openpgp-revocs.d
│   └── 72052A26269F7552DDED36626596C5FA775EB9AB.rev
├── private-keys-v1.d
│   └── 50123401D7AA3CBF514F23D5FA98D3D485075B2E.key
├── pubring.kbx
├── pubring.kbx~
└── trustdb.gpg

2 directories, 6 files

The super cool “keygrip” parameter shows that the binary file 50123401D7AA3CBF514F23D5FA98D3D485075B2E.key contains the private key.

Keygrip = 50123401D7AA3CBF514F23D5FA98D3D485075B2E

The binary file 72052A26269F7552DDED36626596C5FA775EB9AB.rev is the revoke key for the primary key-pair which can be used when the primary key-pair is compromised or stolen.

Both these files are crucial.

The binary file pubring.kbx is the keyring and it contains the public key of the signing key-pair. In the future it will also contain:

  • all the public keys (belonging to others) that I import
  • all the public keys of the key-pairs that I create

The pubring.kbx file, as described here, works like a database and can be queried for statistics:

kbxutil --stats ~/.gnupg/pubring.kbx

Total number of blobs:  2
header:                 1
empty:                  0
openpgp:                1
x509:                   0
non flagged:            1
secret flagged:         0
ephemeral flagged:      0

To be clear: creating a new key-pair won’t produce another 2 files (for a total of 4) but only 1 (for a total of 3): there will be 2 private key files under private-keys-v1.d and the new public key will be stored inside pubring.kbx

WARNING: I’ve tried to describe which file contains/does what but consider that the correct way to operate on keys is via GPG’s own commands.

Primary key-pair fingerprint

In order to create the subkeys I need to know the primary key-pair’s fingerprint which shown by:

gpg -K | grep fingerprint

Output:

Key fingerprint = 7205 2A26 269F 7552 DDED 3662 6596 C5FA 775E B9AB

I can either copy if from the terminal (and manually remove all the spaces) or be lazy and use this command:

fingerprint=$(gpg -K | grep fingerprint | head -n 1 | cut -d= -f2 | sed 's/ //g')
echo ${fingerprint}

Encryption subkey-pair creation

It’s now time to create an encryption subkey:

gpg --quick-add-key ${fingerprint} rsa4096 encr 2019-12-31

I’m asked to provide the passphrase for the primary key (in this example “knapp tiber fist lush hatred we’re”)

Test:

gpg -K

/home/user/.gnupg/pubring.kbx
-----------------------------
pub   rsa4096/0x6596C5FA775EB9AB 2018-10-08 [SC]
    Key fingerprint = 7205 2A26 269F 7552 DDED  3662 6596 C5FA 775E B9AB
    Keygrip = 50123401D7AA3CBF514F23D5FA98D3D485075B2E
uid                   [ultimate] Joe Tester <joe@foo.bar>
sub   rsa4096/0xFCFB0E137879D519 2018-10-08 [E] [expires: 2019-12-31]
    Key fingerprint = 6598 5A20 E7D5 871E E0EF  5A52 FCFB 0E13 7879 D519
    Keygrip = 4CB933841DCDF831B4CFFBC688B055BE472AC778

Signature subkey-pair creation

It’s now time to create a signature subkey:

gpg --quick-add-key ${fingerprint} rsa4096 sign 2019-12-31

I’m asked to provide the passphrase for the primary key (in this example “knapp tiber fist lush hatred we’re”)

Test:

gpg -K

/home/user/.gnupg/pubring.kbx
-----------------------------
pub   rsa4096/0x6596C5FA775EB9AB 2018-10-08 [SC]
    Key fingerprint = 7205 2A26 269F 7552 DDED  3662 6596 C5FA 775E B9AB
    Keygrip = 50123401D7AA3CBF514F23D5FA98D3D485075B2E
uid                   [ultimate] Joe Tester <joe@foo.bar>
sub   rsa4096/0xFCFB0E137879D519 2018-10-08 [E] [expires: 2019-12-31]
    Key fingerprint = 6598 5A20 E7D5 871E E0EF  5A52 FCFB 0E13 7879 D519
    Keygrip = 4CB933841DCDF831B4CFFBC688B055BE472AC778
sub   rsa4096/0xB7CB9817FF022A44 2018-10-08 [S] [expires: 2019-12-31]
    Key fingerprint = 5FF4 7D3F FD9F 95DB 9C96  1455 B7CB 9817 FF02 2A44
    Keygrip = 4E37F90BFA7E9A823283F3976C79499A67E0EA03

This is the content of ~/.gnupg

tree ~/.gnupg

/home/user/.gnupg
├── gpg.conf
├── openpgp-revocs.d
│   └── 72052A26269F7552DDED36626596C5FA775EB9AB.rev
├── private-keys-v1.d
│   ├── 4CB933841DCDF831B4CFFBC688B055BE472AC778.key
│   ├── 4E37F90BFA7E9A823283F3976C79499A67E0EA03.key
│   └── 50123401D7AA3CBF514F23D5FA98D3D485075B2E.key
├── pubring.kbx
├── pubring.kbx~
├── tofu.db
└── trustdb.gpg

2 directories, 9 files

Tofu.db

From the output of the previous command I notice that, after adding the 2 sub-keys, a new file appears in the directory: tofu.db.

What is it?

With a brief research I’ve found out this:

From GPG mailing list:

TOFU stands for Trust on First Use and is a concept that will be familiar to anyone who regularly uses ssh. When you ssh to a host for the first time, ssh asks you to verify the host’s key (most people just say yes here). When connecting to the same host in the future, ssh checks that the key hasn’t changed. If it has, ssh displays a warning.

TOFU for GnuPG works similarly. When you verify a message from some user for the first time, GnuPG saves the binding between the user id (actually, the normalized email address) and the key. When you verify another message from that user, the saved bindings with that user’s address are retrieved. If there is at least one such binding, but none of them include the signer’s key, then either the signer is using a new key or someone is attacking you. In this case, GnuPG displays a warning and prompts you to verify the key and set an appropriate policy (e.g., the key should be considered untrusted).

Authentication subkey-pair creation

The authentication subkey is not relevant from the encryption and signature stand point but I’m interested in the monkeysphere project which uses GPG for the SSH authentication and for the HTTPS validation of websites.

So I’m going the extra mile:

gpg --quick-add-key ${fingerprint} rsa4096 auth 2019-12-31

Now, these are these key-pairs available in my GPG key-ring:

gpg -K

/home/user/.gnupg/pubring.kbx
-----------------------------
pub   rsa4096/0x6596C5FA775EB9AB 2018-10-08 [SC]
    Key fingerprint = 7205 2A26 269F 7552 DDED  3662 6596 C5FA 775E B9AB
    Keygrip = 50123401D7AA3CBF514F23D5FA98D3D485075B2E
uid                   [ultimate] Joe Tester <joe@foo.bar>
sub   rsa4096/0xFCFB0E137879D519 2018-10-08 [E] [expires: 2019-12-31]
    Key fingerprint = 6598 5A20 E7D5 871E E0EF  5A52 FCFB 0E13 7879 D519
    Keygrip = 4CB933841DCDF831B4CFFBC688B055BE472AC778
sub   rsa4096/0xB7CB9817FF022A44 2018-10-08 [S] [expires: 2019-12-31]
    Key fingerprint = 5FF4 7D3F FD9F 95DB 9C96  1455 B7CB 9817 FF02 2A44
    Keygrip = 4E37F90BFA7E9A823283F3976C79499A67E0EA03
sub   rsa4096/0xB358AAABA8703BD8 2018-10-08 [A] [expires: 2019-12-31]
    Key fingerprint = DB1C 141B 9080 57E0 09AA  3F68 B358 AAAB A870 3BD8
    Keygrip = 3880DC542784CFC56B5773E50FF00289620071EA

and this is the content of the ~/.gnupg/ directory:

tree ~/.gnupg

/home/user/.gnupg
├── gpg.conf
├── openpgp-revocs.d
│   └── 72052A26269F7552DDED36626596C5FA775EB9AB.rev
├── private-keys-v1.d
│   ├── 3880DC542784CFC56B5773E50FF00289620071EA.key
│   ├── 4CB933841DCDF831B4CFFBC688B055BE472AC778.key
│   ├── 4E37F90BFA7E9A823283F3976C79499A67E0EA03.key
│   └── 50123401D7AA3CBF514F23D5FA98D3D485075B2E.key
├── pubring.kbx
├── pubring.kbx~
├── tofu.db
└── trustdb.gpg

Adding a photo to the public key

This step is optional but I like the idea to have a small photo embedded in the public key. In this way it will be easier for others to identify my public key among many others. It doesn’t have to be a personal photo, perhaps it can be an avatar.

GPG accepts only the jpg type and it should be small in size and in weight. 50x50 pixel and 2 to 20 KB is OK.

I add the photo with this interactive command:

gpg --edit-key ${fingerprint}

# at the prompt write:
# addphoto

# Then:
# type photo's absolute path
# type your passphrase
# type "save"
# type "quit"

SSL key creation

I don’t want to remember Joe’s GPG passphrase and I’m happy to use openssl to store the passphrase (encrypted with AES 256) next to the coffin key inside the hush-partition.

I check that the sdcard is mounted:

mount | grep hush

Output:

/dev/mapper/hush on /home/user/.hush type ext4 (rw,relatime,data=ordered) /dev/mapper/hush on /rw/home/user/.hush type ext4 (rw,relatime,data=ordered)

If the output is empty then I have to run :

  • dom0: attach_hush_to vault
  • vault: risks mount hush

When openssl asks for the encryption password, I use the same that I use for mpw

echo "knapp tiber fist lush hatred we're" | openssl enc -aes-256-cbc -a > ${HUSH_DIR}/${IDENTITY}-gpg.ssl

I immediately protect the ssl key against accidental deletion or change by making it immutable:

sudo chattr +i ${HUSH_DIR}/${IDENTITY}-gpg.ssl

Test:

risks gpgpass ${IDENTITY}

I should be able to see again “knapp tiber fist lush hatred we’re”. This is the command I use before opening any


Coffin creation

I use one coffin-file to store the GPG configuration files of each identity.

This allows to:

  • quickly load any identity
  • keep identities isolated

Coffin key creation

I create a random binary file (human unreadable) that I use as key for the gpg-coffin:

IDENTITY="joe"
head -c 512 < /dev/urandom > ${HUSH_DIR}/${IDENTITY}-gpg.key

Alternatively I can use a human readable random key (in case I want to transform it in a printable QRcode):

pwgen -y -s -C 64 > ${HUSH_DIR}/${IDENTITY}-gpg.key

I immediately protect the key against accidental deletion or changes by making it immutable:

sudo chattr +i ${HUSH_DIR}/${IDENTITY}-gpg.key

I can test the immutability of files with:

lsattr ${HUSH_DIR}

Output:

—-i———e—- /home/user/.hush/joe-gpg.key

The i character means that the file is marked as immutable.

Coffin creation

I’m ready to create the gpg-coffin container (50MB):

dd if=/dev/urandom of=${GRAVEYARD}/${IDENTITY}-gpg.coffin bs=1M count=50

I lay the gpg-coffin inside the container and I bond it to its key, all in one command:

sudo cryptsetup -v -q --cipher aes-xts-plain64 --master-key-file ${HUSH_DIR}/${IDENTITY}-gpg.key --key-size 512 --hash sha512 --iter-time 5000 --use-random luksFormat ${GRAVEYARD}/${IDENTITY}-gpg.coffin ${HUSH_DIR}/${IDENTITY}-gpg.key

WARNING:

Here I’m not using a passphrase on purpose. I could use a tomb-file instead of a coffin-file and add a passphrase but this would increase a lot my mnemonic effort and, in my situation, it would be too much.

It’s true that who has access to the gpg-coffin and its key is able to open it without a passphrase but it’s also true that GPG is also protected by its own passphrase.

Therefore just having the coffin and its key is not enough to use GPG.

Test:

sudo cryptsetup luksDump ${GRAVEYARD}/${IDENTITY}-gpg.coffin

Output:

LUKS header information for /home/user/.graveyard/joe-gpg.coffin

Version:       	1
Cipher name:   	aes
Cipher mode:   	xts-plain64
Hash spec:     	sha512
Payload offset:	4096
MK bits:       	512
MK digest:     	9c 6f 45 11 92 01 5c 08 54 60 8b d6 9b 25 0b 53 0d 53 d9 26
MK salt:       	1e fa f4 dc c0 cc 2e 15 57 01 5d 52 c3 a2 f8 42
                aa 07 68 54 a5 a4 d5 10 e5 d8 1d d2 50 75 d3 bf
MK iterations: 	560000
UUID:          	fb718c68-add3-4a3d-9bb0-0c89cb81237df

Key Slot 0: ENABLED
    Iterations:         	4596049
    Salt:               	3b c7 98 a3 b3 30 49 43 b0 71 26 8f 57 f8 92 08
                            be c2 49 d2 4c 8b fb 70 5d d4 91 b5 de 9a eb b9
    Key material offset:	8
    AF stripes:            	4000
Key Slot 1: DISABLED
Key Slot 2: DISABLED
Key Slot 3: DISABLED
Key Slot 4: DISABLED
Key Slot 5: DISABLED
Key Slot 6: DISABLED
Key Slot 7: DISABLED

which displays the UUID of the gpg-coffin and shows that only one key has been configured for it.

Coffin setup

I open the gpg-coffin (no passphrase is asked):

sudo cryptsetup open --type luks ${GRAVEYARD}/${IDENTITY}-gpg.coffin coffin-${IDENTITY}-gpg --key-file ${HUSH_DIR}/${IDENTITY}-gpg.key

Test:

sudo cryptsetup status coffin-${IDENTITY}-gpg

Output:

/dev/mapper/coffin-joe-gpg is active.
type:    LUKS1
cipher:  aes-xts-plain64
keysize: 512 bits
device:  /dev/loop0
loop:    /home/user/.graveyard/joe-gpg.coffin
offset:  4096 sectors
size:    98304 sectors
mode:    read/write

The gpg-coffin is open and ready to be formatted. I use the ext4 filesystem:

sudo mkfs.ext4 -m 0 -L coffin-${IDENTITY}-gpg /dev/mapper/coffin-${IDENTITY}-gpg

I create a temporary directory and I mount the gpg-coffin on it:

TMP="/tmp/${IDENTITY}-gpg"
mkdir ${TMP}
sudo mount /dev/mapper/coffin-${IDENTITY}-gpg ${TMP}
sudo chown ${USER} ${TMP}
_```


Test:

``` bash
mount | grep ${IDENTITY}-gpg

I copy the GPG files in the gpg-coffin:

cp -fR ${RAMDISK}/* ${TMP}

The GPG keys shouldn’t be modified nor deleted, especially by mistake, so I make them immutable with chattr

risks open gpg ${IDENTITY}
sudo chattr +i ${TMP}/private-keys-v1.d/*
sudo chattr +i ${TMP}/openpgp-revocs.d/*

I close the coffin for good:

sudo umount ${TMP}
sudo cryptsetup close /dev/mapper/coffin-${IDENTITY}-gpg

and I wipe and umount the ramdisk:

cd
sudo wipe -r ${RAMDISK}
sudo umount ${RAMDISK}

This is the final result from the filesystem stand point:

tree ~/.hush ~/.graveyard
/home/user/.hush
├── joe-gpg.key

/home/user/.graveyard
├── joe-gpg.coffin

Now the GPG files for ${IDENTITY} exists only inside the gpg-coffin which I open or close with risks from vault:

risks open coffin ${IDENTITY}
risks close coffin ${IDENTITY}

At this stage the GPG configuration for ${IDENTITY} is complete and GPG can be used from vault but Cabal’s mitigation is still missing and before proceeding I need to create my first tomb-file.


Recap for copy & paste

I recap here all the commands in a row so that I can later on use “copy and paste” for creating the gpg-coffin for the other identities:

IDENTITY="other_identity"

head -c 512 < /dev/urandom > ${HUSH_DIR}/${IDENTITY}-gpg.key

dd if=/dev/urandom of=${GRAVEYARD}/${IDENTITY}-gpg.coffin bs=1M count=50

sudo cryptsetup -v -q --cipher aes-xts-plain64 --master-key-file ${HUSH_DIR}/${IDENTITY}-gpg.key --key-size 512 --hash sha512 --iter-time 5000 --use-random luksFormat ${GRAVEYARD}/${IDENTITY}-gpg.coffin ${HUSH_DIR}/${IDENTITY}-gpg.key

sudo cryptsetup open --type luks ${GRAVEYARD}/${IDENTITY}-gpg.coffin ${IDENTITY}-gpg --key-file ${HUSH_DIR}/${IDENTITY}-gpg.key

sudo mkfs.ext4 -m 0 -L ${IDENTITY}-gpg /dev/mapper/${IDENTITY}-gpg

TMP="/tmp/${IDENTITY}-gpg"

mkdir ${TMP}

sudo mount /dev/mapper/${IDENTITY}-gpg ${TMP}

sudo chown ${USER} ${TMP}

Then to close the coffin:

sudo umount ${TMP}
sudo cryptsetup close /dev/mapper/${IDENTITY}-gpg