Booting Loop-AES Encrypted Root from USB Stick

IntnsRed's picture

Software: 

OK, verified by three independent admins, so time to remove the header

Loop-AES is not the most popular full disk encryption system around, mainly because of the difficulty involved in it's implementation. That's a shame, because there are features of loop-AES that are not utilized in other encryption schemes, namely bit flipping to scrub keys out of memory, a complex keying arrangement using multiple randomly selected keys, and gpg encryption of those keys. It is strong encryption, among the best available. I will describe here how to boot a fully Loop-AES encrypted Debian laptop from usb, with GRUB, the boot partition, and encrypted keys residing on the usb stick. The end result will be a dual-booting system that boots one OS normally, with no indication of anything else being on the hard drive during the boot process, and when the machine is started with our usb stick present, the hidden Debian system will boot. Stealth install, useful against prying eyes...

The procedures here are a little complex, and they won't be done through a point and click interface. The end result is very easy to use, however, so if you desire to have such a system for your very own but your realm of expertise lies elsewhere, I suggest you pay somebody to build such a system for you. It does take time (it can take roughly two 8 hour days of processing, so plan accordingly), and nobody works for free.

During this process, we'll rearrange disk master boot records, reconfigure the bootloader, build kernel module from source, modify and build complete Debian packages from source, and partition old school, with a calculator. If you find any of this daunting, then most likely this procedure is not for you. If this piques your curiosity, then read on... and READ IT THROUGH BEFORE STARTING.

BE ADVISED

Various goons throughout the world have come to the conclusion that it is not cost effective to even try to decrypt such a scheme without the passphrase. The computer time necessary to perform the analyses is tightly budgeted (hopefully toward finding cures for nasty diseases, feeding the hungry, and analyzing the results from CERN). Instead, if they really want the information, they will lock you up for years, deprive you of sleep, waterboard you, beat you, insult your ancestry and your religion (if you have one) or lack of it, and generally make your life uncomfortable until you give them the passphrase (if you can remember it after all that). In short, they don't really need that computer time, because they have other, cheaper means at their disposal. Call it human engineering, and they like to use it. This system will NOT protect you from any government. It may, however, be of help in protecting your sensitive data from compromise in the event your laptop is stolen or simply lost.

Conventions:

I am using SCSI devices throughout this document, because, well, that's what I have. Returns on your machine may vary (/dev/hda, etc...), so adjust accordingly. It's your machine. Know it. Also, I am assuming that the administrator understands that a computer is a machine, and will always do exactly what you tell it to do. Look first to errors in input prior to complaining. I use the nano editor and for these quick little edits here and there. I prefer it in this case because it does not record history to disk, and so fills the purpose. No, I'm not going to use vi, vim, or emacs here, so shut the hell up. It is possible with Loop-AES to install this type of system in a partionless space on your drive. Done properly, the encrypted Debian system will be completely invisible to the observer, as partitions carrying the encrypted system are not even defined in the partition table, and the space is completely filled with random noise, with no gaps between partitions for the attacker to use as anchor points. This is what we'll do. Lastly, I use Debian here. I don't know and don't care if these procedures can be used with Ubuntu, Sidux, or others. Perhaps you can adapt these procs to your system.

I recommend practicing this whole thing on the original hard drive, before replacing the disk and doing it for real. This way you can sort out any pitfalls you may encounter with your methods without compromising sensitive data Wink Besides, if you get good at it, your boss might want you to do 200 machines, and give you a pay raise to do so...

Preparations

Materials Required:

  1. A laptop, bootable from usb, with an optical drive, preferably with DVD read/write capability. I will describe here how to install on a laptop with 1 Gig of RAM available. Users with less room will have to adjust accordingly. Laptop installs can be twitchy, so I suggest you do a normal install first, using the original hard disk, and work any bugs out, such as buggy bios, twitchy ACPI, funky graphics chip, etc. Make sure USB detection works with the kernel version you select and the versions of HAL and udev you've installed. I had to upgrade to sid and a later kernel to get everything on this slab working properly, and then reinstalled, selecting later the stuff I needed from outside Lenny to get the slab running properly (wifi AND fgrlx, in this case). So get that shit sorted FIRST. Know what you'll need to make everything coordinate. Make sure that the kernel you select at the end will accept a version of the loop-AES modules, so that you will be able to boot loop-AES encrypted root. Here, I'm running loop-aes out of sid, fglrx out of Lenny, built on a pristine kernel 2.6.28.9 from kernel.org, and the latest ath9k drivers from compat-wireless. Apt preferences favor Lenny. You get the idea.
  2. A usb stick, good quality, with no bullshit hidden drives on it (like the notorious Sandisk u3 partition - those bastards want you to download proprietary software (runnable only on windows) to strip it off. What ELSE are they writing to YOUR stick?)
  3. A legitimate copy of another operating system's installation media. You may have to go buy it, if the machine came with something preinstalled.
  4. Debian complete installation media with sources. On an amd64 or i386 machine this will be the DVD set, plus the multiarch DVD, which will include the sources you need. You can do this with a netinstall cd as well, but I HIGHLY recommend doing the netinstall through a BADASS, trusted firewall, such as a dedicated machine running OpenBSD that YOU set up.
  5. A brand new unformatted hard drive for the laptop, and the technical knowledge to be able to install the thing yourself (This is where I get to do an upgrade for the machine - Faster! Bigger! Hot Dang!)
  6. A bootable live disk incorporating loop-aes for rescue purposes - Knoppix. A Knoppix disk will boot just fine on an amd64 system, and will suit your purpose here.
  7. A calculator.

Go get all that stuff together. I'm gonna go play a round of golf, and compose some more (i hate html), and I'll be right back.

Erase the Disk

Boot to the Debian installer in expert mode.

Erase the entire disk by making one huge partition out of the disk and telling the partitioner to erase all data on the partition. This will fill the entire disk with random-looking data. Note: you can also do this by booting the Knoppix disk, partitioning the drive as described and use loop-AES to fill the drive using the methods I will describe a little later in this procedure. Your call.

Exit gracefully the Debian installer. This will leave the cd tray open.

Next, boot the unencrypted OS's installation media, and install it to a primary partition or two at the beginning of the drive.

