Whonix container encryption options

I have read some of the reasons why Whonix can not provide and encrypted file system to the end user; mainly since if the encrypted drive is prepared during the build process the master keys would all be known.

I have another project I am working on that also need to have the option for a user to be able to choose if they want the virtual machine image created or not and have come up with a solution as listed below.

The procedure for creating the encrypted partitions would be a bit different for Whonix since the partition layout is different (Whonix only currently uses one partition and has swap within a file). I listed a few alternative options at the bottom to be able to accomplish this with Whonix.

As I have only started working with Whonix source code yesterday, I do not yet know were I would place custom code I want run on initial boot and where the hooks are so my scripts will be included in image (without writing over the master code).

The following examples code are not complete; more of a general pseudo code overview.

On initial boot… if user chooses to encrypt:

# Partition layout
# /dev/sda1 - 2GB swap partition
# /dev/sda5 - 98G root partition

# Initial boot from /dev/sda5
# Ask user if they want to encrypt -> YES (we are here now)

# Change grub to boot from /dev/sda1 root partition (UN-initialized swap drive)
reboot

# Encrypt disk
cryptsetup --cipher "aes-xts-plain64" --key-size 256 --verify-passphrase luksFormat /dev/sda5

# Update /etc/crypttab
touch /etc/crypttab
echo 'sda5_crypt /dev/sda5 /etc/keys/default_key luks' >> /etc/crypttab

# Mount encrypted volume
cryptdisks_start sda5_crypt

# Create file-system on new encrypted volume and mount it
mkfs.btrfs -L WhonixGateway -l 32k -n 32k /dev/mapper/sda5_crypt
echo '/dev/mapper/sda5_crypt /data btrfs rw,noatime,nodiratime,compress=lzo,space_cache,autodefrag 0 2' >> fstab
mount /dev/mapper/sda5_crypt /mnt

# Copy over root partition data using rsync (I have a better rsync script that exclude /dev, etc)
rsync --progress -av / /mnt 

# Change grub to boot from /dev/sda5
reboot

# Create and initialize an encrypted /dev/sda1 swap partition

# Continue initial Whonix boot sequence

If user chooses not to encrypt:

# Create and initialize a regular swap partition in /dev/sda1

# Continue initial Whonix boot sequence

Since Whonix does not use a partition for swap and instead uses a swap file we would need to add a few steps to above. I do personally prefer having swap on its own partition since it does not play well with COW file-systems such as BTRFS.

Additional steps (option 1):

 - /dev/sda1 would need to be unmounted for the re-size, so we need to have custom initramFS image to do this.  If we used btrfs then we would not need to un-mount and would not need a custom initramFS image; just a few reboots should work
 - fsck -f /dev/sda1 
 - resize2fs /dev/sda1 size
 - delete partition 1
 - recreate partition 1 with new file size
 - create new temp partition /sda2
 - format temp partition
 - rsync files from /dev/sda1 to /dev/sda2
 - set grub entry to boot from /dev/sda2 
 - reboot
 - follow initial steps only we are now working from sda2 -> sda1, not sda1 -> sda5
...
 - once crypt partition is created we need to boot back to initramFS again
 - delete /dev/sda2 partition
 - delete /dev/sda1 partition
 - create /dev/sda1 partition with new size
 - re size file system
 - change grub to boot from new encrypted drive and remove initramFS image we been using

Additional steps (option 2):

 - have user create a second VM container and make sure its available when booting
 - same steps as original, but we will just create encrypted container on /dev/sdb1 and copy files over there.  Then that will be the container to use (remove original from VM)

Additional steps (option 3):

# Either have Whonix create a smaller /dev/sda1 partition than /dev/sda total size (leave 2G at end)
# or
# create a 2G (or whatever size needed) and a mirror of /dev/sda1 minis swap file

