Picryption: TrueCrypt for the Pi

Journey to the Clouds series.
3. Encrypting an external USB drive using TrueCrypt.

picryption
TrueCrypt allows full disk encryption and we are going to use it to encrypt the USB drive attached to the Raspberry Pi so you can happily carry it around when needed. This post will also present two solutions for auto-mounting TrueCrypt volumes. We will use the latest version available, for that we will have to compile it from source and since the target is a headless Raspberry Pi we will compile it without graphical support.

Journey to the Clouds index:

  1. Install Raspbian on a headless Raspberry Pi.
  2. Configuring Dynamic DNS using FreeDNS.
  3. Encrypting an external USB drive using TrueCrypt.
  4. Setting up Nginx web server.
  5. Setting up MySQL database.
  6. Setting up PHP.
  7. Installing ownCloud.

The first question that comes to mind is why TrueCrypt? Because it works in Linux, Windows and Mac, since we are dealing with an external drive it is quite likely that, at some point, you would like to use it in another computer, therefore it is best if no matter the operating system you can access to it. The next question is, why on earth will you compile it? If you find a pre-compiled binary officially supported let me know.

The last philosophical issue to point out is how secure you want it to be. TrueCrypt uses passwords and keyfiles, if you want to avoid user interaction and have the USB drive automatically mounted then the password will have to be stored locally in plain text. That is a big drawback but you will have to make your peace with it or mount the encrypted drive manually. Basically there are two scenarios where storing the password is a major disadvantage: someone steals your Raspberry Pi along with the drive plugged in or someone hacks into the root account of the Raspberry Pi and a later point steals the USB drive attached. The former scenario could be likely in a house break-in due to the small nature of the Pi, but the later usually involves pissing off your geeky revengeful friend (maybe you said that Firefly deserved to be canceled? My advice, do not upset geeks with a lot of free time in their hands).

1. Required packages.

In order to compile TrueCrypt and use exFAT or NTFS we need to install some packages:
$ sudo apt-get install nasm libwxgtk2.8-dev libfuse-dev libgtk2.0-dev ntfs-3g exfat-fuse exfat-utils byobu

What follows is an explanation of the packages.

  • nasm libwxgtk2.8-dev libfuse-dev libgtk2.0-dev: required to compile TrueCrypt, the last package libgtk2.0-dev will install a bunch of extra packages, do not be alarmed.
  • ntfs-3g: provides support for NTFS partitions.
  • exfat-fuse exfat-utils: provides support for exFAT partitions. I recommend exFAT over NTFS because, in my experience, the Linux NTFS driver is quite CPU hungry and the Raspberry Pi is not a abundant in that regard.
  • byobu: a terminal multiplexer (say what???), this package is not actually needed but it can become quite handy. Let me explain, the compilation of TrueCrypt may take a while (~40 min.) therefore it would be a good idea to use a tool which allows us to start processes in a SSH session, close the session, reconnect in a later time and reattach again to the process you left running. In case the SSH connection drops the compilation process would continue instead of stopping, note that you could accomplish a similar behavior using the standard nohup.

2. Download necessary files.

There are three sets of files to download: the TrueCrypt source code, the wxWidgets source code and the PKCS-11 headers. I tried to compile TrueCrypt using the wxWidgets provided by Raspbian but no luck, so better download source code as it mentions the TrueCrypt’s README file.

Since it is a good idea to create a directory and store everything at the same location, create it and change to it:
$ mkdir ~/truecrypt_files
$ cd ~/truecrypt_files

Download wxWidgets:
$ wget https://sourceforge.net/projects/wxwindows/files/2.8.12/wxWidgets-2.8.12.tar.gz
And extract it
$ tar zxvf wxWidgets-2.8.12.tar.gz

