leftfold

A blog about software engineering, C++, functional programming, and related topics.
By Hannes Rantzsch

A Two-Factor Encrypted Flash Drive


In this post I want to show you how you can use your YubiKey to protect an external drive or USB stick with two-factor authentication. Here's a little teaser:

The device /dev/sdc is my encrypted USB flash drive. As you can see, it can only be decrypted using two factors: my password and my YubiKey.

Overview

In the following guide we will encrypt an external device in a way that it will only be accessible using the two factors you saw above. Using the YubiKey we will be able to obtain a very strong passphrase that cannot be broken by brute force. The passphrase itself was not visible in the GIF above, but you saw me typing a password and activating the YubiKey. These are the factors the passphrase is made of.

If you want to follow along, you will need an external device that you want to encrypt, and a YubiKey 4, Neo, or 5. We will make use of the YubiKey's challenge-response mode and I will cover the required configuration of the YubiKey below. For more information about setting up your YubiKey, including how to use it as a SmartCard with GPG, I recommend you have a look at the YubiKey-Guide by drduh, as well as the official documentation of course.

Disclaimer

Be aware that all data on the external device will be lost. If it contains any data that is valuable to you do a backup. Also, be warned that the commands below have the potential to override secrets already configured on your YubiKey. Please proceed with caution and at your own risk.

Step 1: Obtain the Passphrase

In the first step we want to produce a very strong passphrase to encrypt your device with. It will only be possible to obtain this passphrase given two factors: a password you have to remember (knowledge) and your YubiKey (possession).

Generating the passphrase makes use of the YubiKey's challenge-response mode. In this mode of authentication a secret is configured on the YubiKey. In order to authenticate successfully, the YubiKey has to answer an incoming challenge with the correct response, which it can only produce using the secret.

We will take advantage of this mechanism in order to construct our encryption passphrase. However, we will not only compare the YubiKey's response with some shared secret. Instead, we'll make both the challenge and the YubiKey's response part of the passphrase. This way, both factors will be needed to decrypt the device.

The steps to produce the passphrase roughly follow this guide (shout-out to Andrei Gherzan) that provides tools to encrypt a system partition for Arch Linux. First, we have to create the secret on your YubiKey. For this, we need to set one of the YubiKey's OTP slots to HMAC-SHA1 Challenge-Response mode. We will use the second slot in this example because it is not yet configured by default.

Warning: If the slot you choose is already configured, running the following command will override the secret stored there.

ykpersonalize -v -2 -ochal-resp -ochal-hmac -ohmac-lt64 -ochal-btn-trig

The arguments above mean:[2]

  -v: Verbose output
  -2: Use slot 2
  -ochal-resp: Set Challenge-Response mode
  -ochal-hmac: Generate HMAC-SHA1 challenge responses
  -ohmac-lt64: Calculate HMAC on less than 64 bytes input
  -ochal-btn-trig: Require touching YubiKey before issue response

You can test if setting up the slot worked by typing ykchalresp -2 foo. Your YubiKey should start flashing it's LED. Touch it—you should see some output.

We will now create an encryption passphrase using a password you will need to remember. Your password will be the basis of the challenge. The final passphrase will be composed of the challenge and your YubiKey's response to it.

# think of a good password and enter it
# read -s will allow you to enter it silently and without showing up in your bash history
read -s PASSWORD

# use the SHA256 sum of your password as the challenge
CHALLENGE=$(printf "$PASSWORD" | sha256sum | awk '{print $1}')

# get the response from the YubiKey; touch the key once it flashes
RESPONSE=$(ykchalresp -2 $CHALLENGE)

# concatenate challenge and response to obtain the key
KEY=$CHALLENGE$RESPONSE

Now have a look at your key: echo $KEY. It is rather hard to brute-force.

Step 2: Encrypting the Volume

In this step we use the $KEY created above in order to encrypt the device. For this, we will use dm-crypt with the LUKS extension. dm-crypt is the de-facto standard for block device encryption in Linux and ships with the kernel1. The LUKS ("Linux Unified Key Setup") extension provides an additional header of metadata to the encrypted data in order to offer more features. If you are interested in disk encryption technologies for Linux I recommend reading the ArchWiki's article on the topic.

Warning: The next step will irrecoverably erase all data on the device you specify. Please be sure about what you do.

Note that you will need the $KEY variable from the last section to be set. echo $KEY again to be sure. Also note that you will probably have to run all commands in this and the next section using sudo.

# replace `sdX` with the target device you want to format and encrypt
cryptsetup -v luksFormat /dev/sdX <<<$KEY

Step 3: Access

Your device now contains an encrypted LUKS partition. Let's decrypt and format it:

# your device will be mapped to /dev/mapper/data
cryptsetup open --type=luks /dev/sdX data <<<$KEY

# format, for example as exFAT
mkfs.exfat /dev/mapper/data

At this point, you should be able to mount the device using your file manager or simply using mount /dev/mapper/data <wherever you want>. Congratulations! You now own a fully encrypted device protected by two authentication factors.

Obviously, deriving $KEY from your password and the YubiKey's response each time you want to access your device is extremely cumbersome. Here is a simple script I made that will obtain the passphrase as above, decrypt your device, and mount it for you.

Step 4: Backup

As I've pointed out, with this setup both factors are mandatory in order to decrypt your device. If you lose either the password or the YubiKey, you will no longer be able to access your data. It is hence a good idea to have a backup plan. Two safety measures you might consider are

  • print out $KEY and keep it in a save place (if you know the passphrase, you can always just type it)
  • use a second YubiKey for the same procedure

If you decide to add a second YubiKey you can have a look at this script. It follows almost the same procedure we just used to add the first YubiKey, except that it will add the key to an already encrypted device. The script will require minor adjustments to suit your individual needs, as documented in the comments.

More About the YubiKey

I hope you enjoyed making your data safer! If you did, know that I have more posts about what you can do with the YubiKey. Check out all posts tagged 'YubiKey' :)