# If mirror copy was not created during build; then create /dev/sda2 + file system + rsync root partition  data to it
# If user encryts, boot from /dev/sda2 then follow initial instructions.

...

# If user does not want to encrypt, or when encryption is complete
delete /dev/sda2
re-size /dev/sda1 to fit /dev/sda
re-size /dev/sda1 file-system
continue Whonix initial boot sequence

Very interesting!

I am happy to tell as much as I know about where this code could be injected. Hopefully this is as simple as possible. I always had such scenarios in mind. Whonix’s source code is step based (modular), hopefully steps can be injected there.

The base Debian raw image is created in this step:
https://github.com/Whonix/Whonix/blob/master/build-steps.d/1300_create-debian-img

The grml-debootstrap tool (available from Debian package sources) does all the hard work. Whonix is a user of grml-debootstrap. Whonix currently uses a fork of grml-debootstrap that can be found in Whonix’s root source folder. (Not many modifications and no longer neccessary when upstream creates a new release since Whonix’s improvements are merged upstream in grml-debootstrap.)

Custom partition layout:
grml-debootstrap sets up the partition layout. So if you learn how to solve this question with grml-debootstrap, you learned 99,99% of what’s required to do the same with Whonix.

Initial boot from:
mostly grml-debootstrap sets that up (installing grub in a VM image is difficult, but they solved that).
(Mostly: Whonix installs a kernel in a chroot-post.d script [https://github.com/Whonix/Whonix/blob/master/whonix_shared/usr/share/whonix/chroot-scripts-post.d/71_install_686_pae_kernel]. Then grub has to be fixed again by applying a fix that has been attributed to grml-debootstrap [https://github.com/Whonix/Whonix/blob/master/whonix_shared/usr/share/whonix/chroot-scripts-post.d/90_fix_grub].

Change grub to boot from /dev/sda1 root partition:
grml-debootstrap

Encrypt disk:
Update /etc/crypttab:
Mount encrypted volume:
Create file-system on new encrypted volume and mount it:
Change grub to boot from /dev/sda5:
Create and initialize an encrypted /dev/sda1 swap partition:

  • have user create a second VM container and make sure its available when booting:
    Either have Whonix create a smaller /dev/sda1 partition than /dev/sda total size (leave 2G at end):
    or create a 2G (or whatever size needed) and a mirror of /dev/sda1 minis swap file:
    Probably best done in grml-debootstrap?

Copy over root partition data using rsync (I have a better rsync script that exclude /dev, etc):
Not necessary if this gets included in the build process. Setting up full disk encrypted for self-build images works. Just redistributing them won’t work. So your use case is possible.

In the later build process, image gets mounted and unmounted several times. Opening encrypted images could be added as an option here:
https://github.com/Whonix/Whonix/blob/master/help-steps/mount-img
https://github.com/Whonix/Whonix/blob/master/help-steps/unmount-img

I am happy to write the option code, but you must come up with the code to mount encrypted images.

I guess the grml-debootstrap developers would be happy to review a patch that adds an encryption option to grml-debootstrap. They are friendly people, they merged my tiny patches.

All in all, I think the cleaner and more robust solution is to do this during the build process. But then this would only be a useful feature for those who create their own images.

If you prefer to automate this from within an imported VM (which could be downloaded as well), I can think about applicable hooks as well. To prevent confusion I stop for now and wait for your reply.

Currently, I prefer to automate this from within an imported VM as for my use case in my other project I need to be able to have users choose if they want to encrypt the VM image they are using (or not). I will not be expecting them to have to build a VM image.

I think the approach I will initially take is create a script within an already initialized and running Whonix image ( version 8 ) and convert it to an encrypted system (will shift current data 4MB to allow space for luks headers; then encrypt in-place; no rsync; no extra partitions)

If this works well we can then add the script to packages that get installed when building Whonix and provide an option on initial boot to the user if they would like to encrypt the device.

Using this approach will also allow existing users to switch over an existing older version of Whonix by just installing and running the new package.

Most of the code required to accomplish the above can then be incorporated into the build process itself for people that would like to build their own version. I agree that would be cleaner for those wishing to create their own image.

I will also modify grml-debootstrap so it can create an encrypted volume since I envision the default (or alternate) Whonix VM image being shipped with an already encrypted image with default password. What? … It will be quicker much safer to re-encrypt the partition in-place than having to worry about making room for luks. Once the drive is re-encrypted all the master keys, etc are replaced so it will be as secure as it should be. For those wishing not to re-encrypt, then they all share the same master-key.

Just to clarify, this is the task list:
1. [me]  Create script/package to encrypt an existing and running version of Whonix
2. [me]  Lots of testing to make sure #1 works safe
3. [you] Once #2 is complete we will know what hooks we will need; have hooks created
4. [me]  Modify grml-debootstrap to allow it to encrypt volume; Whonix code will live here
5. [???] Whoinx build option for encrypted partition
6. [???] Whonix build option for btrfs file system :)  
7. [me]  Test encrypted partition builds correctly.  
8. [me]  Test that it can also be re-encrypted in place

I think that’s it for now; I better get started on it!

There are two easier solutions, if you are using Linux. Either to use gpg symmetric encryption on top of a compressed archive, or configure qcow2 to do it on the fly.Using LUKS in a vm only introduces alot of unnecessary overhead with no benefits. If the machine running the image is captured while its on then consider the master key compromised. I assume that you want to protect the data while its at rest only, because that is most logical. The ways i have suggested do that for you.

Easier? Ha, I like doing things the hard way :slight_smile:

I did not know about the qcow2 encryption option; I just moved to KVM within the week and am still learning about it. So far I liking it; so thanks for that suggestion.

I think the qcow2 option seems really nice. It would be something I would consider if Virtualbox also supported the format since my use case is not for myself. Personally I may try it since it looks easy enough to implement.

I am almost finished my first test case of encrypting an existing Whonix Gateway. I ran into two small problems. One that there was no actual separate boot partition, so I have to shrink the main partition and create one, and two, that I needed to backport cryptsetup since I need a version > 1.5 to be able to use the cryptsetup-reencrypt binary.

Other than that I don’t think it will take more than a few minutes to create and encrypt the data in place since I don’t need to move the data around.

This won’t be a problem if Whonix provides a VM image with an existing boot partition since it will be needed and pre-encrypts the drive with a master password. Then all a user will need to do is choose an encrypt volume options from grub menu at any time, or just be given the option on initial boot.

Then it will be as simple as running a cryptsetup-reencrypt script that will change the master volume key, and reencrypt all the data in-place. Other things can also be done like changing key size, cipher, cipher mode, or luks header hash algorithm, but I will not dive into that at this moment.

So I tried the encrypted qcow, but the key has to be in the configuration file which defeats its purpose IMO (well, using it with virt-manager). I like the idea of when the VM is shutdown, the data is locked. In my case I only care if someone steals my stuff, so it will be off if I’m not here.

So, anyway, here is a script I created to create an encrypted Whonix container. I’m sure it still needs some work if people want to use it to make it easier to select configuration options, or it can be adapted to work within the build stage. I don’t see a problem with all Whonix VM’s all being shipped with the same master key since we can run cryptsetup-reencrypt on initial setup to re-encrypt the container with new keys (would need to be back ported to wheezy).

I have tested this script with the latest 8.6.6.0 KVM workstation image. You need to create a new volume of whatever size you want, and add it as a virtio drive. The script expects it to be /dev/vdb, so the script will need to be modified if that is not the case. It also uses a btrfs partition instead of ext4 since that’s what I primarily use (can be modified easily for whatever partition type). A /boot, encrypted swap, and encrypted root partition are created; root fills the drive. The existing Whonix swap loop is still there.

Create a snapshot before you run this AND BE SURE TO SELECT CORRECT DEVICE (/dev/vdb) or it will over-write whatever is in that location.

I’m a python coder by trade, so my bash skills are lacking, but it seems to do the job.

#!/bin/bash
#

# TODO
# ----
#
# - replace fstab entries in /mnt/etc with new ones
# - remove debug code
# - move any user configurable options to top; or allow options to 
#   be passed from command line
# - detect if new drive has something on it already and get a user confirmation
#   after printing partition table (YES I want to destory it!)
#

#############################################################################
#DEBUG ONLY 
echo "DEBUGGING STEPS..."

echo "umount proc, sys, dev, dev/pts in /mnt/"
umount /mnt/boot
umount /mnt
cryptsetup luksClose /dev/mapper/root_crypt
cryptsetup luksClose /dev/mapper/swap_crypt
#############################################################################

PATH=/bin:/usr/bin:/sbin:/usr/sbin

# Other Interesting Finds
# =======================
#
# Create, mount and modify image from command line:
# ------------------------------------------------
# root#qemu-img create -f raw test.img 1000M
# root#losetup /dev/loop1 test.img
# root#kpartx -a /dev/loop1
# root# parted --align optimal --script  /dev/loop1 --  mklabel msdos
# root# parted /dev/loop1

# Create Partitions
# =================

# Device to destroy and create partitions
#
# ###### WARNING ###### WARNING ###### WARNING ###### WARNING ###### WARNING ###### WARNING ###### WARNING ###### WARNING ###### WARNING
#
#    BE SURE TO PICK THE CORRECT DEVICE SINCE IT WILL OVER WRITE AND DESTORY ANY EXISTING DATA ON DISK
#    BE SURE TO PICK THE CORRECT DEVICE SINCE IT WILL OVER WRITE AND DESTORY ANY EXISTING DATA ON DISK
#
# ###### WARNING ###### WARNING ###### WARNING ###### WARNING ###### WARNING ###### WARNING ###### WARNING ###### WARNING ###### WARNING
DEVICE=/dev/vdb
DESTROY_PARTITIONS=true
FORMAT_PARTITIONS=true
RSYNC=true
RSYNC_DRY_RUN=false
PASSPHRASE="password"

#ROOT_FORMAT="mkfs.btrfs -L root -l 32k -n 32k"
#ROOT_MOUNT="mount -t btrfs -o rw,noatime,compress=lzo,space_cache,autodefrag,inode_cache"
#ROOT_FSTAB="btrfs rw,noatime,compress=lzo,space_cache,autodefrag,inode_cache 0 1"
ROOT_FORMAT="/sbin/mkfs.btrfs -L root"
ROOT_MOUNT="mount -t btrfs -o rw,noatime,compress=lzo"
ROOT_FSTAB="btrfs rw,noatime,compress=lzo 0 1"

# LOCALMODE (true) will not create or mount any partitions or file systems and will just test with /mnt
# directory.  This is mostly just useful to make sure rsync is working and the chroot routines are
# copying of the correct data.
LOCALMODE_ONLY=false

# You will probably need to explicitly set the grub-install target to i386-pc using --target=i386-pc. Otherwise grub-install sometimes guesses that your configuration is EFI-GPT. 

PARTITION_BIOS="$DEVICE"1 # Start at sector 34 for 1017 KiB to allow proper alignment; type ef02
PARTITION_BOOT="$DEVICE"2
PARTITION_SWAP="$DEVICE"3
PARTITION_ROOT="$DEVICE"4

echo "Starting..."
echo "Make sure we have all the required packages installed"
#------------------------------------------------------
# Make sure we have all the required packages installed
#------------------------------------------------------
#
DEPENDS=('btrfs-tools' 'cryptsetup-bin' 'parted' 'rsync')

for pkg in "${DEPENDS[@]}"; do 
    if [ $(dpkg-query -W -f='${Status}' $pkg 2>/dev/null | grep -c "ok installed") -eq 0 ]; then
        apt-get --force-yes --yes install $pkg
    fi
done

if [ "$LOCALMODE_ONLY" = true ]; then
    DESTROY_PARTITIONS=false
    FORMAT_PARTITIONS=false
fi

echo "Create Partition table and partitions"
# -------------------------------------
# Create Partition table and partitions
# -------------------------------------
if [ "$DESTROY_PARTITIONS" = true ]; then
    while read -r line; do
        if [[ ! $line == '#'* ]] && [[ ! "$line" == "" ]]; then
    	    parted --script -a optimal $DEVICE -- $line
        fi
        if [[ $line == '#'* ]]; then
    	    echo "Comment: $line"
        fi
    done <<-EOF
        print

        # Create GPT partition label
        mklabel gpt

        # Create partition 1 (bios)
        # And set partition flag state (bios_grub)
        mkpart primary 1 3
        name 1 grub
        set 1 bios_grub on

        # Boot partition
        mkpart primary 3 131
        name 2 boot
        set 2 boot on

        # Swap partition
        mkpart primary linux-swap 131 643
        name 3 swap
 
        # Root partition
        mkpart primary 643 100%
        name 4 rootfs

        print
	EOF
fi

echo "Format boot and root partitions and encrypt root partition"
# ----------------------------------------------------------
# Format boot and root partitions and encrypt root partition
# ----------------------------------------------------------
if [ "$FORMAT_PARTITIONS" = true ]; then
    # Format /boot partition with ext4
    echo "Format /boot partition with ext4"
    mkfs.ext4 "$PARTITION_BOOT"

    # Use a defualt password to create luks encryption container.  We will change it once everything is working
    echo "Encrypt root partition"
    echo -e "$PASSPHRASE" | cryptsetup --cipher aes-xts-plain64 --key-size 512 --hash sha512 --batch-mode luksFormat "$PARTITION_ROOT"

    echo "Encrypt swap partition"
    echo -e "$PASSPHRASE" | cryptsetup luksOpen $PARTITION_ROOT root_crypt
    cryptsetup --use-random --cipher aes-xts-plain64 --key-size 256 --key-file /dev/urandom --batch-mode luksFormat "$PARTITION_SWAP"

    # Unlock root luks partition so we can format it
    echo "Unlock root luks partition so we can format it"
    echo -e "$PASSPHRASE" | cryptsetup luksOpen "$PARTITION_ROOT" root_crypt

    # Format newly created luks partition with btrfs
    echo "Format newly created luks partition with btrfs"
    eval "$ROOT_FORMAT" /dev/mapper/root_crypt

    # Mount root and boot
    echo "Mount root and boot"
    eval "$ROOT_MOUNT" /dev/mapper/root_crypt /mnt
fi
    
# --------------------------------------------------------------------------------------------------
# btrfs rsync function 
# --------------------------------------------------------------------------------------------------
SHARE=
BACKUP_DIRECTORY=
SHARE_DIRECTORY=
SNAPSHOT_DIRECTORY=/var
DEFAULT_RSYNCOPTS=('--progress' \
           '--inplace' \
           '--partial' \
           '--no-whole-file' \
           '--delete' \
           '--human-readable' \
           '--itemize-changes' \
           '--one-file-system' \
           '--stats' \
           '--delete-excluded' \
           '-v' \
           '-aHAX' \
          )
if [ "$RSYNC_DRY-RUN" = true ]; then
    DEFAULT_RSYNCOPTS+=('--dry-run')
fi
RSYNCOPTS=( "${DEFAULT_RSYNCOPTS[@]}" )

backup_btrfs_share () {
    echo "Rsync Options Selected:"
    echo -e echo "${RSYNCOPTS[*]}"

    echo "Starting rsync on $SHARE share"
    # Rsync it
    nice -10 rsync "${RSYNCOPTS[@]}" "$SHARE_DIRECTORY/." "$BACKUP_DIRECTORY/$SHARE"
}

###################################################################################################
#
# Backup scripts
#
###################################################################################################


# --------------------------------------------------
# Rsync existing root and root to mounted partitions
# --------------------------------------------------
if [ "$RSYNC" = true ]; then
    echo "Rsync existing root and root to mounted partitions"
    if [ ! "$LOCALMODE_ONLY" = true ]; then
        # Try to mount in case we did not do a format.  Its okay if it says already mounted
        echo "Try to mount in case we did not do a format.  Its okay if it says already mounted"
        echo -e "$PASSPHRASE" | cryptsetup luksOpen "$PARTITION_ROOT" root_crypt
    	eval "$ROOT_MOUNT" /dev/mapper/root_crypt /mnt
    fi

    echo "umount proc, sys, dev, dev/pts in /mnt/"
    for fs in proc sys dev dev/pts; do umount /mnt/$fs; done

    ### root directory with lots of excludes ### 
    BACKUP_DIRECTORY=/mnt
    SHARE_DIRECTORY=
    SHARE=
    FILTER=('/dev' '/proc' '/sys' '/run' '/tmp' '/mnt' '/media' '/lost+found' '/boot')
    for dir in "${FILTER[@]}"; do RSYNCOPTS+=("--filter=- $dir"); done
    echo -e "${RSYNCOPTS[@]}"
    
    backup_btrfs_share
    
    # Re-create excluded directories
    for dir in "${FILTER[@]}"; do rsync -pogtd "$dir" "/mnt/$dir"; done
    
    if [ ! "$LOCALMODE_ONLY" = true ]; then
        # Mount /mnt/boot
        mount -t ext4 "$PARTITION_BOOT" /mnt/boot
    fi
    
    ### Reset RSYNCOPTS back to default ###
    RSYNCOPTS=( "${DEFAULT_RSYNCOPTS[@]}" )
    
    ### /boot ONLY ###
    BACKUP_DIRECTORY=/mnt
    SHARE_DIRECTORY=/boot
    SHARE=boot
    #RSYNCOPTS+=('--filter=+ /boot/***' '--filter=- *')
    backup_btrfs_share
fi

#####################################################################################################
    
if [ ! "$LOCALMODE_ONLY" = true ]; then
    # Try to mount yet again in case we did not do a format, or rsync.  Its okay if it says already mounted
    echo "Try to mount yet again in case we did not do a format, or rsync.  Its okay if it says already mounted"
    echo -e "$PASSPHRASE" | cryptsetup luksOpen "$PARTITION_ROOT" root_crypt
    eval "$ROOT_MOUNT" /dev/mapper/root_crypt /mnt
    mkdir -p /mnt/boot
    mount -t ext4 "$PARTITION_BOOT" /mnt/boot
fi

# Add new /etc/fstab, /etc/cryptab entries for boot, root and swap
# ----------------------------------------------------------------
echo "Add new /etc/fstab, /etc/cryptab entries for boot, root and swap"
touch /mnt/etc/crypttab
mv /mnt/etc/fstab /mnt/etc/fstab.orig
mv /mnt/etc/cyypttab /mnt/etc/cyypttab.orig


# crypttab
# --------
echo "create crypttab"
echo "root_crypt UUID=$(blkid -s UUID -o value $PARTITION_ROOT) none luks" >> /mnt/etc/crypttab
echo "swap_crypt UUID=$(blkid -s UUID -o value $PARTITION_SWAP) /dev/urandom cipher=aes-xts-plain64,size=256,swap" >> /mnt/etc/crypttab


# Current fstab (use for awk / sed search and replace pattern)
# awk on column may be easiest
# ------------------------------------------------------------ 
# #UUID=3af218b0-eac9-4483-9a5d-727dfe8da6b9 /               ext4        errors=remount-ro 0 1
# UUID=850e4358-ce44-4fc2-8af7-7acaf8ddbfdf none            swap        sw                0 0
# /dev/sr0 /media/cdrom0                                    udf,iso9660 user,noauto       0 0


# fstab
# ------
echo "create new fstab"
echo "" >> /mnt/etc/fstab
echo "# New mounts from conversion" >> /mnt/etc/fstab
echo "/dev/mapper/root_crypt / $ROOT_FSTAB" >> /mnt/etc/fstab

echo "/dev/mapper/swap_crypt none swap sw 0 0" >> /mnt/etc/fstab
echo "UUID=$(blkid -s UUID -o value $PARTITION_BOOT) /mnt/boot ext4 defaults 0 0" >> /mnt/etc/fstab

# initramfs and grub
# ------------------
echo "run initramfs and grub"
for fs in proc sys dev dev/pts; do mount --bind /$fs /mnt/$fs; done
chroot /mnt /usr/sbin/update-initramfs -k all -u
chroot /mnt /usr/sbin/update-grub
chroot /mnt /usr/sbin/grub-install $DEVICE

# DEBUG; test to be able to look around and confirm success
# ---------------------------------------------------------
echo "chroot /mnt"
echo "We are now in the newly created partition.  Look around"
echo "to see if everything looks like it copied over okay."
echo "type 'exit' with no quotes to exit chroot"
chroot /mnt

# Change passphrase
# -----------------
#echo "Change passphrase, current passphrase is: $PASSPHRASE"
#echo -e $oldPassword\n$newPassword\n$newPassword | cryptsetup luksAddKey $PARTITION_ROOT
#echo -e "$PASSPHRASE\n" | cryptsetup luksChangeKey --verify-passphrase $PARTITION_ROOT

echo "Done!"

Nice plan. Interesting updates.

6. [???] Whonix build option for btrfs file system :)

