This post describes setup and example usages of Smartcard with a Thinkpad's onboard reader and OpenPGP to handle keys for authentication and encryption.
Your master key will be stored (securely I hope) on a USB drive and rarely used, with your Smart Card containing a couple of subkeys which will be used to sign and authenticate day-to-day.
At the end of the guide you should have a master key securely stored on a USB key, a hard-copy of revocation certificate, some sub-keys stored on your Smart Card and some knowledge about how to use it to emails, and authenticate via ssh:
There are already very technical guides on how to set this up like the one on jclement.ca which steps 1-5 heavily lean on but even if you're pretty tech-savvy you may end up not 100% understanding exactly what you've actually done.
I got my Smart Card by becoming a member of the EFSF fellowship or by picking up another OpenPGP smartcard (or a YubiKey if you don't have a reader, here).
Step 1. Securely create and boot from a Debian Live USB image
Download and verify a Debian live image per my previous guide here. We can now flash the USB key we're going to boot from:
$ sudo dd bs=4M if=./debian-live-8.3.0-amd64-xfce-desktop+nonfree.iso of=/dev/sdb && sync
272+0 records in
272+0 records out
1140850688 bytes (1.1 GB) copied, 214.052 s, 5.3 MB/s
Yes I used a very slow USB flash drive and it was rather painful.
Step 2. Setup the packages
Next couple of sections are pretty much the same steps as the jclement.ca guide - install gnupg2 and libraries we'll use:
$ sudo apt-get install haveged gnupg2 gnupg-agent libpth20 pinentry-curses libccid pcscd scdaemon libksba8 paperkey opensc jpegoptim xloadimage
Change the configuration file for GnuPG so that it uses a different, stronger set of ciphers by default:
$ mkdir ~/.gnupg
$ cat > ~/.gnupg/gpg.conf << !
no-emit-version
no-comments
keyid-format 0xlong
with-fingerprint
use-agent
personal-cipher-preferences AES256 AES192 AES CAST5
personal-digest-preferences SHA512 SHA384 SHA256 SHA224
cert-digest-algo SHA512
default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
!
At this point jclement.ca advise that you disconnect from the network - which is probably a good idea since we're about to generate a handful of keys and we don't want anything to leak.
What we're going to do is create a Master Key - which will be stored on a USB drive - and then use it to create a handful of Sub Keys which will be stored on the Smart Card for day-to-day use. Since the Sub Keys could conceivably be compromised we'll generate a revocation certificate which we can use to notify everyone that they should no longer be trusted - at this point we'd generate a new set of Sub Keys and load them onto our card.
Since there are a number of utilities and technologies you may not be familiar with I'm going to show a diagram at the end of each step in the key-creation process to help visualise what exactly is going on where. Here's a little diagram showing what symbols I'll be using.
Step 3. Creating the Master Key
$ gpg2 --gen-key
gpg (GnuPG) 2.0.26; Copyright (C) 2013 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
gpg: keyring `/home/sean/.gnupg/secring.gpg' created
gpg: keyring `/home/sean/.gnupg/pubring.gpg' created
Please select what kind of key you want:
(1) RSA and RSA (default)
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
Your selection? 4
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
0 = key does not expire
= key expires in n days
w = key expires in n weeks
m = key expires in n months
y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y
GnuPG needs to construct a user ID to identify your key.
Real name: Sean McLemon
Email address: sean.mclemon@gmail.com
Comment:
You selected this USER-ID:
"Sean McLemon "
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
You need a Passphrase to protect your secret key.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: /home/sean/.gnupg/trustdb.gpg: trustdb created
gpg: key 0xC87419541EAC16A8 marked as ultimately trusted
public and secret key created and signed.
gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
pub 4096R/0xC87419541EAC16A8 2016-04-01
Key fingerprint = D90B 2575 6FD3 D781 A856 9AE3 C874 1954 1EAC 16A8
uid [ultimate] Sean McLemon
Note that this key cannot be used for encryption. You may want to use
the command "--edit-key" to generate a subkey for this purpose.
And add a pic:
$ gpg2 --edit-key 0xC87419541EAC16A8
gpg (GnuPG) 2.0.26; Copyright (C) 2013 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Secret key is available.
pub 4096R/0xC87419541EAC16A8 created: 2016-04-01 expires: never usage: SC
trust: ultimate validity: ultimate
[ultimate] (1). Sean McLemon
gpg> addphoto
Pick an image to use for your photo ID. The image must be a JPEG file.
Remember that the image is stored within your public key. If you use a
very large picture, your key will become very large as well!
Keeping the image close to 240x288 is a good size to use.
Enter JPEG filename for photo ID: test.jpg
Is this photo correct (y/N/q)? y
You need a passphrase to unlock the secret key for
user: "Sean McLemon "
4096-bit RSA key, ID 0xC87419541EAC16A8, created 2016-04-01
pub 4096R/0xC87419541EAC16A8 created: 2016-04-01 expires: never usage: SC
trust: ultimate validity: ultimate
[ultimate] (1). Sean McLemon
[ unknown] (2) [jpeg image of size 746]
gpg> save
So now we've got a Master Key our live distro's temporary filesystem. As I mentioned before this should only ever live on a USB key - to do anything useful we'll need to generate some Sub Keys.
Step 4. Creating the Sub Keys
A bit of a better explanation of Sub Keys is at https://wiki.debian.org/Subkeys. Remember, these are the keys we'll be using day-to-day and will be stored on our Smart Card.
$ gpg2 --expert --edit-key 0xC87419541EAC16A8
gpg (GnuPG) 2.0.26; Copyright (C) 2013 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Secret key is available.
gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
pub 4096R/0xC87419541EAC16A8 created: 2016-04-01 expires: never usage: SC
trust: ultimate validity: ultimate
[ultimate] (1). Sean McLemon
[ultimate] (2) [jpeg image of size 746]
gpg> addkey
Key is protected.
You need a passphrase to unlock the secret key for
user: "Sean McLemon "
4096-bit RSA key, ID 0xC87419541EAC16A8, created 2016-04-01
Please select what kind of key you want:
(3) DSA (sign only)
(4) RSA (sign only)
(5) Elgamal (encrypt only)
(6) RSA (encrypt only)
(7) DSA (set your own capabilities)
(8) RSA (set your own capabilities)
Your selection? 4
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 2048
Requested keysize is 2048 bits
Please specify how long the key should be valid.
0 = key does not expire
= key expires in n days
w = key expires in n weeks
m = key expires in n months
y = key expires in n years
Key is valid for? (0) 6m
Key expires at Wed 28 Sep 2016 21:41:58 CEST
Is this correct? (y/N) y
Really create? (y/N) y
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
pub 4096R/0xC87419541EAC16A8 created: 2016-04-01 expires: never usage: SC
trust: ultimate validity: ultimate
sub 2048R/0x191900DBF062921B created: 2016-04-01 expires: 2016-09-28 usage: S
[ultimate] (1). Sean McLemon
[ultimate] (2) [jpeg image of size 746]
gpg> addkey
Key is protected.
You need a passphrase to unlock the secret key for
user: "Sean McLemon "
4096-bit RSA key, ID 0xC87419541EAC16A8, created 2016-04-01
Please select what kind of key you want:
(3) DSA (sign only)
(4) RSA (sign only)
(5) Elgamal (encrypt only)
(6) RSA (encrypt only)
(7) DSA (set your own capabilities)
(8) RSA (set your own capabilities)
Your selection? 6
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 2048
Requested keysize is 2048 bits
Please specify how long the key should be valid.
0 = key does not expire
= key expires in n days
w = key expires in n weeks
m = key expires in n months
y = key expires in n years
Key is valid for? (0) 6m
Key expires at Wed 28 Sep 2016 21:42:14 CEST
Is this correct? (y/N) y
Really create? (y/N) y
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
pub 4096R/0xC87419541EAC16A8 created: 2016-04-01 expires: never usage: SC
trust: ultimate validity: ultimate
sub 2048R/0x191900DBF062921B created: 2016-04-01 expires: 2016-09-28 usage: S
sub 2048R/0x46BDB50E980A2B9B created: 2016-04-01 expires: 2016-09-28 usage: E
[ultimate] (1). Sean McLemon
[ultimate] (2) [jpeg image of size 746]
gpg> addkey
Key is protected.
You need a passphrase to unlock the secret key for
user: "Sean McLemon "
4096-bit RSA key, ID 0xC87419541EAC16A8, created 2016-04-01
Please select what kind of key you want:
(3) DSA (sign only)
(4) RSA (sign only)
(5) Elgamal (encrypt only)
(6) RSA (encrypt only)
(7) DSA (set your own capabilities)
(8) RSA (set your own capabilities)
Your selection? 8
Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Sign Encrypt
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? s
Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Encrypt
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? e
Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions:
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? a
Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Authenticate
(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? q
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048)
Requested keysize is 2048 bits
Please specify how long the key should be valid.
0 = key does not expire
= key expires in n days
w = key expires in n weeks
m = key expires in n months
y = key expires in n years
Key is valid for? (0) 6m
Key expires at Wed 28 Sep 2016 21:42:43 CEST
Is this correct? (y/N) y
Really create? (y/N) y
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
pub 4096R/0xC87419541EAC16A8 created: 2016-04-01 expires: never usage: SC
trust: ultimate validity: ultimate
sub 2048R/0x191900DBF062921B created: 2016-04-01 expires: 2016-09-28 usage: S
sub 2048R/0x46BDB50E980A2B9B created: 2016-04-01 expires: 2016-09-28 usage: E
sub 2048R/0xF1D25AD8AC008AA1 created: 2016-04-01 expires: 2016-09-28 usage: A
[ultimate] (1). Sean McLemon
[ultimate] (2) [jpeg image of size 746]
gpg> save
Now we've got the newly created Master and Sub-keys on the local filesystem.
Step 5. Generate a revocation certificate
$ gpg2 --gen-revoke 0xC87419541EAC16A8
sec 4096R/0xC87419541EAC16A8 2016-04-01 Sean McLemon
Create a revocation certificate for this key? (y/N) y
Please select the reason for the revocation:
0 = No reason specified
1 = Key has been compromised
2 = Key is superseded
3 = Key is no longer used
Q = Cancel
(Probably you want to select 1 here)
Your decision? 1
Enter an optional description; end it with an empty line:
> FSB got hold of my private key
>
Reason for revocation: Key has been compromised
y
Is this okay? (y/N) y
You need a passphrase to unlock the secret key for
user: "Sean McLemon "
4096-bit RSA key, ID 0xC87419541EAC16A8, created 2016-04-01
ASCII armored output forced.
Revocation certificate created.
Please move it to a medium which you can hide away; if Mallory gets
access to this certificate he can use it to make your key unusable.
It is smart to print this certificate and store it away, just in case
your media become unreadable. But have some caution: The print system of
your machine might store the data and make it available to others!
-----BEGIN PGP PUBLIC KEY BLOCK-----
Comment: A revocation certificate should follow
iQIgBCABCgAKBQJW/s+XAx0CeQAKCRDIdBlUHqwWqEsbEACFj7ZDRgwcvG99F1Hb
PHzqGPXh5X04nnjpPbnWaKviycvdCQtFT3N3Hg0c1fmgBBDMXHXKcP8dBwrsgmU0
x1vEFUSmzvaW+s/EZXh8xwfXhGVmBG+H+i5JqfiPXelaKH12/pDPqIIE+jlwFx5O
a+I3TMg5x5pBzpSWmCNmFgxU4jEJ6SBwsYYDCwGjStS3C8Dojk7RfJug/+wZAhk2
nuGbHKeL48TmLwVsoqlbut57yUzqJ16wC9u46oOwKUeUnluEhOm8eT8fvQsHwM11
THx8UshfjY1/2p5oA4e7GOyB93u7mS5+u57dkKiHwDbNKVq++rMnJH5nesgOT3f6
D/5quHjQNUXwGJsxu3H+ZSxAmmj2q8ooaPZfDxeAqSgjLSu3vTQGK8HtsnJ3Cgu5
tANW4SrDrqqvmpNzutGkmfLRgN/stSLi+MJz78h87nCDPQkMUmp6fEk2kEnVmj1B
BEMY5SSrJrIDGwf4CGn4kzHDb9/GlS47x33LcE8g7F1lM1LQ7eNvRNpDU36dmiwj
luJLtl0tKVW4YBz4Yo7AxmT0QYSCgXHWStt9XB1devps1CJ45dlbPNzAE8rJH2+1
3YjZfFAgiSFFHMsq0C1M2+mQaqrAyGUVT/lR42Tok0GgwaZK48VWeP+cRZu07NDr
pxodVfJ7TjcVUF04AEtSxayfbg==
=ck5O
-----END PGP PUBLIC KEY BLOCK-----
JClement suggests printing this out - if you do so it might want to create a QR code to make it easier to digitize. You might want avoid QR code generator sites since we're aiming for security, but you can generate one easily enough using python
qrcode module:
$ pip install qrcode
Downloading/unpacking qrcode
Downloading qrcode-5.2.2-py2.py3-none-any.whl (89kB): 89kB downloaded
Requirement already satisfied (use --upgrade to upgrade): colorama in /usr/lib/python2.7/dist-packages (from qrcode)
Requirement already satisfied (use --upgrade to upgrade): six in /usr/lib/python2.7/dist-packages (from qrcode)
Installing collected packages: qrcode
Successfully installed qrcode
Cleaning up...
$ python
Python 2.7.9 (default, Mar 1 2015, 12:57:24)
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import qrcode
>>> cert = open("revoke_cert.asc")
>>> cert_text = cert.read()
>>> cert_qr = qrcode.make(cert_text)
>>> cert_qr.save("revoke_cert.png")
The certificate itself is pretty sizeable, so the resulting QR code is pretty dense and you'll need a reasonable camera to successfully scan it (my iPhone 6S worked nicely). Using the lines above the resulting image will look a little like
this - it's a little huge so I didn't want to include it in-line.
So assuming we've printed out revoke_cert.png and discarded the .asc file, at this point we should have created:
Step 6. Backup GPG and store keys on SD/USB
Now we've generated our keys we can copy them somewhere safe (an SD card, or USB)
$ tar -czf gnupg.tgz ~/.gnupg
tar: Removing leading `/' from member names
$ gpg2 -a --export-secret-key 0xC87419541EAC16A8 >> 0xC87419541EAC16A8.master.key
$ gpg2 -a --export-secret-subkeys 0xC87419541EAC16A8 >> 0xC87419541EAC16A8.subkeys.key
$ gpg2 -a --export 0xC87419541EAC16A8 > 0xC87419541EAC16A8.public.key.asc
$ sudo cp gnupg.tgz 0xC87419541EAC16A8.master.key 0xC87419541EAC16A8.subkeys.key 0xC87419541EAC16A8.public.key.asc /media/SDCARD/
Note - it is important to do this. Once we restart the filesystem of the live CD will no longer exist, and we'll lose all of our keys. then load the subkeys to the card.
Now we can distribute the key:
$ gpg2 --keyserver hkp://pool.sks-keyservers.net --send-keys 0xC87419541EAC16A8
gpg: sending key 0xC87419541EAC16A8 to hkp server pool.sks-keyservers.net
Now we can reboot, upload our public key to the internet and here's what we have - a master key stored offline/disconnected, a set of sub-keys on the smartcard we can use for everyday tasks, a printed certificate we can use to revoke our subkeys, and a public key somewhere on the net we can share with anyone we need to communicate securely with.
Step 7. Boot into usual OS + load keys
When you're sufficiently certain you've got a nice backup of the .gnupg directory, and the subkeys loaded to the card we can boot into our normal OS and remove the live USB card.
We'll need to
$ gpg2 --import 0xC87419541EAC16A8.public.key.asc
gpg: /home/sean/.gnupg/trustdb.gpg: trustdb created
gpg: key C3969A6B: public key "Sean McLemon " imported
gpg: Total number processed: 1
gpg: imported: 1 (RSA: 1)
Now everything is set - we explore a few situations where you might want to use a smart card.
Example 1. Signing/Encrypting a text file using your card
There's a very good guide produced by the Free Software Foundation @ https://emailselfdefense.fsf.org which you can follow if you want to use EnigMail and Thunderbird - if you want an easy way to sign/encrypt emails you should follow that. However if we just want to sign a message in a text file from the command line, we could do something like the below
$ echo > msg << EOF
> paddy schwartz party time
> EOF
$ gpg2 --output msg.sig --sign msg
Example 2. Decrypting a file using your card
If someone's sent you a file they'll encrypt it using your public key. You can use the keys stored on your card to decrypt it.
To set this up we'll first encrypt a simple text file using our own public key:
$ echo "a funky test message" > plaintext.asc
$ gpg2 --out cyphertext --recipient 0x2F3F79CDC3969A6B --encrypt plaintext.asc
gpg: 720D24AD: There is no assurance this key belongs to the named user
pub 2048R/720D24AD 2016-03-24 Sean McLemon
Primary key fingerprint: 63EB 6DF3 C42E 1AB3 92B5 BF02 2F3F 79CD C396 9A6B
Subkey fingerprint: 3E3C 084E 622A BB06 EEFB A739 A3FE 2BC1 720D 24AD
It is NOT certain that the key belongs to the person named
in the user ID. If you *really* know what you are doing,
you may answer the next question with yes.
Use this key anyway? (y/N) y
OK now we'll verify that the card isn't connected, and that we cannot decrypt it without the card
$ gpg2 --card-status
gpg: selecting openpgp failed: Card not present
gpg: OpenPGP card not available: Card not present
$ gpg2 --out plaintext-decrypted.asc --decrypt cyphertext
gpg: selecting openpgp failed: Card not present
gpg: encrypted with 2048-bit RSA key, ID 720D24AD, created 2016-03-24
"Sean McLemon "
gpg: public key decryption failed: Operation cancelled
gpg: decryption failed: No secret key
Now if we insert the smart card and try to decrypt again we'll be prompted for our PIN, and the file will be decrypted successfully:
$ gpg2 --out plaintext-decrypted.asc --decrypt cyphertext
gpg: encrypted with 2048-bit RSA key, ID 720D24AD, created 2016-03-24
"Sean McLemon "
$ cat plaintext-decrypted.asc
a funky test message
Example 3. Authenticating with a remote machine using your card
$ echo enable-ssh-support >> ~/.gnupg/gpg-agent.conf
$ sudo emacs /etc/X11/Xsession.options # and comment/remove the line "use-ssh-agent"
Now we'll add our public key to the computer we want to connect to using ssh - in my case it's mokpo.local
$ ssh-add -L | ssh mokpo.local 'cat >> ~/.ssh/authorized_keys'
and we can now test logging in
Example 4. Revoking your keys using the QR code
If our key is ever compromised and we'd like to revoke we will need to issue a revocation certificate to say that this key shouldn't ever be trusted. We can use the QR code we previously generated + printed out - first scan the QR code and save the results into a file revoke-certificate-qr.txt, and perform the following steps:
$ gpg2 --import revoke-certificate-qr.txt
$ gpg2 --keyserver hkp://pool.sks-keyservers.net --send-keys 0xC87419541EAC16A8
Now the world should know not to trust our old keypair, and we can go back to the start of this article and generate a completely new one - this time being extra careful to keep it safe!