Welcome

Welcome to my external memory and information on what I'm currently working on. Here you will find snippets of code, tricks and solutions I, or maybe you, may need to reference.

Feel free to comment your suggestions and any constructive criticisms that you may have.
Showing posts with label encryption. Show all posts
Showing posts with label encryption. Show all posts

Thursday, 23 October 2014

Debian Root Partition Encryption Using LUKS, dm-crypt and a Keyfile

The Problem

Debian has offered the option of encrypting your hard drive during installation for some time, however, it only allows you to unlock the drive using a password which is good but not perfect. Unfortunately the installer also doesn't allow you to install to an pre-encrypted hard drive removing the option of setting up an encrypted partition that is unlocked using a keyfile before hand and installing into it.

The Solution

Since the Debian installer does not work with pre-encrypted drives we have to first install Debian on the drive before it's encrypted with /boot being on its own partition; I will explain why in the following paragraph. We'll then backup the installed root partition to another drive, encrypt the partition and restore the contents of the partition. Then we'll need to manually decrypt the drive, chroot it, set up our boot process using initramfs to ensure the dm-crypt module is loaded and configure the system to decrypt the root partition during boot.
There is one thing to bare in mind when dealing with an encrypted root partition. In order to decrypt the root partition the boot partition must be unencrypted otherwise you'll be caught in a catch 22: You'll need to decrypt your boot partition in order to access the logic you need to decrypt your boot partition. So when setting up the base system be sure to create a /boot partition as well.

Things You'll Need

  • Debian (A recent enough version which includes the dm-crypt module and the creyptsetyp package. I have read conflicting reports of this being availible on Debian 6 (Squeeze) but it will be availible on Debian 7 (Wheezy) and later as this is the version I used to set this up for myself.)
  • A live CD/DVD/USB. I suggest a recent version of Ubuntu for its hardware compatibility and ease of use, however, as long as it has cryptsetup and the dm-crypt module any should work.
  • A second hard drive to backup to and restore the root partition from.
  • External storage (be it a USB key, SD Card, etc...) that will be used as the key to unlock the system.

Install the Base System

Installing the base system is outside the scope of the article except for the fact that you must put /boot on its own partition. You will be fine with a /boot partition size of ~100MB-200MB however if you want to be safe and have the extra space it doesn't hurt to make it 512MB.

Backing up the Root Partition

