Geli encrypted container with zfs, truecrypt replacement

FreeBSD Geli encrypted container

FreeBSD geli encrypted container with zfs, truecrypt replacement

Code on Github

Support for geli is available as a loadable kernel module. To configure the system to automatically load the module at boot time, add the following line to /boot/loader.conf:

Code:
geom_eli_load="YES"

Create container with dd

create a 2 gig container with dd on the Desktop called disk.img

  • change directory to the Desktop
cd ~/Desktop

  • switch to root
sudo su

  • use dd to create a 2 gig disk image
dd if=/dev/random of=disk.img bs=1M count=2048

Mount the image with mdconfig

use mdconfig to mount the disk image

mdconfig -a -t vnode -f disk.img -u 0

Here, the -a option forces the disk mounting, -t vnode is used for opening a regular file, and the path of this file is specified after -f. The -u 0 option set the virtual disk identifier to use, in this case /dev/md0.

Generate the masterkey

create the director to store the geli key

mkdir -p ~/.ossuary

Now we want to create a key for GELI to encrypt with, and attach it to our disk image device:

replace username with your username

Code:
dd if=/dev/random of=/usr/home/username/.ossuary/ossuary.key bs=256 count=1
geli init -e aes -l 256 -s 4096 -K /usr/home/username/.ossuary/ossuary.key /dev/md0
geli attach -k /usr/home/username/.ossuary/ossuary.key /dev/md0

Enter the passphrase

Create the ZFS file system

Next, format the device with the ZFS file system and mount it on an existing mount point:

  • use dd to write random data to geli container before adding file system
dd if=/dev/random of=/dev/md0.eli bs=1M

  • To create a simple, non-redundant pool using a single disk device:
zpool create crypt /dev/md0.eli

  • add compression and duplication to the zfs pool
zfs set compression=lz4 crypt

  • set the ZFS mount point
create the mount point in your home directory

mkdir -p ~/mnt

create the ZFS mount point

zfs set mountpoint=/usr/home/username/mnt crypt

  • change the permission on the container, replace username with your username
sudo chown -R username:username ~/mnt

Finally, when you want to unmount, we also want to detach from GELI and detach from md:

  • ZFS umount
zfs umount crypt

  • zpool export
zpool export crypt
  • Geli detach
geli detach md0.eli

  • mdconfig free loop device
mdconfig -d -u 0

Mounting and umounting

Mount
  • use mdconfig to mount the encrypted container to /dev/md0
mdconfig -a -t vnode -f disk.img -u 0
  • use geli with the path to the key and device
geli attach -k /usr/home/username/.ossuary/ossuary.key /dev/md0
  • we need to import the zpool which will also mount the container
zpool import crypt

Umount

  • umount the zfs pool
zfs umount crypt
  • export the ZFS pool before we use geli detach, otherwise geli thinks the device is busy
zpool export crypt

  • use geli to detach the encrypted device
geli detach md0.eli
  • free the loop device
mdconfig -d -u 0

Bash script to mount and umount the container

Change the container, gelikey and poolname variables to match your own set up

Code:
#!/usr/bin/env bash

# geli container mount and umount script
#=======================================

# check to see if script was run as root
if [[ $UID -ne 0 ]]; then
  echo "$0 must be run as root using sudo, make your own sandwich"
  exit 1
fi

# Create the prompt
PS3="Enter your choice: "
options=("mount" "umount" "quit")
OLD_IFS=${IFS}; #ifs space seperator
IFS=$'\t\n' #change ifs seperator from spaces to new line

# container variables
loop="/dev/md0"
loopcrypt="/dev/md0.eli"
container="/usr/home/username/documents/disk.img"
gelikey="/usr/home/username/.ossuary/ossuary.key"
poolname="crypt"

# select and case statement
select opt in "${options[@]}"; do
case $opt in
  mount)
        mdconfig -a -t vnode -f "$container" -u 0
        geli attach -k "$gelikey" "$loop"
        zpool import "$poolname"
        break;;
  umount)
        zfs umount "$poolname"
        zpool export "$poolname"
         sleep 1
        geli detach "$loopcrypt"
        mdconfig -d -u 0
    break;;
  quit)
    echo "Quitting"
    IFS=${OLD_IFS}
    break;;
  *)    echo "Usage: ossuary [ mount | umount | quit ]";;
esac
done

ossuary shell script version

Bash:
#!/bin/sh

# script usage
script_usage () {
echo "\
mount: $(basename "$0") mount -f container -k gelikey
umount: $(basename "$0") umount -f container"
}

# check to see if script was run as root
if [ "$(id -u)" != "0" ]; then
   echo "$0 must be run as root" && script_usage
   exit 1
fi

