Gentoo/Linux Disk Encryption Using LoopAES And SmartCards

Page last edited 1,325 days 8 hours ago
From Alon Bar-Lev's Site
Jump to: navigation, search

Linux, Loop-AES and Optional Smartcard Based Disk Encryption

The goal is to create an encrypted linux system using TuxOnIce or uswsusp on a loop-AES encrypted harddrive that is also encrypted when suspended, optionally storing the encryption keys on PKCS#11 cryptographic tokens (Smartcards).

This manual focus is to demonstrate the process and challenges, and still be productive for actual usage.

We would like to thank the following people:

  • Jari Ruusu who made loop-aes available.
  • Pavel Machek and Rafael J. Wysocki who made uswsusp available.
  • Nigel Cunningham who made TuxOnIce available.
  • Michal Januszewski for his work on fbsplash/gensplash.

The following demonstrates a working method and includes a check to see if the unencrypted /boot partition was changed (leading to a possibly compromised kernel or initrd/initramfs). And If you use frame buffer splash you also get a nice bootsplash with suspend/resume status and a set of tools to compile your kernel correctly.

We hope you will find this information useful.

Required Components

Prerequisites

Knowledge of all of these is easy to obtain with the help of Google and the documentation for TuxOnIce and Loop-AES.

  • You know how to compile utilities in static mode.
  • You know how to create initramfs.
  • Make sure you have a working initramfs and that you control the init/linuxrc script.
  • Make sure you have a working TuxOnIce or uswsusp environment.
  • Make sure you have a working loop-aes environment, test loop on files.
  • Generate keys to be used to encrypt your disk.
  • Compile aescrypt/gpg, losetup, aespipe as static.
  • You have a backup of all data on your system. If something breaks you could easily lose the entire partition.
Warning: No really, back up your data.

Partitions

In order to have a secure encrypted and suspendable environment, you will need to have at least three partitions on your hard drive.

  • boot partition
Unencrypted /boot partition, used to hold kernel, initramfs and keyfile.
  • swap partition
Encrypted swap partition, used for suspending, resuming, and safely swapping memory to disk.
  • root partition
Encrypted root partition, your data may be stored here.
Warning: Throughout this document the following partitions are used, you should replace them with your own.
  • /dev/sda1 - boot
  • /dev/sda2 - swap
  • /dev/sda3 - root
Note: We recommend that you use at least two version of your kernel: a testing one for trying out new kernels and a stable one that is known to work. An encrypted root partition makes this very important as an unbootable kernel unbootable or missing kernel modules can make it very difficult to recover your system and data. You can use the kernel option CONFIG_LOCALVERSION to give each kernel a unique name to avoid confusion. ALWAYS have a WORKING backup kernel once you have a working environment.
Note: We recommend using Loop-AES in Multi-key-v3 mode.

There are a number of ways to store the decryption keys and we try to accommodate them all. A key may be kept on a PKCS#11 cryptographic token, in a keyfile encrypted with symmetric encryption. If you do not have a smartcard, you can store a keyfile on external media such as a cd-rom or usb thumb drive. Please refer to the Loop-AES documentation for instructions on generating keys and a security analysis. Because symmetric encryption is heavily dependent on the strength of the passphrase used, http://www.diceware.com is suggested for generating strong passphrases.

Beginning the Process

Outline

  • Compile a new kernel with necessary patches and additions
  • Test new kernel
  • Create an initramfs
  • Create encryption keys
  • Set up the framework for Loop-AES encrypted root and swap
  • Actually encrypt root and swap
  • Prepare suspend framework
  • Test the final product

Compiling a New Kernel

  • Compile your kernel with TuxOnIce or uswsusp support, initramfs support and NO loop device support.
  • Compile loop-aes module.

Add:

File: /etc/portage/package.use/loop-aes.conf
sys-apps/loop-aes-losetup static
app-crypt/aespipe static
sys-fs/loop-aes keyscrub
app-crypt/aescrypt static # optional if file based key by aescrypt is used
app-crypt/gnupg static # optional if file based key by gnupg is used

sys-apps/loop-aes-losetup is available via overlay at http://github.com/alonbl/alon-barlev-overlay.git

emerge sysfs/loop-aes app-crypt/aespipe sys-apps/loop-aes-losetup

Testing additions

Having done one of the two options above, you should now reboot into your new kernel to test the new features. Use the Loop-AES documentation to ensure that you can create a file-backed encrypted loop and that everything works properly. Don't forget to modprobe loop if you built Loop-AES as a module.

Create Initramfs

An initramfs is a lot like the familiar initrd only it uses a different archiving format (cpio instead of tar) and is accessed by the kernel slightly differently. Initramfs is capable of some things initrd just can't do and is the wave of the future.

Look at initramfs section in order to understand how to create the initramfs.

Initramfs Kernel Parameters

The linuxrc script accepts the following additional kernel parameters:

  • initrd_util
  • pkcs11:application:label,label,label
use PKCS#11 smartcards.
  • aescrypt:device:fstype:file,file,file
use aescrypt files located at device. wait for device to be available.
  • gpgfile:device:fstype:file,file,file
use gnupg files located at device. wait for device to be available.
  • initrd_devices=/dev/sdXN,/dev/sdYM,...
devices to loop over.
  • initrd_loopstart=N
The first loop index (/dev/loopN)
  • initrd_shell=N
Interrupts the initramfs and drops to a shell at a specified location (rescue, install, repare), see the linuxrc for more locations.

If no initrd_* parameter is specify, the initramfs will perform regular boot with no encryption support.

Example:

initrd_util=aescrypt:/dev/sda1:ext2:/swap.key,/root.key initrd_devices=/dev/sda2,/dev/sda3 initrd_loopstart=4

This will load utilities from /dev/sda1 and map:

  • /dev/loop4->/dev/sda2 with key from /swap.key
  • /dev/loop5->/dev/sda3 with key from /root.key

Create Encryption Keys

Using a file

Run the following command:

head -c 2925 /dev/random | uuencode -m - | head -n 66 | tail -n 65 | aescrypt -e -o /boot/root.key -

Using PKCS#11 cryptographic token

Install pkcs11-data:

emerge app-crypt/pkcs11-data

Run the following command, replacing pkcs11_provider_library with your PKCS#11 provider library:

pkcs11-data --add-provider=pkcs11_provider_library --cmd=tokens

The output will include all available tokens, select the correct token, the id='...' field is the token id to be used in next command.

Run the following command, replacing pkcs11_provider_library with your PKCS#11 provider library, and token_id with the output taken from previous command, please remember to add single quote for token_id.

head -c 2925 /dev/random | uuencode -m - | head -n 66 | tail -n 65 | gzip | pkcs11-data --add-provider=pkcs11_provider_library --cmd=import \ --token='token_id' --application=DISK --label=MY

Loop-AES Framework

