Airgapped Media
Format
I’ll save you the explanation of what GPG is. First thing I needed was a USB stick that would be compatible with Arch and MacOS. This fight is always interesting and I would rank the better operating system as the one that can compromise on the filesystem. Naturally, insert the USB stick in the MacOS and format it as a Journaled HFS+ partition because we can install the driver on Arch.
Disable Journaling
sudo diskUtil disableJournal /dev/disk0s1
Or whatever your disk is. Arch doesn’t like the journaling yet.
Note
I tried all the variants of FAT, exFAT, NTFS, and a couple others. This is the only filesystem that preserves permissions and case-sensitivity, so I think it is the safest bet.
fstab
You want to have an /etc/fstab
entry that will let you mount this disk easily.
/dev/sdb1 /mnt/stick hfsplus user,rw,nosuid,nodev,noexec,relatime,sync,umask=22,uid=0,gid=0,nls=utf8
Now you can:
mount /mnt/stick
When your drive is inserted.
Location
Make a directory with sudo
on this drive and own it to your user.
The UID for the rest of the drive will likely be 99
because of the way MacOS deals with users, but you can make this folder be yours to write freely to it.
Making Keys
This article was so good, that I copied the article in plaintext to my storage media for the keys too.
Configuration
Here’s a copy of my ~/.gnupg/gpg.conf
.
Construction
Master
You will be making the GPG keys with your local utility, backing them up to the media, then deleting the master key from your current OS installation. When you take the media to a new computer, you will import the secret subkeys only. That will leave you with full capabilities of GPG but also protection against private key discovery.
First make a key that can only C
ertify:
gpg --expert --full-gen-key
Select 8
and toggle till you see this:
Possible actions for a RSA key: Sign Certify Encrypt Authenticate
Current allowed actions: Certify
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? q
Make the key size 4096
because we live in the future, and give it an expiration of 1y
.
Fill in the rest of the fields how you would like.
For the identity fields, question what the use of this key will be?
Deniable encryption or identity verification?
You should have something like this now:
> gpg -k
/home/drone/.gnupg/pubring.kbx
------------------------------
pub rsa4096/ED152F106BE94245 2018-12-19 [C] [expires: 2020-12-18]
Key fingerprint = 332B DF93 D4CA 7C43 4E87 F0F2 ED15 2F10 6BE9 4245
uid [ultimate] Real Name <[email protected]>
Subkeys
Now that you have your master key, make the sub keys. Get the ID of the key you just made and enter expert mode.
gpg --expert --edit-key ED152F106BE94245
The idea now is to addkey
to make a subkey for each of the tasks:
- Authenticate (A)
- Sign (S)
- Encrypt (E)
So you will select 8
again and toggle until you only have one of those permissions on a key, complete the generation process, then repeat for the other permissions.
You should have this at the end:
sec rsa4096/ED152F106BE94245
created: 2018-12-19 expires: 2020-12-18 usage: C
trust: ultimate validity: ultimate
ssb rsa4096/6D7B797688AD10C7
created: 2018-12-19 expires: 2020-12-18 usage: S
ssb rsa4096/815437E38E23B6EE
created: 2018-12-19 expires: 2020-12-18 usage: E
ssb rsa4096/707FB77767CBEDDD
created: 2018-12-19 expires: 2020-12-18 usage: A
[ultimate] (1). Real Name <[email protected]>
save
to exit GPG.
Revocation
After you have made your keys, generate a revocation key for the master. We will use this in case we need to invalidate the whole shebang.
gpg --output ED152F106BE94245.rev --gen-revoke ED152F106BE94245
ED152F106BE94245.rev Contains the revocation certificate for the master key. I’ve kept it on the media, because that’s where the master private key will only ever be.
Backups
gpg --export --armor ED152F106BE94245 > ED152F106BE94245.pub.asc
ED152F106BE94245.pub.asc Contains all the public keys.
gpg --export-secret-keys --armor ED152F106BE94245 > ED152F106BE94245.sec.asc
ED152F106BE94245.sec.asc Contains the master private key.
gpg --export-secret-subkeys --armor ED152F106BE94245 > ED152F106BE94245.sub.sec.asc
ED152F106BE94245.sub.sec.asc Contains only the private keys of the subkeys.
Deleting the Master
Now, you can delete the master key from your local keyring to complete the setup. First, delete the whole thing, then import only the private subkeys that we just exported.
gpg --delete-secret-key ED152F106BE94245
gpg --delete-key ED152F106BE94245
Now, import the the private subkeys:
gpg --import ED152F106BE94245.sub.sec.asc
You should have this now:
> gpg -k
/home/drone/.gnupg/pubring.kbx
------------------------------
pub rsa4096/ED152F106BE94245 2018-12-19 [C] [expires: 2020-12-18]
Key fingerprint = 332B DF93 D4CA 7C43 4E87 F0F2 ED15 2F10 6BE9 4245
uid [ unknown] Real Name <[email protected]>
sub rsa4096/6D7B797688AD10C7 2018-12-19 [S] [expires: 2020-12-18]
sub rsa4096/815437E38E23B6EE 2018-12-19 [E] [expires: 2020-12-18]
sub rsa4096/707FB77767CBEDDD 2018-12-19 [A] [expires: 2020-12-18]
> gpg -K
/home/drone/.gnupg/pubring.kbx
------------------------------
sec# rsa4096/ED152F106BE94245 2018-12-19 [C] [expires: 2020-12-18]
Key fingerprint = 332B DF93 D4CA 7C43 4E87 F0F2 ED15 2F10 6BE9 4245
uid [ unknown] Real Name <[email protected]>
ssb rsa4096/6D7B797688AD10C7 2018-12-19 [S] [expires: 2020-12-18]
ssb rsa4096/815437E38E23B6EE 2018-12-19 [E] [expires: 2020-12-18]
ssb rsa4096/707FB77767CBEDDD 2018-12-19 [A] [expires: 2020-12-18]
Note the #
near sec
for the list private keys operation.
That means that the master key no longer is present, only a stub.
This is perfect.
Applications
Now that you have a full set of airgapped keys, you can move them back over to the other computer and import the private subkeys again. Then you can give your public key to who you want.
We did create and Authentication key too…
Exporting an SSH Key
gpg --with-keygrip -k
> gpg --with-keygrip -k
/home/drone/.gnupg/pubring.kbx
------------------------------
pub rsa4096/ED152F106BE94245 2018-12-19 [C] [expires: 2020-12-18]
Key fingerprint = 332B DF93 D4CA 7C43 4E87 F0F2 ED15 2F10 6BE9 4245
Keygrip = 9E3B3A733EE6843BFF34A8519B8E2718FAC37CE9
uid [ unknown] Real Name <[email protected]>
sub rsa4096/6D7B797688AD10C7 2018-12-19 [S] [expires: 2020-12-18]
Keygrip = FF269048B780DDCC03C848E1EDC026DDA58112A5
sub rsa4096/815437E38E23B6EE 2018-12-19 [E] [expires: 2020-12-18]
Keygrip = 7848285CC2CF03B10FE43EC4679B86775224FCF9
sub rsa4096/707FB77767CBEDDD 2018-12-19 [A] [expires: 2020-12-18]
Keygrip = 3033CB663B155310BF8B95A92226E3D7A50B8B6E
You can see here the keygrips you need to complete the ssh authentication portion.
Add the keygrip of the [A]
key to the end of ~/.gnupg/sshcontrol
.
Then you can export a key:
gpg --export-ssh-key ED152F106BE94245
And copy that to your remote server authorized keys or give it to Gitlab.
GPG Agent
You can use gpg-agent
instead of ssh-agent
.
The setup is different on Mac and Linux.
TODO: Include the setup once it is working.
As always, The Arch Wiki is a good place to start for configuration.
Signing Commits
Now that you have the keys, you can sign your commits. Github and Gitlab get a copy of you public key first, then you configure your local git installation to sign with your key:
git config --global user.signingkey ED152F106BE94245
git config --global commit.gpgsign true