# mount function
mount () {
    # group commands
    {
    # container
    container="$1" && \
    # gelikey
    gelikey="$2" && \

    # mdconfig loopname from container
    loopdevice=$(mdconfig -lf "$container" | sed 's/[ \t]*$//')

    # eli filepath
    loopcrypt="/dev/${loopdevice}.eli"

    # mdconfig create vnode from container
    echo "+ mdconfig creating vnode for '$container'" && \
    loop=$(mdconfig -a -t vnode -f "$container") && \

    # geli attach key to vnode
    echo "+ geli attaching '$gelikey' key to '$container' file" && \
    geli attach -k "$gelikey" "$loop" && \

    # mdconfig loop device for container
    loopdevice=$(mdconfig -lf "$container" | sed 's/[ \t]*$//') && \

    # path to mdconfig eli file
    loopcrypt="/dev/${loopdevice}.eli" && \

    # zpool name from mdconfig eli file
    poolname=$(zdb -l "$loopcrypt" | awk -F\' '/[[:blank:]]name/ {print $2; exit;}') && \

    # zpool import pool
    echo "+ zpool importing '$poolname'" && \
    zpool import "$poolname" && \

    # mount point from zpool
    mountpoint=$(zfs get -H -o value mountpoint "$poolname") && \
    echo "+ '$poolname' mounted to '$mountpoint'";
    } || { mdconfig -du "$loopdevice" && exit; }
}

# umount function
umount () {
    # group commands
    {
    # container
    container="$1" && \

    # mdconfig loopname from container
    loopdevice=$(mdconfig -lf "$container" | sed 's/[ \t]*$//') && \

    # eli filepath
    loopcrypt="/dev/${loopdevice}.eli" && \

    # zpool name from eli file
    poolname=$(zdb -l "$loopcrypt" | awk -F\' '/[[:blank:]]name/ {print $2; exit;}') && \

    # zfs umount poolname
    echo "zfs unmounting $poolname" && \
    zfs umount "$poolname" && \

    # zpool export poolname
    echo "zpool exporting '$poolname'" && \
    zpool export "$poolname" && \
    sleep 1 && \

    # geli detach
    echo "geli detaching '$loopcrypt'" && \
    geli detach "$loopcrypt" && \

    # mdconfig remove md file
    echo "mdconfig clearing '$loopdevice'" && \
    mdconfig -du "$loopdevice" && \
    echo "unmounted device";
    } || { echo 'container not mounted' && exit; }
}

# check if mount is first argument
# + 2nd argument shuld be -f for the file to mount
# + 3rd argument should be the path to the file to mount
# + 4th argunent should be -k for key
# + 5th argument should be the path to the keyfile

# check if umount is first argument
# + 2nd argument shuld be -f for the file to unmount
# + 3rd argument should be the path to the file to unmount

# check arguments
if [ "$1" = mount ] && [ $# -eq 5 ]; then
   # group commands
   {
   [ "$2" = '-f' ] && \
   [ -f "$3" ] && \
   [ "$4" = '-k' ] && \
   [ -f "$5" ];
   } || { script_usage && exit; }
   # mount function pass conatainer and key to function
   mount "$3" "$5"
elif [ "$1" = umount ] && [ $# -eq 3 ]; then
   # group commands
   {
   [ "$2" = '-f' ] && \
   [ -f "$3" ];
   } || { script_usage && exit; }
   # umount function pass container to function
   umount "$3"
else
   script_usage
fi
 
Last edited:
Code:
dd if=/dev/zero of=/usr/home/username/.ossuary/ossuary.key bs=256 count=1
I would replace that with
Code:
dd if=/dev/random of=/usr/home/username/.ossuary/ossuary.key bs=256 count=1

Making a key with all zeros is just bad form. You might as well not use a key at all.
 
Can someone please fix the thread title? And then delete this message? "Geli" is an encryption thing. "Geil" means horny or lusty in German. And while encryption is a good thing, that word is not appropriate :)
 
Can someone please fix the thread title? And then delete this message? "Geli" is an encryption thing. "Geil" means horny or lusty in German. And while encryption is a good thing, that word is not appropriate :)
Hi Mate

I didnt even notice the miss spelling

You have to admit thats actually very funny
horny encrypted container

Germans arent known for their sense of humour in the UK apart from Henning Wehn

I have changed the title to spare your blushes
 
Hi All

I fixed 2 errors in the post

Bash:
# chown -R username:username ~/mnt

and not chmod
Also you need to do a zpool export crypt before you can use geli to detach the loopdevice

I rewrote the ossuary script as a shell script as well instead of bash and will add to the main post
Sir Dice i changed prinf to echo as well for good measure
 
Back
Top