Download the PKCS-11 headers in a sub-directory:
$ mkdir -p ~/truecrypt_files/pkcs
$ wget -P ~/truecrypt_files/pkcs ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-11/v2-20/*.h

Finally obtain the TrueCrypt source code for Linux. There is no direct link because you have to accept the license. Go to TrueCrypt source code download page and select Mac OS X / Linux (.tar.gz), accept the license and download it. Place the file into the Raspberry Pi in the folder we created above, you can use scp for such a task. For instance, if you downloaded the file in your local computer in the user’s Downloads folder:
(your computer) $ scp Downloads/TrueCrypt\ 7.1a\ Source.tar.gz pi@IpAddressOfPi:~/truecrypt_files

Once the file is in the Raspberry Pi, extract it, remember to be in ~/truecrypt_files:
$ cd ~/truecrypt_files
$ tar xvzf TrueCrypt\ 7.1a\ Source.tar.gz

3. It’s compile time.

As mentioned above, I will use byobu, this is the crash course:

  • Execute byobu to start a new session.
  • Execute any command you like, it will run inside this session.
  • Press F6 to detach from the running session.
  • Execute byobu to reattach again to the running session.

Of course there is more to it but if you only have one byobu session that’s enough.

Just for fun, you can measure the time it takes to compile the packages by appending Bash 'time' command at the beginning of each instruction:
$ byobu
$ cd ~/truecrypt_files/truecrypt-7.1a-source
$ export PKCS11_INC="/home/pi/truecrypt_files/pkcs/"
$ export WX_ROOT=/home/pi/truecrypt_files/wxWidgets-2.8.12
$ time make NOGUI=1 WX_ROOT=/home/pi/truecrypt_files/wxWidgets-2.8.12 wxbuild
$ time make NOGUI=1 WXSTATIC=1

I hope everything went well and the compilation did succeed, you should have the TrueCrypt binary at ~/truecrypt_files/truecrypt-7.1a-source/Main/truecrypt; as a root copy it to /usr/bin and assign proper ownership and permissions:
$ sudo cp Main/truecrypt /usr/bin/
$ sudo chown root:root /usr/bin/truecrypt
$ sudo chmod 555 /usr/bin/truecrypt

From now one we are going to extensively make use of sudo because many commands require root privileges. As usual, when a command needs to be executed as root it will be denoted by starting the line with # instead of $. You can either become root permanently by executing 'sudo -i' or insert 'sudo' at the beginning of each command as we have been doing so far.

4. Let’s encrypt something.

Plug the USB drive and find out its device name (e.g. use lsblk), in my case is /dev/sda.
Create the TrueCrypt container (I will not use any keyfiles):
$ truecrypt --keyfiles="" --protect-hidden=no --filesystem=none --volume-type=normal --create /dev/sda1

You will be asked to select the encryption and hash algorithms to use and a passphrase.

Load the container, you will be prompted for the passphrase:
$ truecrypt --keyfiles="" --protect-hidden=no --filesystem=none --volume-type=normal /dev/sda1

Format it using exFAT:
# mkfs.exfat -n DATA /dev/mapper/truecrypt1

Or, if you prefer, format it using NTFS:
# mkfs.ntfs -L DATA --fast /dev/mapper/truecrypt1

Unmount it:
$ truecrypt --dismount

Our USB drive is encrypted and formatted, it is time to create a permanent mount point. I will use the directory /external and assign public access plus the sticky bit:
# mkdir /external
# chmod 777 /external
# chmod +t /external

I will assume the filesystem used is exFAT if you are using NTFS replace 'exfat' by 'ntfs-3g'. Mount the TrueCrypt volume:
$ truecrypt --verbose --keyfiles="" --protect-hidden=no --slot=1 --filesystem=exfat /dev/sda1 /external

Do not use a password in the command line because it will show when listing the processes (ps -ef). If you want to write the password in the command line use the here-documment approach, e.g.:

truecrypt --verbose --keyfiles="" --protect-hidden=no --slot=1  --filesystem=exfat /dev/sda1 /external <<EOF
HereWriteYourPassphrase
EOF

In that fashion the password will not show in the processes list still it will show in the command history. The best approach for not writing the password is to store it in a file owned by root and only accessible by him. At the beginning of this post I commented on the security risk of this approach however we cannot automate the process otherwise.
# echo 'HereWriteYourPassphrase' > /etc/volume.password
# chmod 600 /etc/volume.password
# truecrypt --verbose --keyfiles="" --protect-hidden=no --slot=1 --filesystem=exfat /dev/sda1 /external < /etc/volume.password

5. Don’t bother me: automating TrueCrypt mounting

The big issue: how do we auto-start the TrueCrypt mounting process? Currently cryptsetup is able to handle TrueCrypt containers however support started on version 1.6 and unfortunately the version available in Raspbian is 1.4.3 therefore we need an ad-hoc solution. I am very generous and instead of one I will give you two, both retrieving the passphrase from external files. The first solution is the simplest, it uses the the command of the above section in a script. The second solution is a bit more complex but it is extensible, it will use a LSB compliant init script, storing the truecrypt information in /etc/fstab.

5.1 Simplicity is beauty: simple auto-mount script.

In this approach we’ll use a simple script which will contain all the information except the volume’s passphrase which will be stored in /etc/volume.password. When the script is invoked without any arguments or with 'start' it will mount the TrueCrypt volume and it will unmount all TrueCrypt volumes when invoked with 'stop'. Error messages, if any, will be logged in /var/log/messages.

/etc/init.d/simplemounttruecrypt.sh

#!/bin/sh
#
# Usage: simplemounttruecrypt.sh [start|stop]
#   no argument | start: Mount a truecrypt volume
#   stop:  Unmount all truecrypt volumes
#
# On success do not print any message
# On failure:
#      1. Record the failure in the temporal file /tmp/truecrypt.error
#      2. Append the error message along with the timestamp to /var/log/messages
#      3. Delete the file temporal file /tmp/truecrypt.error
PROTECT_HIDDEN=no
KEYFILES=""
SLOT=1
#FILESYSTEM=ntfs-3g
FILESYSTEM=exfat
VOLUME_PATH=/dev/sda1
MOUNT_DIRECTORY=/external
PASSWORD_FILE=/etc/volume.password

EXITSTATUS=0
case "$1" in
  ''|start)
    truecrypt \
      --verbose \
      --keyfiles=$KEYFILES \
      --protect-hidden=$PROTECT_HIDDEN \
      --slot=$SLOT  \
      --filesystem=$FILESYSTEM $VOLUME_PATH $MOUNT_DIRECTORY \
      < $PASSWORD_FILE \
      >/tmp/truecrypt.error 2>&1 \
    || EXITSTATUS=1 
    action=mounting
    ;;
  stop)
    truecrypt --dismount >/tmp/truecrypt.error 2>&1 \
    || EXITSTATUS=1 
    action=unmounting
   ;;
  *)
    echo "Usage: $0 [start|stop]"
    exit 3
    ;;
esac

if [ $EXITSTATUS -ne 0 ]; then 
  echo "$(date +"%b %_d %T") $(hostname) $0: ERROR $action device: $(cat /tmp/truecrypt.error)" >> /var/log/messages
fi

rm -f /tmp/truecrypt.error 2>/dev/null
exit $EXITSTATUS

Assign proper permissions and add it to the run levels:
# chmod 755 /etc/init.d/simplemounttruecrypt.sh
# insserv simplemounttruecrypt.sh

When executing insserv you may see several warnings because this script, and possible others, are not LSB compliant.

In order to remove the scripts from the init system execute:
# insserv --remove simplemounttruecrypt.sh
The flag -f forces the services remove even if the files still exist in /etc/init.d

5.2 Automating better: data, logic & LSB.

The previous script is good enough to work with however the script itself contains the information of the TrueCrypt volume. It would be better to separate the data (the info about the TrueCrypt volume) from the logic (the process to mount it). By doing so we can easily extend it to be able to handle any number of TrueCrypt volumes without modifying the logic and only adding more entries to the data files. Since we are in the improving path, we will enhance the script’s output by using the following trick: if it is invoked from a terminal it will output to the screen however if it is invoked by the system then the output will be redirected to the system log /var/log/messages. Finally, let’s also make it LSB compliant.

These are the three files used in this approach:

  • /etc/init.d/mounttruecrypt.sh
    Script which mounts all truecrypt volumes defined in /etc/fstab using the passphrases stored in /etc/truecrypt.pass
    The script will also unmount all truecrypt volumes.

  • /etc/truecrypt.pass
    File, which should be accessible only by root (i.e. chmod 600), containing a passphrase per volume using the following syntax:
    device:Passprhase
    Example:
    /dev/sda1:This is a very good passphrase 49373!@#@!.;Mono

  • /etc/fstab
    As you know, this file defines the filesystems, we are going to append the TrueCrypt definitions using the following syntax:
    ##truecrypt:device mountPoint filesystemType filesystemMountOptions
    Example using exFAT without any extra options:
    ##truecrypt:/dev/sda1 /external exfat

Note that due to the use of fstab and truecrypt.pass we could add as many entries as we like without modifying the script. In fact, the script will walk through the '##truecrypt:' entries of fstab, retrieve the device name and fetch the passphrase for such a device from truecrypt.pass. You can read the logic below.

/etc/init.d/mounttruecrypt.sh

#!/bin/bash
### BEGIN INIT INFO
# Provides:          mounttruecrypt.sh 
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: mount/unmount truecrypt volumes from /etc/fstab
# Description:       on start  mounts the truecrypt 
#                        - volumes are specified in /etc/fstab 
#                        - passwords are defined in  /etc/truecrypt.pass
#                    on shutdown unmount all truecrypt volumes, not only the specified by fstab
#
#                    The entries of /etc/fstab must start by '##truecrypt:'
#                    Entries can be commented by introducing an extra #, i.e. ###truecrypt
#                    The rest of the line is the same as a fstab entry
#                    ##truecrypt:VOLUME_PATH  MOUNT_DIRECTORY   FILESYSTEM  options
#                    Example:
#                    ##truecrypt:/dev/sda1   /external   ntfs-3g options
#
#                    /etc/truecrypt.pass must contain a single line for entry with the format:
#                    volume_path:password
#                    Example
#                    /dev/sda1:MySuperPassphrase
#                    Make sure /etc/truecrypt.pass has permission 600
### END INIT INFO


#VARIABLES for the truecrypt volume
PROTECT_HIDDEN=no
KEYFILES=""
PASSWORD_FILE=/etc/truecrypt.pass

mount_all(){
    slot=0
    while read line; 
    do 
        read -a fields <<< $line
        VOLUME_PATH=${fields[0]}
        MOUNT_DIRECTORY=${fields[1]}
        FILESYSTEM=${fields[2]}
        OPTIONS=${fields[3]}
        slot=$((slot+1))

        truecrypt \
          --text \
          --verbose \
          --keyfiles=$KEYFILES \
          --protect-hidden=$PROTECT_HIDDEN \
          --slot=${slot} \
          --fs-options=$OPTIONS \
          --filesystem=$FILESYSTEM $VOLUME_PATH $MOUNT_DIRECTORY \
          < <(grep $VOLUME_PATH $PASSWORD_FILE | sed "s,^${VOLUME_PATH}:,,")  \
          | grep -v "Enter password for"

    done < <(grep '^##truecrypt' /etc/fstab | sed 's/##truecrypt://g')

}
# Function to redirect the output to syslog 
log_to_syslog(){
    # Temporal file for a named pipe
    script_name=$(basename "$0")
    named_pipe=$(mktemp -u --suffix=${script_name}.$$)
    
    # On exit clean up
    trap "rm -f ${named_pipe}" EXIT

    # create the named pipe
    mknod ${named_pipe} p

    # start syslog and redirect the named pipe
    # append the script name before the messages
    logger <${named_pipe} -t $0 &

    # Redirect stout and stderr to the named pipe
    exec 1>${named_pipe} 2>&1
}

# If the script does not run on a terminal then use syslog
set_log_output(){
    if [ ! -t 1 ]; then
        log_to_syslog    
    fi
}

case "$1" in 
    ''|start)
        EXITSTATUS=0
        set_log_output
        mount_all || EXITSTATUS=1
        exit $EXITSTATUS
        ;;
    stop)
        EXITSTATUS=0
        set_log_output
        truecrypt --verbose --dismount || EXITSTATUS=1
        exit $EXITSTATUS
        ;;
    restart|force-reload)
        EXITSTATUS=0
        $0 stop || EXITSTATUS=1
        $0 start || EXITSTATUS=1
        exit $EXITSTATUS
        ;;
    status)
        EXITSTATUS=0
        truecrypt --list 2>/dev/null || echo "No truecrypt volumes mounted"
        exit $EXITSTATUS
        ;;
    *)
        echo "Usage: $0 [start|stop|restart]"
        exit 3
        ;;
esac

Assign the appropriate permissions and add the service:
# chmod 755 /etc/init.d/mounttruecrypt.sh
# insserv /etc/init.d/mounttruecrypt.sh

In order to remove the service:
# insserv --remove /etc/init.d/mounttruecrypt.sh

By the way, if you have tried the simplemounttruecrypt.sh script and you want to use/try this new one remember to remove the previous:
# insserv --remove simplemounttruecrypt.sh

The End.

In the next chapter we will set up the Nginx web server.

Advertisements
This entry was posted in Journey to the Clouds, Linux, Raspberry Pi, Raspbian, security and tagged , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s