At least the following need to be in your /etc/fstab for your system to boot properly. The suspended image will be written to /dev/loop4. Remember that loop4 maps to sda2 and loop5 maps to sda3. At this time be sure that your system is capable of mounting and unmounting Loop-AES volumes.

Modify:

File: /etc/fstab
/dev/sda1               /boot           ext2            defaults,noatime,ro     1 2
/dev/loop5              /               ext3            noatime                 0 1
/dev/loop4              none            swap            sw                      0 0

Actual Encrypting Step

Boot your new kernel with your new initramfs and the following arguments:

root=/dev/sda3 initrd_shell=install

You should get a shell after the initramfs has setup itself correctly but before it has mounted any partitions.

This next step goes over all of /dev/sda3 (root partition) and encrypts it. Be sure that Loop-AES is functioning in your kernel, you have created the encryption keys and the encryption keys are available on the partition passed as initrd_util. If any of the above are not true it either will not work or you will lose all your data.

Encryption using aescrypt

Run the following command:

mkdir /mnt
mount -o ro /dev/sda1 /mnt
aescrypt -d -o /tmp/key1 /mnt/key1.key
dd if=/dev/sda3 bs=64k | \ aespipe -e AES256 -p 8 8< /tmp/key1 | \ dd of=/dev/sda3 bs=64k conv=notrunc
dd if=/dev/zero of=/tmp/key1 count=10000 conv=notrunc
rm /tmp/key1

Encryption using gpg key

Run the following command:

mkdir /mnt
mount -o ro /dev/sda1 /mnt
dd if=/dev/sda3 bs=64k | \ aespipe -G / -K /mnt/root.gpg -e AES256 | \ dd of=/dev/sda3 bs=64k conv=notrunc

Encryption using PKCS#11 cryptographic token

First start PKCS#11 reader support, usually the following commands will do:

for mod in `cat /etc/modules/pkcs11`; do modprobe ${mod}; done mount -t usbfs usbfs /proc/bus/usb pcscd --force-reader-polling [--force-reader-polling requred for >=pcsc-lite-1.4.0]

Now perform the actual encryption, don't be alarmed that the key is exported to a file, since this file resides in memory, and there is no swap.

pkcs11-data --add-provider=pkcs11_provider_library --cmd=export --application=DISK --label=MY | \ gunzip > /tmp/key1
dd if=/dev/sda3 bs=64k | \ aespipe -e AES256 -p 8 8< /tmp/key1 | \ dd of=/dev/sda3 bs=64k conv=notrunc
dd if=/dev/zero of=/tmp/key1 count=10000 conv=notrunc
rm /tmp/key1

First success boot

If you use aescrypt key, reboot using the following arguments:

root=/dev/loop5 initrd_encmode=loop-aes:AES256 initrd_util=aescrypt:/dev/sda1:ext2:/root.key \
       initrd_devices=/dev/sda3 initrd_loopstart=5

If you use PKCS#11 cryptographic token, reboot using the following arguments:

 root=/dev/loop5 initrd_encmode=loop-aes:AES256 initrd_util=pkcs11:DISK:MY \
       initrd_readers=openct initrd_devices=/dev/sda3 initrd_loopstart=5

You should be prompted for the key password and boot should succeed.

Handle swap

Now we need to encrypt your swap partition.

Create a new key for the swap partition as you have done for your root.

Reboot with the following arguments:

 root=/dev/loop5 initrd_encmode=loop-aes:AES256 initrd_util=gpgfile:/dev/sda1:ext2:/swap.gpg,/root.gpg \
       initrd_devices=/dev/sda2,/dev/sda3 initrd_loopstart=4 resume=/dev/loop4

You should be prompted for the password to the gpg key and boot should succeed.

After boot create swap file:

mkswap /dev/loop4
swapon -a

Congratulations

You have a working Loop-AES environment.

Software Suspend Framework

Now to get software uswsusp or TuxOnIce to work. For TuxOnIce specify a resume= parameter at kernel command-line, for uswsusp update /etc/suspend.conf of initramfs and on your root. Both should point to your swap partition (/dev/loop4).

Specify the suspend mode at kernel command-line

 initrd_suspend_mode=suspend2 or initrd_suspend_mode=uswsusp

If use uswsusp:

emerge sys-power/suspend

hibernate.conf

Add the following lines to hibernate.conf.

This will check the boot partition on every resume, add:

File: /etc/hibernate/common.conf
OnResume 00 /usr/bin/boot-digest-check

This will unmount boot partition so it can be mounted during boot by initramfs with no data loss, add:

File: /etc/hibernate/common.conf
Unmount /boot
Mount /boot

If you are using fbsplsah, this will activate splash during suspend/resume, modify:

File: /etc/hibernate/common.conf
FBSplash on
FBSplashTheme %%THEME%%

Syslinux

File: extlinux.conf
PROMPT 0
DEFAULT menu

TIMEOUT 30
ONTIMEOUT x86_64-3.1.0-gentoo-r1

MENU TITLE Boot

LABEL x86_64-3.1.0-gentoo-r1
KERNEL kernel-x86_64-3.1.0-gentoo-r1
INITRD initramfs-x86_64-3.1.0-gentoo-r1
APPEND root=/dev/sda3 rootfstype=ext4 ro video=inteldrmfb:1920x1200-32@60 splash=silent,fadein,theme:livecd-2007.0 quiet console=tty1 initrd_suspend_mode=uswsusp resume=/dev/sda2 intel_iommu=off initrd_encmode=loop-aes:AES256 initrd_util=gpgfile:ext2:/dev/sda1:/swap.gpg,/root.gpg initrd_devices=/dev/sda2,/dev/sda3 initrd_loopstart=4

LABEL menu
MENU HIDE
KERNEL vesamenu.c32
Note: This example is using the frame buffer driver rather than vanilla vesafb. Plain vesafb would require an additional argument similar to: vga=791

Boot partition integrity

sys-apps/boot-digest is available via overlay at http://github.com/alonbl/alon-barlev-overlay.git .

Use boot-digest-mark utility in order to store the digest of the boot partition, so that you will be notified if it is changed. Configure your system to run boot-digest-check during your boot process.

emerge sys-apps/boot-digest
rc-update addd boot-digest-check boot

After you finish all your modifications, you should mark the current boot partition's digest:

boot-digest-mark

During boot or resume, you will receive a warning message if someone has tampered with your unencrypted boot partition.

Trying It All Out

Now try to hibernate... Good luck!

Extras

Using PKCS#11 cryptographic tokens

You can use PKCS#11 cryptographic tokens to hold secret key. The symmetric keys are stored on the card as private data object. The advantage to this approach is that it is stronger that using RSA encryption on the symmetric keys.

Create a file /etc/pkcs11.conf with the following format, replace pkcs11_provider_library with the actual name of the PKCS#11 provider library.

File: /etc/pkcs11.conf
--token-wait --add-provider=pkcs11_provider_library