Making the Whonix option configurable doesn’t look difficult:
https://github.com/Whonix/Whonix/blob/master/build-steps.d/1300_create-raw-image#L115

Currently hardcoded to ext4, but making this configurable seems trivial. If you wish you can create a github ticket and I’ll do it for Whonix 10.

Whether btrfs will work depends on if grml-debpotstrap supports btrfs. Manual:

https://grml.org/grml-debootstrap/

--filesystem filesystem
Filesystem that should be created when installing to a partition. If unset defaults to ext3. Valid values are all filesystems that can be created through mkfs.filesystem.</blockquote>

Haven’t checked if btrfs would work. I’d say just try hardcoding it in Whonix’s code to btrfs to see if ti works. If not, it’s something you would have to implement into grml-debootstrap. But I speculate it will work without grml-debootstrap patches.

cryptsetup-reencrypt, most interesting! So if that works indeed, I might agree shipping Whonix images encrypted by default with a publicly known master key.

I have been looking over the Whonix code today and I will take a stab at creating a branch based off of 8.6.6.0 and try to implement the crypt code.

I will need to create a /boot, /swap and /root partitions. The nice thing about cryptsetup-reencrypt is that not only can you change just the master key, you can also change the type of encryption used as well. The downside is this needs to happen with the root partition offline (not mounted) and you will need at least cryptsetup-bin 1.6 (available in wheezy-backports or jessie).