We'll use rsync to backup the root partition to another location so it can be restored to the encrypted partition later.
rsync -aAXv --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/lost+found", "/boot/*"} /* /path/to/backup/folder

Command Breakdown

Note you should take a look at the rsync man page for a complete breakdown of this command as I will only be giving a high level overview of it.
  • -a Archive mode. This is a short cut for the options -rlptgoD and in essence recurse through all sub directories and preserves things like ownership, permissions and symlinks making it useful for backups.
  • -A Preserves ACLs (Access Control Lists).
  • -X Preserves extended attributes.
  • -v Verbose output.
  • --exclude={ ... } Folders to exclude during the backup.
  • /* Files we want backed up
  • /path/to/backup/folder Where we want to backup the root partition to. This MUST be on a different device.

Boot to Live CD/DVD/USB

Make sure your BIOS is set to boot from the specific device, insert it and go! Note that if you use UEFI it can cause issues booting to a Live CD/DVD as it may trump any settings in your BIOS if your BIOS is configured to use it.

Randomize Disk

This step is important since it can become apparent where you encrypted files are on your drive if you have any uniform data on it. A potential attack can then look through your drive bit by bit and pick out where the contents of files begin and end. Then knowing that they can attempt to brute force the encryption knowing that the chunk of data they have is probably contiguous data. In essence this step adds background noise to your drive so it's not apparent where your files are located on the partition. There are two ways to do this, one more thorough then the other.

Using badblocks

This method works well and is considerably faster then the second method (using dd and urandom), however, it doesn't randomize every bit which leaves the potential for this vulnerability to still be exploited
sudo badblocks -c 10240 -s -w -t random -v /dev/sdb
*Where /dev/sdb is the block device you wish to encrypt

Command Breakdown

  • -c 10240 specifiers that you want badblocks to you want to have badblocks test 10240 blocks at a time. This amount is quite excessive as the default is 64 but should make the command run faster as it should better fill the write buffer of the drive.
  • -s Shows the progress of the process.
  • -w This option tells badblocks to write test patterns to each block and read them back to verify the block's integrity.
  • -t random Tell badblocks to write random test patterns.
  • -v Verbose mode
  • /dev/sdb The block device to test

Using dd and /dev/urandom

This is the more complete way to randomize the disk as every bit gets semi-random data written to it but can take upwards of a two or three days for large devices (1GB+). Note we are using /dev/urandom and and not /dev/random as our input source as /dev/random is very slow at picking up random bits and would take an incredibly long time to fill a drive.
dd if=/dev/urandom of=/dev/sdb iflag=nocache oflag=direct bs=4096

Command Breakdown

  • if=/dev/urandom The input file to pull data from.
  • of=/dev/sdb The out file to push the data coming from the input file to.
  • iflag=nocache Don't cache data coming from the input file
  • oflag=direct Write directly to the output file
  • bs=4096 The block size, in bytes, to write out.

Prepare Keyfile

dd if=/dev/urandom of=/media/myusbkey/keyfile.enc bs=512 count=1 iflag=fullblock

Command Breakdown

  • if=/dev/urandom The input file to pull data from.
  • of=/media/myusbkey/keyfile.enc The out file to push the data coming from the input file to. This will be the key file that will have to be present in order for your system to boot.
  • bs=512 The block size, in bytes, to write out. This size of 512 is an arbitrary choice of mine and matches the maximum passphrase size for dm-crypt which is 512 characters. However, a keyfile can be up to 8192kB in size and one can make the assumption that the larger the keyfile the harder to gain access to the drive it'll be. However, it's important to note that with LUKS the passphrase/keyfile are just used to unlock the master encryption key which is used to decrypt the drive so in this case having a larger keyfile does not necessarily make it harder to gain access to the drive's contents.

Empty the LUKS Header

Full disclosure: I'm not sure this step is necessary as I have not tested the process without it. If I were to make an assumption this is probably done during the encryption process and shouldn't be required to be done manually.
If you haven't already make sure you've created your partitions you're going to use on the drive. From here on out we'll be working on encrypting the partition it self
Note: In the case of a LUKS partitions the header is the first 592 bytes of the partition, however, due to possible issues with partition alignment the encrypted data area of a LUKS partition doesn't start until after the second megabyte of the drive and header backup processes backup the first 2MB of the drive and as such we will be zeroing out the first 2048 bytes of the partition.

Using Head and Redirection

head -c 2048 /dev/zero > /dev/sda2; sync

Command Breakdown

  • head: this command prints the specified number of bytes to standard out.
  • -c 2048 This is the number of bytes to print out.
  • /dev/zero The file to print out
  • &gt Redirect standard output to another standard in.
  • /dev/sda2 This is the file we want to direct the output to. This is the block device that represents the partition we are going to encrypt.
  • ; Separates multiple commands and tells bash to wait until the preceding command returns before executing the next.
  • sync Force the write buffer to flush which makes sure the data has been written to the physical disk.

Using dd

dd if=/dev/zero of=/dev/sda2 bs=512 count=4
  • if=/dev/zero The input file is going to be /dev/zero
  • of=/dev/sda2 The output file is going to be /dev/sda2. This will be the partition we're encrypting.
  • bs=512 This is the block size we're writing out.
  • count=4 This is the number for blocks we're writing. In total we're writing 4 * 512 bytes (2MB)

Formatting and Encrypting the Partition

cryptsetup luksFormat --verbose -c aes-xts-plain64 -s 512 /dev/sda2 /media/myusbkey/keyfile.enc

Command Breakdown

  • cryptsetup This is a convenience tool which makes encrypting and working with encrypted drives much easier.
  • luckFormat This is the type of format we're using for our encrypted partition.
  • --verbose Make the output verbose so we can see everything that's going on.
  • -c aes-xts-plain64 This sets what cypher to use when encrypting the partition. Note that the default cypher prior to version 1.6.0 is "aes-cbc-essiv" and is considered vulnerable to practical attacks and as such has been changed. To be safe we explicitly set to a secure cypher (Source: Arch Linux: Device Encryption).
  • -s 512 The key size that is used to encrypt the drive in bits. This number has to be a multiple of 8 and defaults to 256 if not specified.
  • /dev/sda2 The device to format
  • /media/myusbkey/keyfile.enc The keyfile we wish to use to unlock the device.

Mapping the Encrypted Partition

In order to mount the partition we have to use cryptsetup to open the drive and create a mapped device which we can treat as a regular block device to mount.
cryptsetup luksOpen --key-file /media/myusbkey/keyfile.enc /dev/sda2 cryptroot

Command Breakdown

  • luksOpen This option tells cryptsetup that we're opening an encrypted volume.
  • --key-file /media/myusbkey/keyfile.enc Tells cryptsetup where to find the keyfile.
  • /dev/sda2 The encrypted block device to decrypt.
  • cryptroot The name of the mapped device.

Formatting the Encrypted Partition

mkfs -t ext4 /dev/mapper/cryptroot

Command Breakdown

  • -t ext4 Specifies a file system type to format to. The default is ext2
  • /dev/mapper/cryptroot The device to format. You'll notice we're accessing the device via its mapped name under /dev/mapper/cryptroot instead of /deb/sda2

Mounting the Encrypted Partition/Filesystem

Create a folder that we will mount the filesystem on top of.
mkdir /media/encrypteddrive
Mount the filesystem via it's mapped name
mount -t ext4 /dev/mapper/cryptroot /media/encrypteddrive

Command Breakdown

  • -t ext4 The file system type of the device we're mounting.
  • /dev/mapper/cryptroot Again we're interfacing with the device via it's mapped name.
  • /media/encrypteddrive Where to mount it.

Get UUID of your USB Key

We will need this when setting up decryption at boot as we'll need to specify the location of the keyfile. The most consistent way to do it is by UUID. It also has the added benefit of requiring a specific device to have the keyfile.
blkid
The above command will usually take a few seconds to run and will return the UUID of all of the storage devices connected to the machine. If you're unsure as to which is your USB Key then run the command once without the key being plugged into the machine then again after plugging it in and finding the new device. If your USB key's partition has a label then it should be displayed next to the UUID after running the command making it easy to pick out the USB key.
Record the UUID of your USB Key somewhre; we will use it in a few steps.

Restoring the Root Partition

rsync -aAXv /path/to/backup/folder /media/encrypteddrive

Command Breakdown

Note you should take a look at the rsync man page for a complete breakdown of this command as I will only be giving a high level overview of it.
  • -a Archive mode: This is a short cut for the options -rlptgoD and in essence recurses through all sub directories and perservers things like ownership, permissions and symlinks making it useful for backups.
  • -A Preserves ACLs (Access Control Lists).
  • -X Preserves extended attributes.
  • -v Verbose output.
  • /path/to/backup/folder Where we have backed up the to.
  • /media/encrypteddrive Where we have the partition mounted.

chroot to Encrypted Root

This is a little tricky since we need to mount the current system's transient/device folders and our original boot partition to the encrypted system's root.
Navigate to the root of the encrypted drive.
cd /media/encrypteddrive
Mount the system's transient/device folders (replacing sda1 with the location of your boot partition that was created in the initial system setup):
mount -t ext4 /dev/sda1 boot/
mount -t proc proc proc/
mount -t sysfs sys sys/
mount -o bind /dev dev/
Change Root
chroot .

Add an Entry to the crypttab

Here you will define the encrypted device and how to access it. Add the following to the file:
cryptroot /dev/sda2 /dev/disk/by-uuid/AC257504DA15b214:/keyfile.enc cipher=aes-xts-plain64,size=512,hash=ripemd160,keyscript=/lib/cryptsetup/scripts/passdev
Where AC257504DA15b214 is the UUID of your USB Key. The rest of the parameters match those we used when using cryptsetup to create the LUKS partition with two exceptions: cryptroot and hash=ripemd160. cryptroot is the mapping name we will use when refering to the drive in our fstab, hash=ripemd160 is the default hash used when using cryptsetup but it has to be specified here explicitly.

Update fstab

We have to update fstab to point to the new mapped root. Update /etc/fstab with the following in place of its root entry:
/dev/mapper/cryptroot / ext4 defaults 0 1

Update initramfs

Run the folloing command
update-initramfs -u
This is a tool that will re-tool your boot process given your current configuration including setting up the auto discovery of your encryption key and decrypting your root partition

Reboot

If all went well you should now be able to reboot (with your Live CD/DVD/USB removed) and the system will boot into Debian as long as the specific USB key with the keyfile on it is plugged into the machine.

Sources

Saturday, 1 February 2014

Setting up OpenVPN on a Virtual Private Server (VPS)

Overview

I recently set up my own VPS. I had installed OpenVPN on my own virtual machines and systems before but setting it up on a VPS created a few unexpected problems. Below is the process that I used to get things up and working.

Assumptions and Out of Scope Items

  • You have OpenVPN already installed at /etc/openvpn
  • You have Easy-RSA 2.0 located at /etc/openvpn/easy-rsa/
  • You have root access (I'm going to assume you're either logged in as root or running under su)
  • Your VPS has provisioned you a Static IP address.
  • OpenVPN Client instillation and configuration.

Special VPS Considerations

Note: A VPS typically operates with a shared kernel between all of it's Guests. Since a VPS operates on the hardware level (unlike a regular virtual machine which is typically hosted by a piece of software like Virtual Box or VMWare) the hardware/kernel level is shared among all systems. You can read more on this on Wikipedia: Virtual Machine.

Because of this we run into two main issues:
  1. OpenVPN requires the Tun kernel module which isn't usually present by default. And since you don't have access to the kernel you can't load it. To get around this you can usually ask your provider to enable it on your VPS or it is an option on your provider's VPS management page.
  2. In order to tunnel traffic you need to set up routing rules with iptables which, in my experience, is typically done using the MASQUERADE option which isn't supported by my VPS Host (OpenVZ). I would assume this is the case for most if not all VPS hosts.

The Process

Creating RSA Keys

If you can use encryption keys to access your VPN server why not? Unless you're making this service open to a large number of people the standard Username/Password approach just isn't as secure. And since, in this case, I can easily control and distribute my private key(s) I can't see a reason not to.
  1. Navigate to /etc/openvpn/easy-rsa/2.0/ and create a directory called keys
  2. Edit the /etc/openvpn/easy-rsa/2.0/vars file and set the following values. Note: These will be your default values when generating keys so you will get an opportunity to override them during the process.
    export KEY_COUNTRY="US"        # Your Country
    export KEY_PROVINCE="CA"       # Your State/Province/Territory 
    export KEY_CITY="SanFrancisco" # Your City
    export KEY_ORG="None"          # Your Organization Name
    export KEY_EMAIL="mail@domain" # Mail Address
    export KEY_EMAIL=mail@domain   # Mail Address
    Note: You can also add/alter the additional fields below, however, typically these values will not be the default when you generate your keys.
    export KEY_CN=OpenVPN.yourdomain.com # Common Name
    export KEY_NAME=yourname             # Your Name
    export KEY_OU=servername             # Organizational Unit
  3. Execute the following commands from the /etc/openvpn/easy-rsa/2.0/ directory. Note: You will be prompted for information when generating keys and this will create all your keys and certs in the /etc/openvpn/easy-rsa/2.0/keys folder:
    ./vars            # Sets up environment variables for key creation
    ./clean-all       # Cleans up any generated files in the folder
    ./build-ca        # Creates the certificate authority key
    ./build-key-server server # Creates the server key
    ./build-dh        # Creates the Diffie-Hellman key
    ./build-key clientname # Creates the client's private key
  4. Transfer, physically if possible encrypted if not, the  ca.crt, clientname.crt, clientname.key files to your client and place them in it's openvpn folder.

Creating a TLS-Auth key (ta.key)

  1. Navigate to /etc/openvpn/
  2. run the command:
    openvpn --genkey --secret ta.key
  3. Done.

Configuring the Server (server.conf)

To make this a little simpler I've included a sample server.conf file. I'd recommend backing up your current server.conf file as it has comments that will help you further configure your server to your needs.

Set up routing/forwarding

  1. We need to enable ip traffic forwarding:
    1. Enable forwarding by executing the following:
      echo 1 > /proc/sys/net/ipv4/ip_forward
    2. Make the change permanent by editing /etc/sysctl.conf and un-commenting the line:
       net.ipv4.ip_forward = 1
  2. Set up IPTables rules to forward the traffic coming in from the tunnel (tun0) to our ethernet adapter (venet0). This is done by setting up forwarding between the client and server's network adapters (tun0 and venet0) as well as traffic coming back to the client (venet0 to tun0). The final step maps the incomming local 10.8.0.0/24 address to the servers IP (This is the step that differs on a VPS).
    1. Enter the following into the command line:
      iptables -A FORWARD -i venet0 -o tun0 -m state --state ESTABLISHED,RELATED -j ACCEPT
      iptables -A FORWARD -s 10.8.0.0/24 -o venet0 -j ACCEPT
    2. The following is the standard way of setting up the ip mapping which uses MASQUERADE but will not work on a VPS
      iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o venet0 -j MASQUERADE
      Because MASQUERADE isn't implemented in the VPS's kernel we have to complete the mapping manually. Keep in mind that as long as you have a static IP this method will work.
      iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o venet0 -j SNAT --to-source <server ip>
  3. Make the changes to iptables persist between reboots. I found some tools to help out with this but I tend to prefer solutions that don't require additional packges. And this one is simple so why not!
    1. Store the current state of your iptables in a iptables rule file.
      iptables-save > /etc/iptables.openvpn.rules
    2. Add the following to to /etc/network/interfaces.
      #Define OpenVPN IP address forwarding
      post-up /sbin/iptables-restore < /etc/iptables.openvpn.rules
      

Sources