You should have udev/mdev support and pcscd in the initramfs and specify initrd_util=pkcs11 as a kernel parameter.

A utility pkcs11-data for import/export of data objects is also required.

Since PKCS#11 provider is a dynamic library, some components of initramfs cannot be compiled statically.

You can import existing gpg keys to smartcard by using the following sequence.

Run the following command, replacing pkcs11_provider_library with your PKCS#11 provider library:

pkcs11-data --add-provider=pkcs11_provider_library --cmd=tokens

The output will include all available tokens, select the correct token, the id='...' field is the token id to be used in next command.

Run the following command, replacing pkcs11_provider_library with your PKCS#11 provider library, and token_id with the output taken from previous command, please remember to add single quote for token_id.

gpg < keyfile.gpg | gzip | pkcs11-data --add-provider=pkcs11_provider_library --cmd=import --token='token_id' \ --application=DISK --label=MY

Reverting

You can revert and decrypt your filesystems. Boot your new kernel with your new initramfs and the following arguments:

 root=/dev/sda3 initrd_shell=install

You should get a shell after the initramfs has setup itself correctly but before it has mounted any partitions.

Decryption using gpg key

Run the following command:

mkdir /mnt
mount -o ro /dev/sda1 /mnt
dd if=/dev/sda3 bs=64k | \ aespipe -G / -K /mnt/keyfile.gpg -e AES256 -d | \ dd of=/dev/sda3 bs=64k conv=notrunc

Decryption using PKCS#11 cryptographic token

First start PKCS#11 reader support, usually the following commands will do:

for mod in `cat /etc/modules/pkcs11`; do modprobe ${mod}; done
mount -t usbfs usbfs /proc/bus/usb
pcscd

or:

mkdir /var/run/openct
openct-control init

Now perform the actual decryption, don't be alarmed that the key is exported to a file, since this file resides in memory, and there is no swap.

pkcs11-data --add-provider=pkcs11_provider_library --cmd=export --application=DISK --label=MY | \ gunzip > /tmp/key1
dd if=/dev/sda3 bs=64k | \ aespipe -e AES256 -d -p 8 8< /tmp/key1 | \ dd of=/dev/sda3 bs=64k conv=notrunc
dd if=/dev/zero of=/tmp/key1 count=10000 conv=notrunc
rm /tmp/key1

Open issues

There is no known way to protect against sophisticated kernel attach on the unencrypted boot partition that will cause the hash check to succeed but will write your password on a location of the disk.

For now the only way to detect this is to digest the boot partition and compare it to hashes stored on the encrypted file system. This comparison is run during every boot and every resume from suspend.

In order to minimize the access of external people to this partition, consider putting the kernel and initramfs on a USB mass storage device and boot from this device. Combining with PKCS#11 cryptographic token it is the best solution.

initramfs

Busybox

Applets