Give it enough room to breathe. A proper operating system's environment will need at least 30 gig or so on the drive to look, feel and be real. If it's another *nix, you may have to incorporate the use of LVM2 in that early setup to be sure the partition permissions you want are available to you. Be secure on the unencrypted side as well... If it's a Microsoft system, well, you're on your own. At this point in my life I don't deal with that piece of shit. Be advised that the Master Boot Record will be rewritten in this procedure, and that you will need to correct that using Microsoft installation media when you want to make the GRUB pointer disappear. I will describe how to do that, but please understand that I do no longer OWN any Microsoft crap so you will need to verify that the procedure works for you, using your own media.

Okay, now for the good stuff:

Install Debian

Use the expert install method. Partition as follows:

  1. /dev/sda1 - your first OS's first partition.
  2. /dev/sda2 - your first OS's 2nd partition.
    Note: if your first OS has a *nix swap, DO NOT allow the installer to use it.
  3. /dev/sda3 - /boot about 250 Mg works OK at present. FORMAT AS EXT2 ONLY.
  4. /dev/sda5 - 1 Gig - swap
  5. /dev/sda6 - 1.5 Gig as / FORMAT AS EXT2 ONLY.
  6. /dev/sda7 - 1 Gig - Do Not Use - right now we're defining this area for future use as a root partition
  7. /dev/sda8 - All the rest - Do Not Use

MAKE SURE you DO NOT use a journaling filesystem on this initial install. Allow the partitions you create to mount with default options for now.

Install, selecting only standard install and laptop for the software suite - you're only going to a gig and a half of space. Of course, you want to allow login as root (this is Debian, and we have no fear), and do create a normal user. DO NOT select GRUB2. Password protect GRUB.

Hint:

You may find it easier to pass vga=791 to the kernel via GRUB prior to starting all the Debian reconfiguration. It's easier to read for me.

