# Geli encrypted container with zfs, truecrypt replacement



## NapoleonWils0n (Apr 11, 2017)

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:


```
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


```
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


```
#!/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


```
#!/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
```


----------



## `Orum (Dec 18, 2019)

Is `dd`ing /dev/zero really necessary?  Can't you simply `truncate -s`?


----------



## SirDice (Dec 19, 2019)

NapoleonWils0n said:


> ```
> dd if=/dev/zero of=/usr/home/username/.ossuary/ossuary.key bs=256 count=1
> ```


I would replace that with

```
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.


----------



## ralphbsz (Dec 20, 2019)

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


----------



## NapoleonWils0n (Dec 20, 2019)

ralphbsz said:


> 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


----------



## NapoleonWils0n (Dec 20, 2019)

SirDice said:


> I would replace that with
> 
> ```
> dd if=/dev/random of=/usr/home/username/.ossuary/ossuary.key bs=256 count=1
> ...


Cheers Sir Dice

Ill amend the post


----------



## NapoleonWils0n (Dec 20, 2019)

Hi All

I fixed 2 errors in the post


```
# 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


----------