[
cat
chroot
chvt                                (Optional, splash)
cp
dd
echo
grep
killall
ln
mdev                                (Optional, mdev)
mkdir
mknod
modprobe
mount
sh
stty                                (Optional, gpg)
test
sed
switch_root
tty
rm
rmmod
umount

In case smartcards are used or plug&play is needed for USB storage, additions to genkernel default configuration:

 CONFIG_FEATURE_DD_IBS_OBS # for initial encryption (notrunc)
 CONFIG_FEATURE_MDEV_CONF
 CONFIG_FEATURE_MDEV_EXEC

Initramfs Structure

+-+-/
  +-+- dev
  | +--- fb0                         (Optional, fbsplash && !mdev)
  | +--- fbsplash                    (Optional, fbsplash && !mdev)
  | +--- snapshot                    (Optional, uswsusp && !mdev)
  | +--- sd[a-d][0-4]                (Optional, !mdev)
  | +--- loop?                       (Optional, !mdev)
  +-+- etc
  | +--- suspend.conf                (Optional, uswsusp)
  | +--- pkcs11.conf                 (Optional, PKCS#11)
  | +--- splash                      (Optional, fbsplash)
  | \-+- modules
  |   +--- boot                      (a list of modules required for boot)
  |   +--- pkcs11                    (Optional, a list of modules required for PKCS#11)
  |   \--- suspend2                  (a list of modules required for TuxOnIce resume)
  +-+- lib
  | \-+- modules
  |   \-+- `uname -r`
  |     +-+- block
  |     | \--- loop.ko
  |     \-+- kernel
  |       \-+- crypto
  |         \--- lzf.ko              (If you want to compress your TuxOnIce image)
  +-+- sbin
  | +--- losetup.crypt               (Must be different name than busybox losetup)
  | +--- fbcondecor_helper           (Optional, fbsplash)
  | +--- tuxoniceui_fbsplash         (Optional, TuxOnIce && fbsplash)
  | +--- tuxoniceui_text             (Optional, TuxOnIce && text)
  | \--- resume                      (Optional, uswsusp)
  \-+- usr
    +-+- bin
    | +--- aespipe
    | +--- gpg                       (Optional, no PKCS#11)
    | +--- gpg-agent                 (Optional, no PKCS#11, gnupg>=2.0)
    | +--- aescrypt                  (Optional, no PKCS#11, aescrypt)
    | \--- pkcs11-data               (Optional, PKCS#11)
    +-+- lib
    | \--- readers                   (Optional, pcsc)
    \-+- sbin
      +--- pcscd                     (Optional, pcsc)
      +--- openct-control            (Optional, openct)
      \--- ifdhandler                (Optional, openct)

linuxrc

Code: linuxrc
#!/bin/sh
# Copyright 2005-2011 Alon Bar-Lev <alon.barlev@gmail.com>
# Distributed under the terms of the GNU General Public License v2
#
# The following standard kernel parameters are supported:
#	root		root device
#	rootfstype	root filesystem type (optional, default is auto detection)
#	ro		mount root as read only
#	[0-9]|S		runlevel
#
# The following custom kernel parameters are supported:
#       initrd_kmap=kmap[:font]
#	       Fullpath(inside initramfs /) to kmap and font(optional).
#	initrd_shell=N
#		Interrupts the initramfs and drops to a shell at a specified location
#		(0-none,1-on start,2-after setup,etc..), see the linuxrc for more locations.
#		Special N=resuce, N=install, N=repair
#       initrd_encmode=<mode>
#		<empty>
#			No encryption.
#		loop-aes[:cipher]
#			Enables loop-AES support.
#		dm-crypt
#			Enables DM-Crypt support.
#	initrd_util
#		pkcs11:application:label,label,label
#			use PKCS#11 smartcards.
#		gpgfile|aescrypt|keyfile:device:fstype:file,file,file[:passphrase]
#			use gnupg or aes crypt file located at device.
#			wait for device to be available.
#			device can be 'none'
#		passphrase:id,id,id			(dm-crypt)
#			use passphrases read from the user, each
#			id signify passphrase for a device, id
#			may be the same.
#	initrd_devices
#		Devices for encryption setup.
#	initrd_suspend_mode
#		tuxonice
#		uswsusp
#	initrd_resume_ui
#		auto (default)
#		none
#		fbsplash
#		text
#
#	initrd_readers
#		pcscd
#			Run pcscd.
#		openct
#			Run openct.
#
#	loop-aes specific
#       -----------------
#	initrd_loopstart=N
#		The first loop index (/dev/loopN)
#
#	dm-crypt specific
#       -----------------
#	initrd_dmnames=name,name
#		Logical names for dmsetup
#
# The following module lists are used files at /dev/modules:
#	boot		boot time modules loaded but not removed.
#	tuxonice	TuxOnIce modules.
#	remdev		modules required to access removable media.
#	pkcs11		modules required to access smartcard.
#
# Examples:
#    loop-AES
#	root=/dev/loop5 rootfstype=ext3 ro \
#		video=radeonfb:1400x1050-32@60 acpi_sleep=s3_bios \
#		splash=silent,fadein,theme:livecd-2006.0 quiet console=tty1 \
#		initrd_encmode=loop-aes \
#		initrd_util=gpgfile:/dev/sda1:ext2:/keys/swap.gpg,/keys/root.gpg \
#		initrd_devices=/dev/hda2,/dev/hda3 initrd_loopstart=4 \
#		initrd_suspend_mode=tuxonice resume=swap:/dev/loop4
#
#     DM-Crypt
#	root=/dev/sda3 \
#		video=radeonfb:1400x1050-32@60 acpi_sleep=s3_bios \
#		splash=verbose,theme:livecd-2006.0 quiet console=tty1 \
#		initrd_encmode=dm-crypt \
#		initrd_util=gpgfile:/dev/sdb1:ext2:/keys/swap.gpg,/keys/root.gpg \
#		initrd_devices=/dev/sda2,/dev/sda3 initrd_dmnames=swap,root
#		initrd_suspend_mode=tuxonice resume=swap:/dev/mapper/swap 
#
# History
# -----------------
# 2012.10.10 - Alon Bar-Lev
#	Added support for aescrypt as alternative of gpg
# 2008.05.06 - Alon Bar-Lev
#	Added initrd_readers= parameters.
#	People who used smartcards need to add initrd_readers=pcscd
#	to keep their configuration working.
# 2008.05.03 - Casper Biering
#	Fix typo in keymap.
# 2008.03.23 - Alon Bar-Lev
#	Update to newer busybox that genkernel supports.
# 2007.11.04 - Matyas Tibor
#	gpg --log-file -> gpg --logger-file
# 2007.11.03 - Alon Bar-Lev
#	TuxOnIce changes.
#	initrd_suspend_mode must be specified on command-line.
# 2007.09.07 - Alon Bar-Lev
#	Added resume= parameter support.
#	Make resume device and splash aware.
# 2007.08.17 - Alon Bar-Lev
#	splashutils-0.5 required.
# 2007.07.14 - Alon Bar-Lev
#	Add uswsusp support.
# 2007.06.04 - Alon Bar-Lev
#	Fixup newroot issue.
#	Fixup initrd_shell to have rescue, install, repair.
# 2007.05.06 - Alon Bar-Lev
#	Support a configuration without legacy sysfs
# 2006.10.19 - Federico Zagarzazú, Alon Bar-Lev
#	Added support for dm-crupt
#	Added support for simple files for storing key
#	Switched to busybox's switch_root
# 2006.10.10 - Alon Bar-Lev
#	Fixed gpg handling, many thanks to Pat Double for doing the tests.
# 2006.09.29 - Alon Bar-Lev
#	Merged some of Federico work.
#	Modified format for initrd_util gpgfile, added fstype.
# 2006.09.07 - Federico Zagarzazú
# 	Initial support for dm-crypt (via cryptsetup(luks))
#	Some style changes.
#	Added support to load kmap and font.
#	Added f_echo for fancy init messages.
#	Support verbose splash at bootup.
# 2006.08.25 - Alon Bar-Lev
#	Switched udev into busybox mdev.
#	Moved PKCS#11 application and label into command line.
#	As recommended from Jari Ruusu a seperate key is required for each loop.
# 2006.05.07 - Alon Bar-Lev
#	Added cipher local option.
#	Removed writing the key into memory file.
# 2006.05.01 - Alon Bar-Lev
#	Added gpg static passphrase option.
# 2006.04.30 - Alon Bar-Lev
#	Allow linuxrc.local to supply defaults.
# 2006.04.27 - Alon Bar-Lev
#	Change initrd_util parameter:
#		pkcs11
#		gpgfile:device:file
#	Support for wait for util device if gpgfile.
#	No need to have stty anymore since gpg does it for us.
# 2006.02.01 - Alon Bar-Lev
#	Support of disabling selected stages.
# 2006.01.24 - Alon Bar-Lev
#	Move to fbsplashds in daemon mode,
#	since none-daemon mode does not paint splash currectly.
# 2005.11.24 - Alon Bar-Lev
#	Added udev support.
#	Added PKCS#11 support.
# 2005.06.07 - Alon Bar-Lev
#	Written template from gentoo.org.
#

# don't edit
global_splash_verbose=0
global_mdev_active=0

# colors
color_black='\x1b[30;01m'
color_red='\x1b[31;01m'
color_green='\x1b[32;01m'
color_yellow='\x1b[33;01m'
color_blue='\x1b[34;01m'
color_off='\x1b[0;0m'

#
# The following variables can(and should) be
# overidden by cryptfs
#

# General 
cfg_setup_initramfs=1		# Setup initramfs enviroment.
cfg_install_applets=1		# Install busybox applets at runtime(creates symlinks for all applets
				# that are compiled into busybox).
cfg_start_mdev=1		# Start mdev(Busybox's mini-udev implementation)
cfg_shell_checkpoint=0		# Shell checkpoint (initrd_shell)
cfg_tmp_keys_rep=/tmp/keys	# Where keys are temporary stored
cfg_tmp_keys_stat=/tmp/keys	# Where keys status stored
cfg_kmap=			# Load kmap (initrd_kmap)
cfg_font=			# Load font (initrd_kmap)
cfg_init=/sbin/init		# Init to execute from root device
cfg_newroot=/newroot		# Mountpoint for root
cfg_remmnt=/mnt			# Mountpoint for removable device
cfg_root_device=		# Root device (root)
cfg_root_mode=ro		# Root mount mode (ro)
cfg_root_type=			# Root filesystem type (rootfstype)
cfg_resume_device=		# Resume device.
cfg_hand_root_control=1		# Execute init from root device
cfg_util_type=			# Type of utility (gpgfile,aescrypt,pkcs11,passphrase,keyfile) (initrd_util)
cfg_remdev=			# Device assigned to removable media for gpgfile|aescrypt utility. (initrd_util=gpgfile|aescrypt)
cfg_remdev_fs=			# Device assigned to removable media for gpgfile|aescrypt utility. (initrd_util=gpgfile|aescrypt)
cfg_key_files=			# Files, one for each loop/device, comma separated (initrd_util=gpgfile|aescrypt)
cfg_gpg_pass=			# Static passphrase (initrd_util=gpgfile|aescrypt)
cfg_pkcs11_application=		# PKCS#11 data object application name (initrd_util=pkcs11)
cfg_pkcs11_labels=		# PKCS#11 data object labels, one for each loop, (initrd_util=pkcs11)
cfg_pkcs11_pass=	 	# PKCS#11 PIN (initrd_util=pkcs11)
cfg_passphrase_id=		# Passphrase comma separated ides (initrd_util=passphrase)
cfg_devices=			# Devices to decrypt (initrd_devices)
cfg_suspend_mode=		# Type of suspend/resume to use
cfg_resume_ui=auto		# Type of ui for resume

# loop-AES
cfg_loopaes=0			# 1 == loopAES support enabled (initrd_encmode=loop-aes)
cfg_loopstart=0			# Loop start index (initrd_loopstart)
cfg_cipher="AES256"             # Encryption cipher

# dm-crypt
cfg_dmcrypt=0			# 1 == dm-crypt support enabled (initrd_encmode=dm-crypt)
cfg_dmnames=			# Logical names of DM crypt
cfg_keyfile_files=		# Files(keyfiles), one for each device, comma separated (initrd_util=keyfile)

# readers
cfg_openct=0			# Enable openct
cfg_pcscd=0			# Enable pcscd

if [ -e /linuxrc.local ]; then
	. /linuxrc.local
fi

f_parse_head() {
	local s="${1}"
	local d="${2}"

	echo "${s%%${d}*}"
}

f_parse_remove_head() {
	local s="${1}"
	local d="${2}"
	
	local r="${s#*${d}}"
	if [ "${r}" = "${s}" ]; then
		echo ""
	else
		echo "${r}"
	fi
}

f_echo() {
	local type="${1}"
	local msg="${2}"
	local opts="${3}"
	local eopts
	local colors_on
	local colors_off

	if [ "${cfg_color_msg}" != 0 ]; then
		colors_off="${color_off}"

		case "${type}" in
			err)
				colors_on="${color_red}"
			;;
			inf)
				colors_on="${color_yellow}"
			;;
			msg|*)
				colors_on="${color_green}"
			;;
		esac

		local o
		for o in $(echo "${opts}" | sed 's/,/ /'); do
			case "${o}" in
				nonl)
					eopts="$eopts -n"
				;;
			esac
		done
	fi

	echo ${eopts} -e " ${colors_on}*${color_off} ${msg}"
}

f_modprobe_group() {
	local group="${1}"

	# Add -k on >=busybox-1.8
	[ -f "/etc/modules/${group}" ] && cat "/etc/modules/${group}" | xargs -n1 modprobe > /dev/null 2>&1
}

f_rmmod_group() {
	local group="${1}"

	# use modprobe -r on >=busybox-1.8
	[ -f "/etc/modules/${group}" ] && cat "/etc/modules/${group}" | xargs -n1 rmmod > /dev/null 2>&1
	rmmod -a
}

f_killallwait() {
	local p="${1}"

	while killall -q -3 "${p}"; do
		sleep 1
	done
}

f_die() {
	local message="${1}"

	f_splash_verbose

	f_echo err "${message}"
	exec /bin/sh
}

f_shell_checkpoint() {
	local level="${1}"

	if [ "${cfg_shell_checkpoint}" = "${level}" ]; then
		f_splash_verbose
		exec /bin/sh
	fi
}

f_splash_verbose() {
	[ "${global_splash_verbose}" = 0 ] && chvt 1
}

f_splash_silent() {
	[ "${global_splash_verbose}" = 0 ] && chvt 2
}

f_splash_message() {
	local msg="${1}"
	[ "${global_splash_verbose}" = 0 ] && BOOT_MSG="${msg}" fbcondecor_helper 2 'repaint'
}

f_loadkmap() {
	if [ -n "${cfg_kmap}" ]; then
		if [ -e "${cfg_kmap}" ]; then
			loadkmap < "${cfg_kmap}"
		else
			f_die "Error: keymap \"${cfg_kmap}\" does not exist."
		fi
	fi
	if [ -n "${cfg_font}" ]; then
		if [ -e "${cfg_font}" ]; then
			loadfont < "${cfg_font}"
		else
			f_die "Error: font \"${cfg_font}\" does not exist."
		fi
	fi
}

f_hand_root_control() {
	[ -d "${cfg_newroot}" ] || mkdir "${cfg_newroot}"

	mount -o "${cfg_root_mode}" ${cfg_root_type:+-t "${cfg_root_type}"} \
		"${cfg_root_device}" "${cfg_newroot}" || f_die "Cannot mount root filesystem"

	f_stop_mdev
	umount /proc
	umount /sys

	exec switch_root -c "/dev/console" "${cfg_newroot}" "${cfg_init}" ${init_arg}
}

f_setup_mdev() {
	if [ -x /sbin/mdev ]; then
		/sbin/mdev -s
		echo /sbin/mdev > /proc/sys/kernel/hotplug
		global_mdev_active=1
	fi
}

f_stop_mdev() {
	if [ ${global_mdev_active} != 0 ]; then
		echo > /proc/sys/kernel/hotplug
	fi
}

f_reset_environment() {
	export PATH="${OLDPATH}"
}

f_mount_remdev() {
	f_shell_checkpoint 302
	f_modprobe_group "remdev"

	local first_time=1
	while ! mount -n -o ro ${cfg_remdev_fs:+-t "${cfg_remdev_fs}"} "${cfg_remdev}" "${cfg_remmnt}" > /dev/null 2>&1; do
		if [ ${first_time} != 0 ]; then
			f_echo inf "Please insert removable device ${cfg_remdev}..."
			first_time=0
		fi
		sleep 2
	done
	f_shell_checkpoint 303
}

f_umount_remdev() {
	umount -n "${cfg_remmnt}"
	f_rmmod_group "remdev"
}

f_resume_uswsusp() {
	local args
	local features="$(resume --version | grep FEATURES)"
	[ -n "${cfg_resume_device}" ] && args="${args} --resume_device=${cfg_resume_device}"
	echo "${features}" | grep fbsplash > /dev/null && [ -n "${splash_theme}" -a "${global_splash_verbose}" = 0 ] && [ "${cfg_resume_ui}" = "auto" -o "${cfg_resume_ui}" = "fbsplash" ] && args="${args} --parameter=\"splash=y\""
	eval resume ${args}
}

f_resume_tuxonice() {
	local tuxonice_userui_program="/sys/power/tuxonice/user_interface/program"
	local tuxonice_do_resume="/sys/power/tuxonice/do_resume"
	local tuxonice_resume="/sys/power/tuxonice/resume"

	#
	# Backward compatibility
	#
	if [ -e /proc/suspend2 ]; then
		tuxonice_userui_program="/sys/power/suspend2/user_interface/program"
		tuxonice_do_resume="/sys/power/suspend2/do_resume"
		tuxonice_resume="/sys/power/suspend2/resume2"
	elif [ -e /proc/suspend2 ]; then
		tuxonice_userui_program="/proc/suspend2/userui_program"
		tuxonice_do_resume="/proc/suspend2/do_resume"
		tuxonice_resume="/proc/suspend2/resume2"
	fi

	f_modprobe_group "tuxonice"
	[ -n "${splash_theme}" ] && ln -s "/etc/splash/${splash_theme}" /etc/splash/suspend2
	if [ "${cfg_resume_ui}" != "none" -a "${global_splash_verbose}" = 0 ]; then
		if [ "${cfg_resume_ui}" = "auto" ]; then
			if [ -z "${splash_theme}" ]; then
				if which "suspend2ui_text" > /dev/null 2>&1; then
					which "suspend2ui_text" > "${tuxonice_userui_program}"
				fi
				if which "tuxonice_text" > /dev/null 2>&1; then
					which "tuxonice_text" > "${tuxonice_userui_program}"
				fi
			else
				if which "suspend2ui_fbsplash" > /dev/null 2>&1; then
					which "suspend2ui_fbsplash" > "${tuxonice_userui_program}"
				fi
				if which "tuxonice_fbsplash" > /dev/null 2>&1; then
					which "tuxonice_fbsplash" > "${tuxonice_userui_program}"
				fi
			fi
		else
			if which "suspend2ui_${cfg_resume_ui}"; > /dev/null 2>&1; then
				which "suspend2ui_${cfg_resume_ui}" > "${tuxonice_userui_program}"
			fi
			if which "tuxonice_${cfg_resume_ui}"; > /dev/null 2>&1; then
				which "tuxonice_${cfg_resume_ui}" > "${tuxonice_userui_program}"
			fi
		fi
	fi
	[ -n "${cfg_resume_device}" ] && echo "${cfg_resume_device}" > "${tuxonice_resume}"
	echo > "${tuxonice_do_resume}"
	f_rmmod_group tuxonice
}

f_resume() {
	case "${cfg_suspend_mode}" in
		tuxonice)	f_resume_tuxonice;;
		uswsusp)	f_resume_uswsusp;;
	esac
}

f_keys_read_pkcs11() {

	f_shell_checkpoint 101
	f_modprobe_group "pkcs11"
	if [ "${cfg_pcscd}" != "0" ]; then
		mount -n -t usbfs usbfs /proc/bus/usb
		sleep 3	# usbfs takes time
		pcscd --force-reader-polling
	fi
	if [ "${cfg_openct}" != "0" ]; then
		mkdir -p /var/run/openct
		openct-control init
	fi
	f_shell_checkpoint 102

	local labels="${cfg_pkcs11_labels}"
	local index=0
	local pkcs11_objects
	while [ -n "${labels}" ]; do
		local label

		label=$(f_parse_head "${labels}" ",")
		labels=$(f_parse_remove_head "${labels}" ",")

		pkcs11_objects="${pkcs11_objects} \"--application=${cfg_pkcs11_application}\" \"--label=${label}\" \"--file=${cfg_tmp_keys_rep}/${index}.raw\""

		index=$((${index}+1))
	done

	while ! eval pkcs11-data $(cat /etc/pkcs11.conf) --cmd=export ${pkcs11_objects}; do
		f_echo msg "Please try again."
	done

	local key
	for key in "${cfg_tmp_keys_rep}"/*; do
		gunzip -c "${key}" > $(echo ${key} | sed 's/.raw//').key
	done

	f_shell_checkpoint 103
	if [ "${cfg_pcscd}" != "0" ]; then
		f_killallwait pcscd
		while ! umount -n /proc/bus/usb > /dev/null 2>&1; do
			sleep 1
		done
	fi
	if [ "${cfg_openct}" != "0" ]; then
		openct-control shutdown > /dev/null
	fi
	f_shell_checkpoint 104
	f_rmmod_group "pkcs11"
	f_shell_checkpoint 105
}

f_keys_read_aescrypt() {

	local index=0
	local bad_pass=1
	while [ ${bad_pass} != 0 ]; do
		if [ -z "${cfg_pass}" ]; then
			stty -echo
			echo -n "Passphrase: "
			read cfg_pass
			echo
			stty echo
		fi
		bad_pass=0

		local file
		for file in $(echo "${cfg_key_files}" | sed 's/,/ /g'); do
			if ! [ -f "${cfg_remmnt}/${file}" ]; then
				f_die "Cannot access ${cfg_remdev}:${file}"
			fi

			if ! aescrypt -d -p "${cfg_pass}" \
				-o "${cfg_tmp_keys_rep}/${index}.key" \
				"${cfg_remmnt}/${file}"; then
				bad_pass=1
			else
				index=$((${index}+1))
			fi
		done

		unset cfg_pass

		if [ ${bad_pass} != 0 ]; then
			echo "Please try again." >&2
		fi
	done
}

f_keys_read_gpg() {

	local index=0
	local bad_pass=1
	while [ ${bad_pass} != 0 ]; do
		if [ -z "${cfg_pass}" ]; then
			stty -echo
			echo -n "Passphrase: "
			read cfg_pass
			echo
			stty echo
		fi
		bad_pass=0

		local file
		for file in $(echo "${cfg_key_files}" | sed 's/,/ /g'); do
			if ! [ -f "${cfg_remmnt}/${file}" ]; then
				f_die "Cannot access ${cfg_remdev}:${file}"
			fi

			if ! echo "${cfg_pass}" | \
				gpg --homedir / \
					--batch \
					--logger-file /dev/null \
					--passphrase-fd 0 \
					--decrypt "${cfg_remmnt}/${file}" > \
			 		"${cfg_tmp_keys_rep}/${index}.key"; then

				bad_pass=1
			else
				index=$((${index}+1))
			fi
		done

		unset cfg_pass

		if [ ${bad_pass} != 0 ]; then
			echo "Please try again." >&2
		fi
	done
}

f_keys_read_keyfile() {
	local index=0 file
	for file in $(echo "${cfg_keyfile_files}" | sed 's/,/ /g'); do
		if ! [ -f "${cfg_remmnt}/${file}" ]; then
			f_die "Cannot access ${cfg_remdev}:${file}"
		else
			cp "${cfg_remmnt}/${file}" "${cfg_tmp_keys_rep}/${index}.key"
		fi
		index=$((${index}+1))
	done
}

f_keys_read_passphrase() {
	local first_time=0
	local index=0
	local id

	#
	# If no rejects assume first time
	#
	[ "$(find "${cfg_tmp_keys_stat}")" = "${cfg_tmp_keys_stat}" ] && first_time=1

	for id in $(echo "${cfg_passphrase_id}" | sed 's/,/ /g'); do

		#
		# If first time or rejected
		#
		if [ "${first_time}" != 0 -o -f "${cfg_tmp_keys_stat}/${index}.rejected" ]; then
			
			rm -f "${cfg_tmp_keys_stat}/${index}.rejected" > /dev/null 2>&1

			if [ -f "${cfg_tmp_keys_rep}/passphrase_${id}" ]; then
				cp "${cfg_tmp_keys_rep}/passphrase_${id}" "${cfg_tmp_keys_rep}/${index}.key"
			else
				local password

				stty -echo
				echo -n "Passphrase (${id}): "
				read password
				echo
				stty echo

				echo "${password}" > "${cfg_tmp_keys_rep}/${index}.key"
				echo "${password}" > "${cfg_tmp_keys_rep}/passphrase_${id}"
			fi
		fi

		index=$((${index}+1))
	done
}

f_keys_clean() {
	if [ -d "${cfg_tmp_keys_rep}" ]; then
		local i
		for i in "${cfg_tmp_keys_rep}"/*; do
			dd if=/dev/zero "of=${i}" conv=notrunc bs=1024 count=10 > /dev/null 2>&1
		done
		rm -fr "${cfg_tmp_keys_rep}"
	fi
}

f_keys_read() {

	[ -d "${cfg_tmp_keys_rep}" ] || mkdir -p "${cfg_tmp_keys_rep}"
	[ -d "${cfg_tmp_keys_stat}" ] || mkdir -p "${cfg_tmp_keys_stat}"

	f_shell_checkpoint 201

	case "${cfg_util_type}" in
		pkcs11)
			f_keys_read_pkcs11
		;;
		gpgfile|aescrypt|keyfile)
			f_mount_remdev
			case "${cfg_util_type}" in
				gpgfile) f_keys_read_gpg ;;
				aescrypt) f_keys_read_aescrypt ;;
				keyfile) f_keys_read_keyfile ;;
			esac
			f_umount_remdev
		;;
		passphrase)
			f_keys_read_passphrase
		;;
	esac

	f_shell_checkpoint 202
}

f_opendevices_loopaes() {
	local error=0

	#
	# map loop devices
	#
	local index=0
	local device
	for device in $(echo "${cfg_devices}" | sed 's/,/ /g'); do
		local keyfile="${cfg_tmp_keys_rep}/${index}.key"

		if [ -f "${keyfile}" ]; then
			if ! losetup.crypt -p 0 -e "${cfg_cipher}" \
				"/dev/loop$((${cfg_loopstart}+${index}))" \
				"${device}" < "${keyfile}"; then

				touch "${cfg_tmp_keys_stat}/${index}.rejected"
				f_echo err "Cannot loop ${device}"
				error=1
			fi
		fi

		index="$((${index}+1))"
	done

	return "${error}"
}

f_opendevices_dmcrypt() {
	local error=0

	#
	# map loop devices
	#
	local index=0
	local names="${cfg_dmnames}"
	local device
	for device in $(echo "${cfg_devices}" | sed 's/,/ /g'); do

		local name=$(f_parse_head "${names}" ",")
		names=$(f_parse_remove_head "${names}" ",")
		[ "${device}" == "${cfg_root_device}" ] && cfg_root_device="/dev/mapper/${name}"

		local keyfile="${cfg_tmp_keys_rep}/${index}.key"

		if [ -f "${keyfile}" ]; then

			f_echo msg "Opening ${name}..."

			local gen_prm
			if cryptsetup isLuks "${device}" > /dev/null 2>&1; then
				gen_prm="luksOpen \"${device}\" \"${name}\""
			else
				gen_prm="create \"${name}\" \"${device}\""
			fi

			local stdin_file
			local key_prm
			if [ "${cfg_util_type}" = "passphrase" ]; then
				stdin_file="${keyfile}"
				key_prm=""
			else
				stdin_file="/dev/null"
				key_prm="-d \"${keyfile}\""
			fi

			if ! eval cryptsetup ${key_prm} ${gen_prm} < "${stdin_file}"; then
				touch "${cfg_tmp_keys_stat}/${index}.rejected"
				f_echo err "Failed to decrypt ${device}"
				error=1
			fi
		fi

		index="$((${index}+1))"
	done

	return "${error}"
}

f_opendevices() {
	local error=0

	if [ "${cfg_dmcrypt}" != 0 ]; then
		f_opendevices_dmcrypt || error=1
	elif [ "${cfg_loopaes}" != 0 ]; then
		f_opendevices_loopaes || error=1
	fi

	return "${error}"
}

f_setup_initramfs() {
	umask 0077

	#
	# basic mounts
	#
	if ! [ -f /proc/cmdline ]; then
		mount -t proc none /proc
	fi
	mount -t sysfs /sys /sys
	mount -o remount,rw /

	#
	# create utilities
	#
	if [ "${cfg_install_applets}" != 0 ]; then
		/bin/busybox --install -s
	fi

	[ "$0" != "/init" ] && f_die "initrd is not supported"
	[ -e /linuxrc -a "$0" = "/init" ] && rm /linuxrc

	[ ! -d /tmp ] && mkdir /tmp
	[ ! -d /var/run ] && mkdir -p /var/run
	[ ! -d "${cfg_remmnt}" ] && mkdir -p "${cfg_remmnt}" 

	[ -e /dev/tty ] && rm /dev/tty
	[ -e /dev/tty0 ] && rm /dev/tty0
	ln -s "$(tty)" /dev/tty
	ln -s "$(tty)" /dev/tty0
}

f_setup_environment() {
	#
	# setup path
	#
	OLDPATH="${PATH}"
	export PATH="${PATH}:/sbin:/bin:/usr/sbin:/usr/bin"

	#
	# parse command line
	#
	local x
	for x in $(cat /proc/cmdline); do
		local v="${x#*=}"
		case "${x}" in
			initrd_suspend_mode=*)
				cfg_suspend_mode="${v}"
			;;
			initrd_util=*)
				local t
				t=$(f_parse_head "${v}" ":")
				v=$(f_parse_remove_head "${v}" ":")
				[ -n "${t}" ] && cfg_util_type="${t}"

				case "${cfg_util_type}" in
					"");;
					pkcs11)
						t=$(f_parse_head "${v}" ":")
						v=$(f_parse_remove_head "${v}" ":")
						[ -n "${t}" ] && cfg_pkcs11_application="${t}"
						t=$(f_parse_head "${v}" ":")
						v=$(f_parse_remove_head "${v}" ":")
						[ -n "${t}" ] && cfg_pkcs11_labels="${t}"
						t=$(f_parse_head "${v}" ":")
						v=$(f_parse_remove_head "${v}" ":")
						[ -n "${t}" ] && cfg_pkcs11_pass="${t}"
					;;
					gpgfile|aescrypt|keyfile)
						t=$(f_parse_head "${v}" ":")
						v=$(f_parse_remove_head "${v}" ":")
						[ -n "${t}" ] && cfg_remdev="${t}"
						t=$(f_parse_head "${v}" ":")
						v=$(f_parse_remove_head "${v}" ":")
						[ -n "${t}" ] && cfg_remdev_fs="${t}"
						t=$(f_parse_head "${v}" ":")
						v=$(f_parse_remove_head "${v}" ":")
						[ -n "${t}" ] && cfg_key_files="${t}"
						t=$(f_parse_head "${v}" ":")
						v=$(f_parse_remove_head "${v}" ":")
						[ -n "${t}" ] && cfg_gpg_pass="${t}"
					;;
					passphrase)
						t=$(f_parse_head "${v}" ":")
						v=$(f_parse_remove_head "${v}" ":")
						[ -n "${t}" ] && cfg_passphrase_id="${t}"
					;;
					*)
						f_die "Error: Invalid util argument ${v}"
					;;
				esac
			;;
			initrd_devices=*)
				cfg_devices="${v}"
			;;
			initrd_loopstart=*)
				cfg_loopstart="${v}"
			;;
			initrd_dmnames=*)
				cfg_dmnames="${v}"
			;;
			initrd_shell=*)
				case "${v}" in
					rescue)		v=3;;
					install)	v=5;;
					repair)		v=10;;
				esac
				cfg_shell_checkpoint="${v}"
			;;
			initrd_kmap=*)
				cfg_kmap=$(f_parse_head "${v}" ":")
				local m=$(f_parse_remove_head "${v}" ":")
				[ -n "${m}" ] && cfg_font="${m}"
			;;
			initrd_encmode=*)
				case "${v}" in
					loop-aes)	cfg_loopaes=1;;
					loop-aes:*)
						cfg_loopaes=1
						local c="${v#*:}"
						cfg_cipher="${c}"
						;;
					dmcrypt)	cfg_dmcrypt=1;;
					dm-crypt)	cfg_dmcrypt=1;;
				esac
			;;
			initrd_resume_ui)
				cfg_resume_ui="${v}"
			;;
			initrd_readers=*)
				echo "${v}" | grep "pcscd" > /dev/null && cfg_pcscd=1
				echo "${v}" | grep "openct" > /dev/null && cfg_openct=1
			;;
			splash=*)
				splash_theme=$(echo "${x}" | sed 's/.*theme://' | sed 's/,.*//')
				[ -n "$(echo ${x} | grep verbose)" ] && global_splash_verbose=1
			;;
			root=*)
				cfg_root_device="${v}"
			;;
			rootfstype=*)
				cfg_root_type="${v}"
			;;
			ro)
				cfg_root_mode=ro
			;;
			resume=*)
				cfg_resume_device="${v}"
			;;
			[0123456Ss])
				init_arg="${x}"
			;;
		esac
	done
}