All this sorted, we need to tell the system to behave the way we want it to:

  1. Login as regular user
  2. Edit your .bashrc file:
    $ nano -w ~/.bashrc
    Add the line:
    HISTFILESIZE=0
    to your .bashrc (this prevents command history from being written to disk - the file will still be written, but it will be empty. Bash history will only be valid during the regular user's current login, drawn from RAM.
  3. Next, remove the current .bash_history file:
    $ rm -rf .bash_history
  4. Logout.
  5. Log back in as regular user.
  6. Generate the regular user's .gnupg directory:
    $ gpg --list-keys
    which sets up the .gnupg directory automatically.
  7. Edit regular user's .gnupg/gpg.conf file:
    $ nano -w ~/.gnupg/gpg.conf
    add the lines:
    s2k-count 8388608
    personal-cipher-preferences TWOFISH
    Note: personal-cipher-preferences can be set to whatever you wish:
    'gpg --version' will list what's available. This will prevent gpg from defaulting to the CAST5 algo on symmetric encryption (BLOWFISH, TWOFISH, and AES256 are all formidable). The s2k-count option forces gpg to to hash passphrase over and over again, making a dictionary attack much more difficult.

    Note: If you want to avoid the "integrity not protected" warning for your symmetrically-encrypted files, you should use TWOFISH or AES256 for your algo. This relates to gpg using or not using MDC as a "sig within a sig" to help protect against message alteration attacks. in our application here, It should make no difference, however, globally, it may be to your advantage to use TWOFISH or AES256, where GPG applies MDC by default

From Loop-AES Readme:

When gpg encrypts data with symmetric cipher only or when gpg encrypts secret keyring keys with secret passphrase, gpg uses seeded (salted) and iterated key setup. However, default amount of iteration is tuned for slow processors and can be increased for better resistance against dictionary attacks. Larger key iteration makes key setup much slower, but also makes dictionary attacks much slower too.
...
If you are using gpg version 1.4.6 or later you achieve same increased
password iteration effect... by setting this
option in your options file ~/.gnupg/gpg.conf

s2k-count 8388608

  1. Next, su to root.
  2. cd to root's home directory:
    # cd
  3. Edit root's .bashrc file:
    # nano -w ~/.bashrc
    Add the line:
    HISTFILESIZE=0
    to root's .bashrc (this prevents command history from being written to disk - the file will still be written, but it will be empty. Bash history will only be valid during root's current login, drawn from RAM.
  4. Next, remove the current .bash_history file:
    # rm -rf .bash_history
  5. Exit su.
    # exit
  6. su back to root, and cd back to root's home directory.
  7. Generate root's .gnupg directory:
    # gpg --list-keys
    which sets up the .gnupg directory automatically.
  8. Edit root's .gnupg/gpg.conf file:
    # nano -w ~/.gnupg/gpg.conf
    add the lines:
    s2k-count 8388608
    personal-cipher-preferences AES256

Now, we're ready to install some software, and begin the encryption process.

Section One

Installing Loop-AES

Note: If you're using a custom kernel for your Debian install for some reason, you need to ensure that loop-aes-source will build against the kernel, and that you use initramfs-tools to build the initramfs (e.g. make-kpkg --initrd kernel-image modules-image). You will also need to install the following packages to use loop-aes: loop-aes-testsuite and loop-aes-utils. I don't use aespipe in this procedure, and initramfs-tools is installed by default.

Use this procedure for a stock kernel:

  1. su to root, if you're not there already.
  2. Get the capability to build the kernel module:
    # apt-get install module-assistant
  3. Tell module-assistant to get what it needs for your kernel:
    # module-assistant prepare
  4. Tell module-assistant to download loop-AES sources, compile the module for your kernel, and install it - this will also bring in all the necessary loop-AES packages for your system as dependencies (just answer 'y' when apt asks you):
    # m-a a-i loop-aes
  5. Pretty slick, eh? Reboot now, to enable the new module.

Section Two

Laying groundwork, and getting sources ready

In the next section, we will build and install Debian Gnupg packages from source. We need to prepare for that.

Loop-AES uses Gnupg encrypted randomly selected keyfiles of great length for it's encryption keys.

Therefore, Loop-aes will be using gnupg to decrypt the keys for the filesystems. As the gnupg binary will try to make calls to libraries not decrypted yet, the gnupg decryption process will fail, and we won't be able to get to the filesystems!

We work around this by compiling the gnupg binaries statically linked with the libraries gnupg needs to do it's work. We'll build genuine Debian packages so that you may install them on other machines without having to go through the compilation process again.

  1. Login as your normal user
  2. su to root
  3. We need some software:
    # apt-get install devscripts gpm parted lvm2
  4. Get the stuff we need to build gnupg:
    # apt-get build-dep gnupg
  5. Now do:
    # apt-get clean
  6. Exit su back to your normal user.
  7. Generate a package signing key for yourself:
    $ gpg --gen-key
    (it only has to be a signing key. If you need a full key, by all means generate one. This is where gpm comes in handy - it's a lot easier to wiggle the mouse than to open another terminal and bang away at the keyboard to generate entropy ;-> )
  8. Make a directory to build packages in, and a subdirectory of that for gnupg:
    $ mkdir -p builds/gnupg
  9. cd into that directory:
    $ cd builds/gnupg
  10. Grab the sources for gnupg (during this process apt will check the sources against the keyrings that were pulled in by devscripts to be sure they're legit):
    $ apt-get source gnupg
    Yes, you do this as your regular user.

You now have the sources for gnupg installed in ~/builds/gnupg, and everything necessary installed on your machine to build a new set of gnupg packages.

Section Three

Modifying, Building, and Installing Gnupg

  1. Login as your normal user, if not there already.
  2. cd to the source build directory:
    $ cd builds/gnupg/gnupg*

There are two files that need to be changed: debian/rules - which will change how gnupg is compiled, and debian/changelog - which will assign a new version number to the package we're building (and explain what we did).

Start with debian/rules:

$ nano -w debian/rules

Look for a line in a SECTION that starts with:
build-deb

that looks like this:
../configure $(CONFARGS) $(HOSTARG)

and make it look EXACTLY like this:
LDFLAGS='-static -s' ../configure $(CONFARGS) --enable-static-rnd=linux $(HOSTARG)

Make sure you preserve all that leads up to and follows that statement.

You are ONLY adding "LDFLAGS='-static -s'" at the beginning, and "--enable-static-rnd=linux" in the middle.

LDFLAGS='-static -s' starts precisely where ../configure originally did
A space follows LDFLAGS='-static -s'
A space follows $(CONFARGS)
Another space follows --enable-static-rnd=linux

It WILL NOT compile if you get this wrong, so it will be the first place for you to look if there's a problem.

Next, let's deal with debian/changelog:

devscripts has a slick little tool called dch that will write a modification to that file for you, and call nano so that you can place info in it precisely:

$ dch -i

..and nano brings up the modified changelog for you to write in. It even put in your name, and an email address for you, and left a blank space for you to explain what you did. Change the name and e-mail address to match the gpg key you generated, and put something like 'built for static binary' in the blank space, then quit nano,saving on the way out. Take care when you edit to make sure you stay in the changelog format, or again, the package will fail to build.

OK, let's build this puppy:

$ dpkg-buildpackage -rfakeroot

If you didn't mess up those two trivial edits, it WILL compile, build two debs, build two udebs, ask for your gpgkey password a couple times along the way, assigning a new version number to the packages.

If you did mess up, sometimes you can reedit and correct, and then try again. Depends. If you totally hose it, simply wipe everything out of ~/builds/gnupg/ and grab the sources again.

Now, then.

cd into the ~/builds/gnupg directory and look around. Two shiny new .deb packages are sitting there, ready to be used. First, we want to see why Debian does not build gnupg in this manner in the first place. Run lintian on them:

$ lintian *.deb

will return:

E: gpgv: statically-linked-binary ./usr/bin/gpgv
W: gnupg: manpage-has-errors-from-man usr/share/man/ru/man1/gpg.1.gz 72: warning: `,' not defined
E: gnupg: statically-linked-binary ./usr/bin/gpg
E: gnupg: statically-linked-binary ./usr/bin/gpgsplit
E: gnupg: statically-linked-binary ./usr/lib/gnupg/gpgkeys_curl
E: gnupg: statically-linked-binary ./usr/lib/gnupg/gpgkeys_finger
E: gnupg: statically-linked-binary ./usr/lib/gnupg/gpgkeys_hkp

so lintian reported a warning about something it didn't understand on a Russian manpage, and 6 Errors about statically-linked-binary. Lintian is a Debian Policy checking tool that Debian package maintainers use to ensure compliance with standard policy, and reports errors when something violates that policy. The policy generally disallows static binaries for a variety of reasons, the main threads being flexibility of the system as a whole, and keeping the overall footprint of the system down. If you statically link a binary, it gets bigger, because the library for the calling program is copied into the program at compilation time. Makes the program binary bigger. If everybody did static links, the system would get to be huge. Like Microsoft Windows.

So what we have done here is make an informed decision to make a local exception to this rule in terms of these two packages, built them the way we wanted to, and assigned specific version numbers to the packages to aid us in tracking them (it makes it much easier to control APT's handling of the package during upgrades and such). We've built everything needed in order use these in a local repository later on, which is very convenient if you want to use these (and other packages you may build) on other machines you administer ;-). This is the Debian way, and it works well.

So let's get on with it, then. While in that directory, su to root, and do:

# dpkg -i *.deb

...and the gnupg packages on your system will be replaced with the ones you've built.

Next, we need to relocate two of the binaries we've just installed to the root filesystem, so that we may decrypt the main body of our filesystems after root is decrypted by the initramfs:

  1. # mv /usr/bin/gpg /bin/gpg
  2. # ln -s /bin/gpg /usr/bin/gpg
  3. # mv /usr/bin/gpgv /bin/gpgv
  4. # ln -s /bin/gpgv /usr/bin/gpgv

Note: If you find this inconvenient, then study more about package building and make the Debian packages for Gnupg do this for you. The method outlined here only entails altering two files in the source, and compiling. After all, what I really needed was the statically linked binaries. Moving them AFTER I install them is a trivial exercise, and there's less chance of error, IMHO.

Okay, Gnupg is taken care of, so let's move on:

Section Four

Scrubbing out and encrypting swap, and making the root keys.

Now, let's setup swap for encryption by editing /etc/fstab:

Change this:
]/dev/sda5                 none          swap    sw          0       0

To this:
/dev/sda5         none          swap    sw,loop=/dev/loop3,encryption=AES256 0       0

And do this:

  1. # swapoff -a
  2. # head -c 15 /dev/urandom | uuencode -m - | head -n 2 | tail -n 1 | losetup -p 0 -e AES128 /dev/loop0 /dev/sda5
  3. # dd if=/dev/zero of=/dev/loop3 bs=4k conv=notrunc
  4. # losetup -d /dev/loop0
  5. # swapon -a

Swap has been taken off line, scrubbed out, encrypted to random keys, and placed back on line. From this point forward, swap will be encrypted to a different set of keys and reformatted as swap every time we boot Wink

Check it out. Reboot now, and run:

# losetup -a

Which will yield something like:

/dev/loop3: [000d]:1965 (/dev/sda5) offset=4096 encryption=AES256 multi-key-v3

And the command:

# free

will let you know that your encrypted swap is on line. The offset is set by default in this swap application by the loop-AES program to 4096 bytes, ie: 4096 bytes into the start of the random-looking data, the encrypted information starts. When we encrypt the rest of the drive, we will use offsets that WE set, because it makes it a heckuva lot harder for an attacker to analyze if the attacker doesn't know where the real stuff begins ;-).

This will get your feet wet, get you up and running, and get you used to bouncing Loop-AES around. Once you get the hang of it, you'll probably want to strip everything off and start over with a layout that more closely suits you and your needs. Please do so, as your adversary will find it much more difficult to approach if you use something other than somebody else's layout, applied with wisdom and forethought.

  1. You need to format and set the bootable flag on the usb stick:
    Plug it in, wait for your machine to recognise it, and do:
    # cfdisk /dev/sdb
  2. Use the menu to make one big linux partition on /dev/sdb (sdb1), SET THE BOOTABLE FLAG ON THAT PARTITION, write it to the stick's MBR, and then quit cfdisk.
  3. Now put ext2 on it:
    # mke2fs /dev/sdb1

    Yes, Mildred, you CAN format a usb stick with ext2... and it works great!

Now mount the stick:

  1. # mkdir /mnt2
  2. # mount /dev/sdb1 /mnt2

And make a directory on it:

# mkdir /mnt2/working

Now, let's make the root keys - this is what you will be challenged for when you boot, so make the passphrase long and complex, and memorize it. I like to use diceware. So do this:

  1. # mkdir /boot/keys
  2. # loop-aes-keygen /boot/keys/boot.gpg

And enter the passphrase you've selected when asked. Then wiggle your mouse a lot... for a long time.. sip a beer...

Section Five

Defining your encrypted loop for root.

This is where parted comes in handy --
with the stick mounted at /mnt2 do:

# parted /dev/sda unit B print >> /mnt2/working/layout

Take a look at the file you just created:

# cat /mnt2/working/layout

you will see something that resembles this:

Model: ST325031 0AS (scsi)
Disk /dev/sda: 250059350016B
Sector size (logical/physical): 512B/512B
Partition Table: msdos

Number  Start          End            Size           Type      File system  Flags
1      32256B         104855869439B  104855837184B  primary   ntfs
2      104855869440B  107479733759B  2623864320B    primary                   
3      107479733760B  107742942719B  263208960B     primary                   
4      107742942720B  250056737279B  142313794560B  extended                  
5      107742974976B  108787553279B  1044578304B    logical                    
6      108787585536B  110358581759B  1570996224B    logical                  
7      110358614016B  111403192319B  1044578304B    logical                    
8      111403224576B  250056737279B  138653512704B  logical

(this does not translate well into html - the actual chart you will see will be well ordered and clear.)

Now it's time to do a little thinking.  We are going to place our encrypted system in pure greyspace, with no reference to the "partitions" at all in the Master boot record of the laptop's disk.  Instead, we will place that information on the usbstick for booting.

We are interested in partitions 7 and 8 in this example:
In the start column of partition 7 we see the exact Byte on the disk where that partition starts.
In the end column of partition 8 we see the exact Byte on the disk where the last partition ends.

We laid this out for ourselves when we installed Debian.

OK, unmount /mnt2 and take the stick out.

Now we delete partitions 7 and 8 using cfdisk:

<code># cfdisk /dev/sda

delete those two, write to the master boot record, and reboot.

Now the MBR knows nothing of those two partitons, but you've retained a record on the stick.

Plug in the stick and mount it at /mnt2

Let's use that record:

As root:

# nano -w /mnt2/working/layout

Now we can record the commands we will use to set up our loops. Remember, bash will not record your steps, so we will need to record them somewhere - the safest place is in this file on the stick. If you are much younger than I and can remember everything exactly while you are performing this, so be it. Just don't rub it in...

Here goes the math:

We want to make a loop that exactly spans the space from the beginning Byte of the original partition 7 to the ending Byte of partition 8. All must be divisible by 512, the standard sector size. Disk Byte numbering begins at Zero. Record the command in the file you have open, before trying to execute, so that you can double check yourself.

We will set the starting edge of the loop with a defined offset=@somebyte, and define the loop's length with sizelimit=somanybytes.

So the first loop we'll make will be one that makes our greyspace even greyer (record this in the layout file at a newline, and make a newline after it, erm, hit return):

head -c 15 /dev/urandom | uuencode -m - | head -n2 | tail -n 1 | losetup -p 0 -e AES128 /dev/loop0 /dev/sda -o @110358614016 -s 139698123264

This command, when executed, will make a loop that is randomly encrypted which extends from the very first Byte of the original partition 7 to the end of the disk in our example. The sizelimit here is arrived at by this:

(partition 8 ending byte) + 1 - (partition 7 starting byte) = sizelimit

250056737279 + 1 - 110358614016 = sizelimit = 139698123264

Remember that byte numbering begins at zero, so the ending byte of the disk will be odd. Also observe that the beginning byte and the sizelimit are both evenly divisible by 512, the standard sector size. Loop-AES requires this to function properly:

110358614016 / 512 = 215544168 check

139698123264 / 512 = 272847897 check

Now exit nano, saving /mnt2/working/layout as you do so.

Now do:
# cat /mnt2/working/layout

And everything in that file will be visible to you. Cut and paste with the mouse the command you just created to your command line, and hit enter.

loop-AES will complain if you've made errors. It will NOT complain if you overlap your loops, however, so bear that in mind when you create the filesystem loops.

Check that the loop has been created where you thought it would be:
# losetup -a

AND DOUBLE CHECK YOUR MATH. There's a sticky key on my calculator...

Now fill that one unified space with random-looking noise:

# dd if=/dev/zero of=/dev/loop0 bs=4k conv=notrunc

And go to dinner....

When it's done, delete that loop:

# losetup -d /dev/loop0

Now, we want to make a command for building the loop that will house our encrypted root filesystem:

Open the file /mnt2/working/layout using nano:

# nano -w /mnt2/working/layout

And build the command there as it's own line followed by a newline:

losetup -e AES256 -K /boot/keys/boot.gpg /dev/loop1 /dev/sda -o @110358619136 -s 1073741824

Notice again that both values given are evenly divisible by 512.

Notice also here that I have offset the starting point of that loop 5120 bytes into the greyspace. What happens here is that standard partitioning programs (and partition recovery programs) will look for partitions at standard cylinder divisions of 63 sectors per cylinder. This is a hangover from olden times (? damn, I feel old now), and can be disregarded on a modern laptop hard disk. We want to avoid being picked up inadvertently, so we offset from standard - the offset can be any multiple of 512. The sizelimit relates to 1 Gig Rootfs space - just fine for Debian. Ubuntu people may need more. Ubuntu uses HUGE emulation and lib32 directories to make their shit work on amd64 systems (is it really amd64?), and will not install with a rootfs partition less than 2.5 gig on basic install, in my experience.

Exit nano, saving /mnt2/working/layout on the way.

Now do:
# cat /mnt2/working/layout

--and cut and paste the command you just built to the command line, hit enter.

You will be asked for the passphrase you memorized, and the loop will be made. Check with:
# losetup -a

AND DOUBLE CHECK YOUR MATH. That key still sticks, dammit (at school, I always blamed it on sticky keys)...

Happy the loop is where you want it on the disk, and it's the right size, format it:

# mke2fs -j /dev/loop1

If not happy, don't format it, delete the loop with 'losetup -d /dev/loop1', edit /mnt2/working/layout to make corrections, and try again.

Once you're happy with all that, and have the loop formatted with ext3 (mke2fs -j), mount it with:

# mount /dev/loop1 /mnt

Now you have your future root filesystem formatted as ext3 (in an area that you, and only you know about), mounted at /mnt, and your keys and loop layout safely tucked away on the usb stick, which is mounted at /mnt2 for your eyes only. You can shut down at this point without losing any work. After reboot, simply mount the stick at mount2, cat the file, cut and paste the command, and the loop will once again be available for mounting. Your usb stick has become the weak physical point in your encryption system, so safeguard it accordingly. We'll get back to this later.

Section Six

Defining an encrypted loop for LVM2 to use.

First, let's set up LVM2 to run on /dev/loop2.
Edit /etc/lvm/lvm.conf and make it read so:

# By default we accept every block device:
# filter = [ "a/.*/" ]

# Exclude the cdrom drive
# filter = [ "r|/dev/cdrom|" ]

# When testing I like to work with just loopback devices:
# filter = [ "a/loop/", "r/.*/" ]

# Or maybe all loops and ide drives except hdc:
# filter =[ "a|loop|", "r|/dev/hdc|", "a|/dev/ide|", "r|.*|" ]

# Use anchors if you want to be really specific
filter = [ "a|^/dev/loop2$|", "r/.*/" ]

Then, restart lvm2 with this:

  1. # /etc/init.d/lvm2 stop
  2. # /etc/init.d/lvm2 start

During the boot process of our encrypted system, we want the system to ask us for one passphrase to unlock the root filesystem. Then we want an initscript on that encrypted filesystem to unlock the rest of the encrypted filesystem, automatically providing passphrase to decrypt keys for this along the way. Of course, we need to protect that passphrase, so let's build the script on the encrypted loop we just mounted.

Now, copy /etc to the new rootfs:

  1. # cd /
  2. # cp -ax etc /mnt/

Next, make a directory there for the keys:

# mkdir /mnt/etc/keys

Make a file that we'll use to build the initscript, and make it read/write/execute by root only:

  1. touch /mnt/etc/rcS.d/S24losetup
  2. chmod 700 /mnt/etc/rcS.d/S24losetup

Now, let's generate a couple random passphrases for that file to use:

  1. head -c 15 /dev/urandom | uuencode -m - | head -n 2 | tail -n 1 >> /mnt/etc/rcS.d/S24losetup
  2. head -c 15 /dev/urandom | uuencode -m - | head -n 2 | tail -n 1 >> /mnt/etc/rcS.d/S24losetup

Looking at the file,

# cat /mnt/etc/rcS.d/S24losetup
you will see two lines that resemble this:

z3Bym0Xvf91FHHNDFejj
8EETctMGVhql9gC4iuvN

We will call z3Bym0Xvf91FHHNDFejj one passphrase, and 8EETctMGVhql9gC4iuvN the second.

Now, we'll make keys using these passphrases:

# loop-aes-keygen /mnt/etc/keys/main.gpg

# loop-aes-keygen /mnt/etc/keys/swap.gpg

(You can use the mouse to cut and paste the lines for the passphrases - takes a little practice - or you can jot them down and enter them manually. Then feed the paper to the dog. Then shoot the dog. I like my dog, so I use the mouse Wink )

Now, we set up our script:

nano -w /mnt/etc/rcS.d/S24losetup

make this:

z3Bym0Xvf91FHHNDFejj
8EETctMGVhql9gC4iuvN

look like this:

#!/bin/sh

echo "z3Bym0Xvf91FHHNDFejj" | losetup -p 0 -K /mnt/etc/keys/main.gpg -e AES256 /dev/loop2 /dev/sda -o @111432393216 -s 138624311808

# 8EETctMGVhql9gC4iuvN

Notice here that I have set the offset well after the end of the root filesystem loop for safety, a full 63 sectors, further burying our encrypted system, and stopped this loop well back from the end of the disk, another full cylinder of 63 sectors or so. Both values are again evenly divisible by 512. We've left the second passphrase commented out for the time being. We will use it later.

Now, let's fire up the loop:

# /mnt/etc/rcS.d/S24losetup

and check with:

# losetup -a

You now have three loops encrypted with loop-aes that you can reestablish manually at any time:

/dev/loop1 - your rootfs
/dev/loop2 - your main loop
/dev/loop3 - encrypted swap

Section Seven

Building the OS on the encrypted loops.

First, unmount the usb stick, remove it, and set it aside for now.

So, we've already setup lvm2 to use /dev/loop2 for volume management, and we've built /dev/loop2

Let's setup the rest of lvm2:

I've got a big drive, so I can give myself plenty of room for growth, and I like to play with a lot of different stuff. I also run a lot of third party stuff in /usr/local. My machine's name is gecko, so I use that. There is the advantage, as well, when running LVM2, of the relative ease of resizing partitions. A standard Debian install will use about 7 gig for /usr and about 3 or so for /var analyze your own usage and adjust as necessary.

I do this:

  1. tell LVM2 about /dev/loop2:
    # pvcreate /dev/loop2
  2. Create a Volume Group on /dev/loop2:
    # vgcreate gecko /dev/loop2
  3. Create logical volume for /usr:
    # lvcreate -L 10Gt -n usr gecko
  4. Create logical volume for /usr/share:
    # lvcreate -L 10Gt -n share gecko
  5. Create logical volume for /usr/local:
    # lvcreate -L 10Gt -n local gecko
  6. Create logical volume for /var:
    # lvcreate -L 3Gt -n var gecko
  7. Create logical volume for /tmp:
    # lvcreate -L 400Mg -n tmp gecko
  8. Figure out how much room you have left:
    # vgdisplay | grep Free
  9. Use the Free PE number to max out /home:
    # lvcreate -l (Free PE number) -n home gecko

Now, format these newly created logical volumes:

  1. # mke2fs -j /dev/mapper/gecko-usr
  2. # mke2fs -j /dev/mapper/gecko-share
  3. # mke2fs -j /dev/mapper/gecko-local
  4. # mke2fs -j /dev/mapper/gecko-var
  5. # mke2fs -j /dev/mapper/gecko-tmp
  6. # mke2fs -j /dev/mapper/gecko-home

Next, setup the encrypted root filesystem:

  1. Make some directories on the loopfs:
    # mkdir /mnt/{boot,home,mnt,proc,sys,tmp,usr,var}
  2. Copy everything EXCEPT boot,etc,home,lost&found,mnt,mnt2,proc,sys,tmp,usr,var from your root directory to it (MAKE SURE you don't have anything extraneous mounted):
    # cp -ax bin cdrom dev emul initrd* lib* media opt root sbin selinux srv vmlinuz* /mnt/

Next, mount the logical volumes on the encrypted root:

  1. # mount /dev/mapper/gecko-usr /mnt/usr
  2. # mkdir /mnt/usr/{share,local}
  3. # mount /dev/mapper/gecko-share /mnt/usr/share
  4. # mount /dev/mapper/gecko-local /mnt/usr/local
  5. # mount /dev/mapper/gecko-var /mnt/var
  6. # mount /dev/mapper/gecko-tmp /mnt/tmp
  7. # mount /dev/mapper/gecko-home /mnt/home

Now, copy the rest of the info you need for this in / over:

  1. # cp -ax /usr/* /mnt/usr/
  2. # cp -ax /var/* /mnt/var/
  3. # cp -ax /tmp/* /mnt/tmp/
  4. # cp -ax /home/* /mnt/home/

Okay, now, let's bring the thing alive:

First, edit /boot/grub/menu.lst

change the line:

# kopt=root=/dev/sda6 ro vga=791

to this:

# kopt=root=/dev/sda ro vga=791

and run:

# update-grub

Edit /mnt/etc/fstab, and make it read so:

# /etc/fstab: static file system information.
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
proc              /proc         proc    defaults        0       0
/dev/sda                 /             ext3    loop=/dev/loop1,encryption=AES256,gpgkey=/boot/keys/boot.gpg,offset=@110358619136,sizelimit=1073741824,errors=remount-ro 0       1
/dev/sda3         /boot         ext2    defaults 0       2
/dev/sda5         none          swap    sw,loop=/dev/loop3,encryption=AES256 0       0
/dev/mapper/gecko-usr   /usr ext3 defaults,nodev 0 2
/dev/mapper/gecko-share   /usr/share ext3 defaults,nodev,nosuid 0 2
/dev/mapper/gecko-local   /usr/local ext3 defaults,nodev,nosuid 0 2
/dev/mapper/gecko-var   /var ext3 defaults,nodev, 0      2
/dev/mapper/gecko-tmp   /tmp ext3 defaults,nodev,nosuid,noexec 0 2
/dev/mapper/gecko-home   /home ext3 rw,nosuid,nodev,exec,auto,nouser,async 0 2
/dev/scd0       /media/cdrom0   udf,iso9660 user,noauto     0       0

Re-Edit /mnt/etc/rcS.d/S24losetup, and make it read so:

#!/bin/sh

echo "z3Bym0Xvf91FHHNDFejj" | losetup -p 0 -K /etc/keys/main.gpg -e AES256 /dev/loop2 /dev/sda -o @111432393216 -s 138624311808

# 8EETctMGVhql9gC4iuvN

...you need to remove the /mnt reference to find main.gpg Wink

Next, we chroot into the new environment and change a couple things:

  1. # cd /mnt
  2. # chroot . /bin/bash
  3. # mount proc -t proc /proc
  4. # mount sys -t sysfs /sys
  5. # mount /boot
  6. Next, tell the initramfs where things are:

    # update-initramfs -u -t `uname -r`

    What's cool here is that initramfs-tools will recognize that root is loop-aes encrypted and load loop-AES, the encrypted root keys, and the gnupg binary into the initramfs.

  7. Don't forget to change permissions on /tmp:

    # chmod a+rwx /tmp

Now, we back out of the chroot:

  1. # umount /boot
  2. # umount /sys
  3. # umount /proc
  4. # exit
  5. # sync

Ready, Set, Reboot!

All goes well, The prediction is this: GRUB loads, and finds /boot partition (/dev/sda3) GRUB loads the the kernel into RAM, loads the initramfs into RAM, and points the kernel at it. The initramfs tells the kernel what it needs to get to the root filesystem, and gives it the tools to get there - the drivers for your root disk, loop-aes, and the encrypted keys to unlock the rootfs. You will be challenged for your passphrase to unlock the keys for the rootfs, then the system will unlock the main loop, and then LVM2 will define all the filesystems on that loop, and the system will continue to boot normally, using the new rootfs, and the new filesystem normally, however they are completely encrypted, out there in a grey space on the disk that only you, your boot partition, and your usb stick know about. No keys have been written to disk unencrypted, and neither have any passphrases. The layout of your root filesystem is, however, on the boot partition, retained in the initramfs. A knowledgeable person can easily take apart an initramfs to see what's in it: read man initramfs-tools. We will get to this in a moment.

Section Eight

Make Debian boot from the usb stick.

Here we're going to move the GRUB bootloader and the contents of the /boot directory onto the usbstick, configure GRUB on the stick to utilize the stick's kernel and initramfs entries. The BIOS will be configured to try to boot first from usb. Upon success, kernel and initramfs will load from the usb stick, and calls will go out to bring the rest of the OS up from the main hard disk.

  1. Login, and su to root.
  2. Change directories to the /boot partition:
    # cd /boot
  3. Plug in your usb stick, and let it register.
  4. Mount it with:
    # mount /dev/sdb1 /mnt
  5. Copy your boot directory's contents to the stick with:
    # cp -ax grub keys config* initrd* System* vmlinuz* /mnt/<code></li>

    <li>..and cd out of the boot directory:
    <code># cd /
  6. Change your /etc/fstab entry for /boot from this:
    /dev/sda3         /boot         ext2    defaults 0       2
    to this:
    /dev/sdb1         /boot         ext2    defaults,noatime 0       2
  7. mount the boot stick as the new boot directory:
    # umount /mnt
    # umount /boot
    # mount /boot
  8. install GRUB on the usb stick:
    # grub-install --recheck /dev/sdb
  9. Note here that GRUB will return a new device.map reading, and ask you to check and correct it:
    (hd0)  /dev/sda
    (hd1) /dev/sdb
  10. You need to edit GRUB's device map (this tells GRUB where it lives, and GRUB always calls hd0 it's home):
    # nano -w /boot/grub/device.map
  11. Make it read so:
    (hd0)  /dev/sdb
    (hd1) /dev/sda
  12. And run:
    # grub-install /dev/sdb
  13. Now point the the stick's GRUB program to the kernel(s) on the stick:
    # nano -w /boot/grub/menu.lst
  14. Find this entry:
    ## default grub root device
    ## e.g. groot=(hd0,0)
    # groot=(hd0,2)
  15. GRUB now lives on the first partition of it's new home, so we need to change groot (GRUB root) - Notice here that GRUB calls the first partition number 0 and counts accordingly, so the first partition on 'hd0' will be '0', the second '1', and so forth:
  16. Make it read so:
    ## default grub root device
    ## e.g. groot=(hd0,0)
    # groot=(hd0,0)
  17. Now run update-grub:
    # update-grub
  18. For good measure, update the initramfs on the usb stick:
    # update-initramfs -u -t `uname -r`

Now, then, time to prove things:

  1. Reboot, pointing your BIOS at the usb stick first, hard drive second along the way. If all is well and good, the boot process should look exactly the same as before, with the exception of the usb stick getting mounted at /boot. Check with:
    # cat /proc/mounts

Once you are satisfied that Debian is booting from the usb stick properly, it's time to correct the hard disk Master Boot Record:

Unmount /boot, remove the usb stick and set it aside for now.

If your first OS is a Microsoft product MAKE SURE YOUR USB STICK IS NOT IN THE MACHINE WHEN YOU DO THIS:

A colleague informed me that the Microsoft crap can hose the MBR on the stick you just set up, so put that cookie jar up and out of this child's reach. We'll bring it down later when they learn to play like adults...

Boot to the Microsoft installation media.

If it's XP, uh, I don't own any copies of XP, but this used to work for me:

  1. Select Repair Installation Using Console, and do:
  2. fixmbr and select:
  3. y after the nasty warning.

If it's Vista, uh, I don't have a copy of Vista anywhere (well, I did, once, on a machine I bought last year, but I immediately stripped it off when I got the machine home), so I got this off the web, and I don't know if this will work, but Microsoft says it does (they claim a lot of crap about their software). If you have problems here, scream at them, not me. I'd try it first on the old disk Wink

  1. Select a language, a time, a currency, a keyboard or an input method, and then click Next.
  2. Click 'Repair your computer'
  3. Click the operating system that you want to repair, and then click 'Next'.
  4. In the System Recovery Options dialog box, click 'Command Prompt'.
  5. Type Bootrec.exe/FixMbr, and then press ENTER.

Now, you should be able to boot into windows without going through GRUB, and your Debian partitions are still intact. You boot to Debian through the usb stick only. Make your BIOS do this:

  1. Set the boot order to USB First, Hard Disk Second, and CDROM Third (or disabled).
  2. Password protect your BIOS

Now, if you start the machine with the usb stick in your pocket, it will boot to Windows. If you start the machine with the usb stick inserted, it will boot to Debian Gnu/Linux. Cool, eh?

If the other OS is another Linux, boot to the encrypted Debian, mount that system's root at /mnt, chroot there, and run grub-install /dev/sda out of the chroot. Specific instructions for each flavor will vary. Gentoo requires the /boot/grub/device.map be rewritten prior to this, for example. I don't know much about lilo, haven't used it since Woody. Sorry.

Section Nine

Finalizing the install.

We need to finish hiding the system. There are three partitions on the disk that we can get rid of, but first, we want to be very thorough about getting rid of some things. The original rootfs should not have anything written to it that would mean anything to an attacker, but we are concerned about the original /boot partition. Here is where the program shred may actually work: non-journaling filesystem, encrypted swap, and so on. Shred's docs are VERY paranoid...

so:

mount /dev/sda3 at /mnt

  1. cd /mnt/grub
  2. shred -n 25 -u -v *
  3. cd /mnt/keys
  4. shred -n 25 -u -v *
  5. cd /mnt/
  6. rm -rf keys grub
  7. shred -n 25 -u -v *

umount /dev/sda3

Now it's time to permanently rearrange our swap:

First, take the current swap off line, and delete the original install partitions:

  1. edit your /etc/fstab, we want to comment out the swap line:

    this:

    /dev/sda5 none swap sw,loop=/dev/loop3,encryption=AES256 0 0

    goes to this:

    # /dev/sda5 none swap sw,loop=/dev/loop3,encryption=AES256 0 0

  2. Next, take the current swap off line:
  3. swapoff -a
  4. now, fire up cfdisk on /dev/sda, remove the partitions 6,5,and 3, write the new configuration to disk, and quit cfdisk.
  5. reboot

Now, it's time to break out the calculator again (damn sticky keys...). The file 'layout' now resides at /boot/working/layout

Edit /boot/working/layout to build a new command, which we can then cut and paste:

We are interested in the original starting Byte of /dev/sda3 and the starting Byte of our root filesystem. This will be a simple subtraction to get the sizelimit we need for the loop.

110358619136 - 107479733760 = 2878885376

so the command in this example will be:

head -c 15 /dev/urandom | uuencode -m - | head -n 2 | tail -n 1 | losetup -p 0 /dev/loop0 /dev/sda -o @107479733760 -s 2878885376

build your command in /boot/working/layout (making a newline after the command), save the file, and exit nano.

Now do:

  1. # cat /boot/working/layout
  2. use the mouse to cut and paste the command to your command line, and execute.
  3. # dd if=/dev/zero of=/dev/loop0 bs=4k conv=notrunc
  4. # losetup -d /dev/loop0
  5. Repeat all three of the above three commands at least three times, in order. (bash history in ram makes it easy ;-> )

Almost there! Now, we want to define a loop for swap: we have one gig of RAM, standard is 2.5 times RAM for swap... hmmm.
And we have /etc/rcS.d/S24losetup with passphrase for a key called swap.gpg in /etc/keys... hmmm.
And we want to offset into the cloud... hmmm.

So edit /etc/rcS.d/S24losetup:

Make it look like so, and save it:

#!/bin/sh

echo "z3Bym0Xvf91FHHNDFejj" | losetup -p 0 -K /etc/keys/main.gpg -e AES256 /dev/loop2 /dev/sda -o @111432393216 -s 138624311808
echo "8EETctMGVhql9gC4iuvN" | losetup -p 0 -K /etc/keys/swap.gpg -e AES256 /dev/loop3 /dev/sda -o @107479766016 -s 2878820864

Here, I've offset some 63 sectors into the cloud of noise, and given a full cylinder before the start of the root filesystem. There is perhaps more than enough space for swapping on this system, no?

Once again, the values are evenly divisible by 512.

Do this:

  1. # cat /etc/rcS.d/S24losetup
  2. Cut and paste the command you just built to your command line, and execute it.
  3. Now Do:
    # mkswap /dev/loop3

Next, edit your /etc/fstab and change the line:

# /dev/sda5 none swap sw,loop=/dev/loop3,encryption=AES256 0 0

to this:

/dev/loop3 none swap sw 0 0

and do:

# swapon -a

Section Ten

Security and Maintenance

There is one file left in your system that we should get rid of: /boot/working/layout

So:

  1. # cd /boot/working
  2. # shred -n 25 -u -v layout
  3. # cd /boot
  4. # rm -rf working

Now a word of caution: That stick is the only means of booting your system. Do not use it for any other purpose, and protect it accordingly.

I even go so far as to change a line in /etc/fstab from this:

/dev/sdb1         /boot         ext2    defaults,noatime 0       2

To this:

UUID=xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx  /boot         ext2    defaults,noatime,noauto 0       0

(the uuid obtained from "tune2fs -l /dev/sdb1 | grep UUID")

Now when I boot the system, once the kernel and initramfs are loaded in RAM, and I am challenged for the passphrase, I remove the stick, put it in my pocket, then enter the passphrase. The system will ignore the stick, and not try to fsck or mount boot.

Prior to updating my system, I insert the stick, wait for usb registration, and do:

  1. # fsck /dev/sdb1
  2. # mount /boot

... and do my upgrade.

You may have noticed that we are mounting /tmp noexec. This will cause no problems normally, but apt may complain on occasion, so we'll make a directory for apt to extract templates in somewhere where we allow executables, so:

# mkdir -p /var/apt/tmp

...and point apt to it by creating the file /etc/apt/apt.conf.d/05local

and make this line in the file:

APT::ExtractTemplates::TempDir "/var/apt/tmp";

When you've completed all this work, you will be tempted to show it off. Do not.

NEVER attempt to hibernate a laptop so rigged. Unencrypted keys in memory are written to disk during hibernate or s2disk, and therefore are blown. Just shutdown. When I build custom kernels for this installation, I remove the suspend capability in the kernel.

Before going on line with your new system, consider firewalling it. I like Shorewall.

You may now remove the line "HISTFILESIZE=0" from your .bashrc's.

And oh, yeah... go ahead and install whatever else you want: Gnome, KDE, XFCE, whatever... the disk encryption will not hurt the operation of any of it ;-}

Final proofs? Try to find your hidden operating system with any disk recovery software. Just don't allow that software to write to disk's empty space...

Final

Credits & Sources

Individuals:

Intense Red, for allowing us to rearrange the magnetic patterns on the hard drive,

Jari Ruusu, author and project administrator of Loop-AES.

jinx, who's provided invaluable input in getting this instruction to work properly...

Jackie, Gentoo hacker extraordinaire, bash expert, and owner of a wickedly accurate short game...

The Debian Loop-AES Team, who's excellent work facilitates this style of implementation.

References:

The Debian Women Wiki:

http://women.debian.org/wiki/English/BuildingTutorial

http://women.debian.org/wiki/English/BuildingWithoutHelper

http://women.debian.org/wiki/English/PackagingTutorial

Loop-AES:

http://mareichelt.de/pub/texts.loop-aes.php (well laid out, excellent resource)

/usr/share/doc/loop-aes-source/README.gz

man pages:

man gpg

man bash

Security:

http://www.debian.org/doc/manuals/securing-debian-howto/ (this is a MUST READ for ALL Debian sysadmins)