So in order to reencrypt, we either need to write the code needed in init, or I figure we could use the swap partition to place temp code and boot from it to reencrypt.

I am also working on another Whonix side project to ‘Whonix-ify’ an existing wheezy, jessie, ubuntu, and fedora using salt ([url=http://www.saltstack.com/]VMware Aria Automation (formerly vRealize Automation) | Infrastructure Automation | VMware). I have developed some nice tools for salt to accomplish this task. I will start a new thread once I have something to show.

The main reason I am interested in creating these new feature sets is for my personal project called DockerNAS which will allow users to have a highly web based configurable AND secure NAS that utilizes docker containers. Guess that means we will also be seeing a Whonix Gateway docker real soon too :slight_smile: I also want the users to be able to choose which ever distribution they are already comfortable with and ‘Whonix-ify’ it using KVM. I will add a disclaimer that it is best to use the Official Whonix Workstation for the best security.

No idea on how to implement the crypt code. And how to encrypt the swap partition? I prefer swap files over swap partitions. Easier to document, easier to grasp, less complexity. And I still think the crypt code would probably be best implemented in grml-debootstrap.

For re-encryption after boot, maybe whonix-initializer would be a good place to implement this. Although it runs with mounted root partition. To make it even more a hack, we could also consider kexec to new kernel. Otherwise perhaps also not mounting root at first boot, re-encrypt, then boot normally could be scripted as well.

As for docker, which should be discussed in a separate thread as well, maybe our existing libvirt files can be reused with minor chances, just speculating.

(Just saying, not trying to convince you or so, because I not yet really know what you’re planing, so I have no opinion yet.)
As for Whonix-ify existing operating systems, alternatively Whonix’s build script with --install-to-root switch could be used (previously called --bare-metal). As another alternative, although there are some minor annoyances, installing Whonix using apt-get could work as well. However, I think Whonix-ify is best discussed in a separate thread.

Making the Whonix option configurable doesn’t look difficult:
https://github.com/Whonix/Whonix/blob/master/build-steps.d/1300_create-raw-image#L115

Currently hardcoded to ext4, but making this configurable seems trivial. If you wish you can create a github ticket and I’ll do it for Whonix 10.

Whether btrfs will work depends on if grml-debpotstrap supports btrfs. Manual:

https://grml.org/grml-debootstrap/

Haven’t checked if btrfs would work. I’d say just try hardcoding it in Whonix’s code to btrfs to see if ti works. If not, it’s something you would have to implement into grml-debootstrap. But I speculate it will work without grml-debootstrap patches.[/quote]

Implemented.

--file-system

https://github.com/Whonix/Whonix/commit/692f25b9f40c468512e3dc0a73f5c0bfc72147e8

So you can now experiment with.

--file-system btrfs

(In git master. Will appear in 8.6.6.4 and above.)

However, won’t work out of the box.

grml-debootstrap fails.

Not changing disk uuid for /dev/mapper/loop1p1 because mkfs.btrfs doesn't seem to match for ext{2,3,4} file system

Might require changing some grml-debootstrap setting / environment variables and/or a small grml-debootstrap patch. See also:

(In git master. Will appear in 8.6.6.4 and above.)

made grml-debootstrap environment variables overrideable:
https://github.com/Whonix/Whonix/commit/3839edcc3aea1367cf9b04818b7b9ad23caf4f28

So you can now experiment with grml-debootstrap environment variables. For example.

export FIXED_DISK_IDENTIFIERS="no"
sudo -E ./whonix_build ...

Although I find the FIXED_DISK_IDENTIFIERS=“yes” feature very useful for preventing issues with grub booting.

So it would be probably best for btrfs support, if you submitted a small patch to grml-debootstrap. The section that needs patching is here:

         if ! echo "$MKFS" | grep -q "mkfs.ext" ; then
           eerror "Not changing disk uuid for $TARGET because $MKFS doesn't seem to match for ext{2,3,4} file system"
           eend 1
           bailout 1
         else
           einfo "Changing disk uuid for $TARGET to fixed (non-random) value using tune2fs"
           tune2fs "$TARGET" -U 26ada0c0-1165-4098-884d-aafd2220c2c6
           eend $?
         fi

In essence the only issue is, that no one made changing disk uuids possible when using btrfs.

Any news about this?

I wrote something long time ago that worked as a prototype; I should find it again. I remember it being a pain cause of the file system layout, but may be of benefit for Qubes.

Its not instant though; it all depends on how much used drive space there is in play.