main() {
	[ ${cfg_setup_initramfs} != 0 ] && f_setup_initramfs

	f_setup_environment
	f_shell_checkpoint 1
	f_modprobe_group "boot"
	f_shell_checkpoint 2
	[ ${cfg_start_mdev} != 0 ] && f_setup_mdev
	f_loadkmap
	f_shell_checkpoint 3	# rescue point

	if [ -z "${cfg_root_device}" ]; then
		f_die "Error: Please specify root kernel parameter at next reboot."
	fi
	if [ -z "${cfg_util_type}" -a -n "${cfg_devices}" ]; then
		f_die "Error: Please specify initrd_util kernel parameter at next reboot."
	fi

	if [ "${cfg_dmcrypt}" != 0 ]; then
		if [ -e "/dev/device-mapper" -a ! -e "/dev/mapper/control" ]; then
			[ -d /dev/mapper ] || mkdir /dev/mapper
			ln -s /dev/device-mapper /dev/mapper/control
		fi
	fi

	f_shell_checkpoint 5	# install point
	if [ -n "${cfg_devices}" ]; then
		local success="0"

		while [ "${success}" = 0 ]; do
			f_shell_checkpoint 6
			f_splash_verbose
			f_shell_checkpoint 7
			f_keys_read
			f_splash_silent
			f_shell_checkpoint 8
			f_opendevices && success="1"
			f_shell_checkpoint 9
			f_keys_clean

			if [ "${cfg_util_type}" != "passphrase" -a "${success}" = 0 ]; then
				f_die "Cannot open/decrypt devices"
			fi
		done
	fi

	f_shell_checkpoint 10	# repair point
	f_splash_message "Trying to resume..."
	f_shell_checkpoint 11
	f_resume
	f_shell_checkpoint 12
	f_splash_message "Booting the system..."
	f_shell_checkpoint 13
	f_reset_environment
	f_shell_checkpoint 14
	[ ${cfg_hand_root_control} != 0 ] && f_hand_root_control
	f_shell_checkpoint 15
}

main

genkernel-utils

Gentoo's genkernel is a wonderful tool that ease kernel compilation process. This tool can be extended in order to provide the following features:

  • Replace the default linuxrc with the one provided here, in order to support TuxOnIce/uswsusp, disk encryption and PKCS#11. As genkernel's linuxrc script is not flexible to add additions.
  • Add required files to initramfs in order to support TuxOnIce/uswsusp, disk encryption and optionally PKCS#11.
  • Handle remerge of kernel depended modules when a new kernel is configured.
  • Support two versions of the same kernel (Debug and production), in order to not lock computer when invalid kernel is installed.
  • Don't install kernel symbol file in order to make it harder to reverse debug the bzImage.

app-misc/genkernel-utils is available via overlay at http://github.com/alonbl/alon-barlev-overlay.git .

Edit mygenkernel.conf and use mygenkernel to create your initramfs.

If you like to use genkernel and not mygenkernel, set the followings in /etc/genkernel.conf that suits your installation, so that it will create the correct module groups, add:

File: /etc/genkernel.conf
disk_mod="scsi_mod sd_mod libata libahci ahci"
export AMODULES_BOOT="${disk_mod} loop ext4 evdev"
export AMODULES_SUSPEND2="suspend_core suspend_compress suspend_userui suspend_block_io suspend_swap lzf"
export AMODULES_PKCS11="unix uhci-hcd"
export AMODULES_GPGFILE="usb-storage uhci-hcd"
export AMODULES_CDROM="sr_mod cdrom zlib_inflate isofs"
export AMODULES_MISC="vfat"

Maintainer

Alon Bar-Lev

Authors

Originally written by: Alon Bar-Lev - 2006-11-01

Originally written by: Alon Bar-Lev - 2011-11-22

Edited by: Will Ashford - 2006-02-06

Edited by: Federico Zagarzazú - 2011-09-07


Authors are people who have worked on this document and have made significant changes to its content. If you have edited this article and wish to add yourself to the authors list please read "Who are Authors".